/* Copyright (C) 2003 Rice1964 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" #include "GeneralCombiner.h" extern const int numOf3StageCombiners; extern const int numOf2StageCombiners; extern GeneralCombinerInfo CombinerTable2Stages[]; extern GeneralCombinerInfo CombinerTable3Stages[]; CGeneralCombiner::CGeneralCombiner() { m_lastGeneralIndex=0; m_ppGeneralDecodedMux=NULL; m_bTxtOpAdd=true; m_bTxtOpSub=false; m_bTxtOpLerp=false; m_bTxtOpAddSmooth=false; m_bTxtOpBlendCurAlpha=false; m_bTxtOpBlendDifAlpha=true; m_bTxtOpBlendFacAlpha=false; m_bTxtOpBlendTxtAlpha=true; m_bTxtOpMulAdd=false; m_dwGeneralMaxStages=2; } bool isTex(DWORD val) { return ( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 ); } int toTex(DWORD val) { return (val&MUX_MASK)-MUX_TEXEL0; } bool isComb(DWORD val) { return (val&MUX_MASK)==MUX_COMBINED; } #ifdef _DEBUG extern char * BlendFuncStr[]; char* cmopstrs[] = { "Sel", "Mod", "Add", "Sub", "Lerp", "AddSmooth", "BlCurA", "BlDifA", "BlFacA", "BlTexA", "MulAdd", }; void CGeneralCombiner::General_DisplayBlendingStageInfo(GeneralCombinerInfo &gci) { char str1[30],str2[30],str3[30]; DebuggerAppendMsg("\nStages:%d, Alpha:%s, Factor:%s, Specular:%s Dif Color:0x%X Dif Alpha:0x%X\n", gci.nStages, BlendFuncStr[gci.blendingFunc], DecodedMux::FormatStr((BYTE)gci.TFactor,str1), DecodedMux::FormatStr((BYTE)gci.specularPostOp,str2), gci.m_dwShadeColorChannelFlag, gci.m_dwShadeAlphaChannelFlag); for( int i=0; im_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( ( m.d == MUX_0 || m.d == MUX_1 ) && curN64Stage==1 ) { if( m.d == MUX_0 ) gci.blendingFunc = DISABLE_COLOR; else gci.blendingFunc = DISABLE_ALPHA; op->op = CM_REPLACE; op->Arg1 = MUX_COMBINED; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; } else { if( isTex(m.d) ) Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.d)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_REPLACE; op->Arg1 = m.d; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; } if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); return curStage; } int CGeneralCombiner::GenCI_Type_A_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci, DWORD dxop) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( CountTexel1Cycle(m) == 2 ) { // As we can not use both texture in one stage // we split them to two stages // Stage1: SELECT txt1 // Stage2: MOD txt2 if( gci.stages[curStage].bTextureUsed && gci.stages[curStage].dwTexture != toTex(m.a) ) swap(m.a,m.c); op->op =CM_REPLACE; op->Arg1 = m.a; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.c)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =dxop; op->Arg1 = (m.c); op->Arg2 = MUX_COMBINED; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.c); textureUsedInStage[curStage][curN64Stage%2] = true; } else { if( CountTexel1Cycle(m) == 1) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } op->op = dxop; op->Arg1 = (m.a); op->Arg2 = (m.c); op->Arg0 = CM_IGNORE; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { DWORD opToUse = m_bTxtOpAdd?CM_ADD:CM_MODULATE; N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; swap(m.c, m.d); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci, opToUse); swap(m.c, m.d); return curStage; } int CGeneralCombiner::GenCI_Type_A_SUB_B(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; if( !m_bTxtOpSub ) { swap(m.c, m.b); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); swap(m.c, m.b); return curStage; } StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( CountTexel1Cycle(m) == 2 ) { Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.b)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =CM_REPLACE; op->Arg1 = (m.b); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.b); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, toTex(m.a)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op =CM_SUBTRACT; op->Arg1 = (m.a); op->Arg2 = MUX_COMBINED; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; } else { if( CountTexel1Cycle(m) == 1) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } op->op = CM_SUBTRACT; op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = CM_IGNORE; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_MOD_C_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( !m_bTxtOpMulAdd ) { N64CombinerType save = m; m.d = MUX_0; curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; m.c = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; return curStage; } if( CountTexel1Cycle(m) == 2 ) { if( !gci.stages[curStage].bTextureUsed ) { gci.stages[curStage].dwTexture = 0; gci.stages[curStage].bTextureUsed = true; } op->op = CM_REPLACE; op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; op->Arg1 = MUX_TEXEL0 + gci.stages[curStage].dwTexture ; N64CombinerType m2 = m; BYTE* vals = (BYTE*)&m2; for( int i=0; i<4; i++ ) { if( (vals[i]&MUX_MASK) == MUX_TEXEL0 + gci.stages[curStage].dwTexture ) { vals[i] = MUX_COMBINED | (vals[i]&0xe0); } } NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m2)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_MULTIPLYADD; op->Arg1 = m2.a; op->Arg2 = m2.c; op->Arg0 = m2.d; if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m2); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m2); } else { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_MULTIPLYADD; op->Arg1 = (m.a); op->Arg2 = (m.c); op->Arg0 = (m.d); if( !gci.stages[curStage].bTextureUsed ) gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); } return curStage; } int CGeneralCombiner::GenCI_Type_A_LERP_B_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); N64CombinerType save = m; if( CountTexel1Cycle(m) == 2 ) { // There are two textures int texToUse = CheckWhichTexToUseInThisStage(curN64Stage, curStage, gci); op->op =CM_REPLACE; op->Arg1 = (MUX_TEXEL0+texToUse); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = texToUse; textureUsedInStage[curStage][curN64Stage%2] = true; (*m_ppGeneralDecodedMux)->ReplaceVal(MUX_TEXEL0+texToUse, MUX_COMBINED, curN64Stage); NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); } // Now we have only 1 texture left Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); if( m.a == MUX_1 ) { op->op = CM_ADDSMOOTH; op->Arg1 = (m.b); op->Arg2 = (m.c); op->Arg0 = CM_IGNORE; } else if( m.a == MUX_0 ) { op->op = CM_MODULATE; m.a = 0; op->Arg1 = (m.b); op->Arg2 = (m.c^MUX_COMPLEMENT); op->Arg0 = CM_IGNORE; } else { if( ((m.c&MUX_ALPHAREPLICATE) || (curN64Stage%2)==1 || m_bTxtOpLerp == false) && ((m.c&MUX_MASK)==MUX_SHADE || (m.c&MUX_MASK)==MUX_COMBINED || (m.c&MUX_MASK)==MUX_TEXEL0 || (m.c&MUX_MASK)==MUX_TEXEL1 ) ) { if( curN64Stage == 2 && (m.c&MUX_ALPHAREPLICATE) == 0 ) { op->op = CM_MODULATE; op->Arg1 = m.b; op->Arg2 = m.c|MUX_COMPLEMENT; op->Arg0 = CM_IGNORE; resultIsGood = false; } else { if( (m.c&MUX_MASK)==MUX_SHADE ) { op->op = CM_BLENDDIFFUSEALPHA; } else if( (m.c&MUX_MASK) == MUX_COMBINED ) { op->op = CM_BLENDCURRENTALPHA; } else if( (m.c&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK)==MUX_TEXEL1 ) { op->op = CM_BLENDTEXTUREALPHA; } else { op->op = CM_BLENDDIFFUSEALPHA; } op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = CM_IGNORE; } } else { if( ((m.c&MUX_ALPHAREPLICATE) || (curN64Stage%2)==1 || m_bTxtOpLerp == false) && ((((m.c&MUX_MASK)==MUX_ENV) || ((m.c&MUX_MASK)==MUX_PRIM)) )) { op->op = CM_BLENDFACTORALPHA; op->Arg1 = (m.a); op->Arg2 = (m.b); op->Arg0 = CM_IGNORE; } else { op->op = CM_INTERPOLATE; op->Arg0 = (m.c); op->Arg1 = (m.a); op->Arg2 = (m.b); } } } gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = IsTxtrUsed(m); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_B_C_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); N64CombinerType save = m; if( CountTexel1Cycle(m) == 2 ) { if( isTex(m.a) && !isTex(m.c) && curN64Stage == 0 && isTex(m.d) && toTex(m.a) != toTex(m.d) ) { op->op = CM_MODULATE; op->Arg1 = m.a; op->Arg2 = m.c; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.a); textureUsedInStage[curStage][curN64Stage%2] = true; NextStage(curStage); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); op->op = CM_ADD; op->Arg1 = MUX_COMBINED; op->Arg2 = m.d; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = toTex(m.d); textureUsedInStage[curStage][curN64Stage%2] = true; resultIsGood = false; } else { // There are two textures int texToUse = CheckWhichTexToUseInThisStage(curN64Stage, curStage, gci); op->op =CM_REPLACE; op->Arg1 = (MUX_TEXEL0+texToUse); op->Arg2 = CM_IGNORE; op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = texToUse; textureUsedInStage[curStage][curN64Stage%2] = true; (*m_ppGeneralDecodedMux)->ReplaceVal(MUX_TEXEL0+texToUse, MUX_COMBINED, curN64Stage); NextStage(curStage); Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + (curN64Stage%2); m.a = MUX_COMBINED; m.c = MUX_TEXEL0+(1-texToUse); m.b = m.d = 0; curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); } } else if( CountTexel1Cycle(m) == 1 ) { Check1TxtrForAlpha(curN64Stage, curStage, gci, GetTexelNumber(m)); op->Arg1 = (MUX_TEXEL0+GetTexelNumber(m)); if( (*m_ppGeneralDecodedMux)->isUsedInCycle(MUX_SHADE, curN64Stage) ) { op->op =CM_MODULATE; op->Arg2 = MUX_SHADE; } else { op->op =CM_REPLACE; op->Arg2 = 0; } op->Arg0 = CM_IGNORE; gci.stages[curStage].dwTexture = GetTexelNumber(m); textureUsedInStage[curStage][curN64Stage%2] = true; /* curStage = GenCI_Type_A_SUB_B_MOD_C(curN64Stage, curStage, gci); m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); */ } else { m.d = 0; curStage = GenCI_Type_A_SUB_B_MOD_C(curN64Stage, curStage, gci); m = save; m.a = MUX_COMBINED; m.b = m.c = 0; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); } m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_SUB_B_ADD_D(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.d = MUX_0; curStage = GenCI_Type_A_SUB_B(curN64Stage, curStage, gci); m = save; m.a = MUX_COMBINED; m.b = MUX_0; NextStage(curStage); curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_ADD_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.d = m.b; m.b = 0; curStage = GenCI_Type_A_ADD_D(curN64Stage, curStage, gci); m = save; m.b = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; return curStage; } int CGeneralCombiner::GenCI_Type_A_B_C_A(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { // We can not do too much with this type, it is not a bad idea to use LERP to simplify it. return GenCI_Type_A_LERP_B_C(curN64Stage, curStage, gci); } int CGeneralCombiner::GenCI_Type_A_SUB_B_MOD_C(int curN64Stage, int curStage, GeneralCombinerInfo &gci) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; N64CombinerType save = m; m.c = MUX_0; curStage = GenCI_Type_A_SUB_B(curN64Stage, curStage, gci); m = save; m.b = MUX_0; m.a = MUX_COMBINED; NextStage(curStage); curStage = GenCI_Type_A_MOD_C(curN64Stage, curStage, gci); m = save; return curStage; } /* * */ void CGeneralCombiner::SkipStage(StageOperate &op, int &curStage) { op.op = CM_REPLACE; op.Arg1 = MUX_COMBINED; op.Arg2 = CM_IGNORE; op.Arg0 = CM_IGNORE; NextStage(curStage); } void CGeneralCombiner::NextStage(int &curStage) { if( curStage < m_dwGeneralMaxStages-1 ) { curStage++; } else { curStage++; resultIsGood = false; TRACE0("Stage overflow"); } } void CGeneralCombiner::Check1TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &gci, int tex) { N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage]; if( curN64Stage%2 && IsTxtrUsed(m) ) { while (curStagem_n64Combiners[curN64Stage]; if( curN64Stage%2 && IsTxtrUsed(m) ) { if( tex1 == tex2 ) { while (curStagesplitType[i+j*2] ) { case CM_FMT_TYPE_NOT_USED: continue; case CM_FMT_TYPE_D: // = D // Alpha channel is using different texture from color channel // and the color channel has already used texture, so alpha // channel can not use different texture for this stage anymore, // alpha channel need to skip a stage n = GenCI_Type_D(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_ADD_D: // = A+D n=GenCI_Type_A_ADD_D(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_MOD_C: // = A*C can mapped to D3D MOD(arg1,arg2) n=GenCI_Type_A_MOD_C(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_SUB_B: // = A-B can mapped to D3D SUB(arg1,arg2) n=GenCI_Type_A_SUB_B(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to D3D MULTIPLYADD(arg1,arg2,arg0) n=GenCI_Type_A_MOD_C_ADD_D(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B can mapped to D3D LERP(arg1,arg2,arg0) // or mapped to BLENDALPHA(arg1,arg2) if C is // alpha channel or DIF, TEX, FAC, CUR n=GenCI_Type_A_LERP_B_C(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+C can not map very well to D3D in 1 stage n=GenCI_Type_A_SUB_B_ADD_D(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well to D3D in 1 stage n=GenCI_Type_A_SUB_B_MOD_C(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_ADD_B_MOD_C: n=GenCI_Type_A_ADD_B_MOD_C(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_B_C_A: n=GenCI_Type_A_B_C_A(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well to D3D in 1 stage n=GenCI_Type_A_B_C_D(j*2+i, n, gci); if( j==0 ) NextStage(n); else n++; break; } } stages[i] = n; } gci.nStages = max(stages[0], stages[1]); if( gci.nStages > m_dwGeneralMaxStages ) { resultIsGood = false; gci.nStages = m_dwGeneralMaxStages; } if( gci.nStages > stages[0] ) //Color has less stages { for( int i=stages[0]; i stages[1] ) //Color has less stages { for( int i=stages[1]; im_dWords[0]; result.muxDWords[1] = (*m_ppGeneralDecodedMux)->m_dWords[1]; result.muxDWords[2] = (*m_ppGeneralDecodedMux)->m_dWords[2]; result.muxDWords[3] = (*m_ppGeneralDecodedMux)->m_dWords[3]; result.m_dwShadeAlphaChannelFlag = (*m_ppGeneralDecodedMux)->m_dwShadeAlphaChannelFlag; result.m_dwShadeColorChannelFlag = (*m_ppGeneralDecodedMux)->m_dwShadeColorChannelFlag; result.colorTextureFlag[0] = (*m_ppGeneralDecodedMux)->m_ColorTextureFlag[0]; result.colorTextureFlag[1] = (*m_ppGeneralDecodedMux)->m_ColorTextureFlag[1]; result.dwMux0 = (*m_ppGeneralDecodedMux)->m_dwMux0; result.dwMux1 = (*m_ppGeneralDecodedMux)->m_dwMux1; m_vCompiledCombinerStages.push_back(result); m_lastGeneralIndex = m_vCompiledCombinerStages.size()-1; return m_lastGeneralIndex; } int CGeneralCombiner::FindCompiledMux( ) { for( uint32 i=0; im_dwMux0 && m_vCompiledCombinerStages[i].dwMux1 == (*m_ppGeneralDecodedMux)->m_dwMux1 ) { m_lastGeneralIndex = i; return i; } } return -1; } bool LM_textureUsedInStage[8]; void CGeneralCombiner::LM_GenCI_Init(GeneralCombinerInfo &gci) { gci.specularPostOp=gci.TFactor=MUX_0; gci.blendingFunc = ENABLE_BOTH; for( int i=0; i<8; i++) { gci.stages[i].dwTexture = 0; LM_textureUsedInStage[i] = false; } } //#define fillstage(opr,a1,a2,a3) {op->op=opr;op->Arg1=a1;op->Arg2=a2;op->Arg0=a3;curStage++;} inline void FillStage(StageOperate &op, DWORD opr, DWORD a1, DWORD a2, DWORD a3) { op.op = opr; op.Arg1 = a1; op.Arg2 = a2; op.Arg0 = a3; } /************************************************************************/ /* New functions, will generate stages within stage limited */ /* and return the number of stages used. */ /************************************************************************/ int CGeneralCombiner::LM_GenCI_Type_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { int originalstage=curStage; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage]))) + channel; if( checktexture && LM_Check1TxtrForAlpha(curStage, gci, m.d ) ) { if( limit > 1 ) { FillStage(*op,CM_REPLACE,MUX_COMBINED,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage]))) + channel; FillStage(*op,CM_REPLACE,m.d,CM_IGNORE,CM_IGNORE); } else { // It is not allowed to use two stages, what to do? // It should not happen anyway TRACE0("Check me here, at LM_GenCI_Type_D"); } } else { FillStage(*op,CM_REPLACE,m.d,CM_IGNORE,CM_IGNORE); } gci.stages[curStage].dwTexture = GetTexelNumber(m); LM_textureUsedInStage[curStage] = IsTxtrUsed(m); curStage++; return curStage-originalstage; } int CGeneralCombiner::LM_GenCI_Type_A_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci, DWORD dxop) { int originalstage=curStage; StageOperate *op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; int numberOfTex = CountTexel1Cycle(m); if( numberOfTex == 2 ) { // As we can not use both texture in one stage // we split them to two stages // Stage1: SELECT txt1 // Stage2: MOD txt2 if( checktexture ) { if( LM_Check1TxtrForAlpha(curStage, gci, m.a ) ) { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } } else if( numberOfTex == 1) { if( checktexture ) { if( isTex(m.a) ) { if( LM_Check1TxtrForAlpha(curStage, gci, m.a ) ) { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); curStage++; } } else { if( LM_Check1TxtrForAlpha(curStage, gci, m.c ) ) { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; } else { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); curStage++; } } } else { if( isTex(m.a) ) { FillStage(*op,CM_REPLACE,m.a,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.a); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.c,MUX_COMBINED,CM_IGNORE); curStage++; } else { FillStage(*op,CM_REPLACE,m.c,CM_IGNORE,CM_IGNORE); gci.stages[curStage].dwTexture = toTex(m.c); LM_textureUsedInStage[curStage] = true; curStage++; op = ((StageOperate*)(&(gci.stages[curStage].colorOp))) + channel; FillStage(*op,dxop,m.a,MUX_COMBINED,CM_IGNORE); curStage++; } } } else { FillStage(*op,dxop,m.a,m.c,CM_IGNORE); curStage++; } return curStage-originalstage; } int CGeneralCombiner::LM_GenCI_Type_A_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_LERP_B_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_MOD_C_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B_ADD_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_SUB_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_ADD_B_MOD_C(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_B_C_D(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_GenCI_Type_A_B_C_A(N64CombinerType &m, int curStage, int limit, int channel, bool checktexture, GeneralCombinerInfo &gci) { return 0; } int CGeneralCombiner::LM_ParseDecodedMux() { GeneralCombinerInfo gci; DecodedMux &mux = *(*m_ppGeneralDecodedMux); // Check some special cases of alpha channel if( mux.splitType[N64Cycle0Alpha]==CM_FMT_TYPE_D && mux.splitType[N64Cycle1Alpha]==CM_FMT_TYPE_NOT_USED ) { if( mux.m_n64Combiners[N64Cycle0Alpha].d == MUX_0 ) gci.blendingFunc = DISABLE_COLOR; else if( mux.m_n64Combiners[N64Cycle0Alpha].d == MUX_1 ) gci.blendingFunc = DISABLE_ALPHA; } else if( mux.splitType[N64Cycle1Alpha]==CM_FMT_TYPE_D ) { if( mux.m_n64Combiners[N64Cycle1Alpha].d == MUX_0 ) gci.blendingFunc = DISABLE_COLOR; else if( mux.m_n64Combiners[N64Cycle1Alpha].d == MUX_1 ) gci.blendingFunc = DISABLE_ALPHA; } return 0; } bool CGeneralCombiner::LM_Check1TxtrForAlpha(int curStage, GeneralCombinerInfo &gci, DWORD val ) { return !( isTex(val) && LM_textureUsedInStage[curStage] && gci.stages[curStage].dwTexture != toTex(val) ); } void CGeneralCombiner::LM_SkipStage(StageOperate &op) { op.op = CM_REPLACE; op.Arg1 = MUX_COMBINED; op.Arg2 = CM_IGNORE; op.Arg0 = CM_IGNORE; }