Rice Video Plugin for GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / GeneralCombiner.cpp
diff --git a/source/rice_gles/src/GeneralCombiner.cpp b/source/rice_gles/src/GeneralCombiner.cpp
new file mode 100644 (file)
index 0000000..9329bd2
--- /dev/null
@@ -0,0 +1,1308 @@
+/*
+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;
+}
+