mupen64plus-oldsvn/rice_video/DecodedMux.cpp
Scott Knauert edcef05047 Changes: Fixed nearly all warnings in Rice (Issue 24) except
one pointer arithmetic one in TextureFilters.cpp (see tracker).
Once that is fixed Issue 24 in current form can be closed.

Testing done: Code compiles for normal and debug use without 
any -Wall warnings and seems to yield the same results and previous 
svn on my r300.
2008-04-04 19:18:54 +00:00

1557 lines
41 KiB
C++

/*
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 "stdafx.h"
#define ALLOW_USE_TEXTURE_FOR_CONSTANTS
static const uint8 sc_Mux32[32] =
{
MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBINED|MUX_ALPHAREPLICATE,
MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,
MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, // Actually k5
MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,
MUX_UNK, MUX_UNK, MUX_UNK, MUX_0
};
static const uint8 sc_Mux16[16] =
{
MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBALPHA,
MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,
MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_0
};
static const uint8 sc_Mux8[8] =
{
MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,
MUX_SHADE, MUX_ENV, MUX_1, MUX_0
};
const char * translatedCombTypes[] =
{
"0",
"1",
"COMBINED",
"TEXEL0",
"TEXEL1",
"PRIM",
"SHADE",
"ENV",
"COMBALPHA",
"T0_ALPHA_wrong",
"T1_ALPHA_wrong",
"PRIM_ALPHA_wrong",
"SHADE_ALPHA_wrong",
"ENV_ALPHA_wrong",
"LODFRAC",
"PRIMLODFRAC",
"K5",
"UNK",
"FACTOR_PRIM_MINUS_ENV",
"FACTOR_ENV_MINUS_PRIM",
"FACTOR_1_MINUS_PRIM",
"FACTOR_0_MINUS_PRIM",
"FACTOR_1_MINUS_ENV",
"FACTOR_0_MINUS_ENV",
"FACTOR_1_MINUS_PRIMALPHA",
"FACTOR_1_MINUS_ENVALPHA",
"FACTOR_HALF",
"PRIM_X_PRIMALPHA",
"1_MINUS_PRIM_X_ENV_PLUS_PRIM",
"ENV_X_PRIM",
"PRIM_X_1_MINUS_ENV",
"PRIM_X_PRIM",
"ENV_X_ENV",
};
const char* muxTypeStrs[] = {
"CM_FMT_TYPE_NOT_USED",
"CM_FMT_TYPE1_D",
"CM_FMT_TYPE2_A_ADD_D",
"CM_FMT_TYPE3_A_MOD_C",
"CM_FMT_TYPE4_A_SUB_B",
"CM_FMT_TYPE5_A_MOD_C_ADD_D",
"CM_FMT_TYPE6_A_LERP_B_C",
"CM_FMT_TYPE7_A_SUB_B_ADD_D",
"CM_FMT_TYPE8_A_SUB_B_MOD_C",
"CM_FMT_TYPE9_A_B_C_D",
"CM_FMT_TYPE_NOT_CHECKED",
};
void DecodedMux::Decode(uint32 dwMux0, uint32 dwMux1)
{
m_dwMux0 = dwMux0;
m_dwMux1 = dwMux1;
aRGB0 = uint8((dwMux0>>20)&0x0F); // c1 c1 // a0
bRGB0 = uint8((dwMux1>>28)&0x0F); // c1 c2 // b0
cRGB0 = uint8((dwMux0>>15)&0x1F); // c1 c3 // c0
dRGB0 = uint8((dwMux1>>15)&0x07); // c1 c4 // d0
aA0 = uint8((dwMux0>>12)&0x07); // c1 a1 // Aa0
bA0 = uint8((dwMux1>>12)&0x07); // c1 a2 // Ab0
cA0 = uint8((dwMux0>>9 )&0x07); // c1 a3 // Ac0
dA0 = uint8((dwMux1>>9 )&0x07); // c1 a4 // Ad0
aRGB1 = uint8((dwMux0>>5 )&0x0F); // c2 c1 // a1
bRGB1 = uint8((dwMux1>>24)&0x0F); // c2 c2 // b1
cRGB1 = uint8((dwMux0 )&0x1F); // c2 c3 // c1
dRGB1 = uint8((dwMux1>>6 )&0x07); // c2 c4 // d1
aA1 = uint8((dwMux1>>21)&0x07); // c2 a1 // Aa1
bA1 = uint8((dwMux1>>3 )&0x07); // c2 a2 // Ab1
cA1 = uint8((dwMux1>>18)&0x07); // c2 a3 // Ac1
dA1 = uint8((dwMux1 )&0x07); // c2 a4 // Ad1
//This fuction will translate the decode mux info further, so we can use
//the decode data better.
//Will translate A,B,C,D to unified presentation
aRGB0 = sc_Mux16[aRGB0];
bRGB0 = sc_Mux16[bRGB0];
cRGB0 = sc_Mux32[cRGB0];
dRGB0 = sc_Mux8[dRGB0];
aA0 = sc_Mux8[aA0];
bA0 = sc_Mux8[bA0];
cA0 = sc_Mux8[cA0];
dA0 = sc_Mux8[dA0];
aRGB1 = sc_Mux16[aRGB1];
bRGB1 = sc_Mux16[bRGB1];
cRGB1 = sc_Mux32[cRGB1];
dRGB1 = sc_Mux8[dRGB1];
aA1 = sc_Mux8[aA1];
bA1 = sc_Mux8[bA1];
cA1 = sc_Mux8[cA1];
dA1 = sc_Mux8[dA1];
m_bShadeIsUsed[1] = isUsedInAlphaChannel(MUX_SHADE);
m_bShadeIsUsed[0] = isUsedInColorChannel(MUX_SHADE);
m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
m_dwShadeColorChannelFlag = 0;
m_dwShadeAlphaChannelFlag = 0;
m_ColorTextureFlag[0] = 0;
m_ColorTextureFlag[1] = 0;
}
int DecodedMux::Count(uint8 val, int cycle, uint8 mask)
{
uint8* pmux = m_bytes;
int count=0;
int start=0;
int end=16;
if( cycle >= 0 )
{
start = cycle*4;
end = start+4;
}
for( int i=start; i<end; i++ )
{
if( (pmux[i]&mask) == (val&mask) )
{
count++;
}
}
return count;
}
bool DecodedMux::isUsed(uint8 val, uint8 mask)
{
uint8* pmux = m_bytes;
bool isUsed = false;
for( int i=0; i<16; i++ )
{
if( (pmux[i]&mask) == (val&mask) )
{
isUsed = true;
break;
}
}
return isUsed;
}
bool DecodedMux::isUsedInAlphaChannel(uint8 val, uint8 mask)
{
uint8* pmux = m_bytes;
bool isUsed = false;
for( int i=0; i<16; i++ )
{
if( (i/4)%2 == 0 )
continue; //Don't test color channel
if( (pmux[i]&mask) == (val&mask) )
{
isUsed = true;
break;
}
}
return isUsed;
}
bool DecodedMux::isUsedInColorChannel(uint8 val, uint8 mask)
{
uint8* pmux = m_bytes;
bool isUsed = false;
for( int i=0; i<16; i++ )
{
if( (i/4)%2 == 0 && (pmux[i]&mask) == (val&mask) )
{
isUsed = true;
break;
}
}
return isUsed;
}
bool DecodedMux::isUsedInCycle(uint8 val, int cycle, CombineChannel channel, uint8 mask)
{
cycle *=2;
if( channel == ALPHA_CHANNEL ) cycle++;
uint8* pmux = m_bytes;
for( int i=0; i<4; i++ )
{
if( (pmux[i+cycle*4]&mask) == (val&mask) )
{
return true;
}
}
return false;
}
bool DecodedMux::isUsedInCycle(uint8 val, int cycle, uint8 mask)
{
return isUsedInCycle(val, cycle/2, cycle%2?ALPHA_CHANNEL:COLOR_CHANNEL, mask);
}
void DecodedMux::ConvertComplements()
{
//For (A-B)*C+D, if A=1, then we can convert A-B to Ac-0
if( aRGB0 != MUX_1 && bRGB0 != MUX_0 )
{
aRGB0 = bRGB0|MUX_COMPLEMENT;
bRGB0 = MUX_0;
}
if( aRGB1 != MUX_1 && bRGB1 != MUX_0 )
{
aRGB1 = bRGB1|MUX_COMPLEMENT;
bRGB1 = MUX_0;
}
if( aA0 != MUX_1 && bA0 != MUX_0 )
{
aA0 = bA0|MUX_COMPLEMENT;
bA0 = MUX_0;
}
if( aA1 != MUX_1 && bA1 != MUX_0 )
{
aA1 = bA1|MUX_COMPLEMENT;
bA1 = MUX_0;
}
}
CombinerFormatType DecodedMux::GetCombinerFormatType(uint32 cycle)
{
//Analyze the formula
/*
C=0 = D
A==B = D
B=0, C=1, D=0 = A
A=1, B=0, D=0 = C
C=1, B==D = A
A=1, C=1, D=0 = 1-B
D = 1 = 1
*/
return CM_FMT_TYPE_D;
}
void DecodedMuxForPixelShader::Simplify(void)
{
CheckCombineInCycle1();
//Reformat();
if( g_curRomInfo.bTexture1Hack )
{
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
}
splitType[0] = CM_FMT_TYPE_NOT_USED;
splitType[1] = CM_FMT_TYPE_NOT_USED;
splitType[2] = CM_FMT_TYPE_NOT_USED;
splitType[3] = CM_FMT_TYPE_NOT_USED;
mType = CM_FMT_TYPE_NOT_USED;
m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
}
void DecodedMuxForSemiPixelShader::Reset(void)
{
Decode(m_dwMux0, m_dwMux1);
splitType[0] = CM_FMT_TYPE_NOT_CHECKED;
splitType[1] = CM_FMT_TYPE_NOT_CHECKED;
splitType[2] = CM_FMT_TYPE_NOT_CHECKED;
splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
Hack();
gRSP.bProcessDiffuseColor = false;
gRSP.bProcessSpecularColor = false;
CheckCombineInCycle1();
if( g_curRomInfo.bTexture1Hack )
{
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
}
m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
}
void DecodedMuxForOGL14V2::Simplify(void)
{
CheckCombineInCycle1();
if( g_curRomInfo.bTexture1Hack )
{
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
}
Reformat();
UseTextureForConstant();
Reformat();
m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
}
void DecodedMux::Simplify(void)
{
CheckCombineInCycle1();
if( gRDP.otherMode.text_lod )
ConvertLODFracTo0();
if( g_curRomInfo.bTexture1Hack )
{
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);
ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);
}
Reformat();
UseShadeForConstant();
Reformat();
if( m_dwShadeColorChannelFlag == MUX_0 )
{
MergeShadeWithConstants();
Reformat();
}
#ifdef ALLOW_USE_TEXTURE_FOR_CONSTANTS
UseTextureForConstant();
for( int i=0; i<2; i++ )
{
if( m_ColorTextureFlag[i] != 0 )
{
if( m_dwShadeColorChannelFlag == m_ColorTextureFlag[i] )
{
ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0RGB);
ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1RGB);
m_dwShadeColorChannelFlag = 0;
}
if( m_dwShadeAlphaChannelFlag == m_ColorTextureFlag[i] )
{
ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0Alpha);
ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1Alpha);
ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle0RGB,MUX_MASK_WITH_ALPHA);
ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle1RGB,MUX_MASK_WITH_ALPHA);
m_dwShadeAlphaChannelFlag = 0;
}
}
}
Reformat();
#endif
m_bTexel0IsUsed = isUsed(MUX_TEXEL0);
m_bTexel1IsUsed = isUsed(MUX_TEXEL1);
}
void DecodedMux::Reformat(bool do_complement)
{
if( m_dWords[N64Cycle0RGB] == m_dWords[N64Cycle1RGB] )
{
aRGB1 = MUX_0;
bRGB1 = MUX_0;
cRGB1 = MUX_0;
dRGB1 = MUX_COMBINED;
splitType[N64Cycle1RGB] = CM_FMT_TYPE_NOT_USED;
}
if( m_dWords[N64Cycle0Alpha] == m_dWords[N64Cycle1Alpha] )
{
aA1 = MUX_0;
bA1 = MUX_0;
cA1 = MUX_0;
dA1 = MUX_COMBINED;
splitType[N64Cycle1Alpha] = CM_FMT_TYPE_NOT_USED;
}
for( int i=0; i<4; i++ )
{
if( splitType[i] == CM_FMT_TYPE_NOT_USED )
{
continue; //Skip this, it is not used
}
N64CombinerType &m = m_n64Combiners[i];
//if( m.a == MUX_0 || m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;
if( m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;
if( do_complement && (m.b == MUX_1 || m.d == MUX_1) ) m.a = m.b = m.c = MUX_0;
if( m.a == MUX_0 && m.b == m.d )
{
m.a = m.b;
m.b = m.d = 0;
//Hack for Mario Tennis
if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && m.c == MUX_TEXEL1 )
{
if( do_complement )
m.c = MUX_TEXEL0|MUX_COMPLEMENT;
else
{
m.a = m.c;
m.c = m.b;
m.b = m.a;
m.a = MUX_1;
}
}
//m.c ^= MUX_COMPLEMENT;
}
//Type 1 == D
//Analyze the formula
//Check Type 1
//D = 1 = D(=1)
//C=0 = D
//A==B = D
//B=0, C=1, D=0 = A
//C=1, B==D = A
//A=1, B=0, D=0 = C
//A=1, C=1, D=0 = 1-B
splitType[i] = CM_FMT_TYPE_NOT_CHECKED; //All Type 1 will be changed to = D
if( m.c == MUX_0 || m.a==m.b || ( do_complement && (m.d == MUX_1 || m.b==MUX_1)) )
{
splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
m.a = m.b = m.c = MUX_0;
if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
}
else if( (m.b == MUX_0 && m.c == MUX_1 && m.d == MUX_0 ) || ( m.c == MUX_1 && m.b==m.d ) )
{
splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
m.d = m.a;
m.a = m.b = m.c = MUX_0;
if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
}
else if( m.a == MUX_1 && m.b == MUX_0 && m.d == MUX_0 )
{
splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
m.d = m.c;
m.a = m.b = m.c = MUX_0;
if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
}
else if( m.a == MUX_1 && m.c == MUX_1 && m.d == MUX_0 && do_complement )
{
splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D
m.d = m.b^MUX_COMPLEMENT;
m.a = m.b = m.c = MUX_0;
if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;
}
if( splitType[i] == CM_FMT_TYPE_NOT_USED )
continue;
if( splitType[i] == CM_FMT_TYPE_D )
{
if( (i == N64Cycle0RGB || i == N64Cycle0Alpha) && splitType[i+2]!=CM_FMT_TYPE_NOT_USED ) //Cycle 1's Color or Alpha
{
uint8 saveD = m.d;
for( int j=0; j<4; j++ )
{
if( (m_bytes[j+i*4+8]&MUX_MASK) == MUX_COMBINED )
{
m_bytes[j+i*4+8] = saveD|(m_bytes[j+i*4+8]&0xC0); //Replace cycle's CMB with D from cycle 1
}
}
m_dWords[i] = m_dWords[i+2];
splitType[i+2]=CM_FMT_TYPE_NOT_USED;
m_dWords[i+2] = 0x02000000;
i=i-1; // Throw the first cycle result away, use 2nd cycle for the 1st cycle
// and then redo the 1st cycle
continue;
}
if( (i==2 || i == 3) && (m.d&MUX_MASK) == MUX_COMBINED )
{
splitType[i] = CM_FMT_TYPE_NOT_USED;
}
continue;
}
//Type 2: A+D ' ADD
//B=0, C=1 = A+D
//A=1, B=0 = C+D
splitType[i] = CM_FMT_TYPE_A_ADD_D; //All Type 2 will be changed to = A+D
if( m.b == MUX_0 && m.c == MUX_1 )
{
if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d);
if( m.a == MUX_COMBINED ) swap(m.a, m.d);
continue;
}
if( m.a == MUX_1 && m.b == MUX_0 )
{
m.a = m.c; //Change format A+D
m.c = MUX_1;
if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d);
continue;
}
//Type 3: A*C
//B=0, D=0 = A*C
//A=1, D=0 = (1-A)*C
splitType[i] = CM_FMT_TYPE_A_MOD_C; //A*C
if( m.b == MUX_0 && m.d == MUX_0 )
{
if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);
if( m.a == MUX_COMBINED ) swap(m.a, m.c);
continue;
}
if( m.a == MUX_1 && m.d == MUX_0 && do_complement )
{
m.a = m.b^MUX_COMPLEMENT;
m.b = MUX_0;
if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);
if( m.a == MUX_COMBINED ) swap(m.a, m.c);
continue;
}
//Type 4: A-B ' SUB
//C=1, D=0 = A-B
splitType[i] = CM_FMT_TYPE_A_SUB_B; //A-B
if( m.c == MUX_1 && m.d == MUX_0 )
{
continue;
}
//Type 5: A*C+D , ' MULTIPLYADD
//B=0 = A*C+D
//A=1 = (1-B) * C + D
splitType[i] = CM_FMT_TYPE_A_MOD_C_ADD_D;
if( m.b == MUX_0 )
{
if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);
if( m.a == MUX_COMBINED ) swap(m.a, m.c);
continue;
}
if( m.a == MUX_1 && m.b!=m.d && do_complement )
{
m.a = m.b^MUX_COMPLEMENT;
m.b = MUX_0;
if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);
if( m.a == MUX_COMBINED ) swap(m.a, m.c);
continue;
}
//Type 6: (A-B)*C+B Map to LERP, or BLENDALPHA
//D==B
splitType[i] = CM_FMT_TYPE_A_LERP_B_C;
if( m.b == m.d )
{
continue;
}
//Type 7: A-B+D
//C=1 = A-B+D
splitType[i] = CM_FMT_TYPE_A_SUB_B_ADD_D;
if( m.c == MUX_1 )
{
if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);
continue;
}
//Type 8: (A-B)*C
splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
if( m.d == MUX_0 )
{
continue;
}
if( m.c == m.d && do_complement ) // (A-B)*C+C ==> (A + B|C ) * C
{
m.d = MUX_0;
m.b |= MUX_COMPLEMENT;
continue;
}
if( m.a == m.d )
{
splitType[i] = CM_FMT_TYPE_A_B_C_A;
continue;
}
//Type 9: (A-B)*C+D
splitType[i] = CM_FMT_TYPE_A_B_C_D;
}
if( (splitType[0] == CM_FMT_TYPE_D && splitType[2]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 1 Color
(isUsedInCycle(MUX_COMBINED,1,COLOR_CHANNEL) == false && isUsedInCycle(MUX_COMBINED,1,ALPHA_CHANNEL) == false && splitType[2]!= CM_FMT_TYPE_NOT_USED) )
{
//Replace cycle 1 color with cycle 2 color because we have already replace cycle2's cmb
aRGB0 = aRGB1;
bRGB0 = bRGB1;
cRGB0 = cRGB1;
dRGB0 = dRGB1;
aRGB1 = MUX_0;
bRGB1 = MUX_0;
cRGB1 = MUX_0;
dRGB1 = MUX_COMBINED;
splitType[0] = splitType[2];
splitType[2] = CM_FMT_TYPE_NOT_USED;
}
if( (splitType[1] == CM_FMT_TYPE_D && splitType[3]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 2 Alpha
( isUsedInCycle(MUX_COMBINED,1,ALPHA_CHANNEL) == false && isUsedInCycle(MUX_COMBINED|MUX_ALPHAREPLICATE,1,COLOR_CHANNEL,MUX_MASK_WITH_ALPHA) == false && splitType[3]!= CM_FMT_TYPE_NOT_USED) )
{
//Replace cycle 1 alpha with cycle 2 alpha because we have already replace cycle2's cmb
aA0 = aA1;
bA0 = bA1;
cA0 = cA1;
dA0 = dA1;
aA1 = MUX_0;
bA1 = MUX_0;
cA1 = MUX_0;
dA1 = MUX_COMBINED;
splitType[1] = splitType[3];
splitType[3] = CM_FMT_TYPE_NOT_USED;
}
if( splitType[0] == CM_FMT_TYPE_A_MOD_C && splitType[2] == CM_FMT_TYPE_A_ADD_D )
{
m_n64Combiners[0].d = (m_n64Combiners[2].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[2].d : m_n64Combiners[2].a;
splitType[0] = CM_FMT_TYPE_A_MOD_C_ADD_D;
splitType[2] = CM_FMT_TYPE_NOT_USED;
m_n64Combiners[2].a = MUX_0;
m_n64Combiners[2].c = MUX_0;
m_n64Combiners[2].d = MUX_COMBINED;
}
if( splitType[1] == CM_FMT_TYPE_A_MOD_C && splitType[3] == CM_FMT_TYPE_A_ADD_D )
{
m_n64Combiners[1].d = (m_n64Combiners[3].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[3].d : m_n64Combiners[3].a;
splitType[1] = CM_FMT_TYPE_A_MOD_C_ADD_D;
splitType[3] = CM_FMT_TYPE_NOT_USED;
m_n64Combiners[3].a = MUX_0;
m_n64Combiners[3].c = MUX_0;
m_n64Combiners[3].d = MUX_COMBINED;
}
mType = max(max(max(splitType[0], splitType[1]),splitType[2]),splitType[3]);
}
const char* MuxGroupStr[4] =
{
"Color0",
"Alpha0",
"Color1",
"Alpha1",
};
char* DecodedMux::FormatStr(uint8 val, char *buf)
{
if( val == CM_IGNORE_BYTE )
{
strcpy(buf," ");
}
else
{
strcpy(buf, translatedCombTypes[val&MUX_MASK]);
if( val&MUX_ALPHAREPLICATE )
strcat(buf,"|A");
if( val&MUX_COMPLEMENT )
strcat(buf,"|C");
if( val&MUX_NEG )
strcat(buf,"|N");
}
return buf;
}
void DecodedMux::Display(bool simplified,FILE *fp)
{
DecodedMux decodedMux;
DecodedMux *mux;
if( simplified )
{
mux = this;
}
else
{
decodedMux.Decode(m_dwMux0, m_dwMux1);
mux = &decodedMux;
}
char buf0[30];
char buf1[30];
char buf2[30];
char buf3[30];
for( int i=0; i<2; i++ )
{
for(int j=0;j<2;j++)
{
N64CombinerType &m = mux->m_n64Combiners[i+2*j];
if( fp )
{
fprintf(fp,"%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),
FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));
}
else
{
DebuggerAppendMsg("%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),
FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));
}
}
}
}
int DecodedMux::HowManyConstFactors()
{
int n=0;
if( isUsed(MUX_PRIM) ) n++;
if( isUsed(MUX_ENV) ) n++;
if( isUsed(MUX_LODFRAC) ) n++;
if( isUsed(MUX_PRIMLODFRAC) ) n++;
return n;
}
int DecodedMux::HowManyTextures()
{
int n=0;
if( isUsed(MUX_TEXEL0) ) n++;
if( isUsed(MUX_TEXEL1) ) n++;
return n;
}
int DecodedMux::CountTexels(void)
{
int count=0;
for( int i=0; i<4; i++ )
{
N64CombinerType &m = m_n64Combiners[i];
count = max(count, ::CountTexel1Cycle(m));
if( count == 2 )
break;
}
return count;
}
void DecodedMux::ReplaceVal(uint8 val1, uint8 val2, int cycle, uint8 mask)
{
int start = 0;
int end = 16;
if( cycle >= 0 )
{
start = cycle*4;
end = start+4;
}
uint8* pmux = m_bytes;
for( int i=start; i<end; i++ )
{
if( (pmux[i]&mask) == (val1&mask) )
{
pmux[i] &= (~mask);
pmux[i] |= val2;
}
}
}
uint32 DecodedMux::GetCycle(int cycle, CombineChannel channel)
{
uint32* pmux = m_dWords;
if( channel == COLOR_CHANNEL )
{
return pmux[cycle*2];
}
else
{
return pmux[cycle*2+1];
}
}
uint32 DecodedMux::GetCycle(int cycle)
{
return m_dWords[cycle];
}
enum ShadeConstMergeType
{
SHADE_DO_NOTHING,
SHADE_ADD_PRIM, // Shade+PRIM
SHADE_ADD_ENV, // Shade+ENV
SHADE_ADD_PRIM_ALPHA, // Shade+PRIM_ALPHA
SHADE_ADD_ENV_ALPHA, // Shade+ENV_ALPHA
SHADE_MINUS_PRIM_PLUS_ENV,
SHADE_MINUS_ENV_PLUS_PRIM,
SHADE_MOD_ENV,
};
typedef struct
{
uint64 mux; // simplified
ShadeConstMergeType op;
} ShadeConstMergeMapType;
ShadeConstMergeMapType MergeShadeWithConstantsMaps[] =
{
{0, SHADE_DO_NOTHING},
{0x0007000600070006LL, SHADE_MOD_ENV}, // SHADE * ENV
};
// 0x05070501, 0x00070006 //(1 - PRIM) * ENV + PRIM
// 0x00050003, 0x00050003 //(TEXEL0 - 0) * PRIM + 0
void DecodedMux::MergeShadeWithConstants(void)
{
// This function should be called afte the mux has been simplified
// The goal of this function is to merge as many as possible constants with shade
// so to reduce the totally number of constants to 0 or 1
// And at the same time, to reduce the complexity of the whole mux
// so we can implement the mux easiler when lower end video cards
// We can only try to merge shade with constants for:
// 1 cycle mode or 2 cycle mode and shade is not used in the 2nd cycle
if( m_bShadeIsUsed[0] ) MergeShadeWithConstantsInChannel(COLOR_CHANNEL);
if( m_bShadeIsUsed[1] ) MergeShadeWithConstantsInChannel(ALPHA_CHANNEL);
}
void DecodedMux::MergeShadeWithConstantsInChannel(CombineChannel channel)
{
bool usedIn[2];
uint32 cycleVal;
int cycleNum;
usedIn[0] = isUsedInCycle(MUX_SHADE,channel);
usedIn[1] = isUsedInCycle(MUX_SHADE,channel+2);
if( usedIn[0] && usedIn[1] && GetCycle(channel)!=GetCycle(channel+2) )
{
//Shade is used in more than 1 cycles, and the ways it is used are different
//in cycles, so we can not merge shade with const factors
return;
}
if( usedIn[0] ) { cycleVal = GetCycle(channel);cycleNum=0;}
else {cycleVal = GetCycle(channel+2);cycleNum=1;}
//Update to here, Shade is either used only in 1 cycle, or the way it is used are totally
//the same in different cycles
if( cycleVal == 0x06000000 || isUsedInCycle(MUX_COMBINED,channel+cycleNum*2) ) // (0-0)*0+Shade
{
return;
}
//Now we can merge shade with consts
for( int i=0; i<2; i++ )
{
if( usedIn[i] )
{
N64CombinerType &m = m_n64Combiners[channel+i*2];
if( isUsedInCycle(MUX_TEXEL0,i*2+channel) || isUsedInCycle(MUX_TEXEL1,i*2+channel) )
{
if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.a&MUX_MASK) == MUX_TEXEL1 )
{
// m.a is texel, can not merge constant with shade
return;
}
else if( (m.b&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL1 )
{
// m.b is texel, can not merge constant with shade
return;
}
else if(( (m.c&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL1 ) )
{
if( (m.d&MUX_MASK) != MUX_SHADE )
{
cycleVal &= 0x0000FFFF; // A-B
}
else if( (m.a&MUX_MASK) == MUX_SHADE || (m.b&MUX_MASK) == MUX_SHADE )
{
return;
}
}
else if( (m.d&MUX_MASK) == MUX_TEXEL0 || (m.d&MUX_MASK) == MUX_TEXEL1 )
{
cycleVal &= 0x00FFFFFF; // (A-B)*C
}
}
else
{
m.a = m.b = m.c = MUX_0;
m.d = MUX_SHADE;
splitType[i*2+channel] = CM_FMT_TYPE_D;
}
}
}
if( channel == COLOR_CHANNEL )
m_dwShadeColorChannelFlag = cycleVal;
else
m_dwShadeAlphaChannelFlag = cycleVal;
}
void DecodedMux::MergeConstants(void)
{
// This function should be called afte the mux has been simplified
// The goal of this function is to merge remain constants and to reduce the
// total number of constants, so we can implement the mux easiler
// This function should be called after the MergeShadeWithConstants() function
}
void DecodedMux::UseShadeForConstant(void)
{
// If shade is not used in the mux, we can use it for constants
// This function should be called after constants have been merged
bool doAlphaChannel = true;
uint8 mask = (uint8)~MUX_COMPLEMENT;
int constants = 0;
if( isUsed(MUX_ENV) ) constants++;
if( isUsed(MUX_PRIM) ) constants++;
if( isUsed(MUX_LODFRAC) ) constants++;
if( isUsed(MUX_PRIMLODFRAC) ) constants++;
bool forceToUsed = constants>m_maxConstants;
if( !isUsedInColorChannel(MUX_SHADE) && (forceToUsed || max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D) )
{
int countEnv = Count(MUX_ENV, N64Cycle0RGB, mask) + Count(MUX_ENV, N64Cycle1RGB, mask);
int countPrim = Count(MUX_PRIM, N64Cycle0RGB, mask) + Count(MUX_PRIM, N64Cycle1RGB, mask);
if( countEnv+countPrim > 0 )
{
if( countPrim >= countEnv )
{
//TRACE0("Use Shade for PRIM in color channel");
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0RGB);
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1RGB);
m_dwShadeColorChannelFlag = MUX_PRIM;
}
else if( countEnv>0 )
{
//TRACE0("Use Shade for ENV in color channel");
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0RGB);
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1RGB);
m_dwShadeColorChannelFlag = MUX_ENV;
}
if( isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE, mask) )
{
m_dwShadeAlphaChannelFlag = m_dwShadeColorChannelFlag;
ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle0Alpha);
ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle1Alpha);
doAlphaChannel = false;
}
}
}
if( doAlphaChannel && !isUsedInAlphaChannel(MUX_SHADE) && !isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE,MUX_MASK_WITH_ALPHA))
{
int countEnv = Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
int countPrim = Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
if( forceToUsed || max(splitType[1], splitType[3]) >= CM_FMT_TYPE_A_MOD_C_ADD_D ||
(max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D && countEnv+countPrim > 0 ) )
{
countEnv = Count(MUX_ENV, N64Cycle0Alpha) + Count(MUX_ENV, N64Cycle1Alpha) +
Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
countPrim = Count(MUX_PRIM, N64Cycle0Alpha) + Count(MUX_PRIM, N64Cycle1Alpha) +
Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
if( countEnv+countPrim > 0 )
{
if( countPrim>0 && m_dwShadeColorChannelFlag == MUX_PRIM )
{
//TRACE0("Use Shade for PRIM in alpha channel");
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha);
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha);
ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
m_dwShadeAlphaChannelFlag = MUX_PRIM;
}
else if( countEnv>0 && m_dwShadeColorChannelFlag == MUX_ENV )
{
//TRACE0("Use Shade for PRIM in alpha channel");
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha);
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha);
ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
m_dwShadeAlphaChannelFlag = MUX_ENV;
}
else if( countPrim >= countEnv )
{
//TRACE0("Use Shade for PRIM in alpha channel");
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha);
ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha);
ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
m_dwShadeAlphaChannelFlag = MUX_PRIM;
}
else if( countEnv>0 )
{
//TRACE0("Use Shade for ENV in alpha channel");
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha);
ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha);
ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);
ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);
m_dwShadeAlphaChannelFlag = MUX_ENV;
}
}
}
}
}
void DecodedMux::UseTextureForConstant(void)
{
int numofconst = HowManyConstFactors();
int numOftex = HowManyTextures();
if( numofconst > m_maxConstants && numOftex < m_maxTextures )
{
// We can use a texture for a constant
for( int i=0; i<2 && numofconst > m_maxConstants ; i++ )
{
if( isUsed(MUX_TEXEL0+i) )
{
continue; // can not use this texture
}
if( isUsed(MUX_PRIM) )
{
ReplaceVal(MUX_PRIM, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_PRIM;
numofconst--;
continue;
}
if( isUsed(MUX_ENV) )
{
ReplaceVal(MUX_ENV, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_ENV;
numofconst--;
continue;
}
if( isUsed(MUX_LODFRAC) )
{
ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_LODFRAC;
numofconst--;
continue;
}
if( isUsed(MUX_PRIMLODFRAC) )
{
ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;
numofconst--;
continue;
}
}
}
}
void DecodedMuxForOGL14V2::UseTextureForConstant(void)
{
bool envused = isUsed(MUX_ENV);
bool lodused = isUsed(MUX_LODFRAC);
int numofconst = 0;
if( envused ) numofconst++;
if( lodused ) numofconst++;
int numOftex = HowManyTextures();
if( numofconst > 0 && numOftex < 2 )
{
// We can use a texture for a constant
for( int i=0; i<2 && numofconst > 0 ; i++ )
{
if( isUsed(MUX_TEXEL0+i) )
{
continue; // can not use this texture
}
if( envused )
{
ReplaceVal(MUX_ENV, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_ENV;
numofconst--;
envused = false;
continue;
}
if( isUsed(MUX_LODFRAC) )
{
ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_LODFRAC;
numofconst--;
continue;
}
if( isUsed(MUX_PRIMLODFRAC) )
{
ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i);
m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;
numofconst--;
continue;
}
}
}
}
#ifdef _DEBUG
extern const char *translatedCombTypes[];
void DecodedMux::DisplayMuxString(const char *prompt)
{
DebuggerAppendMsg("//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
Display(false);
TRACE0("\n");
}
void DecodedMux::DisplaySimpliedMuxString(const char *prompt)
{
DebuggerAppendMsg("//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
DebuggerAppendMsg("Simplied DWORDs=%08X, %08X, %08X, %08X", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);
Display(true);
DebuggerAppendMsg("Simplfied type: %s", muxTypeStrs[mType]);
if( m_dwShadeColorChannelFlag != 0 )
{
if( m_dwShadeColorChannelFlag == MUX_ENV )
TRACE0("Shade = ENV in color channel")
else if( m_dwShadeColorChannelFlag == MUX_PRIM )
TRACE0("Shade = PRIM in color channel")
else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )
TRACE0("Shade = MUX_LODFRAC in color channel")
else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )
TRACE0("Shade = MUX_PRIMLODFRAC in color channel")
else
DisplayConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL);
}
if( m_dwShadeAlphaChannelFlag != 0 )
{
if( m_dwShadeAlphaChannelFlag == MUX_ENV )
TRACE0("Shade = ENV in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )
TRACE0("Shade = PRIM in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )
TRACE0("Shade = MUX_LODFRAC in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )
TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")
else
DisplayConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL);
}
for( int i=0; i<2; i++ )
{
if( m_ColorTextureFlag[i] != 0 )
{
if( m_ColorTextureFlag[i] == MUX_ENV )
TRACE1("Tex %d = ENV", i)
else if( m_ColorTextureFlag[i] == MUX_PRIM )
TRACE1("Tex %d = PRIM", i)
else if( m_ColorTextureFlag[i] == MUX_LODFRAC )
TRACE1("Tex %d = MUX_LODFRAC", i)
else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )
TRACE1("Tex %d = MUX_PRIMLODFRAC", i)
}
}
TRACE0("\n");
}
void DecodedMux::DisplayConstantsWithShade(uint32 flag,CombineChannel channel)
{
DebuggerAppendMsg("Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");
}
#else
extern const char *translatedCombTypes[];
void DecodedMux::LogMuxString(const char *prompt, FILE *fp)
{
fprintf(fp,"//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
Display(false,fp);
TRACE0("\n");
}
void DecodedMux::LogSimpliedMuxString(const char *prompt, FILE *fp)
{
fprintf(fp,"//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);
fprintf(fp,"Simplied DWORDs=%08X, %08X, %08X, %08X\n", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);
Display(true,fp);
fprintf(fp,"Simplfied type: %s", muxTypeStrs[mType]);
if( m_dwShadeColorChannelFlag != 0 )
{
if( m_dwShadeColorChannelFlag == MUX_ENV )
TRACE0("Shade = ENV in color channel")
else if( m_dwShadeColorChannelFlag == MUX_PRIM )
TRACE0("Shade = PRIM in color channel")
else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )
TRACE0("Shade = MUX_LODFRAC in color channel")
else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )
TRACE0("Shade = MUX_PRIMLODFRAC in color channel")
else
LogConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL,fp);
}
if( m_dwShadeAlphaChannelFlag != 0 )
{
if( m_dwShadeAlphaChannelFlag == MUX_ENV )
TRACE0("Shade = ENV in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )
TRACE0("Shade = PRIM in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )
TRACE0("Shade = MUX_LODFRAC in alpha channel")
else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )
TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")
else
LogConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL,fp);
}
for( int i=0; i<2; i++ )
{
if( m_ColorTextureFlag[i] != 0 )
{
if( m_ColorTextureFlag[i] == MUX_ENV )
TRACE1("Tex %d = ENV", i)
else if( m_ColorTextureFlag[i] == MUX_PRIM )
TRACE1("Tex %d = PRIM", i)
else if( m_ColorTextureFlag[i] == MUX_LODFRAC )
TRACE1("Tex %d = MUX_LODFRAC", i)
else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )
TRACE1("Tex %d = MUX_PRIMLODFRAC", i)
}
}
TRACE0("\n");
}
void DecodedMux::LogConstantsWithShade(uint32 flag,CombineChannel channel, FILE *fp)
{
fprintf(fp,"Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");
}
#endif
void DecodedMux::To_AB_Add_CD_Format(void) // Use by TNT,Geforce
{
// This function should be called after calling reformat
// This function will not be called by default, can be called optionally
// by TNT/Geforce combiner compilers
for( int i=0; i<2; i++ )
{
N64CombinerType &m0 = m_n64Combiners[i];
N64CombinerType &m1 = m_n64Combiners[i+2];
switch( splitType[i] )
{
case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage
if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )
{
m1.a = m0.d;
m1.d = MUX_COMBINED;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m0.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_SUB_B;
}
else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )
{
if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c);
m1.b = m1.d = m1.c;
m1.c = (m0.d | (m1.a & (~MUX_MASK)));
splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;
m0.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_SUB_B;
}
break;
case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage
m0.d = m0.b;
m0.b = m0.c;
splitType[i] = CM_FMT_TYPE_AB_SUB_CD;
break;
case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage
m0.d = m0.b;
m0.b = m0.c;
splitType[i] = CM_FMT_TYPE_AB_ADD_CD;
break;
case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D
case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D
if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )
{
m1.a = m0.d;
m1.d = MUX_COMBINED;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m0.d = m0.b;
m0.b = m0.c;
splitType[i] = CM_FMT_TYPE_AB_SUB_CD;
}
else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )
{
if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c);
m1.b = m1.d = m1.c;
m1.c = (m0.d | (m1.a & (~MUX_MASK)));
splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;
m0.d = m0.b;
m0.b = m0.c;
splitType[i] = CM_FMT_TYPE_AB_ADD_CD;
}
break;
default:
break;
}
}
}
void DecodedMux::To_AB_Add_C_Format(void) // Use by ATI Radeon
{
// This function should be called after calling reformat
// This function will not be called by default, can be called optionally
// by ATI combiner compilers
}
void DecodedMux::CheckCombineInCycle1(void)
{
if( isUsedInCycle(MUX_COMBINED,0,COLOR_CHANNEL) )
{
ReplaceVal(MUX_COMBINED, MUX_SHADE, 0);
}
if( isUsedInCycle(MUX_COMBALPHA,0,COLOR_CHANNEL) )
{
ReplaceVal(MUX_COMBALPHA, MUX_SHADE|MUX_ALPHAREPLICATE, 0);
}
if( isUsedInCycle(MUX_COMBINED,0,ALPHA_CHANNEL) )
{
if( cA0 == MUX_COMBINED && cRGB0 == MUX_LODFRAC && bRGB0 == dRGB0 && bA0 == dA0 )
{
cA0 = MUX_LODFRAC;
}
else
{
ReplaceVal(MUX_COMBINED, MUX_SHADE, 1);
}
}
if( isUsedInCycle(MUX_COMBALPHA,0,ALPHA_CHANNEL) )
{
ReplaceVal(MUX_COMBALPHA, MUX_SHADE, 1);
}
}
void DecodedMux::SplitComplexStages()
{
for( int i=0; i<2; i++) // Color channel and alpha channel
{
if( splitType[i+2] != CM_FMT_TYPE_NOT_USED )
continue;
N64CombinerType &m = m_n64Combiners[i];
N64CombinerType &m2 = m_n64Combiners[i+2];
switch( splitType[i] )
{
case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0)
m2.a = m.d;
m2.d = MUX_COMBINED;
m2.c = MUX_1;
m2.b = 0;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_MOD_C;
break;
case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage
m2.a = m.d;
m2.d = MUX_COMBINED;
m2.c = MUX_1;
m2.b=0;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_SUB_B;
break;
case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage
m2.a = m.c;
m2.c = MUX_COMBINED;
m2.d = m2.b=0;
splitType[i+2] = CM_FMT_TYPE_A_MOD_C;
m.c = MUX_1;
splitType[i] = CM_FMT_TYPE_A_SUB_B;
break;
case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage
m2.a = m.c;
m2.c = MUX_COMBINED;
m2.d = m2.b = 0;
splitType[i+2] = CM_FMT_TYPE_A_MOD_C;
m.c = MUX_1;
m.d = m.b;
m.b = MUX_0;
splitType[i] = CM_FMT_TYPE_A_ADD_D;
break;
case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well in 1 stage
m2.a = m.d;
m2.d = MUX_COMBINED;
m2.c = MUX_1;
m2.b = 0;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
break;
case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+A can not map very well in 1 stage
m2.a = m.d;
m2.d = MUX_COMBINED;
m2.c = MUX_1;
m2.b = 0;
splitType[i+2] = CM_FMT_TYPE_A_ADD_D;
m.d = MUX_0;
splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;
break;
default:
break;
}
}
//Reformat();
//UseShadeForConstant();
}
void DecodedMux::ConvertLODFracTo0()
{
ReplaceVal(MUX_LODFRAC,MUX_0);
ReplaceVal(MUX_PRIMLODFRAC,MUX_0);
}
void DecodedMux::Hack(void)
{
if( options.enableHackForGames == HACK_FOR_TONYHAWK )
{
if( gRSP.curTile == 1 )
{
ReplaceVal(MUX_TEXEL1, MUX_TEXEL0);
}
}
else if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM)
{
if( m_dwMux1 == 0xfffd9238 && m_dwMux0 == 0x00ffadff )
{
ReplaceVal(MUX_TEXEL1, MUX_TEXEL0);
}
else if( m_dwMux1 == 0xff5bfff8 && m_dwMux0 == 0x00121603 )
{
// The Zelda road trace
ReplaceVal(MUX_TEXEL1, MUX_0);
}
}
else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
{
if( m_dwMux1 == 0xffebdbc0 && m_dwMux0 == 0x00ffb9ff )
{
// Player shadow
//m_decodedMux.dRGB0 = MUX_TEXEL0;
//m_decodedMux.dRGB1 = MUX_COMBINED;
cA1 = MUX_TEXEL0;
}
}
else if( options.enableHackForGames == HACK_FOR_MARIO_GOLF )
{
// Hack for Mario Golf
if( m_dwMux1 == 0xf1ffca7e || m_dwMux0 == 0x00115407 )
{
// The grass
ReplaceVal(MUX_TEXEL0, MUX_TEXEL1);
}
}
else if( options.enableHackForGames == HACK_FOR_TOPGEARRALLY )
{
//Mux=0x00317e025ffef3fa Used in TOP GEAR RALLY
//Color0: (PRIM - ENV) * TEXEL1 + ENV
//Color1: (COMBINED - 0) * TEXEL1 + 0
//Alpha0: (0 - 0) * 0 + TEXEL0
//Alpha1: (0 - 0) * 0 + TEXEL1
if( m_dwMux1 == 0x5ffef3fa || m_dwMux0 == 0x00317e02 )
{
// The grass
//ReplaceVal(MUX_TEXEL0, MUX_TEXEL1);
dA1 = MUX_COMBINED;
//aA1 = MUX_COMBINED;
//cA1 = MUX_TEXEL1;
//dA1 = MUX_0;
cRGB1 = MUX_TEXEL0;
}
}
}