/******************************Module*Header**********************************\ * * ******************* * * D3D SAMPLE CODE * * ******************* * * Module Name: d3dtxt.c * * Content: D3D texture setup * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "glint.h" #include "dma.h" #include "chroma.h" #include "tag.h" //----------------------------------------------------------------------------- // Some variables shared through this module (not globals) // These are set up in _D3DChangeTextureP3RX. // P3 has 16 texture map base address slots, numbered 0 to 15 hence ... #define P3_TEX_MAP_MAX_LEVEL 15 typedef struct { DWORD dwTex0MipBase; DWORD dwTex0MipMax; DWORD dwTex0ActMaxLevel; // Controlled by D3DTSS_MAXMIPLEVEL, default 0 DWORD dwTex1MipBase; DWORD dwTex1MipMax; DWORD dwTex1ActMaxLevel; // Same for Texture 1 } P3_MIP_BASES; #define TSSTATE(stageno,argno) \ ( pContext->TextureStageState[stageno].m_dwVal[argno] ) #define TSSTATESELECT(stageno,argno) \ ( TSSTATE(stageno,argno) & D3DTA_SELECTMASK ) #define TSSTATEINVMASK(stageno,argno) \ ( TSSTATE(stageno,argno) & ~D3DTA_COMPLEMENT ) #define TSSTATEALPHA(stageno,argno) \ ( TSSTATE(stageno,argno) & ~D3DTA_ALPHAREPLICATE ) #define IS_ALPHA_ARG 1 #define IS_COLOR_ARG 0 #if DX8_DDI //----------------------------------------------------------------------------- // // __TXT_MapDX8toDX6TexFilter // // map DX8 enums into DX6(&7) texture filtering enums // //----------------------------------------------------------------------------- DWORD __TXT_MapDX8toDX6TexFilter( DWORD dwStageState, DWORD dwValue ) { switch (dwStageState) { case D3DTSS_MAGFILTER: switch (dwValue) { case D3DTEXF_POINT : return D3DTFG_POINT; case D3DTEXF_LINEAR : return D3DTFG_LINEAR; case D3DTEXF_FLATCUBIC : return D3DTFG_FLATCUBIC; case D3DTEXF_GAUSSIANCUBIC : return D3DTFG_GAUSSIANCUBIC; case D3DTEXF_ANISOTROPIC : return D3DTFG_ANISOTROPIC; } break; case D3DTSS_MINFILTER: switch (dwValue) { case D3DTEXF_POINT : return D3DTFN_POINT; case D3DTEXF_LINEAR : return D3DTFN_LINEAR; case D3DTEXF_FLATCUBIC : return D3DTFN_ANISOTROPIC; } break; case D3DTSS_MIPFILTER: switch (dwValue) { case D3DTEXF_NONE : return D3DTFP_NONE; case D3DTEXF_POINT : return D3DTFP_POINT; case D3DTEXF_LINEAR : return D3DTFP_LINEAR; } break; } return 0x0; } // __TXT_MapDX8toDX6TexFilter #endif // DX8_DDI //----------------------------------------------------------------------------- // // _D3D_TXT_ParseTextureStageStates // // Parse the texture state stages command token and update our context state // // Note : bTranslateDX8FilterValueToDX6 will only be FALSE when it is called // from _D3D_SB_ExecuteStateSet if that state set's value has been // changes by _D3D_SB_CaptureStateSet (Basically DX6 filter values are // stored in the state set directly, thus no need to translate them.) // //----------------------------------------------------------------------------- void _D3D_TXT_ParseTextureStageStates( P3_D3DCONTEXT* pContext, D3DHAL_DP2TEXTURESTAGESTATE *pState, DWORD dwCount, BOOL bTranslateDX8FilterValueToDX6) { DWORD i; DWORD dwStage, dwState, dwValue; DISPDBG((DBGLVL,"*** In _D3D_TXT_ParseTextureStageStates")); for (i = 0; i < dwCount; i++, pState++) { dwStage = pState->wStage; dwState = pState->TSState; dwValue = pState->dwValue; // check for range before continuing if ( (dwStage < D3DHAL_TSS_MAXSTAGES) && (dwState < D3DTSS_MAX)) { #if DX7_D3DSTATEBLOCKS if (pContext->bStateRecMode) { // Record this texture stage state into the //current state set being recorded _D3D_SB_RecordStateSetTSS(pContext, dwStage, dwState, dwValue); // skip any further processing and go to the next TSS continue; } #endif //DX7_D3DSTATEBLOCKS #if DX7_TEXMANAGEMENT if ((D3DTSS_TEXTUREMAP == dwState) && (0 != dwValue)) { P3_SURF_INTERNAL* pTexture; pTexture = GetSurfaceFromHandle(pContext, dwValue); // If this is a valid managed texture if (CHECK_SURF_INTERNAL_AND_DDSURFACE_VALIDITY(pTexture) && (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) { // Update stats _D3D_TM_STAT_Inc_NumTexturesUsed(pContext); _D3D_TM_STAT_Inc_NumUsedTexInVid(pContext, pTexture); } } #endif // DX7_TEXMANAGEMENT DISPDBG((DBGLVL," Stage = %d, State = 0x%x, Value = 0x%x", dwStage, dwState, dwValue)); // Special case a texture handle change and the address update switch ( dwState ) { case D3DTSS_TEXTUREMAP: DISPDBG((DBGLVL," D3DTSS_TEXTUREMAP: Handle=0x%x", dwValue)); if (pContext->TextureStageState[dwStage].m_dwVal[dwState] != dwValue) { pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); } break; case D3DTSS_ADDRESS: DISPDBG((DBGLVL," D3DTSS_ADDRESS")); // map single set ADDRESS to both U and V controls pContext->TextureStageState[dwStage].m_dwVal[D3DTSS_ADDRESSU] = pContext->TextureStageState[dwStage].m_dwVal[D3DTSS_ADDRESSV] = pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); break; case D3DTSS_COLOROP: case D3DTSS_ALPHAOP: case D3DTSS_COLORARG1: case D3DTSS_COLORARG2: case D3DTSS_ALPHAARG1: case D3DTSS_ALPHAARG2: pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; pContext->Flags &= ~SURFACE_MODULATE; DIRTY_TEXTURESTAGEBLEND(pContext); DIRTY_TEXTURE(pContext); break; case D3DTSS_TEXCOORDINDEX: DISPDBG((DBGLVL," D3DTSS_TEXCOORDINDEX: stage %d, value %d", dwStage, dwValue )); pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; // Update the offsets to the texture coordinates // NOTE: The texture coordinate index can contain various flags // in addition to the actual value. These flags are: // D3DTSS_TCI_PASSTHRU (default - resolves to zero) // D3DTSS_TCI_CAMERASPACENORMAL // D3DTSS_TCI_CAMERASPACEPOSITION // D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR // and are used for texture coordinate generation. // // These flags are not relevant when considering the offset of // texture coordinates in the vertex stream. These flags appear // in the high word of the index value DWORD. Only the low word // contains actual index data. Therefore, we will mask of the // low word when looking up the offset table for this texture // coordinate index. pContext->FVFData.dwTexOffset[dwStage] = pContext->FVFData.dwTexCoordOffset[dwValue & 0x0000FFFFul]; DIRTY_TEXTURE(pContext); break; case D3DTSS_MIPMAPLODBIAS: DISPDBG((DBGLVL," D3DTSS_MIPMAPLODBIAS: stage %d, value %d", dwStage, dwValue )); pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); break; case D3DTSS_MAGFILTER: case D3DTSS_MINFILTER: case D3DTSS_MIPFILTER: #if DX8_DDI if((!IS_DX7_OR_EARLIER_APP(pContext)) && bTranslateDX8FilterValueToDX6) { // filtering values are somewhat different in DX8 // so translate them before using them. dwValue = __TXT_MapDX8toDX6TexFilter(dwState, dwValue); } #endif DX8_DDI pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); break; case D3DTSS_MAXMIPLEVEL: DISPDBG((DBGLVL," D3DTSS_MAXMIPLEVEL: stage %d, value %d", dwStage, dwValue )); pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); break; default: pContext->TextureStageState[dwStage].m_dwVal[dwState] = dwValue; DIRTY_TEXTURE(pContext); break; } // switch } else { DISPDBG((WRNLVL,"Out of range stage/state %d %d",dwStage,dwState)); }// if } // for } // _D3D_TXT_ParseTextureStageStates //----------------------------------------------------------------------------- // // SETARG // // dwArg = the argument. // num = argument number (1 or 2). // bIsAlpha = TRUE if this is the alpha channel, // FALSE if this is the colour channel. // iD3DStage = D3D stage number. // iChipStageNo = chip stage number (should only be 0 or 1 on P3) // //----------------------------------------------------------------------------- void SETARG( P3_D3DCONTEXT *pContext, struct TextureCompositeRGBAMode *pMode, DWORD dwArg, DWORD num, BOOL bIsAlpha, DWORD iD3DStage, DWORD iChipStageNo) { BOOL bSetArgToggleInvert; DWORD dwArgValue, dwInvertArgValue; BOOL bArgValueAssigned = FALSE, bInvertArgValueAssigned; bSetArgToggleInvert = FALSE; switch (dwArg & D3DTA_SELECTMASK) { case D3DTA_TEXTURE: if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { dwArgValue = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_T0A : P3RX_TEXCOMP_T1A; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," Tex%dA", pContext->iStageTex[iD3DStage] )); } else { dwArgValue = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_T0C : P3RX_TEXCOMP_T1C; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," Tex%dC", pContext->iStageTex[iD3DStage] )); } break; case D3DTA_DIFFUSE: if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { dwArgValue = P3RX_TEXCOMP_CA; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," DiffA" )); } else { dwArgValue = P3RX_TEXCOMP_CC; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," DiffC" )); } break; case D3DTA_CURRENT: // Cope with a "current" argument in texcomp0 if ( iChipStageNo == 0 ) { // This is texcomp0 if ( pContext->bBumpmapEnabled ) { // Emboss bumpmapping is on if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { // This is the alpha-channel, where the D3D stages 0 & 1 // should have put the heightfield info. dwArgValue = P3RX_TEXCOMP_HEIGHTA; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," BumpA" )); // And cope with inverted bumpmaps. bSetArgToggleInvert = pContext->bBumpmapInverted; } else { // Colour channel - this will hold the diffuse colour. dwArgValue = P3RX_TEXCOMP_CC; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," DiffC" )); } } else { // Embossing is off - default to diffuse. if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { dwArgValue = P3RX_TEXCOMP_CA; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," DiffA" )); } else { dwArgValue = P3RX_TEXCOMP_CC; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," DiffC" )); } } } else { // texcomp stage 1 if ( pContext->bStage0DotProduct ) { // Need to take the dotproduct sum result, // even in the alpha channel, according to the docs. dwArgValue = P3RX_TEXCOMP_SUM; bArgValueAssigned = TRUE; } else { if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { dwArgValue = P3RX_TEXCOMP_OA; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," CurrA" )); } else { dwArgValue = P3RX_TEXCOMP_OC; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," CurrC" )); } } } break; case D3DTA_TFACTOR: if ((dwArg & D3DTA_ALPHAREPLICATE) || (bIsAlpha)) { dwArgValue = P3RX_TEXCOMP_FA; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," TfactA" )); } else { dwArgValue = P3RX_TEXCOMP_FC; bArgValueAssigned = TRUE; DISPDBG((DBGLVL," TfactC" )); } break; default: if ( bIsAlpha ) { DISPDBG((ERRLVL,"ERROR: Invalid AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_ALPHA_ARG ); } else { DISPDBG((ERRLVL,"ERROR: Invalid ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_COLOR_ARG ); } break; } // switch if ( ( (dwArg & D3DTA_COMPLEMENT) == 0 ) == bSetArgToggleInvert ) { dwInvertArgValue= __PERMEDIA_ENABLE; bInvertArgValueAssigned = TRUE; DISPDBG((DBGLVL," inverted" )); } else { dwInvertArgValue = __PERMEDIA_DISABLE; bInvertArgValueAssigned = TRUE; } // Set up the I input for MODULATExxx_ADDxxx modes. if ( num == 1 ) { switch (dwArg & D3DTA_SELECTMASK) { case D3DTA_TEXTURE: pMode->I = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_I_T0A : P3RX_TEXCOMP_I_T1A; DISPDBG((DBGLVL," I: Tex%dA", pContext->iStageTex[iD3DStage] )); break; case D3DTA_DIFFUSE: pMode->I = P3RX_TEXCOMP_I_CA; DISPDBG((DBGLVL," I: DiffA" )); break; case D3DTA_CURRENT: if ( iChipStageNo == 0 ) { if ( pContext->bBumpmapEnabled ) { // Bumpmapping mode. pMode->I = P3RX_TEXCOMP_I_HA; DISPDBG((DBGLVL," I: BumpA" )); } else { pMode->I = P3RX_TEXCOMP_I_CA; DISPDBG((DBGLVL," I: DiffA" )); } } else { pMode->I = P3RX_TEXCOMP_I_OA; DISPDBG((DBGLVL," I: CurrA" )); } break; case D3DTA_TFACTOR: pMode->I = P3RX_TEXCOMP_I_FA; DISPDBG((DBGLVL," I: TfactA" )); break; default: if ( bIsAlpha ) { DISPDBG((ERRLVL,"ERROR: Invalid AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_ALPHA_ARG ); } else { DISPDBG((ERRLVL,"ERROR: Invalid ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_COLOR_ARG ); } break; } // switch if ( ( (dwArg & D3DTA_COMPLEMENT) == 0 ) == bSetArgToggleInvert ) { pMode->InvertI = __PERMEDIA_ENABLE; } else { pMode->InvertI = __PERMEDIA_DISABLE; } } // if ( num == 1 ) if (bArgValueAssigned) { if (num == 1) { pMode->Arg1 = dwArgValue; } else { pMode->Arg2 = dwArgValue; } } if (bInvertArgValueAssigned) { if (num == 1) { pMode->InvertArg1 = dwInvertArgValue; } else { pMode->InvertArg2 = dwInvertArgValue; } } } // SETARG //----------------------------------------------------------------------------- // // SETTAARG_ALPHA // // TexApp blend mode for the alpha channel. // //----------------------------------------------------------------------------- void SETTAARG_ALPHA( P3_D3DCONTEXT *pContext, struct TextureApplicationMode *pMode, DWORD dwArg, DWORD num) { switch (dwArg & D3DTA_SELECTMASK) { case D3DTA_TEXTURE: DISPDBG((ERRLVL,"ERROR: Invalid TA AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_ARG_HERE ); break; case D3DTA_DIFFUSE: if ( (num) == 1 ) { pMode->AlphaA = P3RX_TEXAPP_A_CA; DISPDBG((DBGLVL," DiffA" )); } else { DISPDBG((ERRLVL,"ERROR: Invalid TA AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_ARG_HERE ); } break; case D3DTA_CURRENT: if ( (num) == 2 ) { pMode->AlphaB = P3RX_TEXAPP_B_TA; DISPDBG((DBGLVL," CurrA" )); } else { // Can't do DISPDBG((ERRLVL,"ERROR: Invalid TA AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_ARG_HERE ); } break; case D3DTA_TFACTOR: if ( (num) == 1 ) { pMode->AlphaA = P3RX_TEXAPP_A_KA; DISPDBG((DBGLVL," TfactA" )); } else { if ( (num) != 2) { DISPDBG((ERRLVL," ** SETTAARG: num must be 1 or 2")); } pMode->AlphaB = P3RX_TEXAPP_B_KA; DISPDBG((DBGLVL," TfactA" )); } break; default: DISPDBG((ERRLVL,"ERROR: Unknown TA AlphaArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_ALPHA_ARG ); break; } if ( (dwArg & D3DTA_COMPLEMENT) != 0 ) { // Can't do COMPLEMENT on the args. DISPDBG((ERRLVL,"ERROR: Can't do COMPLEMENT in TA unit")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_ARG_HERE ); } } // SETTAARG_ALPHA //----------------------------------------------------------------------------- // // SETTAARG_COLOR // // TexApp blend mode for the color channel. // //----------------------------------------------------------------------------- void SETTAARG_COLOR( P3_D3DCONTEXT *pContext, struct TextureApplicationMode *pMode, DWORD dwArg, DWORD num) { switch (dwArg & D3DTA_SELECTMASK) { DISPDBG((ERRLVL,"ERROR: Invalid TA ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_ARG_HERE ); break; case D3DTA_DIFFUSE: if ( (num) == 1 ) { if ( (dwArg & D3DTA_ALPHAREPLICATE) != 0 ) { pMode->ColorA = P3RX_TEXAPP_A_CA; DISPDBG((DBGLVL," DiffA" )); } else { pMode->ColorA = P3RX_TEXAPP_A_CC; DISPDBG((DBGLVL," DiffC" )); } // Set up the I input for MODULATExxx_ADDxxx modes pMode->ColorI = P3RX_TEXAPP_I_CA; DISPDBG((DBGLVL," I: DiffA" )); } else { DISPDBG((ERRLVL,"ERROR: Invalid TA ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_ARG_HERE ); } break; case D3DTA_CURRENT: if ( (num) == 2 ) { if (dwArg & D3DTA_ALPHAREPLICATE) { pMode->ColorB = P3RX_TEXAPP_B_TA; DISPDBG((DBGLVL," CurrA" )); } else { pMode->ColorB = P3RX_TEXAPP_B_TC; DISPDBG((DBGLVL," CurrC" )); } } else { // Can't do. DISPDBG((ERRLVL,"ERROR: Invalid TA ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_ARG_HERE ); } break; case D3DTA_TFACTOR: if ( (num) == 1 ) { if ( (dwArg & D3DTA_ALPHAREPLICATE) != 0 ) { pMode->ColorA = P3RX_TEXAPP_A_KA; DISPDBG((DBGLVL," TfactA" )); } else { pMode->ColorA = P3RX_TEXAPP_A_KC; DISPDBG((DBGLVL," TfactC" )); } // Set up the I input for MODULATExxx_ADDxxx modes. pMode->ColorI = P3RX_TEXAPP_I_KA; DISPDBG((DBGLVL," I: TfactA" )); } else { if ( (num) != 2) { DISPDBG((ERRLVL," ** SETTAARG: num must be 1 or 2")); } if (dwArg & D3DTA_ALPHAREPLICATE) { pMode->ColorB = P3RX_TEXAPP_B_KA; DISPDBG((DBGLVL," TfactA" )); } else { pMode->ColorB = P3RX_TEXAPP_B_KC; DISPDBG((DBGLVL," TfactC" )); } } break; default: DISPDBG((ERRLVL,"ERROR: Unknown TA ColorArgument")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_COLOR_ARG ); break; } if ( (dwArg & D3DTA_COMPLEMENT) != 0 ) { // Can't do COMPLEMENT on the args. DISPDBG((ERRLVL,"ERROR: Can't do COMPLEMENT in TA unit")); SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_ARG_HERE ); } } // SETTAARG_COLOR //----------------------------------------------------------------------------- // // SETOP // // Note - SETOP must be done after SETARG for DISABLE to work. // //----------------------------------------------------------------------------- void SETOP( P3_D3DCONTEXT *pContext, struct TextureCompositeRGBAMode* pMode, DWORD dwOperation, DWORD iD3DStage, DWORD iChipStageNo, BOOL bIsAlpha) { pMode->Enable = __PERMEDIA_ENABLE; pMode->Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pMode->InvertI = __PERMEDIA_DISABLE; pMode->A = P3RX_TEXCOMP_ARG1; pMode->B = P3RX_TEXCOMP_ARG2; switch (dwOperation) { case D3DTOP_DISABLE: if ( bIsAlpha ) { // Just pass through "current" pMode->Operation = P3RX_TEXCOMP_OPERATION_PASS_A; if ( iChipStageNo == 0 ) { if ( pContext->bBumpmapEnabled ) { // Embossing is on. pMode->Arg1 = P3RX_TEXCOMP_HEIGHTA; } else { // Current = diffuse in stage0. pMode->Arg1 = P3RX_TEXCOMP_CA; } } else { if ( pContext->bStage0DotProduct ) { pMode->Arg1 = P3RX_TEXCOMP_SUM; } else { pMode->Arg1 = P3RX_TEXCOMP_OA; } } } else { DISPDBG((ERRLVL,"SETOP: Colour op was DISABLE" " - should never have got here.")); } break; case D3DTOP_SELECTARG1: DISPDBG((DBGLVL," D3DTOP_SELECTARG1")); pMode->Operation = P3RX_TEXCOMP_OPERATION_PASS_A; break; case D3DTOP_SELECTARG2: DISPDBG((DBGLVL," D3DTOP_SELECTARG2")); pMode->Operation = P3RX_TEXCOMP_OPERATION_PASS_A; // No Pass B pMode->A = P3RX_TEXCOMP_ARG2; break; case D3DTOP_MODULATE: DISPDBG((DBGLVL," D3DTOP_MODULATE")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; break; case D3DTOP_MODULATE2X: DISPDBG((DBGLVL," D3DTOP_MODULATE2X")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; pMode->Scale = P3RX_TEXCOMP_OPERATION_SCALE_TWO; break; case D3DTOP_MODULATE4X: DISPDBG((DBGLVL," D3DTOP_MODULATE4X")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; pMode->Scale = P3RX_TEXCOMP_OPERATION_SCALE_FOUR; break; case D3DTOP_ADD: DISPDBG((DBGLVL," D3DTOP_ADD")); pMode->Operation = P3RX_TEXCOMP_OPERATION_ADD_AB; break; case D3DTOP_ADDSIGNED: DISPDBG((DBGLVL," D3DTOP_ADDSIGNED")); pMode->Operation = P3RX_TEXCOMP_OPERATION_ADDSIGNED_AB; break; case D3DTOP_ADDSIGNED2X: DISPDBG((DBGLVL," D3DTOP_ADDSIGNED2X")); pMode->Operation = P3RX_TEXCOMP_OPERATION_ADDSIGNED_AB; pMode->Scale = P3RX_TEXCOMP_OPERATION_SCALE_TWO; break; case D3DTOP_SUBTRACT: DISPDBG((DBGLVL," D3DTOP_SUBTRACT")); pMode->Operation = P3RX_TEXCOMP_OPERATION_SUBTRACT_AB; break; case D3DTOP_ADDSMOOTH: DISPDBG((DBGLVL," D3DTOP_ADDSMOOTH")); pMode->Operation = P3RX_TEXCOMP_OPERATION_ADD_AB_SUB_MODULATE_AB; break; case D3DTOP_BLENDDIFFUSEALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDDIFFUSEALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_LERP_ABI; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->I = P3RX_TEXCOMP_I_CA; break; case D3DTOP_BLENDTEXTUREALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDTEXTUREALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_LERP_ABI; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->I = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_I_T0A : P3RX_TEXCOMP_I_T1A; DISPDBG((DBGLVL," alpha: Tex%dA", pContext->iStageTex[iD3DStage] )); break; case D3DTOP_BLENDFACTORALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDFACTORALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_LERP_ABI; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->I = P3RX_TEXCOMP_I_FA; break; case D3DTOP_BLENDCURRENTALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDCURRENTALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_LERP_ABI; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->I = P3RX_TEXCOMP_I_OA; break; case D3DTOP_BLENDTEXTUREALPHAPM: DISPDBG((DBGLVL," D3DTOP_BLENDTEXTUREALPHAPM")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AI_ADD_B; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->I = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_I_T0A : P3RX_TEXCOMP_I_T1A; DISPDBG((DBGLVL," alpha: Tex%dA", pContext->iStageTex[iD3DStage] )); pMode->InvertI = __PERMEDIA_ENABLE; break; case D3DTOP_PREMODULATE: DISPDBG((DBGLVL," D3DTOP_PREMODULATE")); // result = current_tex * next_stage_tex - ignore arguments. if ( ( pContext->iStageTex[iD3DStage] != -1 ) && ( pContext->iStageTex[iD3DStage+1] != -1 ) ) { pMode->Arg1 = ( pContext->iStageTex[iD3DStage] == 0 ) ? P3RX_TEXCOMP_T0C : P3RX_TEXCOMP_T1C; DISPDBG((DBGLVL," Arg1: Tex%d", pContext->iStageTex[iD3DStage] )); pMode->Arg2 = ( pContext->iStageTex[iD3DStage+1] == 0 ) ? P3RX_TEXCOMP_T0C : P3RX_TEXCOMP_T1C; DISPDBG((DBGLVL," Arg2: Tex%d", pContext->iStageTex[iD3DStage+1] )); } else { // Not enough textures DISPDBG((ERRLVL,"** SETOP: PREMODULATE didn't have two " "textures to play with.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_OP_HERE ); } else { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_OP_HERE ); } pMode->Arg1 = P3RX_TEXCOMP_CC; pMode->Arg2 = P3RX_TEXCOMP_CC; } pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; break; case D3DTOP_MODULATEALPHA_ADDCOLOR: DISPDBG((DBGLVL," D3DTOP_MODULATEALPHA_ADDCOLOR")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AI_ADD_B; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; // I input set up by SETARG break; case D3DTOP_MODULATECOLOR_ADDALPHA: DISPDBG((DBGLVL," D3DTOP_MODULATECOLOR_ADDALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB_ADD_I; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; // I input set up by SETARG break; case D3DTOP_MODULATEINVALPHA_ADDCOLOR: DISPDBG((DBGLVL," D3DTOP_MODULATEINVALPHA_ADDCOLOR")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AI_ADD_B; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; // I input set up by SETARG pMode->InvertI = 1 - pMode->InvertI; break; case D3DTOP_MODULATEINVCOLOR_ADDALPHA: DISPDBG((DBGLVL," D3DTOP_MODULATEINVCOLOR_ADDALPHA")); pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB_ADD_I; pMode->A = P3RX_TEXCOMP_ARG2; pMode->B = P3RX_TEXCOMP_ARG1; pMode->InvertArg1 = 1 - pMode->InvertArg1; // I input set up by SETARG break; case D3DTOP_DOTPRODUCT3: DISPDBG((DBGLVL," D3DTOP_DOTPRODUCT3")); if ( iChipStageNo == 0 ) { pMode->Operation = P3RX_TEXCOMP_OPERATION_MODULATE_SIGNED_AB; // Signal that the special input to stage 1 is needed. pContext->bStage0DotProduct = TRUE; } else { // Can't do stage 1 dotproduct. Fail. DISPDBG((ERRLVL,"** SETOP: Can't do DOTPRODUCT3 in second stage.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_OP_HERE ); } else { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_OP_HERE ); } pMode->Operation = P3RX_TEXCOMP_OPERATION_PASS_A; } break; case D3DTOP_BUMPENVMAP: case D3DTOP_BUMPENVMAPLUMINANCE: DISPDBG((ERRLVL,"** SETOP: Unsupported operation.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_ALPHA_OP ); } else { SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_COLOR_OP ); } break; default: DISPDBG((ERRLVL,"** SETOP: Unknown operation.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_ALPHA_OP ); } else { SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_COLOR_OP ); } break; } // switch } // SETOP //----------------------------------------------------------------------------- // // SETTAOP // // Must be done after SETTAARG to set up DISABLE properly. // //----------------------------------------------------------------------------- void SETTAOP( P3_D3DCONTEXT *pContext, struct TextureApplicationMode* pMode, DWORD dwOperand, BOOL bIsAlpha, DWORD iD3DStage, DWORD iChipStageNo) { DWORD dwInvertI, dwOperation, dwI = 0, dwA = 0; BOOL bOperation = FALSE, bI = FALSE, bA = FALSE; pMode->Enable = __PERMEDIA_ENABLE; dwInvertI = __PERMEDIA_DISABLE; switch (dwOperand) { case D3DTOP_DISABLE: if ( bIsAlpha ) { // Just pass through "current" dwOperation = P3RX_TEXAPP_OPERATION_PASS_A; bOperation = TRUE; dwA = P3RX_TEXAPP_A_CA; bA = TRUE; } else { DISPDBG((ERRLVL,"SETTAOP: Colour op was DISABLE " " should never have got here.")); } break; case D3DTOP_SELECTARG1: DISPDBG((DBGLVL," D3DTOP_SELECTARG1")); dwOperation = P3RX_TEXAPP_OPERATION_PASS_A; bOperation = TRUE; break; case D3DTOP_SELECTARG2: DISPDBG((DBGLVL," D3DTOP_SELECTARG2")); dwOperation = P3RX_TEXAPP_OPERATION_PASS_B; bOperation = TRUE; break; case D3DTOP_MODULATE: DISPDBG((DBGLVL," D3DTOP_MODULATE")); dwOperation = P3RX_TEXAPP_OPERATION_MODULATE_AB; bOperation = TRUE; break; case D3DTOP_ADD: DISPDBG((DBGLVL," D3DTOP_ADD")); dwOperation = P3RX_TEXAPP_OPERATION_ADD_AB; bOperation = TRUE; break; case D3DTOP_BLENDDIFFUSEALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDDIFFUSEALPHA")); dwOperation = P3RX_TEXAPP_OPERATION_LERP_ABI; bOperation = TRUE; dwInvertI = 1 - dwInvertI; dwI = P3RX_TEXAPP_I_CA; bI = TRUE; break; case D3DTOP_BLENDFACTORALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDFACTORALPHA")); dwOperation = P3RX_TEXAPP_OPERATION_LERP_ABI; bOperation = TRUE; dwInvertI = 1 - dwInvertI; dwI = P3RX_TEXAPP_I_KA; bI = TRUE; break; case D3DTOP_BLENDCURRENTALPHA: DISPDBG((DBGLVL," D3DTOP_BLENDCURRENTALPHA")); dwOperation = P3RX_TEXAPP_OPERATION_LERP_ABI; bOperation = TRUE; dwInvertI = 1 - dwInvertI; dwI = P3RX_TEXAPP_I_TA; bI = TRUE; break; case D3DTOP_MODULATEALPHA_ADDCOLOR: DISPDBG((DBGLVL," D3DTOP_MODULATEALPHA_ADDCOLOR")); dwOperation = P3RX_TEXAPP_OPERATION_MODULATE_BI_ADD_A; bOperation = TRUE; // I should have been set up by SETTAARG. // dwI = P3RX_TEXAPP_I_TA; break; case D3DTOP_MODULATECOLOR_ADDALPHA: DISPDBG((DBGLVL," D3DTOP_MODULATECOLOR_ADDALPHA")); dwOperation = P3RX_TEXAPP_OPERATION_MODULATE_AB_ADD_I; bOperation = TRUE; // I should have been set up by SETTAARG. // dwI = P3RX_TEXAPP_I_TA; break; case D3DTOP_MODULATEINVALPHA_ADDCOLOR: DISPDBG((DBGLVL," D3DTOP_MODULATEINVALPHA_ADDCOLOR")); dwOperation = P3RX_TEXAPP_OPERATION_MODULATE_BI_ADD_A; bOperation = TRUE; dwInvertI = 1 - dwInvertI; // I should have been set up by SETTAARG. // dwI = P3RX_TEXAPP_I_TA; break; case D3DTOP_MODULATE2X: case D3DTOP_MODULATE4X: case D3DTOP_ADDSIGNED: case D3DTOP_ADDSIGNED2X: case D3DTOP_SUBTRACT: case D3DTOP_ADDSMOOTH: case D3DTOP_BLENDTEXTUREALPHA: case D3DTOP_BLENDTEXTUREALPHAPM: case D3DTOP_PREMODULATE: case D3DTOP_MODULATEINVCOLOR_ADDALPHA: case D3DTOP_DOTPRODUCT3: DISPDBG((ERRLVL,"** SETTAOP: Unsupported operation in TA unit.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_ALPHA_OP_HERE ); } else { SET_BLEND_ERROR ( pContext, BSF_CANT_USE_COLOR_OP_HERE ); } break; case D3DTOP_BUMPENVMAP: case D3DTOP_BUMPENVMAPLUMINANCE: DISPDBG((ERRLVL,"** SETTAOP: Unsupported operation.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_ALPHA_OP ); } else { SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_COLOR_OP ); } break; default: // What is this?. //azn DISPDBG((ERRLVL,"** SETTAOP: Unknown operation.")); if ( bIsAlpha ) { SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_ALPHA_OP ); } else { SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_COLOR_OP ); } break; } if(bIsAlpha) { pMode->AlphaInvertI = dwInvertI; if (bOperation) { pMode->AlphaOperation = dwOperation; } if (bI) { pMode->AlphaI = dwI; } if (bA) { pMode->AlphaA = dwA; } } else { pMode->ColorInvertI = dwInvertI; if (bOperation) { pMode->ColorOperation = dwOperation; } if (bI) { pMode->ColorI = dwI; } if (bA) { pMode->ColorA = dwA; } } } // SETTAOP //----------------------------------------------------------------------------- // // _D3DDisplayWholeTSSPipe // // Dumps the whole TSS pipe state out to the debug stream. // Also dumps fog, specular and alpha-blend state out. // //----------------------------------------------------------------------------- void _D3DDisplayWholeTSSPipe ( P3_D3DCONTEXT* pContext, int iDebugNumber ) { #if DBG int i; char *pszTemp, *pszTempPre, *pszTempPost; char *pszOp; char *pszArg1Pre, *pszArg1, *pszArg1Post; char *pszArg2Pre, *pszArg2, *pszArg2Post; char *pszSrc, *pszDest; P3_SURF_INTERNAL* pTexture; P3_SURF_FORMAT* pFormatSurface; DISPDBG((iDebugNumber,"TSS dump:")); #define SWITCH_ARG(prefix,opname) \ case prefix##_##opname##: pszTemp = #opname; break i = 0; while ( ( i < 8 ) && ( TSSTATE ( i, D3DTSS_COLOROP ) != D3DTOP_DISABLE ) ) { switch ( TSSTATE ( i, D3DTSS_COLOROP ) ) { SWITCH_ARG ( D3DTOP,DISABLE ); SWITCH_ARG ( D3DTOP,SELECTARG1 ); SWITCH_ARG ( D3DTOP,SELECTARG2 ); SWITCH_ARG ( D3DTOP,MODULATE ); SWITCH_ARG ( D3DTOP,MODULATE2X ); SWITCH_ARG ( D3DTOP,MODULATE4X ); SWITCH_ARG ( D3DTOP,ADD ); SWITCH_ARG ( D3DTOP,ADDSIGNED ); SWITCH_ARG ( D3DTOP,ADDSIGNED2X ); SWITCH_ARG ( D3DTOP,SUBTRACT ); SWITCH_ARG ( D3DTOP,ADDSMOOTH ); SWITCH_ARG ( D3DTOP,BLENDDIFFUSEALPHA ); SWITCH_ARG ( D3DTOP,BLENDTEXTUREALPHA ); SWITCH_ARG ( D3DTOP,BLENDFACTORALPHA ); SWITCH_ARG ( D3DTOP,BLENDTEXTUREALPHAPM ); SWITCH_ARG ( D3DTOP,BLENDCURRENTALPHA ); SWITCH_ARG ( D3DTOP,PREMODULATE ); SWITCH_ARG ( D3DTOP,MODULATEALPHA_ADDCOLOR ); SWITCH_ARG ( D3DTOP,MODULATECOLOR_ADDALPHA ); SWITCH_ARG ( D3DTOP,MODULATEINVALPHA_ADDCOLOR ); SWITCH_ARG ( D3DTOP,MODULATEINVCOLOR_ADDALPHA ); SWITCH_ARG ( D3DTOP,BUMPENVMAP ); SWITCH_ARG ( D3DTOP,BUMPENVMAPLUMINANCE ); SWITCH_ARG ( D3DTOP,DOTPRODUCT3 ); default: pszTemp = "Unknown"; break; } pszOp = pszTemp; switch ( TSSTATESELECT ( i, D3DTSS_COLORARG1 ) ) { SWITCH_ARG ( D3DTA,DIFFUSE ); SWITCH_ARG ( D3DTA,CURRENT ); SWITCH_ARG ( D3DTA,TEXTURE ); SWITCH_ARG ( D3DTA,TFACTOR ); default: pszTemp = "Unknown"; break; } if ( ( TSSTATE ( i, D3DTSS_COLORARG1 ) & D3DTA_ALPHAREPLICATE ) != 0 ) { pszTempPost = ".A"; } else { pszTempPost = ".C"; } if ( ( TSSTATE ( i, D3DTSS_COLORARG1 ) & D3DTA_COMPLEMENT ) != 0 ) { pszTempPre = "1-"; } else { pszTempPre = ""; } pszArg1Pre = pszTempPre; pszArg1Post = pszTempPost; pszArg1 = pszTemp; switch ( TSSTATESELECT ( i, D3DTSS_COLORARG2 ) ) { SWITCH_ARG ( D3DTA,DIFFUSE ); SWITCH_ARG ( D3DTA,CURRENT ); SWITCH_ARG ( D3DTA,TEXTURE ); SWITCH_ARG ( D3DTA,TFACTOR ); default: pszTemp = "Unknown"; break; } if ( ( TSSTATE ( i, D3DTSS_COLORARG2 ) & D3DTA_ALPHAREPLICATE ) != 0 ) { pszTempPost = ".A"; } else { pszTempPost = ".C"; } if ( ( TSSTATE ( i, D3DTSS_COLORARG2 ) & D3DTA_COMPLEMENT ) != 0 ) { pszTempPre = "1-"; } else { pszTempPre = ""; } pszArg2Pre = pszTempPre; pszArg2Post = pszTempPost; pszArg2 = pszTemp; DISPDBG((iDebugNumber," C%i: %s: %s%s%s, %s%s%s", i, pszOp, pszArg1Pre, pszArg1, pszArg1Post, pszArg2Pre, pszArg2, pszArg2Post )); switch ( TSSTATE ( i, D3DTSS_ALPHAOP ) ) { SWITCH_ARG ( D3DTOP,DISABLE ); SWITCH_ARG ( D3DTOP,SELECTARG1 ); SWITCH_ARG ( D3DTOP,SELECTARG2 ); SWITCH_ARG ( D3DTOP,MODULATE ); SWITCH_ARG ( D3DTOP,MODULATE2X ); SWITCH_ARG ( D3DTOP,MODULATE4X ); SWITCH_ARG ( D3DTOP,ADD ); SWITCH_ARG ( D3DTOP,ADDSIGNED ); SWITCH_ARG ( D3DTOP,ADDSIGNED2X ); SWITCH_ARG ( D3DTOP,SUBTRACT ); SWITCH_ARG ( D3DTOP,ADDSMOOTH ); SWITCH_ARG ( D3DTOP,BLENDDIFFUSEALPHA ); SWITCH_ARG ( D3DTOP,BLENDTEXTUREALPHA ); SWITCH_ARG ( D3DTOP,BLENDFACTORALPHA ); SWITCH_ARG ( D3DTOP,BLENDTEXTUREALPHAPM ); SWITCH_ARG ( D3DTOP,BLENDCURRENTALPHA ); SWITCH_ARG ( D3DTOP,PREMODULATE ); SWITCH_ARG ( D3DTOP,MODULATEALPHA_ADDCOLOR ); SWITCH_ARG ( D3DTOP,MODULATECOLOR_ADDALPHA ); SWITCH_ARG ( D3DTOP,MODULATEINVALPHA_ADDCOLOR ); SWITCH_ARG ( D3DTOP,MODULATEINVCOLOR_ADDALPHA ); SWITCH_ARG ( D3DTOP,BUMPENVMAP ); SWITCH_ARG ( D3DTOP,BUMPENVMAPLUMINANCE ); SWITCH_ARG ( D3DTOP,DOTPRODUCT3 ); default: pszTemp = "Unknown"; break; } pszOp = pszTemp; switch ( TSSTATESELECT ( i, D3DTSS_ALPHAARG1 ) ) { SWITCH_ARG ( D3DTA,DIFFUSE ); SWITCH_ARG ( D3DTA,CURRENT ); SWITCH_ARG ( D3DTA,TEXTURE ); SWITCH_ARG ( D3DTA,TFACTOR ); default: pszTemp = "Unknown"; break; } if ( ( TSSTATE ( i, D3DTSS_ALPHAARG1 ) & D3DTA_ALPHAREPLICATE ) != 0 ) { // Alpharep doesn't mean much in the alpha channel. pszTempPost = ".AR???"; } else { pszTempPost = ".A"; } if ( ( TSSTATE ( i, D3DTSS_ALPHAARG1 ) & D3DTA_COMPLEMENT ) != 0 ) { pszTempPre = "1-"; } else { pszTempPre = ""; } pszArg1Pre = pszTempPre; pszArg1Post = pszTempPost; pszArg1 = pszTemp; switch ( TSSTATESELECT ( i, D3DTSS_ALPHAARG2 ) ) { SWITCH_ARG ( D3DTA,DIFFUSE ); SWITCH_ARG ( D3DTA,CURRENT ); SWITCH_ARG ( D3DTA,TEXTURE ); SWITCH_ARG ( D3DTA,TFACTOR ); default: pszTemp = "Unknown"; break; } if ( ( TSSTATE ( i, D3DTSS_ALPHAARG2 ) & D3DTA_ALPHAREPLICATE ) != 0 ) { pszTempPost = ".AR???"; } else { pszTempPost = ".A"; } if ( ( TSSTATE ( i, D3DTSS_ALPHAARG2 ) & D3DTA_COMPLEMENT ) != 0 ) { pszTempPre = "1-"; } else { pszTempPre = ""; } pszArg2Pre = pszTempPre; pszArg2Post = pszTempPost; pszArg2 = pszTemp; DISPDBG((iDebugNumber," A%i: %s: %s%s%s, %s%s%s", i, pszOp, pszArg1Pre, pszArg1, pszArg1Post, pszArg2Pre, pszArg2, pszArg2Post )); if ( TSSTATE ( i, D3DTSS_TEXTUREMAP ) != 0 ) { char szTemp[4]; // Setup texture 0. pTexture = GetSurfaceFromHandle(pContext, TSSTATE(i, D3DTSS_TEXTUREMAP)); if ( pTexture == NULL ) { DISPDBG((iDebugNumber," Tex%i: 0x%x, TCI: %i, INVALID TEXTURE", i, TSSTATE ( i, D3DTSS_TEXTUREMAP ), TSSTATE ( i, D3DTSS_TEXCOORDINDEX ) )); } else { pFormatSurface = pTexture->pFormatSurface; ASSERTDD ( pFormatSurface != NULL, "** _D3DDisplayWholeTSSPipe: " "Surface had NULL format!" ); // Find the filtering mode. szTemp[3] = '\0'; switch ( TSSTATE ( i, D3DTSS_MINFILTER ) ) { case D3DTFN_POINT: szTemp[0] = 'P'; break; case D3DTFN_LINEAR: szTemp[0] = 'L'; break; case D3DTFN_ANISOTROPIC: szTemp[0] = 'A'; break; default: szTemp[0] = '?'; break; } switch ( TSSTATE ( i, D3DTSS_MIPFILTER ) ) { case D3DTFP_NONE: szTemp[1] = 'x'; break; case D3DTFP_POINT: szTemp[1] = 'P'; break; case D3DTFP_LINEAR: szTemp[1] = 'L'; break; default: szTemp[1] = '?'; break; } switch ( TSSTATE ( i, D3DTSS_MAGFILTER ) ) { case D3DTFG_POINT: szTemp[2] = 'P'; break; case D3DTFG_LINEAR: szTemp[2] = 'L'; break; case D3DTFG_FLATCUBIC: szTemp[2] = 'F'; break; case D3DTFG_GAUSSIANCUBIC: szTemp[2] = 'G'; break; case D3DTFG_ANISOTROPIC: szTemp[2] = 'A'; break; default: szTemp[2] = '?'; break; } DISPDBG((iDebugNumber," Tex%i: 0x%x, TCI: %i, %s:%dx%d %s", i, TSSTATE ( i, D3DTSS_TEXTUREMAP ), TSSTATE ( i, D3DTSS_TEXCOORDINDEX ), pFormatSurface->pszStringFormat, pTexture->wWidth, pTexture->wHeight, szTemp )); } } else { DISPDBG((iDebugNumber," Tex%i: NULL, TCI: %i", i, TSSTATE ( i, D3DTSS_TEXCOORDINDEX ) )); } i++; } // Alpha-test. if ( pContext->RenderStates[D3DRENDERSTATE_ALPHATESTENABLE] != 0 ) { switch ( pContext->RenderStates[D3DRENDERSTATE_ALPHAFUNC] ) { SWITCH_ARG ( D3DCMP,NEVER ); SWITCH_ARG ( D3DCMP,LESS ); SWITCH_ARG ( D3DCMP,EQUAL ); SWITCH_ARG ( D3DCMP,LESSEQUAL ); SWITCH_ARG ( D3DCMP,GREATER ); SWITCH_ARG ( D3DCMP,NOTEQUAL ); SWITCH_ARG ( D3DCMP,GREATEREQUAL ); SWITCH_ARG ( D3DCMP,ALWAYS ); default: pszTemp = "Unknown"; break; } DISPDBG((iDebugNumber,"Alpha-test: %s:0x%x.", pszTemp, pContext->RenderStates[D3DRENDERSTATE_ALPHAREF] )); } else { DISPDBG((iDebugNumber,"No alpha-test.")); } // Alpha-blend. if ( pContext->RenderStates[D3DRENDERSTATE_BLENDENABLE] != 0 ) { switch ( pContext->RenderStates[D3DRENDERSTATE_SRCBLEND] ) { SWITCH_ARG ( D3DBLEND,ZERO ); SWITCH_ARG ( D3DBLEND,ONE ); SWITCH_ARG ( D3DBLEND,SRCCOLOR ); SWITCH_ARG ( D3DBLEND,INVSRCCOLOR ); SWITCH_ARG ( D3DBLEND,SRCALPHA ); SWITCH_ARG ( D3DBLEND,INVSRCALPHA ); SWITCH_ARG ( D3DBLEND,DESTALPHA ); SWITCH_ARG ( D3DBLEND,INVDESTALPHA ); SWITCH_ARG ( D3DBLEND,DESTCOLOR ); SWITCH_ARG ( D3DBLEND,INVDESTCOLOR ); SWITCH_ARG ( D3DBLEND,SRCALPHASAT ); SWITCH_ARG ( D3DBLEND,BOTHSRCALPHA ); SWITCH_ARG ( D3DBLEND,BOTHINVSRCALPHA ); default: pszTemp = "Unknown"; break; } pszSrc = pszTemp; switch ( pContext->RenderStates[D3DRENDERSTATE_DESTBLEND] ) { SWITCH_ARG ( D3DBLEND,ZERO ); SWITCH_ARG ( D3DBLEND,ONE ); SWITCH_ARG ( D3DBLEND,SRCCOLOR ); SWITCH_ARG ( D3DBLEND,INVSRCCOLOR ); SWITCH_ARG ( D3DBLEND,SRCALPHA ); SWITCH_ARG ( D3DBLEND,INVSRCALPHA ); SWITCH_ARG ( D3DBLEND,DESTALPHA ); SWITCH_ARG ( D3DBLEND,INVDESTALPHA ); SWITCH_ARG ( D3DBLEND,DESTCOLOR ); SWITCH_ARG ( D3DBLEND,INVDESTCOLOR ); SWITCH_ARG ( D3DBLEND,SRCALPHASAT ); SWITCH_ARG ( D3DBLEND,BOTHSRCALPHA ); SWITCH_ARG ( D3DBLEND,BOTHINVSRCALPHA ); default: pszTemp = "Unknown"; break; } pszDest = pszTemp; DISPDBG((iDebugNumber,"Blend %s:%s", pszSrc, pszDest)); } else { DISPDBG((iDebugNumber,"No alpha-blend.")); } #undef SWITCH_ARG #endif //DBG } // _D3DDisplayWholeTSSPipe //----------------------------------------------------------------------------- // // __TXT_TranslateToChipBlendMode // // Translates the blend mode from D3D into what the chip understands // //----------------------------------------------------------------------------- void __TXT_TranslateToChipBlendMode( P3_D3DCONTEXT *pContext, TexStageState* pState, P3_SOFTWARECOPY* pSoftP3RX, int iTSStage, int iChipStageNo ) { struct TextureCompositeRGBAMode* pColorMode; struct TextureCompositeRGBAMode* pAlphaMode; struct TextureApplicationMode* pTAMode; switch(iChipStageNo) { default: DISPDBG((ERRLVL,"ERROR: Invalid texture stage!")); // Fall through and treat as #0 in order not to AV anything case 0: pColorMode = &pSoftP3RX->P3RXTextureCompositeColorMode0; pAlphaMode = &pSoftP3RX->P3RXTextureCompositeAlphaMode0; pTAMode = NULL; break; case 1: pColorMode = &pSoftP3RX->P3RXTextureCompositeColorMode1; pAlphaMode = &pSoftP3RX->P3RXTextureCompositeAlphaMode1; pTAMode = NULL; break; case 2: pColorMode = NULL; pAlphaMode = NULL; pTAMode = &pSoftP3RX->P3RXTextureApplicationMode; break; } DISPDBG((DBGLVL,"*** In __TXT_TranslateToChipBlendMode: " "Chip Stage %d, D3D TSS Stage %d", iChipStageNo, iTSStage )); // Setup the arguments if ( ( iChipStageNo == 0 ) || ( iChipStageNo == 1 ) ) { // Texture composite unit. DISPDBG((DBGLVL,"TexComp%d:", iChipStageNo )); DISPDBG((DBGLVL,"Arg1:" )); SETARG(pContext, pColorMode, pState->m_dwVal[D3DTSS_COLORARG1], 1, IS_COLOR_ARG, iTSStage, iChipStageNo); SETARG(pContext, pAlphaMode, pState->m_dwVal[D3DTSS_ALPHAARG1], 1, IS_ALPHA_ARG, iTSStage, iChipStageNo); DISPDBG((DBGLVL,"Arg2:" )); SETARG(pContext, pColorMode, pState->m_dwVal[D3DTSS_COLORARG2], 2, IS_COLOR_ARG, iTSStage, iChipStageNo); SETARG(pContext, pAlphaMode, pState->m_dwVal[D3DTSS_ALPHAARG2], 2, IS_ALPHA_ARG, iTSStage, iChipStageNo); DISPDBG((DBGLVL,"Op:" )); SETOP(pContext, pColorMode, pState->m_dwVal[D3DTSS_COLOROP], iTSStage, iChipStageNo, IS_COLOR_ARG); SETOP(pContext, pAlphaMode, pState->m_dwVal[D3DTSS_ALPHAOP], iTSStage, iChipStageNo, IS_ALPHA_ARG); } else if ( iChipStageNo == 2 ) { DISPDBG((DBGLVL,"TexApp:" )); DISPDBG((DBGLVL,"Arg1:" )); SETTAARG_COLOR(pContext, pTAMode, pState->m_dwVal[D3DTSS_COLORARG1], 1 ); if ( ( pState->m_dwVal[D3DTSS_ALPHAOP] != D3DTOP_DISABLE ) && ( pState->m_dwVal[D3DTSS_ALPHAOP] != D3DTOP_SELECTARG2 ) ) { SETTAARG_ALPHA(pContext, pTAMode, pState->m_dwVal[D3DTSS_ALPHAARG1], 1 ); } DISPDBG((DBGLVL,"Arg2:" )); SETTAARG_COLOR(pContext, pTAMode, pState->m_dwVal[D3DTSS_COLORARG2], 2 ); if ( ( pState->m_dwVal[D3DTSS_ALPHAOP] != D3DTOP_DISABLE ) && ( pState->m_dwVal[D3DTSS_ALPHAOP] != D3DTOP_SELECTARG1 ) ) { SETTAARG_ALPHA(pContext, pTAMode, pState->m_dwVal[D3DTSS_ALPHAARG2], 2); } DISPDBG((DBGLVL,"Op:" )); SETTAOP(pContext, pTAMode, pState->m_dwVal[D3DTSS_COLOROP], IS_COLOR_ARG, iTSStage, iChipStageNo); SETTAOP(pContext, pTAMode, pState->m_dwVal[D3DTSS_ALPHAOP], IS_ALPHA_ARG, iTSStage, iChipStageNo); } else { DISPDBG(( ERRLVL,"** __TXT_TranslateToChipBlendMode: " "iChipStage must be 0 to 2" )); } } // __TXT_TranslateToChipBlendMode //----------------------------------------------------------------------------- // // __TXT_ValidateTextureUnitStage // // Validate the texture which we're trying to set up in stage iChipStage of // the hardware, iTSStage of the D3D TSS. // //----------------------------------------------------------------------------- BOOL __TXT_ValidateTextureUnitStage( P3_D3DCONTEXT* pContext, int iChipStage, int iTSStage, P3_SURF_INTERNAL* pTexture) { DWORD dwTexHandle = pContext->TextureStageState[iTSStage].m_dwVal[D3DTSS_TEXTUREMAP]; if( CHECK_SURF_INTERNAL_AND_DDSURFACE_VALIDITY(pTexture) && (pTexture->Location != SystemMemory) && (dwTexHandle != 0) ) { // Texture is valid. Mark pCurrentTexturep[iChipStage] to point // to its P3_SURF_INTERNAL structure. pContext->pCurrentTexture[iChipStage] = pTexture; DISPDBG((DBGLVL, "__TXT_ValidateTextureUnitStage: valid texture %x " "(handle %d) for iChipStage= %d iTSStage= %d", pTexture, dwTexHandle, iChipStage, iTSStage)); } else { // Set texture as invalid & force texturing off pContext->bTextureValid = FALSE; pContext->pCurrentTexture[iChipStage] = NULL; pContext->dwDirtyFlags |= CONTEXT_DIRTY_TEXTURE; // Setup error if we're asked to validate the TSS setup SET_BLEND_ERROR ( pContext, BSF_INVALID_TEXTURE ); DISPDBG((WRNLVL, "__TXT_ValidateTextureUnitStage: INVALID texture %x " "(handle %d) for iChipStage= %d iTSStage= %d " "Location=%d", pTexture, dwTexHandle, iChipStage, iTSStage, (pTexture !=NULL)?pTexture->Location:0)); } return ( (BOOL)pContext->bTextureValid ); } // __TXT_ValidateTextureUnitStage //----------------------------------------------------------------------------- // // __TXT_ConsiderSrcChromaKey // // Setup chromakeying for a certain texture bound to a certain stage. // Note - "stage" is the chip stage, not the D3D stage. //----------------------------------------------------------------------------- static void __TXT_ConsiderSrcChromaKey( P3_D3DCONTEXT *pContext, P3_SURF_INTERNAL* pTexture, int stage ) { P3_THUNKEDDATA * pThisDisplay = pContext->pThisDisplay; P3_SOFTWARECOPY* pSoftP3RX = &pContext->SoftCopyGlint; P3_DMA_DEFS(); if ((pTexture->dwFlagsInt & DDRAWISURF_HASCKEYSRCBLT) && pContext->RenderStates[D3DRENDERSTATE_COLORKEYENABLE]) { DWORD LowerBound = 0x00000000; DWORD UpperBound = 0xFFFFFFFF; DWORD* pPalEntries = NULL; DWORD dwPalFlags = 0; DISPDBG((DBGLVL," Can Chroma Key texture stage %d", stage)); pContext->bCanChromaKey = TRUE; #if DX7_PALETTETEXTURE // Get the palette entries if (pTexture->pixFmt.dwFlags & DDPF_PALETTEINDEXED8) { D3DHAL_DP2UPDATEPALETTE *pPalette = NULL; pPalette = GetPaletteFromHandle(pContext, pTexture->dwPaletteHandle); if (pPalette) { pPalEntries = (LPDWORD)(pPalette + 1); } else { SET_BLEND_ERROR(pContext, BSF_INVALID_TEXTURE); } dwPalFlags = pTexture->dwPaletteFlags; } #endif // Get the correct chroma value for the texture map to send to the chip. Get8888ScaledChroma(pThisDisplay, pTexture->dwFlagsInt, &pTexture->pixFmt, pTexture->dwCKLow, pTexture->dwCKHigh, &LowerBound, &UpperBound, pPalEntries, dwPalFlags & DDRAWIPAL_ALPHA, FALSE); P3_DMA_GET_BUFFER_ENTRIES( 8); // Send the upper and lower bounds for the alpha-map filtering if( stage == 0 ) { SEND_P3_DATA(TextureChromaLower0, LowerBound ); SEND_P3_DATA(TextureChromaUpper0, UpperBound ); pSoftP3RX->P3RXTextureFilterMode.AlphaMapEnable0 = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureFilterMode.AlphaMapSense0 = P3RX_ALPHAMAPSENSE_INRANGE; } else { ASSERTDD ( stage == 1, "** __TXT_ConsiderSrcChromaKey: stage must be 0 or 1" ); } // If we are mipmapping, we need to set up texture1's chromakey as well. // If not, then this will be overridden when this gets called for tex1. SEND_P3_DATA(TextureChromaLower1, LowerBound ); SEND_P3_DATA(TextureChromaUpper1, UpperBound ); pSoftP3RX->P3RXTextureFilterMode.AlphaMapEnable1 = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureFilterMode.AlphaMapSense1 = P3RX_ALPHAMAPSENSE_INRANGE; P3_DMA_COMMIT_BUFFER(); pSoftP3RX->P3RXTextureFilterMode.AlphaMapFiltering = __PERMEDIA_ENABLE; } else { DISPDBG((DBGLVL," Can't Chroma Key texture stage %d", stage)); if( stage == 0 ) { pSoftP3RX->P3RXTextureFilterMode.AlphaMapEnable0 = __PERMEDIA_DISABLE; } else { ASSERTDD ( stage == 1, "** __TXT_ConsiderSrcChromaKey: stage must be 0 or 1" ); } // If we are mipmapping, we need to set up texture1's chromakey (or // lack of it) as well. If not, then this will be overridden when // this gets called for tex1. pSoftP3RX->P3RXTextureFilterMode.AlphaMapEnable1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureFilterMode.AlphaMapFiltering = __PERMEDIA_DISABLE; } } // __TXT_ConsiderSrcChromaKey //----------------------------------------------------------------------------- // // __TXT_SetupTexture // // This is the new all-singing all-dancing texture setup code. // Return is TRUE if setup succeeded, FALSE if it failed (for ValidateDevice) // This sets up either texture 0 or texture 1, taking its wrapping, etc, // info from iTSStage. // //----------------------------------------------------------------------------- BOOL __TXT_SetupTexture ( P3_THUNKEDDATA * pThisDisplay, int iTexNo, int iTSStage, P3_D3DCONTEXT* pContext, P3_SURF_INTERNAL* pTexture, P3_SOFTWARECOPY* pSoftP3RX, BOOL bBothTexturesValid, P3_MIP_BASES *pMipBases) { P3_SURF_FORMAT* pFormatSurface; int iT0MaxLevel, iT1MaxLevel; P3_DMA_DEFS(); ASSERTDD ( ( iTexNo >= 0 ) && ( iTexNo <= 1 ), "**__TXT_SetupTexture: we only have two texture units!" ); if ( pTexture != NULL ) { pFormatSurface = pTexture->pFormatSurface; } else { // Suceeded, but should never have got here! DISPDBG((ERRLVL,"**__TXT_SetupTexture: should never " "be called with handle of NULL")); return ( TRUE ); } P3_DMA_GET_BUFFER(); P3_ENSURE_DX_SPACE(32); WAIT_FIFO(32); // Set up the texture-relevant things. switch ( iTexNo ) { case 0: { // Set both bits in case we are mipmapping pSoftP3RX->P3RXTextureFilterMode.ForceAlphaToOne0 = pFormatSurface->bAlpha ? __PERMEDIA_DISABLE : __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureFilterMode.ForceAlphaToOne1 = pFormatSurface->bAlpha ? __PERMEDIA_DISABLE : __PERMEDIA_ENABLE; // D3D UV Wrapping if (pContext->RenderStates[D3DRENDERSTATE_WRAP0+iTSStage] & D3DWRAP_U) { pSoftP3RX->P4DeltaFormatControl.WrapS = 1; } else { pSoftP3RX->P4DeltaFormatControl.WrapS = 0; } if (pContext->RenderStates[D3DRENDERSTATE_WRAP0+iTSStage] & D3DWRAP_V) { pSoftP3RX->P4DeltaFormatControl.WrapT = 1; } else { pSoftP3RX->P4DeltaFormatControl.WrapT = 0; } // U Wrapping switch (TSSTATE ( iTSStage, D3DTSS_ADDRESSU )) { case D3DTADDRESS_CLAMP: pSoftP3RX->P3RXTextureCoordMode.WrapS = __GLINT_TEXADDRESS_WRAP_CLAMP; pSoftP3RX->P3RXTextureIndexMode0.WrapU = P3RX_TEXINDEXMODE_WRAP_CLAMPEDGE; break; case D3DTADDRESS_WRAP: pSoftP3RX->P3RXTextureCoordMode.WrapS = __GLINT_TEXADDRESS_WRAP_REPEAT; pSoftP3RX->P3RXTextureIndexMode0.WrapU = P3RX_TEXINDEXMODE_WRAP_REPEAT; break; case D3DTADDRESS_MIRROR: pSoftP3RX->P3RXTextureCoordMode.WrapS = __GLINT_TEXADDRESS_WRAP_MIRROR; pSoftP3RX->P3RXTextureIndexMode0.WrapU = P3RX_TEXINDEXMODE_WRAP_MIRROR; break; default: DISPDBG((ERRLVL,"ERROR: Unknown ADDRESSU!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_STATE ); break; } // V Wrapping switch (TSSTATE ( iTSStage, D3DTSS_ADDRESSV )) { case D3DTADDRESS_CLAMP: pSoftP3RX->P3RXTextureCoordMode.WrapT = __GLINT_TEXADDRESS_WRAP_CLAMP; pSoftP3RX->P3RXTextureIndexMode0.WrapV = P3RX_TEXINDEXMODE_WRAP_CLAMPEDGE; break; case D3DTADDRESS_WRAP: pSoftP3RX->P3RXTextureCoordMode.WrapT = __GLINT_TEXADDRESS_WRAP_REPEAT; pSoftP3RX->P3RXTextureIndexMode0.WrapV = P3RX_TEXINDEXMODE_WRAP_REPEAT; break; case D3DTADDRESS_MIRROR: pSoftP3RX->P3RXTextureCoordMode.WrapT = __GLINT_TEXADDRESS_WRAP_MIRROR; pSoftP3RX->P3RXTextureIndexMode0.WrapV = P3RX_TEXINDEXMODE_WRAP_MIRROR; break; default: DISPDBG((ERRLVL,"ERROR: Unknown ADDRESSV!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_STATE ); break; } #if DX8_3DTEXTURES if (pTexture->b3DTexture) { // W Wrapping switch (TSSTATE ( iTSStage, D3DTSS_ADDRESSW )) { case D3DTADDRESS_CLAMP: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_CLAMP; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_CLAMPEDGE; break; case D3DTADDRESS_WRAP: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_REPEAT; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_REPEAT; break; case D3DTADDRESS_MIRROR: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_MIRROR; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_MIRROR; break; default: DISPDBG((ERRLVL,"ERROR: Unknown ADDRESSW!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_STATE ); break; } } #endif // DX8_3DTEXTURES if(( TSSTATE( iTSStage, D3DTSS_ADDRESSU ) == D3DTADDRESS_CLAMP ) || ( TSSTATE( iTSStage, D3DTSS_ADDRESSV ) == D3DTADDRESS_CLAMP )) { if( (TSSTATE( iTSStage, D3DTSS_ADDRESSU ) != D3DTADDRESS_CLAMP) || (TSSTATE( iTSStage, D3DTSS_ADDRESSV ) != D3DTADDRESS_CLAMP)) { DISPDBG((ERRLVL,"Warning: One texture coord clamped, but not " "the other - can't appply TextureShift")); } pSoftP3RX->P4DeltaFormatControl.TextureShift = __PERMEDIA_DISABLE; } else { pSoftP3RX->P4DeltaFormatControl.TextureShift = __PERMEDIA_ENABLE; } ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: " "pFormatSurace is NULL" ); switch (pFormatSurface->DeviceFormat) { case SURF_CI8: pSoftP3RX->P3RXTextureReadMode0.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_8BITINDEXED; break; case SURF_YUV422: pSoftP3RX->P3RXTextureReadMode0.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_422_YVYU; break; default: pSoftP3RX->P3RXTextureReadMode0.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_NORMAL; break; } // MAG Filter switch(TSSTATE ( iTSStage, D3DTSS_MAGFILTER )) { case D3DTFG_POINT: pSoftP3RX->P3RXTextureIndexMode0.MagnificationFilter = __GLINT_TEXTUREREAD_FILTER_NEAREST; break; case D3DTFG_LINEAR: pSoftP3RX->P3RXTextureIndexMode0.MagnificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEAR; break; case D3DTFG_FLATCUBIC: case D3DTFG_GAUSSIANCUBIC: case D3DTFG_ANISOTROPIC: DISPDBG((ERRLVL,"ERROR: Unsupported MAGFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_FILTER ); break; default: DISPDBG((ERRLVL,"ERROR: Unknown MAGFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEAREST; break; case D3DTFN_LINEAR: pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEAR; break; case D3DTFN_ANISOTROPIC: DISPDBG((ERRLVL,"ERROR: Unsupported MINFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_FILTER ); break; default: DISPDBG((ERRLVL,"ERROR: Unknown MINFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } switch(TSSTATE ( iTSStage, D3DTSS_MIPFILTER )) { case D3DTFP_NONE: // No need to set the minification filter, it was done above break; case D3DTFP_POINT: switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: // Point Min, Point Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEARMIPNEAREST; break; case D3DTFN_LINEAR: // Linear Min, Point Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEARMIPNEAREST; break; } break; case D3DTFP_LINEAR: if( bBothTexturesValid ) { // We can only do per-poly mipmapping while // multi-texturing, so don't enable inter-map filtering. // Non-fatal error - drop back to nearest // mipmap filtering. SET_BLEND_ERROR ( pContext, BS_INVALID_FILTER ); switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: // Point Min, Point Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEARMIPNEAREST; break; case D3DTFN_LINEAR: // Linear Min, Point Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEARMIPNEAREST; break; } } else { // Single texture - do inter-map filtering switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: // Point Min, Linear Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEARMIPLINEAR; break; case D3DTFN_LINEAR: // Linear Min, Linear Mip pSoftP3RX->P3RXTextureIndexMode0.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEARMIPLINEAR; break; } } break; default: DISPDBG((ERRLVL,"ERROR: Unknown MIPFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } // MipMapping if( (TSSTATE ( iTSStage, D3DTSS_MIPFILTER ) != D3DTFP_NONE) && (pTexture->bMipMap)) { int iLOD; INT iTexLOD; DISPDBG(( DBGLVL, "Multiple texture levels" )); // Load the mipmap levels for texture 0 // Mip level from pMipBases->dwTex0ActMaxLevel to // pTexture->iMipLevels will be mapped to base address slot // from pMipBases->dwTex0Mipbase to dwTex0MipMax ASSERTDD ( pMipBases->dwTex0MipBase == 0, "** __TXT_SetupTexture: " "Texture 0 mipmap base is not 0" ); iLOD = pMipBases->dwTex0MipBase; iTexLOD = pMipBases->dwTex0ActMaxLevel; iT0MaxLevel = iTexLOD; while(( iTexLOD < pTexture->iMipLevels ) && ( iLOD <= (int)pMipBases->dwTex0MipMax )) { DISPDBG((DBGLVL, " Setting Texture Base Address %d to 0x%x", iLOD, pTexture->MipLevels[iLOD].dwOffsetFromMemoryBase)); pSoftP3RX->P3RXTextureMapWidth[iLOD] = pTexture->MipLevels[iTexLOD].P3RXTextureMapWidth; #if DX7_TEXMANAGEMENT // If this is a driver managed texture surface, we need // to use our privately allocated mem ptr if (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { SEND_P3_DATA_OFFSET(TextureBaseAddr0, (DWORD)D3DTMMIPLVL_GETOFFSET(pTexture->MipLevels[iTexLOD], pThisDisplay), iLOD); } else #endif { SEND_P3_DATA_OFFSET(TextureBaseAddr0, pTexture->MipLevels[iTexLOD].dwOffsetFromMemoryBase, iLOD); } iLOD++; iTexLOD++; } // If both textures are enabled we can't do per-pixel // mipmapping because that uses both sets of texcoord // DDAs to generate the LOD level. So we must do per-poly // mipmapping. Per-poly mipmapping can only be done in // hardware on P4 - we use a Delta renderer on P3 when // mipmapping with both textures enabled. if( bBothTexturesValid ) { DISPDBG(( DBGLVL, "Both textures valid" )); // Do per-poly mipmapping in the P4 DeltaFormat unit pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_DISABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap = __PERMEDIA_ENABLE; { DWORD d; *(float *)&d = pContext->MipMapLODBias[TEXSTAGE_0] * pTexture->dwPixelPitch * pTexture->wHeight; SEND_P3_DATA(TextureLODScale, d); } } else { DISPDBG(( DBGLVL, "Single texture only" )); // Do per-pixel mipmapping pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_ENABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap = __PERMEDIA_DISABLE; //@@BEGIN_DDKSPLIT #if 0 // azn this would disable "automatic" mip mapping and we would be using the // values supplied by writing into LOD and LOD1 (d3dprim.c) - don't forget! pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_DISABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap = __PERMEDIA_ENABLE; SEND_P3_DATA(TextureLODScale, 0); #endif //@@END_DDKSPLIT { float bias; DWORD b; bias = pContext->TextureStageState[TEXSTAGE_0].m_fVal[D3DTSS_MIPMAPLODBIAS]; // Convert LOD bias from float to 6.8 myFtoi( &b, bias * 256.0f ); SEND_P3_DATA(TextureLODBiasS, b); SEND_P3_DATA(TextureLODBiasT, b); } } pSoftP3RX->P3RXTextureIndexMode0.MipMapEnable = __PERMEDIA_ENABLE; } else { int iTexLOD; // No mipmapping. DISPDBG(( DBGLVL, "Single texture level" )); pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_DISABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode0.MipMapEnable = __PERMEDIA_DISABLE; ASSERTDD ( pMipBases->dwTex0MipBase == 0, "** __TXT_SetupTexture: " "Texture 0 mipmap base is not 0" ); // Use the maximum level indicated by D3DTSS_MAXMIPLEVEL iTexLOD = pMipBases->dwTex0ActMaxLevel; iT0MaxLevel = iTexLOD; #if DX7_TEXMANAGEMENT // If this is a driver managed texture surface, we need // to use our privately allocated mem ptr if (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { SEND_P3_DATA_OFFSET(TextureBaseAddr0, (DWORD)D3DTMMIPLVL_GETOFFSET(pTexture->MipLevels[iTexLOD], pThisDisplay), 0); } else #endif { SEND_P3_DATA_OFFSET(TextureBaseAddr0, pTexture->MipLevels[iTexLOD].dwOffsetFromMemoryBase, 0); } // No mipmapping, but could be combining the caches. pSoftP3RX->P3RXTextureMapWidth[0] = pTexture->MipLevels[iTexLOD].P3RXTextureMapWidth; pSoftP3RX->P3RXTextureMapWidth[1] = pTexture->MipLevels[iTexLOD].P3RXTextureMapWidth; } //@@BEGIN_DDKSPLIT // There is only one TextureCoordMode, it is possible that it is // not used at all //@@END_DDKSPLIT // Set maximum dimension of the texture pSoftP3RX->P3RXTextureCoordMode.Width = pTexture->MipLevels[iT0MaxLevel].logWidth; pSoftP3RX->P3RXTextureCoordMode.Height = pTexture->MipLevels[iT0MaxLevel].logHeight; #if DX7_PALETTETEXTURE // If it is a palette indexed texture, we simply follow the chain // down from the surface to its palette and pull out the LUT values // from the PALETTEENTRY's in the palette. ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: pFormatSurace is NULL" ); if (pFormatSurface->DeviceFormat == SURF_CI8) { WAIT_FIFO(8); pSoftP3RX->P3RXLUTMode.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXLUTMode.InColorOrder = __PERMEDIA_ENABLE; SEND_P3_DATA(LUTAddress, 0); SEND_P3_DATA(LUTTransfer, 0); SEND_P3_DATA(LUTIndex, 0); COPY_P3_DATA(LUTMode, pSoftP3RX->P3RXLUTMode); // In this case simply download the 256 entries each time the // texture handle changes. { DWORD dwCount1, dwCount2; D3DHAL_DP2UPDATEPALETTE *pPalette; // associated palette LPDWORD lpColorTable; // array of palette entries pPalette = GetPaletteFromHandle(pContext, pTexture->dwPaletteHandle); if (pPalette) // If palette can be found { lpColorTable = (LPDWORD)(pPalette + 1); if (pTexture->dwPaletteFlags & DDRAWIPAL_ALPHA) { for (dwCount1 = 0; dwCount1 < 16; dwCount1++) { P3_ENSURE_DX_SPACE(17); WAIT_FIFO(17); P3RX_HOLD_CMD(LUTData, 16); for (dwCount2 = 0; dwCount2 < 16; dwCount2++) { *dmaPtr++ = *lpColorTable++; CHECK_FIFO(1); } } } else { for (dwCount1 = 0; dwCount1 < 16; dwCount1++) { P3_ENSURE_DX_SPACE(17); WAIT_FIFO(17); P3RX_HOLD_CMD(LUTData, 16); for (dwCount2 = 0; dwCount2 < 16; dwCount2++) { *dmaPtr++ = CHROMA_UPPER_ALPHA(*(DWORD*)lpColorTable++); CHECK_FIFO(1); } } } } else { DISPDBG((ERRLVL,"Palette handle is missing for CI8 surf!")); } } // Make sure there is room left over for the rest of the routine P3_ENSURE_DX_SPACE(2); WAIT_FIFO(2); SEND_P3_DATA(LUTIndex, 0); } else #endif // DX7_PALETTETEXTURE { // No LUT. P3_ENSURE_DX_SPACE(4); WAIT_FIFO(4); pSoftP3RX->P3RXLUTMode.Enable = __PERMEDIA_DISABLE; SEND_P3_DATA(LUTTransfer, __PERMEDIA_DISABLE); COPY_P3_DATA(LUTMode, pSoftP3RX->P3RXLUTMode) } #if DX8_3DTEXTURES P3_ENSURE_DX_SPACE(4); WAIT_FIFO(4); if (pTexture->b3DTexture) { // // Set size of each 2D texture slice in texel size to TextureMapSize. // SEND_P3_DATA(TextureMapSize, pTexture->dwSliceInTexel); } else { SEND_P3_DATA(TextureMapSize, 0); } #endif // DX8_3DTEXTURES P3_DMA_COMMIT_BUFFER(); __TXT_ConsiderSrcChromaKey( pContext, pTexture, 0 ); P3_DMA_GET_BUFFER(); // Setup TextureReadMode pSoftP3RX->P3RXTextureReadMode0.MapBaseLevel = pMipBases->dwTex0MipBase; pSoftP3RX->P3RXTextureReadMode0.MapMaxLevel = pMipBases->dwTex0MipMax; pSoftP3RX->P3RXTextureReadMode0.Width = pTexture->MipLevels[iT0MaxLevel].logWidth; pSoftP3RX->P3RXTextureReadMode0.Height = pTexture->MipLevels[iT0MaxLevel].logHeight; pSoftP3RX->P3RXTextureReadMode0.TexelSize = pTexture->dwPixelSize; pSoftP3RX->P3RXTextureReadMode0.LogicalTexture = __PERMEDIA_DISABLE; // Enable stage 0 pSoftP3RX->P3RXTextureIndexMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureReadMode0.Enable = __PERMEDIA_ENABLE; // Never set CombineCaches - chip bug pSoftP3RX->P3RXTextureReadMode0.CombineCaches = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureFilterMode.CombineCaches = __PERMEDIA_DISABLE; // Always copy TRM0 to TRM1 in case we are combining the caches pSoftP3RX->P3RXTextureReadMode1 = pSoftP3RX->P3RXTextureReadMode0; // Enable the texture index unit // (this is a bit like the the texture read) pSoftP3RX->P3RXTextureIndexMode0.Width = pTexture->MipLevels[iT0MaxLevel].logWidth; pSoftP3RX->P3RXTextureIndexMode0.Height = pTexture->MipLevels[iT0MaxLevel].logHeight; // Set both formats to be equal for texture 0 - this will be correct // for single-texture per-pixel mipmap or non-mipmapped with a // combined cache. If the second texture is valid it's setup below // will set Format1 appropriately. ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: " "pFormatSurace is NULL" ); pSoftP3RX->P3RXTextureFilterMode.Format0 = pFormatSurface->FilterFormat; pSoftP3RX->P3RXTextureFilterMode.Format1 = pFormatSurface->FilterFormat; #if DX8_3DTEXTURES if (pTexture->b3DTexture) { // // Enable 3D Texture registers. // pSoftP3RX->P3RX_P3DeltaMode.Texture3DEnable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureReadMode0.Texture3D = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureIndexMode0.Texture3DEnable = __PERMEDIA_ENABLE; // // ReadMode1 and IndexMode1 should have same data as 0. // pSoftP3RX->P3RXTextureReadMode1 = pSoftP3RX->P3RXTextureReadMode0; pSoftP3RX->P3RXTextureIndexMode1 = pSoftP3RX->P3RXTextureIndexMode0; // // And put logDepth into IndexMode1.Width. // pSoftP3RX->P3RXTextureIndexMode1.Width = pTexture->logDepth; } else { pSoftP3RX->P3RXTextureReadMode0.Texture3D = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode0.Texture3DEnable = __PERMEDIA_DISABLE; } #endif // DX8_3DTEXTURES break; } // Texture Stage 1 case 1: { pSoftP3RX->P3RXTextureFilterMode.ForceAlphaToOne1 = pFormatSurface->bAlpha ? __PERMEDIA_DISABLE : __PERMEDIA_ENABLE; // D3D UV Wrapping if (pContext->RenderStates[D3DRENDERSTATE_WRAP0+iTSStage] & D3DWRAP_U) { pSoftP3RX->P4DeltaFormatControl.WrapS1 = 1; } else { pSoftP3RX->P4DeltaFormatControl.WrapS1 = 0; } if (pContext->RenderStates[D3DRENDERSTATE_WRAP0+iTSStage] & D3DWRAP_V) { pSoftP3RX->P4DeltaFormatControl.WrapT1 = 1; } else { pSoftP3RX->P4DeltaFormatControl.WrapT1 = 0; } // U Addressing switch (TSSTATE ( iTSStage, D3DTSS_ADDRESSU )) { case D3DTADDRESS_CLAMP: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_CLAMP; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_CLAMPEDGE; break; case D3DTADDRESS_WRAP: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_REPEAT; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_REPEAT; break; case D3DTADDRESS_MIRROR: pSoftP3RX->P3RXTextureCoordMode.WrapS1 = __GLINT_TEXADDRESS_WRAP_MIRROR; pSoftP3RX->P3RXTextureIndexMode1.WrapU = P3RX_TEXINDEXMODE_WRAP_MIRROR; break; default: DISPDBG((ERRLVL,"ERROR: Unknown ADDRESSU!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_STATE ); break; } // V Addressing switch (TSSTATE ( iTSStage, D3DTSS_ADDRESSV )) { case D3DTADDRESS_CLAMP: pSoftP3RX->P3RXTextureCoordMode.WrapT1 = __GLINT_TEXADDRESS_WRAP_CLAMP; pSoftP3RX->P3RXTextureIndexMode1.WrapV = P3RX_TEXINDEXMODE_WRAP_CLAMPEDGE; break; case D3DTADDRESS_WRAP: pSoftP3RX->P3RXTextureCoordMode.WrapT1 = __GLINT_TEXADDRESS_WRAP_REPEAT; pSoftP3RX->P3RXTextureIndexMode1.WrapV = P3RX_TEXINDEXMODE_WRAP_REPEAT; break; case D3DTADDRESS_MIRROR: pSoftP3RX->P3RXTextureCoordMode.WrapT1 = __GLINT_TEXADDRESS_WRAP_MIRROR; pSoftP3RX->P3RXTextureIndexMode1.WrapV = P3RX_TEXINDEXMODE_WRAP_MIRROR; break; default: DISPDBG((ERRLVL,"ERROR: Unknown ADDRESSV!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_STATE ); break; } if(( TSSTATE( iTSStage, D3DTSS_ADDRESSU ) == D3DTADDRESS_CLAMP ) || ( TSSTATE( iTSStage, D3DTSS_ADDRESSV ) == D3DTADDRESS_CLAMP )) { if ((TSSTATE( iTSStage, D3DTSS_ADDRESSU ) != D3DTADDRESS_CLAMP) || (TSSTATE( iTSStage, D3DTSS_ADDRESSV ) != D3DTADDRESS_CLAMP)) { DISPDBG((ERRLVL,"Warning: One texture coord clamped, but not " "the other - can't appply TextureShift")); } pSoftP3RX->P4DeltaFormatControl.TextureShift1 = __PERMEDIA_DISABLE; } else { pSoftP3RX->P4DeltaFormatControl.TextureShift1 = __PERMEDIA_ENABLE; } ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: " "pFormatSurace is NULL" ); switch (pFormatSurface->DeviceFormat) { case SURF_CI8: pSoftP3RX->P3RXTextureReadMode1.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_8BITINDEXED; break; case SURF_YUV422: pSoftP3RX->P3RXTextureReadMode1.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_422_YVYU; break; default: pSoftP3RX->P3RXTextureReadMode1.TextureType = P3RX_TEXREADMODE_TEXTURETYPE_NORMAL; break; } // MAG Filter switch(TSSTATE ( iTSStage, D3DTSS_MAGFILTER )) { case D3DTFG_POINT: pSoftP3RX->P3RXTextureIndexMode1.MagnificationFilter = __GLINT_TEXTUREREAD_FILTER_NEAREST; break; case D3DTFG_LINEAR: pSoftP3RX->P3RXTextureIndexMode1.MagnificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEAR; break; case D3DTFG_FLATCUBIC: case D3DTFG_GAUSSIANCUBIC: case D3DTFG_ANISOTROPIC: DISPDBG((ERRLVL,"ERROR: Unsupported MAGFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_FILTER ); break; default: DISPDBG((ERRLVL,"ERROR: Unknown MAGFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: pSoftP3RX->P3RXTextureIndexMode1.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEAREST; break; case D3DTFN_LINEAR: pSoftP3RX->P3RXTextureIndexMode1.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEAR; break; case D3DTFN_ANISOTROPIC: DISPDBG((ERRLVL,"ERROR: Unsupported MINFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNSUPPORTED_FILTER ); break; default: DISPDBG((ERRLVL,"ERROR: Unknown MINFILTER!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } switch(TSSTATE ( iTSStage, D3DTSS_MIPFILTER )) { case D3DTFP_NONE: // No need to set the minification filter // it was done above break; case D3DTFP_LINEAR: case D3DTFP_POINT: if( bBothTexturesValid ) { if ( TSSTATE ( iTSStage, D3DTSS_MIPFILTER ) == D3DTFP_LINEAR ) { // Can't do trilinear with both textures // - fall back to per-poly. SET_BLEND_ERROR ( pContext, BS_INVALID_FILTER ); } // We can only do per-poly mipmapping while // multi-texturing, so don't enable //inter-map filtering. switch(TSSTATE ( iTSStage, D3DTSS_MINFILTER )) { case D3DTFN_POINT: // Point Min, Point Mip pSoftP3RX->P3RXTextureIndexMode1.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_NEARMIPNEAREST; break; case D3DTFN_LINEAR: // Linear Min, Point Mip pSoftP3RX->P3RXTextureIndexMode1.MinificationFilter = __GLINT_TEXTUREREAD_FILTER_LINEARMIPNEAREST; break; } } else { DISPDBG((ERRLVL,"** Setting up the second stage, but " "only one texture is valid")); } break; default: DISPDBG((ERRLVL,"ERROR: Invalid Mip filter!")); SET_BLEND_ERROR ( pContext, BSF_UNDEFINED_FILTER ); break; } // MipMapping // If the app chooses to have two mip-mapped textures or a // single mip-mapped texture in stage 1 they only get // per-poly mipmapping. if( (TSSTATE ( iTSStage, D3DTSS_MIPFILTER ) != D3DTFP_NONE) && pTexture->bMipMap ) { int iLOD, iTexLOD; // Load the mipmap levels for texture 1 // Mip level from pMipBases->dwTex1ActMaxLevel to // pTexture->iMipLevels will be mapped to base address slot // from pMipBases->dwTex1Mipbase to dwTex1MipMax iLOD = pMipBases->dwTex1MipBase; iTexLOD = pMipBases->dwTex1ActMaxLevel; iT1MaxLevel = iTexLOD; P3_ENSURE_DX_SPACE(32); WAIT_FIFO(32); while(( iTexLOD < pTexture->iMipLevels ) && ( iLOD <= (int)pMipBases->dwTex1MipMax )) { DISPDBG((DBGLVL, " Setting Texture Base Address %d to 0x%x", iLOD, pTexture->MipLevels[iTexLOD].dwOffsetFromMemoryBase)); pSoftP3RX->P3RXTextureMapWidth[iLOD] = pTexture->MipLevels[iTexLOD].P3RXTextureMapWidth; #if DX7_TEXMANAGEMENT // If this is a driver managed texture surface, we need // to use our privately allocated mem ptr if (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { SEND_P3_DATA_OFFSET(TextureBaseAddr0, (DWORD)D3DTMMIPLVL_GETOFFSET(pTexture->MipLevels[iTexLOD], pThisDisplay), iLOD); } else #endif { SEND_P3_DATA_OFFSET(TextureBaseAddr0, pTexture->MipLevels[iTexLOD].dwOffsetFromMemoryBase, iLOD); } iLOD++; iTexLOD++; } pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_DISABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap1 = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureIndexMode1.MipMapEnable = __PERMEDIA_ENABLE; P3_ENSURE_DX_SPACE(2); WAIT_FIFO(2); { DWORD d; *(float *)&d = pContext->MipMapLODBias[TEXSTAGE_1] * pTexture->dwPixelPitch * pTexture->wHeight; SEND_P3_DATA(TextureLODScale1, d); } } else { int iTexLOD; // Use the maximum level indicated by D3DTSS_MAXMIPLEVEL iTexLOD = pMipBases->dwTex0ActMaxLevel; iT1MaxLevel = iTexLOD; pSoftP3RX->P3RXTextureCoordMode.EnableLOD = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCoordMode.EnableDY = __PERMEDIA_DISABLE; pSoftP3RX->P4DeltaFormatControl.PerPolyMipMap1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode1.MipMapEnable = __PERMEDIA_DISABLE; P3_ENSURE_DX_SPACE(2); WAIT_FIFO(2); #if DX7_TEXMANAGEMENT // If this is a driver managed texture surface, we need // to use our privately allocated mem ptr if (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { SEND_P3_DATA_OFFSET(TextureBaseAddr0, (DWORD)D3DTMMIPLVL_GETOFFSET(pTexture->MipLevels[iTexLOD], pThisDisplay), pMipBases->dwTex1MipBase); } else #endif { SEND_P3_DATA_OFFSET(TextureBaseAddr0, pTexture->MipLevels[iTexLOD].dwOffsetFromMemoryBase, pMipBases->dwTex1MipBase); } // No mipmapping. pSoftP3RX->P3RXTextureMapWidth[pMipBases->dwTex1MipBase] = pTexture->MipLevels[iTexLOD].P3RXTextureMapWidth; } ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: " "pFormatSurace is NULL" ); if (pFormatSurface->DeviceFormat == SURF_CI8) { // In the future, this will work as long as texture 0 isn't // palettised, or if they share the palette. // But that needs some restructuring - the whole LUT setup // should be in a single bit of code in _D3DChangeTextureP3RX, // since it is a shared resource. DISPDBG((ERRLVL,"** SetupTextureUnitStage: allow second texture " "to use LUTs")); // For now, fail. SET_BLEND_ERROR ( pContext, BSF_TOO_MANY_PALETTES ); } P3_DMA_COMMIT_BUFFER(); __TXT_ConsiderSrcChromaKey( pContext, pTexture, 1 ); P3_DMA_GET_BUFFER(); // Setup TextureReadMode pSoftP3RX->P3RXTextureReadMode1.MapBaseLevel = pMipBases->dwTex1MipBase; pSoftP3RX->P3RXTextureReadMode1.MapMaxLevel = pMipBases->dwTex1MipMax; pSoftP3RX->P3RXTextureReadMode1.Width = pTexture->MipLevels[iT1MaxLevel].logWidth; pSoftP3RX->P3RXTextureReadMode1.Height = pTexture->MipLevels[iT1MaxLevel].logHeight; pSoftP3RX->P3RXTextureReadMode1.TexelSize = pTexture->dwPixelSize; pSoftP3RX->P3RXTextureReadMode1.LogicalTexture = __PERMEDIA_DISABLE; // Enable the texture index unit (this is a bit like the // the texture read) pSoftP3RX->P3RXTextureIndexMode1.Width = pTexture->MipLevels[iT1MaxLevel].logWidth; pSoftP3RX->P3RXTextureIndexMode1.Height = pTexture->MipLevels[iT1MaxLevel].logHeight; ASSERTDD ( pFormatSurface != NULL, "** SetupTextureUnitStage: logic error: " "pFormatSurace is NULL" ); pSoftP3RX->P3RXTextureFilterMode.Format1 = pFormatSurface->FilterFormat; // Enable stage 1 pSoftP3RX->P3RXTextureIndexMode1.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureReadMode1.Enable = __PERMEDIA_ENABLE; #if DX7_PALETTETEXTURE #if 0 // D3DValidateDeviceP3() will return error code for this case ASSERTDD((pFormatSurface->DeviceFormat != SURF_CI8 && pFormatSurface->DeviceFormat != SURF_CI4), "Texture surface can't be palettized when using a " "second map!"); #endif #endif break; } } P3_DMA_COMMIT_BUFFER(); return TRUE; } // __TXT_SetupTexture //----------------------------------------------------------------------------- // // __bD3DTexturesMatch // // // A function to compare the two textures in two D3D stages, and determine // if they could be satisfied by the same on-chip texture. // // int iStage1 D3D stage number of first texture. // int iStage2 D3D stage number of second texture. // *pContext The context. // // result: TRUE if the textures match, FALSE if they don't. // // An ASSERT is triggered if either stage is not using a texture. In the // release build, the result will be TRUE, meaning that we could pack both // textures stages requirements into one texture (because one or both do // not use a texture). // //----------------------------------------------------------------------------- BOOL __bD3DTexturesMatch ( int iStage1, int iStage2, P3_D3DCONTEXT* pContext ) { ASSERTDD ( iStage1 != iStage2, "** __bD3DTexturesMatch: both stages are the same " "- pointless comparison!" ); if ( TSSTATE ( iStage1, D3DTSS_TEXTUREMAP ) == 0 ) { DISPDBG((ERRLVL,"** __bD3DTexturesMatch: first considered stage's " "texture is NULL")); return ( TRUE ); } else if ( TSSTATE ( iStage2, D3DTSS_TEXTUREMAP ) == 0 ) { DISPDBG((ERRLVL,"** __bD3DTexturesMatch: second considered stage's " "texture is NULL")); return ( TRUE ); } else { #define CHECK_EQUALITY(name) ( TSSTATE ( iStage1, name ) == TSSTATE ( iStage2, name ) ) if (CHECK_EQUALITY ( D3DTSS_TEXTUREMAP ) && CHECK_EQUALITY ( D3DTSS_TEXCOORDINDEX ) ) { // Yes, the textures have the same handle and coord set. Do // some further checks. // If the pointers are different, or the texcoord sets are // different (for bumpmapping), this is a common occurrance, // and need not be flagged. However, if they are the same, // but a filter mode or something like that is different, // it is likely to be an app bug, so flag it. if ( // Should not need to check ADDRESS // - should have been mirrored to ADDRESS[UV]. CHECK_EQUALITY ( D3DTSS_ADDRESSU ) && CHECK_EQUALITY ( D3DTSS_ADDRESSV ) && CHECK_EQUALITY ( D3DTSS_MAGFILTER ) && CHECK_EQUALITY ( D3DTSS_MINFILTER ) && CHECK_EQUALITY ( D3DTSS_MIPFILTER ) ) // I should also check all the other variables like // MIPMAPLODBIAS, but they rely on mipmapping being // enabled, etc, so it's more of a hassle. If an app // really does manage to be this perverse, it's doing well! { // Looks good. return ( TRUE ); } else { // Well, the texcoords agree and the handle agree, but the // others don't. I bet this is an app bug - you are unlikely // to do this deliberately. _D3DDisplayWholeTSSPipe ( pContext, WRNLVL ); DISPDBG((ERRLVL,"** __bD3DTexturesMatch: textures agree in " "handle and texcoord, but not other things - " "likely app bug.")); return ( FALSE ); } } else { // No, different textures. return ( FALSE ); } #undef CHECK_EQUALITY } return TRUE; } // __bD3DTexturesMatch //----------------------------------------------------------------------------- // // _D3DChangeTextureP3RX // // This function does whole setup of necessary texturing state according to // the current renderestates and texture stage states. Disables texturing // accordingly if this is needed. // //----------------------------------------------------------------------------- void _D3DChangeTextureP3RX( P3_D3DCONTEXT* pContext) { P3_SURF_INTERNAL* pTexture0 = NULL; P3_SURF_INTERNAL* pTexture1 = NULL; P3_THUNKEDDATA * pThisDisplay = pContext->pThisDisplay; P3_SOFTWARECOPY* pSoftP3RX = &pContext->SoftCopyGlint; P3_MIP_BASES mipBases; DWORD* pFlags = &pContext->Flags; INT i, iLastChipStage; DWORD dwT0MipLevels, dwT1MipLevels, dwTexAppTfactor, dwTexComp0Tfactor, dwTexComp1Tfactor; BOOL bBothTexturesValid, bProcessChipStage0, bProcessChipStage1, bProcessChipStage2, bAlphaBlendDouble; P3_DMA_DEFS(); DBG_ENTRY(_D3DChangeTextureP3RX); pContext->iTexStage[0] = -1; pContext->iTexStage[1] = -1; // This is checked against the current state at the end of the routine. bAlphaBlendDouble = FALSE; // Verify if texturing should be disabled if ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) == D3DTOP_DISABLE ) || ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_TEXTUREMAP ) == 0 ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLOROP ) == D3DTOP_DISABLE ) && ( ( ( TSSTATESELECT ( TEXSTAGE_0, D3DTSS_COLORARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) != D3DTOP_SELECTARG2 ) ) || ( ( TSSTATESELECT ( TEXSTAGE_0, D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) != D3DTOP_SELECTARG1 ) ) ) ) ) { // Stage 0 is disabled, so they just want the diffuse colour. // Or, the texture handle is 0 , stage 1 is D3DTOP_DISABLE and in stage // 0 we are selecting an arg that is not a D3DTA_TEXTURE DISPDBG((DBGLVL, "All composite units disabled - setting diffuse colour")); P3_DMA_GET_BUFFER_ENTRIES(20); // Turn off texture address generation pSoftP3RX->P3RXTextureCoordMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureCoordMode, pSoftP3RX->P3RXTextureCoordMode); // Turn off texture reads pSoftP3RX->P3RXTextureReadMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureReadMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureReadMode0, pSoftP3RX->P3RXTextureReadMode0); COPY_P3_DATA(TextureReadMode1, pSoftP3RX->P3RXTextureReadMode1); pSoftP3RX->P3RXTextureIndexMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureIndexMode0, pSoftP3RX->P3RXTextureIndexMode0); COPY_P3_DATA(TextureIndexMode1, pSoftP3RX->P3RXTextureIndexMode1); // Turn off the texture filter mode unit pSoftP3RX->P3RXTextureFilterMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureFilterMode, pSoftP3RX->P3RXTextureFilterMode); // Turn off texture color mode unit pSoftP3RX->P3RXTextureApplicationMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureApplicationMode, pSoftP3RX->P3RXTextureApplicationMode); // Not compositing SEND_P3_DATA(TextureCompositeMode, __PERMEDIA_DISABLE); *pFlags &= ~SURFACE_TEXTURING; pSoftP3RX->P3RXLUTMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(LUTMode, pSoftP3RX->P3RXLUTMode); // Specular texture can be enabled without texturing on COPY_P3_DATA(DeltaMode, pSoftP3RX->P3RX_P3DeltaMode); P3_DMA_COMMIT_BUFFER(); // Turn off texturing in the render command RENDER_TEXTURE_DISABLE(pContext->RenderCommand); pContext->bTextureValid = TRUE; pContext->pCurrentTexture[0] = NULL; pContext->pCurrentTexture[1] = NULL; // Track just for debugging purpouses pContext->bTexDisabled = TRUE; bAlphaBlendDouble = FALSE; if ( bAlphaBlendDouble != pContext->bAlphaBlendMustDoubleSourceColour ) { pContext->bAlphaBlendMustDoubleSourceColour = bAlphaBlendDouble; DIRTY_ALPHABLEND(pContext); } DBG_EXIT(_D3DChangeTextureP3RX,1); return; } if ( TSSTATE ( TEXSTAGE_0, D3DTSS_TEXTUREMAP ) == 0 ) if ( ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLORARG1 ) == D3DTA_TFACTOR ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) ) || ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLORARG2 ) == D3DTA_TFACTOR ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) == D3DTOP_SELECTARG2 ) ) ) { // This is an unusual way to set up the diffuse color : take // it from the the D3DTA_TFACTOR. But some apps use it. // we need to treat it separately for the Perm3 setup because // it might not be binded with any texture DISPDBG((DBGLVL, "Diffuse color comes from D3DTA_TFACTOR")); P3_DMA_GET_BUFFER_ENTRIES(30); // Turn off texture address generation pSoftP3RX->P3RXTextureCoordMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureCoordMode, pSoftP3RX->P3RXTextureCoordMode); // Turn off texture reads pSoftP3RX->P3RXTextureReadMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureReadMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureReadMode0, pSoftP3RX->P3RXTextureReadMode0); COPY_P3_DATA(TextureReadMode1, pSoftP3RX->P3RXTextureReadMode1); pSoftP3RX->P3RXTextureIndexMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureIndexMode0, pSoftP3RX->P3RXTextureIndexMode0); COPY_P3_DATA(TextureIndexMode1, pSoftP3RX->P3RXTextureIndexMode1); // Turn off the texture filter mode unit pSoftP3RX->P3RXTextureFilterMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureFilterMode, pSoftP3RX->P3RXTextureFilterMode); // Setup texture color mode unit pSoftP3RX->P3RXTextureApplicationMode.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureApplicationMode.ColorA = P3RX_TEXAPP_A_KC; pSoftP3RX->P3RXTextureApplicationMode.ColorOperation = P3RX_TEXAPP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureApplicationMode.AlphaA = P3RX_TEXAPP_A_KA; pSoftP3RX->P3RXTextureApplicationMode.AlphaOperation = P3RX_TEXAPP_OPERATION_PASS_A; COPY_P3_DATA(TextureApplicationMode, pSoftP3RX->P3RXTextureApplicationMode); // Setup compositing pSoftP3RX->P3RXTextureCompositeAlphaMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg1 = P3RX_TEXCOMP_FA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; COPY_P3_DATA(TextureCompositeAlphaMode0, pSoftP3RX->P3RXTextureCompositeAlphaMode0); pSoftP3RX->P3RXTextureCompositeColorMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg1 = P3RX_TEXCOMP_FC; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeColorMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeColorMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; COPY_P3_DATA(TextureCompositeColorMode0, pSoftP3RX->P3RXTextureCompositeColorMode0); pSoftP3RX->P3RXTextureCompositeAlphaMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureCompositeAlphaMode1, pSoftP3RX->P3RXTextureCompositeAlphaMode1); pSoftP3RX->P3RXTextureCompositeColorMode1.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(TextureCompositeColorMode1, pSoftP3RX->P3RXTextureCompositeColorMode1); SEND_P3_DATA(TextureCompositeMode, __PERMEDIA_ENABLE); *pFlags &= ~SURFACE_TEXTURING; pSoftP3RX->P3RXLUTMode.Enable = __PERMEDIA_DISABLE; COPY_P3_DATA(LUTMode, pSoftP3RX->P3RXLUTMode); // Specular texture can be enabled without texturing on COPY_P3_DATA(DeltaMode, pSoftP3RX->P3RX_P3DeltaMode); P3_DMA_COMMIT_BUFFER(); // Turn off texturing in the render command // RENDER_TEXTURE_DISABLE(pContext->RenderCommand); RENDER_TEXTURE_ENABLE(pContext->RenderCommand); pContext->bTextureValid = TRUE; pContext->pCurrentTexture[0] = NULL; pContext->pCurrentTexture[1] = NULL; // Track just for debugging purpouses pContext->bTexDisabled = FALSE; DBG_EXIT(_D3DChangeTextureP3RX,1); return; } // Track just for debugging purpouses pContext->bTexDisabled = FALSE; // Dump to the debugger our current TSS setup _D3DDisplayWholeTSSPipe(pContext, DBGLVL); // Deal with the textures. // Find the texture mappings. If D3D stage 0 uses a texture, it must // always be chip texture 0 to keep the bumpmap working. Fortunately, // this is the only non-orthogonal case, so everything else can cope // with this restriction. for ( i = TEXSTAGE_0; i < D3DTSS_MAX; i++ ) { if ( TSSTATE ( i, D3DTSS_COLOROP ) == D3DTOP_DISABLE ) { // Finished processing. break; } // This code could be slightly optimised - if a texture is set up, // but none of the relevant arguments are TEXTURE (with additional // flags), then of course we don't need to set the texture up at all. // Normally, both arguments are "relevant", but with SELECTARG1 and // SELECTARG2, one of them is not. Also, watch out for PREMODULATE - // it is an implicit reference to a stage's texture. if ( ( TSSTATE ( i, D3DTSS_TEXTUREMAP ) == 0 ) || ( ( ( ( TSSTATESELECT ( i, D3DTSS_COLORARG1 ) != D3DTA_TEXTURE ) || ( TSSTATE ( i, D3DTSS_COLOROP ) == D3DTOP_SELECTARG2 ) ) && ( ( TSSTATESELECT ( i, D3DTSS_COLORARG2 ) != D3DTA_TEXTURE ) || ( TSSTATE ( i, D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) ) && ( ( TSSTATESELECT ( i, D3DTSS_ALPHAARG1 ) != D3DTA_TEXTURE ) || ( TSSTATE ( i, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG2 ) ) && ( ( TSSTATESELECT ( i, D3DTSS_ALPHAARG2 ) != D3DTA_TEXTURE ) || ( TSSTATE ( i, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) ) ) && ( TSSTATE ( i, D3DTSS_COLOROP ) != D3DTOP_PREMODULATE ) && ( TSSTATE ( i-1, D3DTSS_COLOROP ) != D3DTOP_PREMODULATE ) ) ) { // This D3D stage doesn't use a texture. pContext->iStageTex[i] = -1; } else { // Note that the below code should be put into a little loop // for any future devices that have more than 2 textures, otherwise // the code will get big, nested and crufty. But for only 2, it's // manageable, and slightly faster this way. // A texture is used - is texture 0 free? if ( pContext->iTexStage[0] == -1 ) { // Texture 0 is free - make it this stage. ASSERTDD ( pContext->iTexStage[1] == -1, "** _D3DChangeTextureP3RX: pContext->iTexStage[1] " "should be -1 if pContext->iTexStage[0] is" ); pContext->iTexStage[0] = i; pContext->iStageTex[i] = 0; } else { // Texture 0 is assigned - see if this is the same as it. if ( __bD3DTexturesMatch ( i, pContext->iTexStage[0], pContext ) ) { // Yes, they match - no need to use texture 1. pContext->iStageTex[i] = 0; } else { // No, they don't match. Is texture 1 free? if ( pContext->iTexStage[1] == -1 ) { // Texture 1 is free - make it this stage. ASSERTDD ( pContext->iTexStage[0] != -1, "** _D3DChangeTextureP3RX: " "pContext->iTexStage[0] should not be " "-1 if pContext->iTexStage[1] is not." ); pContext->iTexStage[1] = i; pContext->iStageTex[i] = 1; } else { // Texture 1 is assigned - see if this is the same // as it. if ( __bD3DTexturesMatch ( i, pContext->iTexStage[1], pContext ) ) { // Yes, they match - mark it. pContext->iStageTex[i] = 1; } else { // No, they don't match, and both chip textures // have been assigned. Fail a ValidateDevice(). DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: app tried " "to use more than two textures.")); SET_BLEND_ERROR ( pContext, BSF_TOO_MANY_TEXTURES ); pContext->iStageTex[i] = -1; } } } } } // A quick sanity check. #if DBG if ( TSSTATE ( i, D3DTSS_TEXTUREMAP ) == 0 ) { // That's fine, then. ASSERTDD ( pContext->iStageTex[i] == -1, "** _D3DChangeTextureP3RX: something failed with the " "texture-assignment logic" ); } else if ( pContext->iStageTex[i] == -1 ) { // That's fine - texture may have been set up but not referenced. } else if ( pContext->iTexStage[pContext->iStageTex[i]] == -1 ) { // Oops. DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: something failed with " "the texture-assignment logic")); } else if ( pContext->iTexStage[pContext->iStageTex[i]] == i ) { // That's fine, then. } else if ( __bD3DTexturesMatch ( i, pContext->iTexStage[pContext->iStageTex[i]], pContext ) ) { // That's fine, then. } else { // Oops. DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: something failed with " "the texture-assignment logic")); } #endif // DBG } // And a few more gratuitous sanity checks at the end of the loop. ASSERTDD ( ( pContext->iTexStage[0] == -1 ) || ( pContext->iStageTex[pContext->iTexStage[0]] == 0 ), "** _D3DChangeTextureP3RX: something failed with the " "texture-assignment logic" ); ASSERTDD ( ( pContext->iTexStage[1] == -1 ) || ( pContext->iStageTex[pContext->iTexStage[1]] == 1 ), "** _D3DChangeTextureP3RX: something failed with the " "texture-assignment logic" ); #if DBG if ( pContext->iTexStage[0] != -1 ) { DISPDBG((DBGLVL, "Setting new texture0 data, Handle: 0x%x", TSSTATE ( pContext->iTexStage[0], D3DTSS_TEXTUREMAP ))); } else { DISPDBG((DBGLVL, "Texture0 not used" )); } if ( pContext->iTexStage[1] != -1 ) { DISPDBG((DBGLVL, "Setting new texture1 data, Handle: 0x%x", TSSTATE ( pContext->iTexStage[1], D3DTSS_TEXTUREMAP ))); } else { DISPDBG((DBGLVL, "Texture1 not used" )); } #endif //DBG // Set the texture valid flag to true. // If anything resets it then the texture state is invalid. pContext->bTextureValid = TRUE; pContext->bCanChromaKey = FALSE; pContext->bTex0Valid = FALSE; pContext->bTex1Valid = FALSE; pContext->bStage0DotProduct = FALSE; // Set up the textures. if ( pContext->iTexStage[0] != -1 ) { // Setup texture 0. pTexture0 = GetSurfaceFromHandle(pContext, TSSTATE(pContext->iTexStage[0], D3DTSS_TEXTUREMAP) ); if (NULL == pTexture0) { DISPDBG((ERRLVL, "ERROR: Texture Surface (0) is NULL")); DBG_EXIT(_D3DChangeTextureP3RX,1); return; } #if DX7_TEXMANAGEMENT if (pTexture0->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { if (!_D3D_TM_Preload_Tex_IntoVidMem(pContext, pTexture0)) { return; // something bad happened !!! } _D3D_TM_TimeStampTexture(pContext->pTextureManager, pTexture0); } #endif // DX7_TEXMANAGEMENT pContext->bTex0Valid = __TXT_ValidateTextureUnitStage(pContext, 0, pContext->iTexStage[0], pTexture0 ); if ( !pContext->bTex0Valid ) { SET_BLEND_ERROR ( pContext, BSF_INVALID_TEXTURE ); // Pretend that no texture was set. pSoftP3RX->P3RXTextureReadMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode0.Enable = __PERMEDIA_DISABLE; pContext->bTex0Valid = FALSE; pTexture0 = NULL; } } else { pSoftP3RX->P3RXTextureReadMode0.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode0.Enable = __PERMEDIA_DISABLE; pContext->bTex0Valid = FALSE; pTexture0 = NULL; } if ( pContext->iTexStage[1] != -1 ) { // Setup texture 1. if ( pContext->iTexStage[0] == -1 ) { DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: Should not be " "using tex1 if tex0 not used.")); SET_BLEND_ERROR ( pContext, BSF_TOO_MANY_BLEND_STAGES ); } pTexture1 = GetSurfaceFromHandle(pContext, TSSTATE ( pContext->iTexStage[1], D3DTSS_TEXTUREMAP ) ); if (NULL == pTexture1) { DISPDBG((ERRLVL, "ERROR: Texture Surface (1) is NULL")); DBG_EXIT(_D3DChangeTextureP3RX,1); return; } #if DX7_TEXMANAGEMENT if (pTexture1->dwCaps2 & DDSCAPS2_TEXTUREMANAGE) { if (!_D3D_TM_Preload_Tex_IntoVidMem(pContext, pTexture1)) { return; // something bad happened !!! } _D3D_TM_TimeStampTexture(pContext->pTextureManager, pTexture1); } #endif // DX7_TEXMANAGEMENT pContext->bTex1Valid = __TXT_ValidateTextureUnitStage(pContext, 1, pContext->iTexStage[1], pTexture1 ); if ( !pContext->bTex1Valid ) { SET_BLEND_ERROR ( pContext, BSF_INVALID_TEXTURE ); // Pretend that no texture was set. pSoftP3RX->P3RXTextureReadMode1.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode1.Enable = __PERMEDIA_DISABLE; pContext->bTex1Valid = FALSE; pTexture1 = NULL; } } else { pSoftP3RX->P3RXTextureReadMode1.Enable = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureIndexMode1.Enable = __PERMEDIA_DISABLE; pContext->bTex1Valid = FALSE; pTexture1 = NULL; } bBothTexturesValid = pContext->bTex0Valid && pContext->bTex1Valid; if( pContext->bTex0Valid ) { dwT0MipLevels = pContext->TextureStageState[0].m_dwVal[D3DTSS_MAXMIPLEVEL]; #if DX7_TEXMANAGEMENT if ( dwT0MipLevels < pTexture0->m_dwTexLOD) { dwT0MipLevels = pTexture0->m_dwTexLOD; } #endif // DX7_TEXMANAGEMENT if (dwT0MipLevels > ((DWORD)(pTexture0->iMipLevels - 1))) { // Set the actuall maximum mip level that will be used in rendering mipBases.dwTex0ActMaxLevel = pTexture0->iMipLevels - 1; dwT0MipLevels = 1; } else { // Set the actuall maximum mip level that will be used in rendering mipBases.dwTex0ActMaxLevel = dwT0MipLevels; dwT0MipLevels = pTexture0->iMipLevels - dwT0MipLevels; } } if( pContext->bTex1Valid ) { ASSERTDD ( pContext->bTex0Valid, "** _D3DChangeTextureP3RX: tex1 should not be used " "unless tex0 is used as well" ); dwT1MipLevels = pContext->TextureStageState[1].m_dwVal[D3DTSS_MAXMIPLEVEL]; #if DX7_TEXMANAGEMENT if ( dwT1MipLevels < pTexture1->m_dwTexLOD) { dwT1MipLevels = pTexture1->m_dwTexLOD; } #endif // DX7_TEXMANAGEMENT if (dwT1MipLevels > ((DWORD)(pTexture1->iMipLevels - 1))) { // Set the actuall maximum mip level that will be used in rendering mipBases.dwTex1ActMaxLevel = pTexture1->iMipLevels - 1; dwT1MipLevels = 1; } else { // Set the actuall maximum mip level that will be used in rendering mipBases.dwTex1ActMaxLevel = dwT1MipLevels; dwT1MipLevels = pTexture1->iMipLevels - dwT1MipLevels; } // Enable generation of the second set of texture coordinates. // Strictly, we should check whether texture 0 is being used, and // if not move the second texture to the first (thus enabling // mipmapping, etc) but that's for later. pSoftP3RX->P3RX_P3DeltaMode.TextureEnable1 = __PERMEDIA_ENABLE; pSoftP3RX->P3RX_P3DeltaControl.ShareQ = 1; } else { // Turn off generation of the second set of texture coordinates pSoftP3RX->P3RX_P3DeltaMode.TextureEnable1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RX_P3DeltaControl.ShareQ = 0; } if( bBothTexturesValid ) { float totBases, baseRatio; DWORD t0Count, res; totBases = (float)dwT0MipLevels + dwT1MipLevels; // Adjust mip levels to fit in N - 2 slots as each texture // needs at least one slot. baseRatio = ( P3_TEX_MAP_MAX_LEVEL - 1 ) / totBases; // Calculate number of slots for texture 0, texture 1 then // gets the remainder. myFtoi( &res, dwT0MipLevels * baseRatio ); t0Count = 1 + res; ASSERTDD( t0Count > 0, "No slots for texture 0" ); ASSERTDD( t0Count <= P3_TEX_MAP_MAX_LEVEL, "No slots for texture 1" ); #define FIXED_ALLOC 0 #if FIXED_ALLOC mipBases.dwTex0MipBase = 0; mipBases.dwTex0MipMax = min( dwT0MipLevels - 1, 7 ); mipBases.dwTex1MipBase = 8; mipBases.dwTex1MipMax = 8 + min( dwT1MipLevels - 1, P3_TEX_MAP_MAX_LEVEL - 8 ); #else mipBases.dwTex0MipBase = 0; mipBases.dwTex0MipMax = min( dwT0MipLevels - 1, t0Count - 1 ); mipBases.dwTex1MipBase = t0Count; mipBases.dwTex1MipMax = t0Count + min( dwT1MipLevels - 1, P3_TEX_MAP_MAX_LEVEL - t0Count ); #endif } else { if( pContext->bTex0Valid ) { mipBases.dwTex0MipBase = 0; mipBases.dwTex0MipMax = min( dwT0MipLevels - 1, P3_TEX_MAP_MAX_LEVEL ); mipBases.dwTex1MipBase = 0; mipBases.dwTex1MipMax = min( dwT0MipLevels - 1, P3_TEX_MAP_MAX_LEVEL ); } if( pContext->bTex1Valid ) { mipBases.dwTex0MipBase = 0; mipBases.dwTex0MipMax = min( dwT1MipLevels - 1, P3_TEX_MAP_MAX_LEVEL ); mipBases.dwTex1MipBase = 0; mipBases.dwTex1MipMax = min( dwT1MipLevels - 1, P3_TEX_MAP_MAX_LEVEL ); } } DISPDBG(( DBGLVL, "tex0 base %d", mipBases.dwTex0MipBase )); DISPDBG(( DBGLVL, "tex0 max %d", mipBases.dwTex0MipMax )); DISPDBG(( DBGLVL, "tex1 base %d", mipBases.dwTex1MipBase )); DISPDBG(( DBGLVL, "tex1 max %d", mipBases.dwTex1MipMax )); // Recalculate the LOD biases for per-poly mipmapping pContext->MipMapLODBias[TEXSTAGE_0] = pow4( pContext->TextureStageState[TEXSTAGE_0]. m_fVal[D3DTSS_MIPMAPLODBIAS] ); pContext->MipMapLODBias[TEXSTAGE_1] = pow4( pContext->TextureStageState[TEXSTAGE_1]. m_fVal[D3DTSS_MIPMAPLODBIAS] ); if ( pTexture0 != NULL ) { __TXT_SetupTexture ( pThisDisplay, 0, pContext->iTexStage[0], pContext, pTexture0, pSoftP3RX, bBothTexturesValid, &mipBases); } if ( pTexture1 != NULL ) { __TXT_SetupTexture ( pThisDisplay, 1, pContext->iTexStage[1], pContext, pTexture1, pSoftP3RX, bBothTexturesValid, &mipBases); #if DX7_PALETTETEXTURE if (GET_BLEND_ERROR(pContext) == BSF_TOO_MANY_PALETTES) { if (pTexture0 && (pTexture0->dwPaletteHandle == pTexture1->dwPaletteHandle)) { RESET_BLEND_ERROR(pContext); } } #endif } // Fix up the D3DRENDERSTATE_MODULATE case. if( pTexture0 != NULL ) { if( pContext->Flags & SURFACE_MODULATE ) { // If SURFACE_MODULATE is set then we must have seen a // DX5-style texture blend // Note : bAlpha is true for CI8 and CI4 textures BOOL bSelectArg1 = pTexture0->pFormatSurface->bAlpha; #if DX7_PALETTETEXTURE if( pTexture0->pixFmt.dwFlags & DDPF_PALETTEINDEXED8 ) { bSelectArg1 = pTexture0->dwPaletteFlags & DDRAWIPAL_ALPHA; } #endif if( bSelectArg1 ) { TSSTATE( pContext->iChipStage[0], D3DTSS_ALPHAOP ) = D3DTOP_SELECTARG1; } else { TSSTATE( pContext->iChipStage[0], D3DTSS_ALPHAOP ) = D3DTOP_SELECTARG2; } } } P3_DMA_GET_BUFFER(); // Textures set up - now do the blending. // These might be overidden later for special blends. dwTexAppTfactor = pContext->RenderStates[D3DRENDERSTATE_TEXTUREFACTOR]; dwTexComp0Tfactor = pContext->RenderStates[D3DRENDERSTATE_TEXTUREFACTOR]; dwTexComp1Tfactor = pContext->RenderStates[D3DRENDERSTATE_TEXTUREFACTOR]; // Detect the stage 0 & 1 bumpmap setup code. if (( TSSTATE ( TEXSTAGE_0, D3DTSS_TEXTUREMAP ) != 0 ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_TEXTUREMAP ) != 0 ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_COLOROP ) != D3DTOP_DISABLE ) ) { // Looking good for a bumpmap. Now find various special cases. // First of all, do they want anything in the stage 2 current colour? if ( ( ( ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_COLORARG1 ) != D3DTA_CURRENT ) && ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_COLORARG2 ) != D3DTA_CURRENT ) ) || ( ( TSSTATE ( TEXSTAGE_2, D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) && ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_COLORARG1 ) != D3DTA_CURRENT ) ) || ( ( TSSTATE ( TEXSTAGE_2, D3DTSS_COLOROP ) == D3DTOP_SELECTARG2 ) && ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_COLORARG2 ) != D3DTA_CURRENT ) ) ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) != D3DTOP_DOTPRODUCT3 ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLOROP ) != D3DTOP_DOTPRODUCT3 ) ) { // Nope - they don't care what the current colour channel is, and // no dotproducts are used in stages 0 and 1 (they affect the alpha // channel) so ignore what is in the colour channel - this is a // bumpmap so far. // Now see if they want a bumpmap or an inverted bumpmap. People // are so fussy. // Check first stage. if (( ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATEALPHA ( TEXSTAGE_0, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) ) || ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG2 ) && ( TSSTATEALPHA ( TEXSTAGE_0, D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) ) ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) ) { // First stage fine and not inverted. Check second stage. if (( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == ( D3DTA_TEXTURE | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) || ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_TEXTURE | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) ) ) { // Fine, not inverted. pContext->bBumpmapEnabled = TRUE; pContext->bBumpmapInverted = FALSE; } else if ( ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) ) || ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) ) ) { // Fine, inverted. pContext->bBumpmapEnabled = TRUE; pContext->bBumpmapInverted = TRUE; } else { // Nope, second stage is no good. pContext->bBumpmapEnabled = FALSE; pContext->bBumpmapInverted = FALSE; } } else if ( ( ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATEALPHA ( TEXSTAGE_0, D3DTSS_ALPHAARG1 ) == (D3DTA_TEXTURE | D3DTA_COMPLEMENT) ) ) || ( ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG2 ) && ( TSSTATEALPHA ( TEXSTAGE_0, D3DTSS_ALPHAARG2 ) == (D3DTA_TEXTURE | D3DTA_COMPLEMENT) ) ) ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) ) { // First stage fine and inverted. Check second stage. if (( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) || ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) ) ) { // Fine, inverted. pContext->bBumpmapEnabled = TRUE; pContext->bBumpmapInverted = TRUE; } else if ( ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_TEXTURE | D3DTA_COMPLEMENT ) ) ) || ( ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) && ( TSSTATEALPHA ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == ( D3DTA_TEXTURE | D3DTA_COMPLEMENT ) ) ) ) { // Fine, not inverted. pContext->bBumpmapEnabled = TRUE; pContext->bBumpmapInverted = FALSE; } else { // Nope, second stage is no good. pContext->bBumpmapEnabled = FALSE; pContext->bBumpmapInverted = FALSE; } } else { // Nope, first stage is no good. pContext->bBumpmapEnabled = FALSE; pContext->bBumpmapInverted = FALSE; } } else { // Could do some more checking, e.g. is all they want in the current colour // channel easily available from a single input, e.g. tex0.c, in which case // that's fine. A non-bumpmap variant also needs to sense that the first // stage is simply a selectarg1/2 and thus can ignore the first stage as // a texcomp stage. // But that's for later. pContext->bBumpmapEnabled = FALSE; pContext->bBumpmapInverted = FALSE; } } else { pContext->bBumpmapEnabled = FALSE; pContext->bBumpmapInverted = FALSE; } if ( pContext->bBumpmapEnabled ) { DISPDBG((DBGLVL,"Enabling emboss bumpmapping")); // Remap stages 1 & 2 out of existence. pContext->iChipStage[0] = TEXSTAGE_2; pContext->iChipStage[1] = TEXSTAGE_3; pContext->iChipStage[2] = TEXSTAGE_4; pContext->iChipStage[3] = TEXSTAGE_5; } else { // Normal mapping. pContext->iChipStage[0] = TEXSTAGE_0; pContext->iChipStage[1] = TEXSTAGE_1; pContext->iChipStage[2] = TEXSTAGE_2; pContext->iChipStage[3] = TEXSTAGE_3; } iLastChipStage = 0; // Set these flags to FALSE as the stages are processed. bProcessChipStage0 = TRUE; bProcessChipStage1 = TRUE; bProcessChipStage2 = TRUE; // Turn on the basic enables. pSoftP3RX->P3RXTextureApplicationMode.Enable = __PERMEDIA_ENABLE; // pSoftP3RX->P3RXTextureApplicationMode.EnableKs = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureApplicationMode.EnableKd = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureApplicationMode.MotionCompEnable = __PERMEDIA_DISABLE; // Handle chip stage 0. // Detect the very special-case glossmap+bumpmap code. There is no easy way // to generalise it, so the whole chunk gets checked here. if ( bProcessChipStage0 && bProcessChipStage1 && bProcessChipStage2 && pContext->bTex0Valid && pContext->bTex1Valid && // Colour channel of stage 0 can be whatever you want. ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLOROP ) == D3DTOP_MODULATEALPHA_ADDCOLOR ) && // Early-out test - nothing uses this! ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAARG1 ) == D3DTA_DIFFUSE ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) && ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATEINVMASK ( TEXSTAGE_2, D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) && ( TSSTATE ( TEXSTAGE_3, D3DTSS_COLOROP ) == D3DTOP_MODULATE2X ) && ( TSSTATE ( TEXSTAGE_3, D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( TEXSTAGE_3, D3DTSS_COLORARG2 ) == (D3DTA_CURRENT | D3DTA_ALPHAREPLICATE) ) && ( TSSTATE ( TEXSTAGE_3, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_3, D3DTSS_ALPHAARG1 ) == D3DTA_TFACTOR ) && ( TSSTATE ( TEXSTAGE_4, D3DTSS_COLOROP ) == D3DTOP_DISABLE ) && ( pContext->iStageTex[0] == 0 ) && ( pContext->iStageTex[1] == 1 ) && ( pContext->iStageTex[2] == 0 ) ) { int iMode; // OK, looks good. Check which way round the bumpmapping is being done. if (( TSSTATE ( TEXSTAGE_2, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_ALPHAARG2 ) == (D3DTA_CURRENT | D3DTA_COMPLEMENT) ) ) { // Standard emboss. iMode = 0; } else if (( TSSTATE ( TEXSTAGE_2, D3DTSS_ALPHAARG1 ) == (D3DTA_TEXTURE | D3DTA_COMPLEMENT) ) && ( TSSTATE ( TEXSTAGE_2, D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) { // Inverted emboss. iMode = 1; } else { // No good - can't do it. iMode = -1; } if ( iMode == -1 ) { // Nope. SET_BLEND_ERROR ( pContext, BSF_TOO_MANY_BLEND_STAGES ); bProcessChipStage0 = FALSE; bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; iLastChipStage = 3; } else { // Set up the colour channel of tc0. // Alpha channel will be overridden later. __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[0], pSoftP3RX, 0, 0); // Pass through bump.a, maybe inverted. pSoftP3RX->P3RXTextureCompositeAlphaMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg1 = P3RX_TEXCOMP_HEIGHTA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg2 = P3RX_TEXCOMP_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeAlphaMode0.B = P3RX_TEXCOMP_ARG2; if ( iMode ) { // Inverted bumpmap. pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_ENABLE; } else { // Non-inverted bumpmap. pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_DISABLE; } pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertI = __PERMEDIA_DISABLE; // Do tex1.c * diff.a + current.c pSoftP3RX->P3RXTextureCompositeColorMode1.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeColorMode1.Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AI_ADD_B; pSoftP3RX->P3RXTextureCompositeColorMode1.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode1.Arg1 = P3RX_TEXCOMP_T1C; pSoftP3RX->P3RXTextureCompositeColorMode1.Arg2 = P3RX_TEXCOMP_OC; pSoftP3RX->P3RXTextureCompositeColorMode1.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeColorMode1.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeColorMode1.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode1.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode1.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode1.InvertI = __PERMEDIA_DISABLE; // Pass through bump.a again. pSoftP3RX->P3RXTextureCompositeAlphaMode1.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Arg1 = P3RX_TEXCOMP_OA; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Arg2 = P3RX_TEXCOMP_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode1.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode1.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeAlphaMode1.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeAlphaMode1.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.InvertI = __PERMEDIA_DISABLE; // Do current.c * current.a, by doing B*I+A. A=black, B=current.c, I=current.a pSoftP3RX->P3RXTextureApplicationMode.ColorA = P3RX_TEXAPP_A_KC; pSoftP3RX->P3RXTextureApplicationMode.ColorB = P3RX_TEXAPP_B_TC; pSoftP3RX->P3RXTextureApplicationMode.ColorI = P3RX_TEXAPP_I_TA; pSoftP3RX->P3RXTextureApplicationMode.ColorInvertI = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureApplicationMode.ColorOperation = P3RX_TEXAPP_OPERATION_MODULATE_BI_ADD_A; // Set the colour channel to black (allow the alpha channel to be preserved). dwTexAppTfactor &= 0xff000000; // Alpha channel selects the constant color. pSoftP3RX->P3RXTextureApplicationMode.AlphaA = P3RX_TEXAPP_A_KA; pSoftP3RX->P3RXTextureApplicationMode.AlphaB = P3RX_TEXAPP_B_KA; pSoftP3RX->P3RXTextureApplicationMode.AlphaInvertI = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureApplicationMode.AlphaOperation = P3RX_TEXAPP_OPERATION_PASS_B; // Do *2 in alpha-blend unit. bAlphaBlendDouble = TRUE; // We don't actually need the remap (and it doesn't mean much), // but it stops erroneous errors being flagged. pContext->iChipStage[0] = TEXSTAGE_0; pContext->iChipStage[1] = TEXSTAGE_1; pContext->iChipStage[2] = TEXSTAGE_3; pContext->iChipStage[3] = TEXSTAGE_4; bProcessChipStage0 = FALSE; bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; iLastChipStage = 3; } } // Detect the special-case 3-blend-unit bumpmapping mode. // Third stage will be set up by the standard routines - only the first // two are special-cased and shoehorned into TexComp0. if ( bProcessChipStage0 && !pContext->bBumpmapEnabled && pContext->bTex0Valid && pContext->bTex1Valid && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLOROP ) == D3DTOP_MODULATE ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLORARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_COLORARG2 ) == D3DTA_DIFFUSE ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && // ( TSSTATE ( TEXSTAGE_0, D3DTSS_ALPHAARG2 ) == D3DTA_DIFFUSE ) dont care && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) && ( ( ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == ( D3DTA_TEXTURE | D3DTA_COMPLEMENT ) ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) || ( ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) ) ) ) { // Yep, looks good. Set it up. ASSERTDD ( pContext->iTexStage[0] == 0, "** _D3DChangeTextureP3RX: textures not correct for special bumpmapping" ); ASSERTDD ( pContext->iTexStage[1] == 1, "** _D3DChangeTextureP3RX: textures not correct for special bumpmapping" ); pSoftP3RX->P3RXTextureCompositeColorMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; pSoftP3RX->P3RXTextureCompositeColorMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg1 = P3RX_TEXCOMP_T0C; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg2 = P3RX_TEXCOMP_CC; pSoftP3RX->P3RXTextureCompositeColorMode0.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeColorMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeColorMode0.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertI = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg1 = P3RX_TEXCOMP_HEIGHTA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg2 = P3RX_TEXCOMP_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeAlphaMode0.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertI = __PERMEDIA_DISABLE; if ( ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( TEXSTAGE_1, D3DTSS_ALPHAARG2 ) == ( D3DTA_CURRENT | D3DTA_COMPLEMENT ) ) ) { // Inverted bumpmap. pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_ENABLE; } else { // Normal bumpmap. pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_DISABLE; } // Done chip stage 0, TSS stage 0 & 1. Move chip stage 1 on a notch. pContext->iChipStage[0] = TEXSTAGE_0; pContext->iChipStage[1] = TEXSTAGE_2; pContext->iChipStage[2] = TEXSTAGE_3; pContext->iChipStage[3] = TEXSTAGE_4; iLastChipStage = 1; bProcessChipStage0 = FALSE; } // Detect a chipstage 0 MODULATE+ADD concatenation. Used by lightmaps. // This compresses two stages into texcomp0. The alpha channel has // two modes - either one of the two stages just does a selectarg1 (current), // and the other gets set up as normal, or (for specular stuff) they // both do ADDSIGNED (cur, cur), in which case it's special-cased. if ( bProcessChipStage0 && pContext->bBumpmapEnabled && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLOROP ) == D3DTOP_MODULATE ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLORARG1 ) == ( D3DTA_CURRENT | D3DTA_ALPHAREPLICATE ) ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLORARG2 ) == D3DTA_DIFFUSE ) && ( ( ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) == D3DTOP_ADD ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) ) || ( ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLORARG1 ) == D3DTA_CURRENT ) ) ) ) { // Colour channel is correct and can be squashed down to one stage. // Check that the alpha channel is OK. int bOK; if (( ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) ) || ( ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG2 ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) ) { // Stage 0 is set to pass-through - set up texcomp0 as stage 1. // Colour channel will be overridden later. __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[pContext->iChipStage[1]], pSoftP3RX, pContext->iChipStage[1], 0); bOK = TRUE; } else if (( ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG1 ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) ) || ( ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAOP ) == D3DTOP_SELECTARG2 ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) ) { // Stage 1 is set to pass-through - set up texcomp0 as stage 0. // Colour channel will be overridden later. __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[pContext->iChipStage[0]], pSoftP3RX, pContext->iChipStage[0], 0); bOK = TRUE; } else if (( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAOP ) == D3DTOP_ADDSIGNED ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAARG1 ) == D3DTA_CURRENT ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAARG2 ) == D3DTA_CURRENT ) ) { // Set up to do ( 4 * cur.a - 1.5 ), or rather 4 * ( cur.a - 0.375 ) dwTexComp0Tfactor = 0x60606060; // All channels set to (0.375) pSoftP3RX->P3RXTextureCompositeAlphaMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Operation = P3RX_TEXCOMP_OPERATION_SUBTRACT_AB; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_FOUR; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg1 = P3RX_TEXCOMP_HEIGHTA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg2 = P3RX_TEXCOMP_FA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.I = P3RX_TEXCOMP_I_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeAlphaMode0.B = P3RX_TEXCOMP_ARG2; if ( pContext->bBumpmapInverted ) { pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_ENABLE; } else { pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_DISABLE; } pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertI = __PERMEDIA_DISABLE; bOK = TRUE; } else { bOK = FALSE; } if ( bOK ) { // OK, the alpha channel is fine - set up the colour channel now. pSoftP3RX->P3RXTextureCompositeColorMode0.Enable = __PERMEDIA_ENABLE; if ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) == D3DTOP_ADD ) { // Yes, this is the ((diff.c*cur.a)+tex.c) case. pSoftP3RX->P3RXTextureCompositeColorMode0.Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AI_ADD_B; pSoftP3RX->P3RXTextureCompositeColorMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg1 = P3RX_TEXCOMP_CC; if ( pContext->iStageTex[pContext->iChipStage[1]] == 0 ) { pSoftP3RX->P3RXTextureCompositeColorMode0.Arg2 = P3RX_TEXCOMP_T0C; } else { pSoftP3RX->P3RXTextureCompositeColorMode0.Arg2 = P3RX_TEXCOMP_T1C; } pSoftP3RX->P3RXTextureCompositeColorMode0.I = P3RX_TEXCOMP_I_HA; pSoftP3RX->P3RXTextureCompositeColorMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeColorMode0.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg2 = __PERMEDIA_DISABLE; if ( pContext->bBumpmapInverted ) { pSoftP3RX->P3RXTextureCompositeColorMode0.InvertI = __PERMEDIA_ENABLE; } else { pSoftP3RX->P3RXTextureCompositeColorMode0.InvertI = __PERMEDIA_DISABLE; } } else { // Yes, this is just the (diff.c*cur.a) case. pSoftP3RX->P3RXTextureCompositeColorMode0.Operation = P3RX_TEXCOMP_OPERATION_MODULATE_AB; pSoftP3RX->P3RXTextureCompositeColorMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg1 = P3RX_TEXCOMP_CC; pSoftP3RX->P3RXTextureCompositeColorMode0.Arg2 = P3RX_TEXCOMP_HEIGHTA; pSoftP3RX->P3RXTextureCompositeColorMode0.I = P3RX_TEXCOMP_I_OA; pSoftP3RX->P3RXTextureCompositeColorMode0.A = P3RX_TEXCOMP_ARG1; pSoftP3RX->P3RXTextureCompositeColorMode0.B = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg2 = __PERMEDIA_DISABLE; if ( pContext->bBumpmapInverted ) { pSoftP3RX->P3RXTextureCompositeColorMode0.InvertI = __PERMEDIA_ENABLE; } else { pSoftP3RX->P3RXTextureCompositeColorMode0.InvertI = __PERMEDIA_DISABLE; } } // Done chip stage 0, TSS stage 0 & 1. Move chip stage 1 on a notch. pContext->iChipStage[1]++; pContext->iChipStage[2]++; pContext->iChipStage[3]++; iLastChipStage = 1; bProcessChipStage0 = FALSE; } } if ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLOROP ) == D3DTOP_DISABLE ) { // Nothing more to do. bProcessChipStage0 = FALSE; bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; } if ( pContext->iStageTex[pContext->iChipStage[0]] == -1 ) { // This stage has no texture - is anyone trying to use it? if (( TSSTATESELECT ( pContext->iChipStage[0], D3DTSS_COLORARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLOROP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[0], D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_COLOROP ) != D3DTOP_SELECTARG1 ) || ( TSSTATESELECT ( pContext->iChipStage[0], D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[0], D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[0], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG1 ) ) { // Panic! In future, we should feed white to the argument using the TFACTOR thing, // but for now just disable the rest of the pipeline. bProcessChipStage0 = FALSE; bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; } } if ( bProcessChipStage0 ) { // Set up stage 0 DISPDBG((DBGLVL,"Texture Stage 0 is valid - setting it up")); __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[pContext->iChipStage[0]], pSoftP3RX, pContext->iChipStage[0], 0); iLastChipStage = 1; bProcessChipStage0 = FALSE; } // Handle chip stage 1. if ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) == D3DTOP_DISABLE ) { // Nothing more to do. bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; } if ( pContext->iStageTex[pContext->iChipStage[1]] == -1 ) { // This stage has no texture - is anyone trying to use it? if (( TSSTATESELECT ( pContext->iChipStage[1], D3DTSS_COLORARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[1], D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_COLOROP ) != D3DTOP_SELECTARG1 ) || ( TSSTATESELECT ( pContext->iChipStage[1], D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[1], D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[1], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG1 ) ) { // Panic! In future, we should feed white to the argument using the TFACTOR thing, // but for now just disable the rest of the pipeline. bProcessChipStage1 = FALSE; bProcessChipStage2 = FALSE; } } if ( bProcessChipStage1 ) { // Set up stage 1 DISPDBG((DBGLVL,"Texture Stage 1 is valid - setting it up")); __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[pContext->iChipStage[1]], pSoftP3RX, pContext->iChipStage[1], 1); iLastChipStage = 2; bProcessChipStage1 = FALSE; } // Handle chip stage 2. if ( TSSTATE ( pContext->iChipStage[2], D3DTSS_COLOROP ) == D3DTOP_DISABLE ) { // Nothing more to do. bProcessChipStage2 = FALSE; } if ( pContext->iStageTex[pContext->iChipStage[2]] == -1 ) { // This stage has no texture - is anyone trying to use it? if (( TSSTATESELECT ( pContext->iChipStage[2], D3DTSS_COLORARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[2], D3DTSS_COLOROP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[2], D3DTSS_COLORARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[2], D3DTSS_COLOROP ) != D3DTOP_SELECTARG1 ) || ( TSSTATESELECT ( pContext->iChipStage[2], D3DTSS_ALPHAARG1 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[2], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG2 ) || ( TSSTATESELECT ( pContext->iChipStage[2], D3DTSS_ALPHAARG2 ) == D3DTA_TEXTURE ) && ( TSSTATE ( pContext->iChipStage[2], D3DTSS_ALPHAOP ) != D3DTOP_SELECTARG1 ) ) { // Panic! In future, we should feed white to the argument using the TFACTOR thing, // but for now just disable the rest of the pipeline. bProcessChipStage2 = FALSE; } } if ( bProcessChipStage2 ) { // Set up chip stage 2 - texapp. DISPDBG((DBGLVL,"Texture Stage 2 is valid - setting it up")); DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: Cool - an app is using the " "TexApp unit - tell someone!")); __TXT_TranslateToChipBlendMode(pContext, &pContext->TextureStageState[pContext->iChipStage[2]], pSoftP3RX, pContext->iChipStage[2], 2); iLastChipStage = 3; bProcessChipStage2 = FALSE; } // This must be last. if ( TSSTATE ( pContext->iChipStage[3], D3DTSS_COLOROP ) != D3DTOP_DISABLE ) { // Oops - ran out of stages to set up. SET_BLEND_ERROR ( pContext, BSF_TOO_MANY_BLEND_STAGES ); iLastChipStage = 3; } switch ( iLastChipStage ) { case 0: DISPDBG((DBGLVL,"Texture Composite 0 is disabled")); // This should have been caught ages ago. pSoftP3RX->P3RXTextureCompositeColorMode0.Arg2 = P3RX_TEXCOMP_CC; pSoftP3RX->P3RXTextureCompositeColorMode0.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode0.A = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeColorMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode0.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Arg2 = P3RX_TEXCOMP_CA; pSoftP3RX->P3RXTextureCompositeAlphaMode0.InvertArg1 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.A = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeAlphaMode0.Enable = __PERMEDIA_ENABLE; // fall through case 1: DISPDBG((DBGLVL,"Texture Composite 1 is disabled")); // Make sure the second stage passes the texel that the first stage generated if ( pContext->bStage0DotProduct ) { // First stage was a dot-product - do the summing (even in the alpha channel). pSoftP3RX->P3RXTextureCompositeColorMode1.Arg2 = P3RX_TEXCOMP_SUM; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Arg2 = P3RX_TEXCOMP_SUM; } else { pSoftP3RX->P3RXTextureCompositeColorMode1.Arg2 = P3RX_TEXCOMP_OC; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Arg2 = P3RX_TEXCOMP_OA; } pSoftP3RX->P3RXTextureCompositeColorMode1.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeColorMode1.A = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeColorMode1.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeColorMode1.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeColorMode1.Enable = __PERMEDIA_ENABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.InvertArg2 = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.A = P3RX_TEXCOMP_ARG2; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Operation = P3RX_TEXCOMP_OPERATION_PASS_A; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Scale = P3RX_TEXCOMP_OPERATION_SCALE_ONE; pSoftP3RX->P3RXTextureCompositeAlphaMode1.Enable = __PERMEDIA_ENABLE; // fall through case 2: // Texapp to passthrough. DISPDBG((DBGLVL,"Texture Application is disabled")); pSoftP3RX->P3RXTextureApplicationMode.ColorB = P3RX_TEXAPP_B_TC; pSoftP3RX->P3RXTextureApplicationMode.ColorOperation = P3RX_TEXAPP_OPERATION_PASS_B; pSoftP3RX->P3RXTextureApplicationMode.ColorInvertI = __PERMEDIA_DISABLE; pSoftP3RX->P3RXTextureApplicationMode.AlphaB = P3RX_TEXAPP_B_TC; pSoftP3RX->P3RXTextureApplicationMode.AlphaOperation = P3RX_TEXAPP_OPERATION_PASS_B; pSoftP3RX->P3RXTextureApplicationMode.AlphaInvertI = __PERMEDIA_DISABLE; // fall through case 3: // Nothing else in the pipeline to disable. // fall through break; default: DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: iLastChipStage was > 3 - oops.")); break; } // Set up the alpha-map filtering to reflect the single/multi/mip-mapped texturing status // All the other colour-key stuff has already been set up. if( pContext->bCanChromaKey ) { ASSERTDD ( pTexture0 != NULL, "** _D3DChangeTextureP3RX: pTexture was NULL" ); if( pTexture0->bMipMap ) { pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit0 = 4; pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit1 = 4; if ( pContext->bTex0Valid ) { // Filter mode is irrelevant - this just works! pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit01 = 7; } else { DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: Trying to mipmap without a valid texture.")); pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit01 = 8; } ASSERTDD ( !pContext->bTex1Valid, "** _D3DChangeTextureP3RX: Trying to mipmap with too many textures." ); } else { // No mipmapping. if ( pContext->bTex0Valid ) { // Don't care about filter mode - this just works. pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit0 = 7; } else { pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit0 = 4; } if ( pContext->bTex1Valid ) { // Don't care about filter mode - this just works. pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit1 = 7; } else { pSoftP3RX->P3RXTextureFilterMode.AlphaMapFilterLimit1 = 4; } } } // Enable Texture Address calculation pSoftP3RX->P3RXTextureCoordMode.Enable = __PERMEDIA_ENABLE; // Enable filtering pSoftP3RX->P3RXTextureFilterMode.Enable = __PERMEDIA_ENABLE; // // Enable Texel color generation // pSoftP3RX->P3RXTextureApplicationMode.Enable = __PERMEDIA_ENABLE; // Do we need to share the texture coordinates ? if ( pContext->bTex0Valid && pContext->bTex1Valid && ( TSSTATE ( pContext->iTexStage[0], D3DTSS_TEXCOORDINDEX ) == TSSTATE ( pContext->iTexStage[1], D3DTSS_TEXCOORDINDEX ) ) ) { pSoftP3RX->P3RX_P3DeltaControl.ShareS = __PERMEDIA_ENABLE; pSoftP3RX->P3RX_P3DeltaControl.ShareT = __PERMEDIA_ENABLE; } else { pSoftP3RX->P3RX_P3DeltaControl.ShareS = __PERMEDIA_DISABLE; pSoftP3RX->P3RX_P3DeltaControl.ShareT = __PERMEDIA_DISABLE; } P3_ENSURE_DX_SPACE((P3_LOD_LEVELS*2)); WAIT_FIFO((P3_LOD_LEVELS*2)); for (i = 0; i < P3_LOD_LEVELS; i++) { COPY_P3_DATA_OFFSET(TextureMapWidth0, pSoftP3RX->P3RXTextureMapWidth[i], i); } if ( ( GET_BLEND_ERROR(pContext) & BLEND_STATUS_FATAL_FLAG ) != 0 ) { // Got a fatal blend error - signal it to the user. DISPDBG((ERRLVL,"** _D3DChangeTextureP3RX: invalid blend mode")); _D3DDisplayWholeTSSPipe ( pContext, WRNLVL ); // And make sure this is re-evaluated next time we render, // so that this (probably very munged) invalid setup doesn't cripple // any subsequent valid renderstates. DIRTY_EVERYTHING(pContext); } P3_ENSURE_DX_SPACE(32); WAIT_FIFO(32); SEND_P3_DATA(TextureCompositeMode, __PERMEDIA_ENABLE); COPY_P3_DATA(TextureFilterMode, pSoftP3RX->P3RXTextureFilterMode); COPY_P3_DATA(TextureApplicationMode, pSoftP3RX->P3RXTextureApplicationMode); COPY_P3_DATA(TextureCoordMode, pSoftP3RX->P3RXTextureCoordMode); COPY_P3_DATA(DeltaControl, pSoftP3RX->P3RX_P3DeltaControl); // Copy the current TFACTOR values. SEND_P3_DATA ( TextureEnvColor, FORMAT_8888_32BIT_BGR(dwTexAppTfactor) ); SEND_P3_DATA ( TextureCompositeFactor0, FORMAT_8888_32BIT_BGR(dwTexComp0Tfactor) ); SEND_P3_DATA ( TextureCompositeFactor1, FORMAT_8888_32BIT_BGR(dwTexComp1Tfactor) ); DISPDBG((DBGLVL,"Current TFACTOR values. %x %x %x", dwTexAppTfactor, dwTexComp0Tfactor, dwTexComp1Tfactor)); COPY_P3_DATA(DeltaMode, pSoftP3RX->P3RX_P3DeltaMode); P3_ENSURE_DX_SPACE(32); WAIT_FIFO(32); COPY_P3_DATA(TextureCompositeColorMode0, pSoftP3RX->P3RXTextureCompositeColorMode0); COPY_P3_DATA(TextureCompositeColorMode1, pSoftP3RX->P3RXTextureCompositeColorMode1); COPY_P3_DATA(TextureCompositeAlphaMode0, pSoftP3RX->P3RXTextureCompositeAlphaMode0); COPY_P3_DATA(TextureCompositeAlphaMode1, pSoftP3RX->P3RXTextureCompositeAlphaMode1); COPY_P3_DATA(TextureReadMode1, pSoftP3RX->P3RXTextureReadMode1); COPY_P3_DATA(TextureIndexMode1, pSoftP3RX->P3RXTextureIndexMode1); COPY_P3_DATA(TextureReadMode0, pSoftP3RX->P3RXTextureReadMode0); COPY_P3_DATA(TextureIndexMode0, pSoftP3RX->P3RXTextureIndexMode0); // Make sure the texture cache is invalidated P3RX_INVALIDATECACHE(__PERMEDIA_ENABLE, __PERMEDIA_DISABLE); SEND_P3_DATA(LOD, 0); SEND_P3_DATA(LOD1, 0); { struct LodRange range; // Clear down whole register *(DWORD *)&range = 0; // Each of the Min and Max LODs are in 4.8 format. We only deal // with integer LODs in the range (0, N) so we just compute the // upper value N and shift it up 8 bits. range.Min = 0; range.Max = ( mipBases.dwTex0MipMax - mipBases.dwTex0MipBase ) << 8; COPY_P3_DATA( LodRange0, range ); range.Min = 0; range.Max = ( mipBases.dwTex1MipMax - mipBases.dwTex1MipBase ) << 8; COPY_P3_DATA( LodRange1, range ); } *pFlags |= SURFACE_TEXTURING; // Turn texturing on in the render command RENDER_TEXTURE_ENABLE(pContext->RenderCommand); P3_DMA_COMMIT_BUFFER(); // See if the alpha-blend unit needs to be updated. if ( bAlphaBlendDouble != pContext->bAlphaBlendMustDoubleSourceColour ) { pContext->bAlphaBlendMustDoubleSourceColour = bAlphaBlendDouble; DIRTY_ALPHABLEND(pContext); } DBG_EXIT(_D3DChangeTextureP3RX,0); } // _D3DChangeTextureP3RX