Rice Video Plugin for GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / Combiner.cpp
diff --git a/source/rice_gles/src/Combiner.cpp b/source/rice_gles/src/Combiner.cpp
new file mode 100644 (file)
index 0000000..bc121c6
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+Copyright (C) 2002 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 "Combiner.h"
+#include "Config.h"
+#include "RenderBase.h"
+
+//static BOOL g_bHiliteRGBAHack = FALSE;
+
+
+#ifdef DEBUGGER
+const char *constStrs[] = {
+    "MUX_0",
+    "MUX_1",
+    "MUX_COMBINED",
+    "MUX_TEXEL0",
+    "MUX_TEXEL1",
+    "MUX_PRIM",
+    "MUX_SHADE",
+    "MUX_ENV",
+    "MUX_COMBALPHA",
+    "MUX_T0_ALPHA",
+    "MUX_T1_ALPHA",
+    "MUX_PRIM_ALPHA",
+    "MUX_SHADE_ALPHA",
+    "MUX_ENV_ALPHA",
+    "MUX_LODFRAC",
+    "MUX_PRIMLODFRAC",
+    "MUX_K5",
+    "MUX_UNK",
+};
+
+const char *cycleTypeStrs[] = {
+    "1 Cycle",
+    "2 Cycle",
+    "Copy Mode",
+    "Fill Mode"
+};
+
+const char* constStr(uint32 op)
+{
+if(op<=MUX_UNK)
+    return constStrs[op];
+else
+   return "Invalid-Const";
+}
+#endif
+
+void swap(uint8 &a, uint8 &b)
+{
+    uint8 c=a;
+    a=b;
+    b=c;
+}
+
+
+//========================================================================
+
+//========================================================================
+
+inline IColor GetIColor(uint8 flag, uint32 curCol)
+{
+    IColor newc;
+    switch(flag&MUX_MASK)
+    {
+    case MUX_0:
+        newc = 0;
+        break;
+    case MUX_1:
+        newc = 0xFFFFFFFF;
+        break;
+    case MUX_PRIM:
+        newc = gRDP.primitiveColor;
+        break;
+    case MUX_ENV:
+        newc = gRDP.envColor;
+        break;
+    case MUX_COMBINED:
+    case MUX_SHADE:
+        newc = curCol;
+        break;
+    case MUX_K5:
+        newc = 0xFFFFFFFF;
+        break;
+    case MUX_UNK:
+        newc = curCol;
+        if( options.enableHackForGames == HACK_FOR_CONKER )
+            newc = 0xFFFFFFFF;
+        break;
+    default:
+        newc = curCol;
+        break;
+    }
+
+    if( flag&MUX_COMPLEMENT )
+    {
+        newc.Complement();
+    }
+
+    if( flag&MUX_ALPHAREPLICATE )
+    {
+        newc.AlphaReplicate();
+    }
+
+    return newc;
+}
+
+COLOR CalculateConstFactor(uint32 colorOp, uint32 alphaOp, uint32 curCol)
+{
+    N64CombinerType m;
+    IColor color(curCol);
+    IColor alpha(curCol);
+
+    // For color channel
+    *(uint32*)&m = colorOp;
+    if( m.c != MUX_0 && m.a!=m.b)
+    {
+        if( m.a != MUX_0 )  color = GetIColor(m.a, curCol);
+        if( m.b != MUX_0 )  color -= GetIColor(m.b, curCol);
+        if( m.c != MUX_1 )  color *= GetIColor(m.c, curCol);
+    }
+    if( m.d != MUX_0 )  color += GetIColor(m.d, curCol);
+
+    // For alpha channel
+    *(uint32*)&m = alphaOp;
+    if( m.c != MUX_0 && m.a!=m.b)
+    {
+        if( m.a != MUX_0 )  alpha = GetIColor(m.a, curCol);
+        if( m.b != MUX_0 )  alpha -= GetIColor(m.b, curCol);
+        if( m.c != MUX_1 )  alpha *= GetIColor(m.c, curCol);
+    }
+    if( m.d != MUX_0 )  alpha += GetIColor(m.d, curCol);
+
+    return (COLOR)(((uint32)color&0x00FFFFFF)|((uint32)alpha&0xFF000000));
+}
+
+
+COLOR CColorCombiner::GetConstFactor(uint32 colorFlag, uint32   alphaFlag, uint32 defaultColor)
+{
+    // Allows a combine mode to select what TFACTOR should be
+    uint32 color = defaultColor;
+    uint32 alpha = defaultColor;
+
+    switch (colorFlag&MUX_MASK)
+    {
+    case MUX_0:
+        break;
+    case MUX_FORCE_0:
+        color = 0;
+        break;
+    case MUX_1:
+        color = 0xFFFFFFFF;
+        break;
+    case MUX_PRIM:
+        color = gRDP.primitiveColor;
+        break;
+    case MUX_ENV:
+        color = gRDP.envColor;
+        break;
+    case MUX_LODFRAC:
+        color = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac);
+        break;
+    case MUX_PRIMLODFRAC:
+        color = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac);
+        break;
+    case MUX_PRIM_ALPHA:
+        {
+            IColor col(gRDP.primitiveColor);
+            col.AlphaReplicate();
+            color = (COLOR)col;
+        }
+        break;
+    case MUX_ENV_ALPHA:
+        {
+            IColor col(gRDP.envColor);
+            col.AlphaReplicate();
+            color = (COLOR)col;
+        }
+        break;
+    case MUX_K5:
+        color = 0xFFFFFFFF;
+        break;
+    case MUX_UNK:
+        color = defaultColor;
+        if( options.enableHackForGames == HACK_FOR_CONKER ) color = 0xFFFFFFFF;
+        break;
+    default:
+        color = defaultColor;
+        break;
+    }
+
+    if( colorFlag & MUX_COMPLEMENT )
+    {
+        color = 0xFFFFFFFF - color;
+    }
+    if( colorFlag & MUX_ALPHAREPLICATE )
+    {
+        color = color>>24;
+        color = color | (color<<8) | (color <<16) | (color<<24);
+    }
+
+    color &= 0x00FFFFFF;    // For color channel only, not the alpha channel
+
+
+    switch (alphaFlag&MUX_MASK)
+    {
+    case MUX_0:
+        break;
+    case MUX_FORCE_0:
+        alpha = 0;
+        break;
+    case MUX_1:
+        alpha = 0xFFFFFFFF;
+        break;
+    case MUX_PRIM:
+        alpha = gRDP.primitiveColor;
+        break;
+    case MUX_ENV:
+        alpha = gRDP.envColor;
+        break;
+    case MUX_LODFRAC:
+        alpha = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac);
+        break;
+    case MUX_PRIMLODFRAC:
+        alpha = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac);
+        break;
+    case MUX_PRIM_ALPHA:
+        {
+            IColor col(gRDP.primitiveColor);
+            col.AlphaReplicate();
+            alpha = (COLOR)col;
+        }
+        break;
+    case MUX_ENV_ALPHA:
+        {
+            IColor col(gRDP.envColor);
+            col.AlphaReplicate();
+            alpha = (COLOR)col;
+        }
+        break;
+    default:
+        alpha = defaultColor;
+        break;
+    }
+
+    if( alphaFlag & MUX_COMPLEMENT )
+    {
+        alpha = 0xFFFFFFFF - alpha;
+    }
+
+    alpha &= 0xFF000000;
+
+    return (color|alpha);
+}
+
+//*****************************************************************************
+//
+//*****************************************************************************
+bool    gUsingPrimColour = false;
+bool    gUsingEnvColour = false;
+
+int CountTexel1Cycle(N64CombinerType &m)
+{
+    int hasTexel[2];
+    uint8 *p = (uint8*)&m;
+
+    for( int i=0; i<2; i++)
+    {
+        hasTexel[i]=0;
+        for( int j=0; j<4; j++)
+        {
+            if( (p[j]&MUX_MASK) == MUX_TEXEL0+i )
+            {
+                hasTexel[i]=1;
+                break;
+            }
+        }
+    }
+
+    return hasTexel[0]+hasTexel[1];
+}
+
+uint32 GetTexelNumber(N64CombinerType &m)
+{
+    if( (m.a&MUX_MASK) == MUX_TEXEL1 || (m.b&MUX_MASK) == MUX_TEXEL1 || (m.c&MUX_MASK) == MUX_TEXEL1  || (m.d&MUX_MASK) == MUX_TEXEL1 )
+        return TEX_1;
+    else
+        return TEX_0;
+}
+
+bool IsTxtrUsed(N64CombinerType &m)
+{
+    if( (m.a&MUX_MASK) == MUX_TEXEL1 || (m.b&MUX_MASK) == MUX_TEXEL1 || (m.c&MUX_MASK) == MUX_TEXEL1  || (m.d&MUX_MASK) == MUX_TEXEL1 )
+        return true;
+    if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL0  || (m.d&MUX_MASK) == MUX_TEXEL0 )
+        return true;
+    else
+        return false;
+}
+
+//========================================================================
+
+void CColorCombiner::InitCombinerMode(void)
+{
+#ifdef DEBUGGER
+    LOG_UCODE(cycleTypeStrs[gRDP.otherMode.cycle_type]);
+    if( debuggerDropDecodedMux )
+    {
+        UpdateCombiner(m_pDecodedMux->m_dwMux0, m_pDecodedMux->m_dwMux1);
+    }
+#endif
+
+    if( currentRomOptions.bNormalCombiner )
+    {
+        DisableCombiner();
+    }
+    else if( gRDP.otherMode.cycle_type  == CYCLE_TYPE_COPY )
+    {
+        InitCombinerCycleCopy();
+        m_bCycleChanged = true;
+    }
+    else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL )
+    //else if ( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL && gRSP.ucode != 5 )   //hack
+    {
+        InitCombinerCycleFill();
+        m_bCycleChanged = true;
+    }
+    else
+    {
+        InitCombinerCycle12();
+        m_bCycleChanged = false;
+    }
+}
+
+
+bool bConkerHideShadow=false;
+void CColorCombiner::UpdateCombiner(uint32 dwMux0, uint32 dwMux1)
+{
+#ifdef DEBUGGER
+    if( debuggerDropDecodedMux )
+    {
+        debuggerDropDecodedMux = false;
+        m_pDecodedMux->m_dwMux0 = m_pDecodedMux->m_dwMux1 = 0;
+        m_DecodedMuxList.clear();
+    }
+#endif
+
+    DecodedMux &m_decodedMux = *m_pDecodedMux;
+    if( m_decodedMux.m_dwMux0 != dwMux0 || m_decodedMux.m_dwMux1 != dwMux1 )
+    {
+        if( options.enableHackForGames == HACK_FOR_DR_MARIO )
+        {
+            // Hack for Dr. Mario
+            if( dwMux1 == 0xfffcf239 && 
+                ((m_decodedMux.m_dwMux0 == dwMux0 && dwMux0 == 0x00ffffff && 
+                m_decodedMux.m_dwMux1 != dwMux1 && m_decodedMux.m_dwMux1 == 0xfffcf279 ) || 
+                (m_decodedMux.m_dwMux0 == 0x00ffb3ff && m_decodedMux.m_dwMux1 == 0xff64fe7f && dwMux0 == 0x00ffffff ) ))
+            {
+                //dwMux1 = 0xffcf23A;
+                dwMux1 = 0xfffcf438;
+            }
+        }
+        uint64 mux64 = (((uint64)dwMux1)<<32)+dwMux0;
+        int index=m_DecodedMuxList.find(mux64);
+
+        if( options.enableHackForGames == HACK_FOR_CONKER )
+        {
+            // Conker's shadow, to disable the shadow
+            //Mux=0x00ffe9ff    Used in CONKER BFD
+            //Color0: (0 - 0) * 0 + SHADE
+            //Color1: (0 - 0) * 0 + SHADE
+            //Alpha0: (1 - TEXEL0) * SHADE + 0
+            //Alpha1: (1 - TEXEL0) * SHADE + 0              
+            if( dwMux1 == 0xffd21f0f && dwMux0 == 0x00ffe9ff )
+            {
+                bConkerHideShadow = true;
+            }
+            else
+            {
+                bConkerHideShadow = false;
+            }
+        }
+
+        if( index >= 0 )
+        {
+            m_decodedMux = m_DecodedMuxList[index];
+        }
+        else
+        {
+            m_decodedMux.Decode(dwMux0, dwMux1);
+            m_decodedMux.splitType[0] = CM_FMT_TYPE_NOT_CHECKED;
+            m_decodedMux.splitType[1] = CM_FMT_TYPE_NOT_CHECKED;
+            m_decodedMux.splitType[2] = CM_FMT_TYPE_NOT_CHECKED;
+            m_decodedMux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
+
+            m_decodedMux.Hack();
+
+            if( !m_bSupportMultiTexture )
+            {
+                m_decodedMux.ReplaceVal(MUX_TEXEL1, MUX_TEXEL0);
+                m_decodedMux.ReplaceVal(MUX_LODFRAC,1);
+                m_decodedMux.ReplaceVal(MUX_PRIMLODFRAC,1);
+            }
+
+            m_decodedMux.Simplify();
+            if( m_supportedStages>1)    
+                m_decodedMux.SplitComplexStages();
+            
+            m_DecodedMuxList.add(m_decodedMux.m_u64Mux, *m_pDecodedMux);
+#ifdef DEBUGGER
+            if( logCombiners ) 
+            {
+                TRACE0("Add a new mux");
+                DisplayMuxString();
+            }
+#endif
+        }
+
+        m_bTex0Enabled = m_decodedMux.m_bTexel0IsUsed;
+        m_bTex1Enabled = m_decodedMux.m_bTexel1IsUsed;
+        m_bTexelsEnable = m_bTex0Enabled||m_bTex1Enabled;
+
+        gRSP.bProcessDiffuseColor = (m_decodedMux.m_dwShadeColorChannelFlag != MUX_0 || m_decodedMux.m_dwShadeAlphaChannelFlag != MUX_0);
+        gRSP.bProcessSpecularColor = false;
+    }
+}
+
+
+#ifdef DEBUGGER
+void CColorCombiner::DisplayMuxString(void)
+{
+    if( gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY)
+    {
+        TRACE0("COPY Mode\n");
+    }   
+    else if( gRDP.otherMode.cycle_type == CYCLE_TYPE_FILL)
+    {
+        TRACE0("FILL Mode\n");
+    }
+
+    m_pDecodedMux->DisplayMuxString("Used");
+}
+
+void CColorCombiner::DisplaySimpleMuxString(void)
+{
+    m_pDecodedMux->DisplaySimpliedMuxString("Used");
+}
+#endif
+