--- /dev/null
+/*
+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 <algorithm>
+
+#include "GeneralCombiner.h"
+#include "Combiner.h"
+#include "Debugger.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(uint32 val)
+{
+ return ( (val&MUX_MASK) == MUX_TEXEL0 || (val&MUX_MASK) == MUX_TEXEL1 );
+}
+int toTex(uint32 val)
+{
+ return (val&MUX_MASK)-MUX_TEXEL0;
+}
+
+bool isComb(uint32 val)
+{
+ return (val&MUX_MASK)==MUX_COMBINED;
+}
+
+#ifdef DEBUGGER
+const char* BlendFuncStr[] = {
+ "Enable both",
+ "Disable alpha",
+ "Disable color",
+ "Disable both",
+ "Color one",
+ "Alpha one",
+};
+const 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((uint8)gci.TFactor,str1),
+ DecodedMux::FormatStr((uint8)gci.specularPostOp,str2), gci.m_dwShadeColorChannelFlag, gci.m_dwShadeAlphaChannelFlag);
+
+ for( int i=0; i<gci.nStages; i++ )
+ {
+ GeneralCombineStage &s = gci.stages[i];
+ DebuggerAppendMsg("%d:Color: %s - %s, %s, %s%s\n", i,
+ cmopstrs[s.colorOp.op], DecodedMux::FormatStr((uint8)s.colorOp.Arg1, str1), s.colorOp.Arg2==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.colorOp.Arg2, str2),
+ s.colorOp.Arg0==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.colorOp.Arg0, str3),
+ s.dwTexture!=0?" -Tex1":"");
+ }
+
+ for( int i=0; i<gci.nStages; i++ )
+ {
+ GeneralCombineStage &s = gci.stages[i];
+ DebuggerAppendMsg("%d:Alpha: %s - %s, %s, %s%s\n", i,
+ cmopstrs[s.alphaOp.op], DecodedMux::FormatStr((uint8)s.alphaOp.Arg1, str1),
+ s.alphaOp.Arg2==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.alphaOp.Arg2, str2),
+ s.alphaOp.Arg0==CM_IGNORE?"":DecodedMux::FormatStr((uint8)s.alphaOp.Arg0, str3),
+ s.dwTexture!=0?" -Tex1":"");
+ }
+ TRACE0("\n\n");
+}
+#endif
+
+
+///////////////////////////////////////
+// Combiner gci generating functions //
+///////////////////////////////////////
+
+bool textureUsedInStage[8][2];
+bool resultIsGood;
+
+void CGeneralCombiner::GenCI_Init(GeneralCombinerInfo &gci)
+{
+ gci.specularPostOp=gci.TFactor=MUX_0;
+
+ gci.blendingFunc = ENABLE_BOTH;
+ resultIsGood = true;
+
+ //After the mux is reformated and simplified, we can use it to generate combine stages
+ //return false if we can not generate it
+
+ for( int i=0; i<8; i++)
+ {
+ gci.stages[i].dwTexture = 0;
+ textureUsedInStage[i][0] = false; // For color
+ textureUsedInStage[i][1] = false; // For alpha
+ gci.stages[i].bTextureUsed = false;
+ gci.stages[i].dwTexture = 0;
+ gci.stages[i].colorOp.op = gci.stages[i].alphaOp.op = CM_REPLACE;
+ gci.stages[i].colorOp.Arg1 = gci.stages[i].alphaOp.Arg1 = MUX_COMBINED;
+ gci.stages[i].colorOp.Arg2 = gci.stages[i].alphaOp.Arg2 = CM_IGNORE;
+ gci.stages[i].colorOp.Arg0 = gci.stages[i].alphaOp.Arg0 = CM_IGNORE;
+ }
+
+ 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;
+ }
+
+ if( mux.splitType[N64Cycle0RGB]==CM_FMT_TYPE_D && mux.splitType[N64Cycle1RGB]==CM_FMT_TYPE_NOT_USED )
+ {
+ if( mux.m_n64Combiners[N64Cycle0RGB].d == MUX_0 )
+ gci.blendingFunc = DISABLE_COLOR;
+ }
+
+}
+
+int CGeneralCombiner::GenCI_Type_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.d == MUX_0 || m.d == MUX_1 ) && curN64Stage==1 )
+ {
+ //if( m.d == MUX_0 )
+ // gci.blendingFunc = DISABLE_COLOR;
+ //if( m.d == MUX_1 )
+ // 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, uint32 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 != (unsigned int)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)
+{
+ uint32 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;
+
+ uint8* vals = (uint8*)&m2;
+ for( int i=0; i<4; i++ )
+ {
+ if( (unsigned int)(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 )
+ {
+ op->op = CM_BLENDTEXTUREALPHA;
+ }
+ else if( (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 = m.c|MUX_ALPHAREPLICATE;
+ }
+ }
+ 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 = m.c|MUX_ALPHAREPLICATE;
+ }
+ 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) )
+ {
+ if( m_dwGeneralMaxStages >= 4 )
+ {
+ op->op = CM_SUBTRACT;
+ op->Arg1 = m.a;
+ op->Arg2 = m.b;
+ 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_MULTIPLYADD;
+ op->Arg1 = MUX_COMBINED;
+ op->Arg2 = m.c;
+ op->Arg0 = m.d;
+ gci.stages[curStage].dwTexture = toTex(m.d);
+ textureUsedInStage[curStage][curN64Stage%2] = true;
+ resultIsGood = true;
+ }
+ else
+ {
+ 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 )
+ {
+ if( m_dwGeneralMaxStages < 4 )
+ {
+ 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;
+ }
+ else
+ {
+ 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);
+ return GenCI_Type_A_B_C_D(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;
+}
+
+ /////////////////////////////////////
+ // End of gci generating functions //
+ /////////////////////////////////////
+
+
+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 (curStage<m_dwGeneralMaxStages-1 && textureUsedInStage[curStage][0] && gci.stages[curStage].dwTexture != (unsigned int)(tex) )
+ {
+ StageOperate &op = ((StageOperate*)(&(gci.stages[curStage].colorOp)))[curN64Stage%2];
+ SkipStage(op, curStage);
+ }
+ }
+}
+
+
+int CGeneralCombiner::Check2TxtrForAlpha(int curN64Stage, int &curStage, GeneralCombinerInfo &gci, int tex1, int tex2)
+{
+ N64CombinerType &m = (*m_ppGeneralDecodedMux)->m_n64Combiners[curN64Stage];
+ if( curN64Stage%2 && IsTxtrUsed(m) )
+ {
+ if( tex1 == tex2 )
+ {
+ while (curStage<m_dwGeneralMaxStages-1 && textureUsedInStage[curStage][0] && gci.stages[curStage].dwTexture != (unsigned int)tex1 )
+ {
+ StageOperate &op = ((StageOperate*)(&(gci.stages[curStage].colorOp)))[curN64Stage%2];
+ SkipStage(op, curStage);
+ }
+ return 1;
+ }
+ else
+ {
+ int stage1 = curStage;
+ int stage2 = curStage;
+
+ while (stage1<m_dwGeneralMaxStages-1 && textureUsedInStage[stage1][0] && gci.stages[stage1].dwTexture != (unsigned int)tex1 )
+ {
+ StageOperate &op = ((StageOperate*)(&(gci.stages[stage1].colorOp)))[curN64Stage%2];
+ SkipStage(op, stage1);
+ }
+
+ while (stage2<m_dwGeneralMaxStages-1 && textureUsedInStage[stage2][0] && gci.stages[stage2].dwTexture != (unsigned int)tex2 )
+ {
+ StageOperate &op = ((StageOperate*)(&(gci.stages[stage2].colorOp)))[curN64Stage%2];
+ SkipStage(op, stage2);
+ }
+
+ if( stage1 <= stage2 )
+ {
+ curStage = stage1;
+ return 1;
+ }
+ else
+ {
+ curStage = stage2;
+ return 2;
+ }
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+int CGeneralCombiner::CheckWhichTexToUseInThisStage(int curN64Stage, int curStage, GeneralCombinerInfo &gci)
+{
+ // There are two texels to used, which one I should use in the current DirectX stage?
+ if( curN64Stage%2 )
+ {
+ if( !textureUsedInStage[curStage][0] )
+ return 0;
+ else
+ return gci.stages[curStage].dwTexture;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*
+ *
+ */
+
+int CGeneralCombiner::ParseDecodedMux()
+{
+ GeneralCombinerInfo gci;
+ int stages[2];
+
+ DecodedMux &mux = *(*m_ppGeneralDecodedMux);
+
+ GenCI_Init(gci);
+
+ for( int i=0; i<2; i++ )
+ {
+ //i=0 Color Channel
+ //i=1 Alpha Channel
+
+ stages[i] = 0;
+ int n=0; //stage count
+
+ for( int j=0; j<2; j++ )
+ {
+ switch( mux.splitType[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 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) 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 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_MOD_C: // = A*C can mapped to MOD(arg1,arg2)
+ n=GenCI_Type_A_MOD_C(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_SUB_B: // = A-B can mapped to SUB(arg1,arg2)
+ n=GenCI_Type_A_SUB_B(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0)
+ n=GenCI_Type_A_MOD_C_ADD_D(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_LERP_B_C: // = (A-B)*C+B can mapped to 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 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+C can not map very well in 1 stage
+ n=GenCI_Type_A_SUB_B_ADD_D(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage
+ n=GenCI_Type_A_SUB_B_MOD_C(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) 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 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) 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 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well in 1 stage
+ n=GenCI_Type_A_B_C_D(j*2+i, n, gci);
+ if( j==0 && mux.splitType[i+2] != CM_FMT_TYPE_NOT_USED ) NextStage(n); else n++;
+ break;
+ default:
+ break;
+ }
+ }
+ stages[i] = n;
+ }
+
+ gci.nStages = max(stages[0], stages[1]);
+ if( gci.nStages > m_dwGeneralMaxStages )
+ {
+ resultIsGood = false;
+ gci.nStages = m_dwGeneralMaxStages;
+ }
+
+ if( mux.m_ColorTextureFlag[0] != 0 || mux.m_ColorTextureFlag[1] != 0 )
+ {
+ resultIsGood = false;
+ }
+
+ // The bResultIsGoodWithinStages is for Semi-Pixel shader combiner, don't move the code down
+ gci.bResultIsGoodWithinStages = resultIsGood;
+ if( mux.HowManyConstFactors() > 1 || gci.specularPostOp != MUX_0 || gci.blendingFunc != ENABLE_BOTH )
+ {
+ gci.bResultIsGoodWithinStages = false;
+ }
+
+ if( gci.nStages > stages[0] ) // Color has less stages
+ {
+ for( int i=stages[0]; i<gci.nStages; i++ )
+ {
+ gci.stages[i].colorOp.op = CM_REPLACE;
+ gci.stages[i].colorOp.Arg1 = MUX_COMBINED;
+ gci.stages[i].colorOp.Arg2 = CM_IGNORE;
+ gci.stages[i].colorOp.Arg0 = CM_IGNORE;
+ }
+ }
+
+ if( gci.nStages > stages[1] ) // Color has less stages
+ {
+ for( int i=stages[1]; i<gci.nStages; i++ )
+ {
+ gci.stages[i].alphaOp.op = CM_REPLACE;
+ gci.stages[i].alphaOp.Arg1 = MUX_COMBINED;
+ gci.stages[i].alphaOp.Arg2 = CM_IGNORE;
+ gci.stages[i].alphaOp.Arg0 = CM_IGNORE;
+ }
+ }
+
+ for( int i=0;i<gci.nStages;i++)
+ {
+ gci.stages[i].bTextureUsed = IsTextureUsedInStage(gci.stages[i]);
+ }
+
+ if( !resultIsGood && gci.nStages >= m_dwGeneralMaxStages )
+ {
+ extern int noOfTwoStages;
+ extern GeneralCombinerInfo twostages[];
+
+ for( int k=0; k<noOfTwoStages; k++ )
+ {
+ GeneralCombinerInfo &info = twostages[k];
+ if( (mux.m_dwMux0 == info.dwMux0 && mux.m_dwMux1 == info.dwMux1) ||
+ (info.dwMux0+info.dwMux1 == 0 && info.muxDWords[0] == mux.m_dWords[0] &&
+ info.muxDWords[1] == mux.m_dWords[1] && info.muxDWords[2] == mux.m_dWords[2] &&
+ info.muxDWords[3] == mux.m_dWords[3] && info.m_dwShadeAlphaChannelFlag == mux.m_dwShadeAlphaChannelFlag &&
+ info.m_dwShadeColorChannelFlag == mux.m_dwShadeColorChannelFlag ) )
+ {
+ memcpy(&gci, &info, sizeof(GeneralCombinerInfo) );
+ resultIsGood = true;
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUGGER
+ if( !resultIsGood )
+ {
+ DecodedMux &mux = *(*m_ppGeneralDecodedMux);
+ // Generated combiner mode is not good enough within the limited stages
+ DebuggerAppendMsg("\n/*");
+ mux.DisplayMuxString("Overflowed");
+ mux.DisplaySimpliedMuxString("Overflowed");
+ DebuggerAppendMsg("Generated combiners:");
+ General_DisplayBlendingStageInfo(gci);
+ DebuggerAppendMsg("*/\n");
+ DebuggerAppendMsg("\n\n");
+ DebuggerAppendMsg("{\n\t0x%08X, 0x%08X, 0x%08X, 0x%08X,\t// Simplified mux\n\t0x%08X, 0x%08X,\t\t// 64bit Mux\n",
+ mux.m_dWords[0],mux.m_dWords[1],mux.m_dWords[2],mux.m_dWords[3],mux.m_dwMux0,mux.m_dwMux1);
+ DebuggerAppendMsg("\t%d,\t// number of stages\n\tENABLE_BOTH,\n\t0,\t\t// Constant color\n\t0x%08X, 0x%08X, 0,\t// Shade and specular color flags\n\t0x%08X, 0x%08X,\t// constant color texture flags\n",
+ 2,mux.m_dwShadeColorChannelFlag, mux.m_dwShadeAlphaChannelFlag,mux.m_ColorTextureFlag[0],mux.m_ColorTextureFlag[1]);
+ DebuggerAppendMsg("\t{\n\t\t{MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0\n");
+ DebuggerAppendMsg("\t\t{MOD(T0,DIF), SKIP, 1, true}, // Stage 1\n\t}\n},");
+ }
+#else
+ if( !resultIsGood )
+ {
+ FILE *fp=NULL;
+ fp = fopen("C:\\rice\\RiceVideoMUX.log","a");
+ if( fp )
+ {
+ fprintf(fp,"\n/*\n");
+ mux.LogMuxString("Overflowed",fp);
+ fprintf(fp,"\n\n");
+ mux.LogSimpliedMuxString("Overflowed",fp);
+ fprintf(fp,"Generated combiners:");
+ //General_DisplayBlendingStageInfo(gci);
+ fprintf(fp,"\n*/\n");
+ fprintf(fp,"\n");
+ fprintf(fp,"{\n\t0x%08X, 0x%08X, 0x%08X, 0x%08X,\t// Simplified mux\n\t0x%08X, 0x%08X,\t\t// 64bit Mux\n",
+ mux.m_dWords[0],mux.m_dWords[1],mux.m_dWords[2],mux.m_dWords[3],mux.m_dwMux0,mux.m_dwMux1);
+ fprintf(fp,"\t%d,\t// number of stages\n\tENABLE_BOTH,\n\tMUX_ENV,\t\t// Constant color\n\t0x%08X, 0x%08X, 0,\t// Shade and specular color flags\n\t0x%08X, 0x%08X,\t// constant color texture flags\n",
+ 2,mux.m_dwShadeColorChannelFlag, mux.m_dwShadeAlphaChannelFlag,mux.m_ColorTextureFlag[0],mux.m_ColorTextureFlag[1]);
+ fprintf(fp,"\t{\n\t\t{MOD(T0,DIF), MOD(T0,DIF), 0, true}, // Stage 0\n");
+ fprintf(fp,"\t\t{LERP(T1,CUR,DIF), SKIP, 1, true}, // Stage 1\n\t}\n},");
+
+ fclose(fp);
+ }
+ }
+#endif
+
+ return SaveParserResult(gci);
+}
+
+
+bool CGeneralCombiner::IsTextureUsedInStage(GeneralCombineStage &stage)
+{
+ if( (stage.colorOp.Arg1&MUX_MASK)==MUX_TEXEL0 || (stage.colorOp.Arg2&MUX_MASK)==MUX_TEXEL0 || (stage.colorOp.Arg0 &MUX_MASK)==MUX_TEXEL0 ||
+ (stage.alphaOp.Arg1&MUX_MASK)==MUX_TEXEL0 || (stage.alphaOp.Arg2&MUX_MASK)==MUX_TEXEL0 || (stage.alphaOp.Arg0 &MUX_MASK)==MUX_TEXEL0 ||
+ (stage.colorOp.Arg1&MUX_MASK)==MUX_TEXEL1 || (stage.colorOp.Arg2&MUX_MASK)==MUX_TEXEL1 || (stage.colorOp.Arg0 &MUX_MASK)==MUX_TEXEL1 ||
+ (stage.alphaOp.Arg1&MUX_MASK)==MUX_TEXEL1 || (stage.alphaOp.Arg2&MUX_MASK)==MUX_TEXEL1 || (stage.alphaOp.Arg0 &MUX_MASK)==MUX_TEXEL1 )
+ {
+ return true;
+ }
+ else
+ return false;
+}
+
+
+int CGeneralCombiner::SaveParserResult(GeneralCombinerInfo &result)
+{
+ result.muxDWords[0] = (*m_ppGeneralDecodedMux)->m_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( )
+{
+#ifdef DEBUGGER
+ if( debuggerDropCombiners || debuggerDropGeneralCombiners )
+ {
+ m_vCompiledCombinerStages.clear();
+ //m_dwLastMux0 = m_dwLastMux1 = 0;
+ debuggerDropCombiners = false;
+ debuggerDropGeneralCombiners = false;
+ }
+#endif
+
+ for( uint32 i=0; i<m_vCompiledCombinerStages.size(); i++ )
+ {
+ if( m_vCompiledCombinerStages[i].dwMux0 == (*m_ppGeneralDecodedMux)->m_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, uint32 opr, uint32 a1, uint32 a2, uint32 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, uint32 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()
+{
+ return 0;
+}
+
+bool CGeneralCombiner::LM_Check1TxtrForAlpha(int curStage, GeneralCombinerInfo &gci, uint32 val )
+{
+ return !( isTex(val) && LM_textureUsedInStage[curStage] && gci.stages[curStage].dwTexture != (unsigned int)toTex(val) );
+}
+
+
+void CGeneralCombiner::LM_SkipStage(StageOperate &op)
+{
+ op.op = CM_REPLACE;
+ op.Arg1 = MUX_COMBINED;
+ op.Arg2 = CM_IGNORE;
+ op.Arg0 = CM_IGNORE;
+}
+