Path: blob/master/libmupen64plus/mupen64plus-video-rice/src/DecodedMux.cpp
2 views
/*1Copyright (C) 2002 Rice196423This program is free software; you can redistribute it and/or4modify it under the terms of the GNU General Public License5as published by the Free Software Foundation; either version 26of the License, or (at your option) any later version.78This program is distributed in the hope that it will be useful,9but WITHOUT ANY WARRANTY; without even the implied warranty of10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11GNU General Public License for more details.1213You should have received a copy of the GNU General Public License14along with this program; if not, write to the Free Software15Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.16*/1718#include <algorithm>1920#include "GeneralCombiner.h"21#include "Combiner.h"22#include "Config.h"23#include "RenderBase.h"2425#define ALLOW_USE_TEXTURE_FOR_CONSTANTS2627static const uint8 sc_Mux32[32] =28{29MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,30MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBINED|MUX_ALPHAREPLICATE,31MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,32MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_K5, // Actually k533MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,34MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,35MUX_UNK, MUX_UNK, MUX_UNK, MUX_UNK,36MUX_UNK, MUX_UNK, MUX_UNK, MUX_037};3839static const uint8 sc_Mux16[16] =40{41MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,42MUX_SHADE, MUX_ENV, MUX_1, MUX_COMBALPHA,43MUX_TEXEL0|MUX_ALPHAREPLICATE, MUX_TEXEL1|MUX_ALPHAREPLICATE, MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE,44MUX_ENV|MUX_ALPHAREPLICATE, MUX_LODFRAC, MUX_PRIMLODFRAC, MUX_045};46static const uint8 sc_Mux8[8] =47{48MUX_COMBINED, MUX_TEXEL0, MUX_TEXEL1, MUX_PRIM,49MUX_SHADE, MUX_ENV, MUX_1, MUX_050};515253const char * translatedCombTypes[] =54{55"0",56"1",57"COMBINED",58"TEXEL0",59"TEXEL1",60"PRIM",61"SHADE",62"ENV",63"COMBALPHA",64"T0_ALPHA_wrong",65"T1_ALPHA_wrong",66"PRIM_ALPHA_wrong",67"SHADE_ALPHA_wrong",68"ENV_ALPHA_wrong",69"LODFRAC",70"PRIMLODFRAC",71"K5",72"UNK",73"FACTOR_PRIM_MINUS_ENV",74"FACTOR_ENV_MINUS_PRIM",75"FACTOR_1_MINUS_PRIM",76"FACTOR_0_MINUS_PRIM",77"FACTOR_1_MINUS_ENV",78"FACTOR_0_MINUS_ENV",79"FACTOR_1_MINUS_PRIMALPHA",80"FACTOR_1_MINUS_ENVALPHA",81"FACTOR_HALF",82"PRIM_X_PRIMALPHA",83"1_MINUS_PRIM_X_ENV_PLUS_PRIM",84"ENV_X_PRIM",85"PRIM_X_1_MINUS_ENV",86"PRIM_X_PRIM",87"ENV_X_ENV",88};8990const char* muxTypeStrs[] = {91"CM_FMT_TYPE_NOT_USED",92"CM_FMT_TYPE1_D",93"CM_FMT_TYPE2_A_ADD_D",94"CM_FMT_TYPE3_A_MOD_C",95"CM_FMT_TYPE4_A_SUB_B",96"CM_FMT_TYPE5_A_MOD_C_ADD_D",97"CM_FMT_TYPE6_A_LERP_B_C",98"CM_FMT_TYPE7_A_SUB_B_ADD_D",99"CM_FMT_TYPE8_A_SUB_B_MOD_C",100"CM_FMT_TYPE9_A_B_C_D",101"CM_FMT_TYPE_NOT_CHECKED",102};103104void DecodedMux::Decode(uint32 dwMux0, uint32 dwMux1)105{106m_dwMux0 = dwMux0;107m_dwMux1 = dwMux1;108109aRGB0 = uint8((dwMux0>>20)&0x0F); // c1 c1 // a0110bRGB0 = uint8((dwMux1>>28)&0x0F); // c1 c2 // b0111cRGB0 = uint8((dwMux0>>15)&0x1F); // c1 c3 // c0112dRGB0 = uint8((dwMux1>>15)&0x07); // c1 c4 // d0113114aA0 = uint8((dwMux0>>12)&0x07); // c1 a1 // Aa0115bA0 = uint8((dwMux1>>12)&0x07); // c1 a2 // Ab0116cA0 = uint8((dwMux0>>9 )&0x07); // c1 a3 // Ac0117dA0 = uint8((dwMux1>>9 )&0x07); // c1 a4 // Ad0118119aRGB1 = uint8((dwMux0>>5 )&0x0F); // c2 c1 // a1120bRGB1 = uint8((dwMux1>>24)&0x0F); // c2 c2 // b1121cRGB1 = uint8((dwMux0 )&0x1F); // c2 c3 // c1122dRGB1 = uint8((dwMux1>>6 )&0x07); // c2 c4 // d1123124aA1 = uint8((dwMux1>>21)&0x07); // c2 a1 // Aa1125bA1 = uint8((dwMux1>>3 )&0x07); // c2 a2 // Ab1126cA1 = uint8((dwMux1>>18)&0x07); // c2 a3 // Ac1127dA1 = uint8((dwMux1 )&0x07); // c2 a4 // Ad1128129//This fuction will translate the decode mux info further, so we can use130//the decode data better.131//Will translate A,B,C,D to unified presentation132aRGB0 = sc_Mux16[aRGB0];133bRGB0 = sc_Mux16[bRGB0];134cRGB0 = sc_Mux32[cRGB0];135dRGB0 = sc_Mux8[dRGB0];136137aA0 = sc_Mux8[aA0];138bA0 = sc_Mux8[bA0];139cA0 = sc_Mux8[cA0];140dA0 = sc_Mux8[dA0];141142aRGB1 = sc_Mux16[aRGB1];143bRGB1 = sc_Mux16[bRGB1];144cRGB1 = sc_Mux32[cRGB1];145dRGB1 = sc_Mux8[dRGB1];146147aA1 = sc_Mux8[aA1];148bA1 = sc_Mux8[bA1];149cA1 = sc_Mux8[cA1];150dA1 = sc_Mux8[dA1];151152m_bShadeIsUsed[1] = isUsedInAlphaChannel(MUX_SHADE);153m_bShadeIsUsed[0] = isUsedInColorChannel(MUX_SHADE);154m_bTexel0IsUsed = isUsed(MUX_TEXEL0);155m_bTexel1IsUsed = isUsed(MUX_TEXEL1);156157m_dwShadeColorChannelFlag = 0;158m_dwShadeAlphaChannelFlag = 0;159m_ColorTextureFlag[0] = 0;160m_ColorTextureFlag[1] = 0;161}162163int DecodedMux::Count(uint8 val, int cycle, uint8 mask)164{165uint8* pmux = m_bytes;166int count=0;167int start=0;168int end=16;169170if( cycle >= 0 )171{172start = cycle*4;173end = start+4;174}175176177for( int i=start; i<end; i++ )178{179if( (pmux[i]&mask) == (val&mask) )180{181count++;182}183}184185return count;186}187188189bool DecodedMux::isUsed(uint8 val, uint8 mask)190{191uint8* pmux = m_bytes;192bool isUsed = false;193for( int i=0; i<16; i++ )194{195if( (pmux[i]&mask) == (val&mask) )196{197isUsed = true;198break;199}200}201202return isUsed;203}204205bool DecodedMux::isUsedInAlphaChannel(uint8 val, uint8 mask)206{207uint8* pmux = m_bytes;208bool isUsed = false;209for( int i=0; i<16; i++ )210{211if( (i/4)%2 == 0 )212continue; //Don't test color channel213214if( (pmux[i]&mask) == (val&mask) )215{216isUsed = true;217break;218}219}220221return isUsed;222}223224bool DecodedMux::isUsedInColorChannel(uint8 val, uint8 mask)225{226uint8* pmux = m_bytes;227bool isUsed = false;228for( int i=0; i<16; i++ )229{230if( (i/4)%2 == 0 && (pmux[i]&mask) == (val&mask) )231{232isUsed = true;233break;234}235}236237return isUsed;238}239240241bool DecodedMux::isUsedInCycle(uint8 val, int cycle, CombineChannel channel, uint8 mask)242{243cycle *=2;244if( channel == ALPHA_CHANNEL ) cycle++;245246uint8* pmux = m_bytes;247for( int i=0; i<4; i++ )248{249if( (pmux[i+cycle*4]&mask) == (val&mask) )250{251return true;252}253}254255return false;256}257258bool DecodedMux::isUsedInCycle(uint8 val, int cycle, uint8 mask)259{260return isUsedInCycle(val, cycle/2, cycle%2?ALPHA_CHANNEL:COLOR_CHANNEL, mask);261}262263264void DecodedMux::ConvertComplements()265{266//For (A-B)*C+D, if A=1, then we can convert A-B to Ac-0267if( aRGB0 != MUX_1 && bRGB0 != MUX_0 )268{269aRGB0 = bRGB0|MUX_COMPLEMENT;270bRGB0 = MUX_0;271}272if( aRGB1 != MUX_1 && bRGB1 != MUX_0 )273{274aRGB1 = bRGB1|MUX_COMPLEMENT;275bRGB1 = MUX_0;276}277if( aA0 != MUX_1 && bA0 != MUX_0 )278{279aA0 = bA0|MUX_COMPLEMENT;280bA0 = MUX_0;281}282if( aA1 != MUX_1 && bA1 != MUX_0 )283{284aA1 = bA1|MUX_COMPLEMENT;285bA1 = MUX_0;286}287}288289290CombinerFormatType DecodedMux::GetCombinerFormatType(uint32 cycle)291{292//Analyze the formula293/*294C=0 = D295A==B = D296B=0, C=1, D=0 = A297A=1, B=0, D=0 = C298C=1, B==D = A299A=1, C=1, D=0 = 1-B300D = 1 = 1301*/302return CM_FMT_TYPE_D;303}304305void DecodedMuxForPixelShader::Simplify(void)306{307CheckCombineInCycle1();308//Reformat();309310if( g_curRomInfo.bTexture1Hack )311{312ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);313ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);314}315splitType[0] = CM_FMT_TYPE_NOT_USED;316splitType[1] = CM_FMT_TYPE_NOT_USED;317splitType[2] = CM_FMT_TYPE_NOT_USED;318splitType[3] = CM_FMT_TYPE_NOT_USED;319mType = CM_FMT_TYPE_NOT_USED;320321m_bTexel0IsUsed = isUsed(MUX_TEXEL0);322m_bTexel1IsUsed = isUsed(MUX_TEXEL1);323}324325void DecodedMuxForSemiPixelShader::Reset(void)326{327Decode(m_dwMux0, m_dwMux1);328splitType[0] = CM_FMT_TYPE_NOT_CHECKED;329splitType[1] = CM_FMT_TYPE_NOT_CHECKED;330splitType[2] = CM_FMT_TYPE_NOT_CHECKED;331splitType[3] = CM_FMT_TYPE_NOT_CHECKED;332333Hack();334335gRSP.bProcessDiffuseColor = false;336gRSP.bProcessSpecularColor = false;337338CheckCombineInCycle1();339if( g_curRomInfo.bTexture1Hack )340{341ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);342ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);343}344345m_bTexel0IsUsed = isUsed(MUX_TEXEL0);346m_bTexel1IsUsed = isUsed(MUX_TEXEL1);347}348349void DecodedMuxForOGL14V2::Simplify(void)350{351CheckCombineInCycle1();352if( g_curRomInfo.bTexture1Hack )353{354ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);355ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);356}357Reformat();358359UseTextureForConstant();360Reformat();361362m_bTexel0IsUsed = isUsed(MUX_TEXEL0);363m_bTexel1IsUsed = isUsed(MUX_TEXEL1);364}365366void DecodedMux::Simplify(void)367{368CheckCombineInCycle1();369if( gRDP.otherMode.text_lod )370ConvertLODFracTo0();371if( g_curRomInfo.bTexture1Hack )372{373ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,2);374ReplaceVal(MUX_TEXEL1,MUX_TEXEL0,3);375}376Reformat();377378UseShadeForConstant();379Reformat();380381if( m_dwShadeColorChannelFlag == MUX_0 )382{383MergeShadeWithConstants();384Reformat();385}386387#ifdef ALLOW_USE_TEXTURE_FOR_CONSTANTS388UseTextureForConstant();389for( int i=0; i<2; i++ )390{391if( m_ColorTextureFlag[i] != 0 )392{393if( m_dwShadeColorChannelFlag == m_ColorTextureFlag[i] )394{395ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0RGB);396ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1RGB);397m_dwShadeColorChannelFlag = 0;398}399if( m_dwShadeAlphaChannelFlag == m_ColorTextureFlag[i] )400{401ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle0Alpha);402ReplaceVal(MUX_SHADE,MUX_TEXEL0+i,N64Cycle1Alpha);403ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle0RGB,MUX_MASK_WITH_ALPHA);404ReplaceVal(MUX_SHADE|MUX_ALPHAREPLICATE,(MUX_TEXEL0+i)|MUX_ALPHAREPLICATE,N64Cycle1RGB,MUX_MASK_WITH_ALPHA);405m_dwShadeAlphaChannelFlag = 0;406}407}408}409Reformat();410#endif411412m_bTexel0IsUsed = isUsed(MUX_TEXEL0);413m_bTexel1IsUsed = isUsed(MUX_TEXEL1);414}415416void DecodedMux::Reformat(bool do_complement)417{418if( m_dWords[N64Cycle0RGB] == m_dWords[N64Cycle1RGB] )419{420aRGB1 = MUX_0;421bRGB1 = MUX_0;422cRGB1 = MUX_0;423dRGB1 = MUX_COMBINED;424splitType[N64Cycle1RGB] = CM_FMT_TYPE_NOT_USED;425}426427if( m_dWords[N64Cycle0Alpha] == m_dWords[N64Cycle1Alpha] )428{429aA1 = MUX_0;430bA1 = MUX_0;431cA1 = MUX_0;432dA1 = MUX_COMBINED;433splitType[N64Cycle1Alpha] = CM_FMT_TYPE_NOT_USED;434}435436for( int i=0; i<4; i++ )437{438if( splitType[i] == CM_FMT_TYPE_NOT_USED )439{440continue; //Skip this, it is not used441}442443N64CombinerType &m = m_n64Combiners[i];444//if( m.a == MUX_0 || m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;445if( m.c == MUX_0 || m.a == m.b ) m.a = m.b = m.c = MUX_0;446if( do_complement && (m.b == MUX_1 || m.d == MUX_1) ) m.a = m.b = m.c = MUX_0;447if( m.a == MUX_0 && m.b == m.d )448{449m.a = m.b;450m.b = m.d = 0;451//Hack for Mario Tennis452if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && m.c == MUX_TEXEL1 )453{454if( do_complement )455m.c = MUX_TEXEL0|MUX_COMPLEMENT;456else457{458m.a = m.c;459m.c = m.b;460m.b = m.a;461m.a = MUX_1;462}463}464//m.c ^= MUX_COMPLEMENT;465}466467//Type 1 == D468//Analyze the formula469//Check Type 1470//D = 1 = D(=1)471//C=0 = D472//A==B = D473//B=0, C=1, D=0 = A474//C=1, B==D = A475//A=1, B=0, D=0 = C476//A=1, C=1, D=0 = 1-B477478splitType[i] = CM_FMT_TYPE_NOT_CHECKED; //All Type 1 will be changed to = D479if( m.c == MUX_0 || m.a==m.b || ( do_complement && (m.d == MUX_1 || m.b==MUX_1)) )480{481splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D482m.a = m.b = m.c = MUX_0;483if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;484}485else if( (m.b == MUX_0 && m.c == MUX_1 && m.d == MUX_0 ) || ( m.c == MUX_1 && m.b==m.d ) )486{487splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D488m.d = m.a;489m.a = m.b = m.c = MUX_0;490if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;491}492else if( m.a == MUX_1 && m.b == MUX_0 && m.d == MUX_0 )493{494splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D495m.d = m.c;496m.a = m.b = m.c = MUX_0;497if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;498}499else if( m.a == MUX_1 && m.c == MUX_1 && m.d == MUX_0 && do_complement )500{501splitType[i] = CM_FMT_TYPE_D; //All Type 1 will be changed to = D502m.d = m.b^MUX_COMPLEMENT;503m.a = m.b = m.c = MUX_0;504if( m.d == MUX_COMBINED && i>=N64Cycle1RGB ) splitType[i] = CM_FMT_TYPE_NOT_USED;505}506507if( splitType[i] == CM_FMT_TYPE_NOT_USED )508continue;509510if( splitType[i] == CM_FMT_TYPE_D )511{512if( (i == N64Cycle0RGB || i == N64Cycle0Alpha) && splitType[i+2]!=CM_FMT_TYPE_NOT_USED ) //Cycle 1's Color or Alpha513{514uint8 saveD = m.d;515for( int j=0; j<4; j++ )516{517if( (m_bytes[j+i*4+8]&MUX_MASK) == MUX_COMBINED )518{519m_bytes[j+i*4+8] = saveD|(m_bytes[j+i*4+8]&0xC0); //Replace cycle's CMB with D from cycle 1520}521}522m_dWords[i] = m_dWords[i+2];523splitType[i+2]=CM_FMT_TYPE_NOT_USED;524m_dWords[i+2] = 0x02000000;525i=i-1; // Throw the first cycle result away, use 2nd cycle for the 1st cycle526// and then redo the 1st cycle527continue;528}529530if( (i==2 || i == 3) && (m.d&MUX_MASK) == MUX_COMBINED )531{532splitType[i] = CM_FMT_TYPE_NOT_USED;533}534continue;535}536537538//Type 2: A+D ' ADD539//B=0, C=1 = A+D540//A=1, B=0 = C+D541splitType[i] = CM_FMT_TYPE_A_ADD_D; //All Type 2 will be changed to = A+D542if( m.b == MUX_0 && m.c == MUX_1 )543{544if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d);545if( m.a == MUX_COMBINED ) swap(m.a, m.d);546continue;547}548549if( m.a == MUX_1 && m.b == MUX_0 )550{551m.a = m.c; //Change format A+D552m.c = MUX_1;553if( m.d == MUX_TEXEL0 || m.d == MUX_TEXEL1 ) swap(m.a, m.d);554continue;555}556557558//Type 3: A*C559//B=0, D=0 = A*C560//A=1, D=0 = (1-A)*C561splitType[i] = CM_FMT_TYPE_A_MOD_C; //A*C562if( m.b == MUX_0 && m.d == MUX_0 )563{564if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);565if( m.a == MUX_COMBINED ) swap(m.a, m.c);566continue;567}568569if( m.a == MUX_1 && m.d == MUX_0 && do_complement )570{571m.a = m.b^MUX_COMPLEMENT;572m.b = MUX_0;573if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);574if( m.a == MUX_COMBINED ) swap(m.a, m.c);575continue;576}577578//Type 4: A-B ' SUB579//C=1, D=0 = A-B580splitType[i] = CM_FMT_TYPE_A_SUB_B; //A-B581if( m.c == MUX_1 && m.d == MUX_0 )582{583continue;584}585586//Type 5: A*C+D , ' MULTIPLYADD587//B=0 = A*C+D588//A=1 = (1-B) * C + D589splitType[i] = CM_FMT_TYPE_A_MOD_C_ADD_D;590if( m.b == MUX_0 )591{592if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);593if( m.a == MUX_COMBINED ) swap(m.a, m.c);594continue;595}596597if( m.a == MUX_1 && m.b!=m.d && do_complement )598{599m.a = m.b^MUX_COMPLEMENT;600m.b = MUX_0;601if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);602if( m.a == MUX_COMBINED ) swap(m.a, m.c);603continue;604}605606//Type 6: (A-B)*C+B Map to LERP, or BLENDALPHA607//D==B608splitType[i] = CM_FMT_TYPE_A_LERP_B_C;609if( m.b == m.d )610{611continue;612}613614615//Type 7: A-B+D616//C=1 = A-B+D617splitType[i] = CM_FMT_TYPE_A_SUB_B_ADD_D;618if( m.c == MUX_1 )619{620if( m.c == MUX_TEXEL0 || m.c == MUX_TEXEL1 ) swap(m.a, m.c);621continue;622}623624//Type 8: (A-B)*C625splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;626if( m.d == MUX_0 )627{628continue;629}630631if( m.c == m.d && do_complement ) // (A-B)*C+C ==> (A + B|C ) * C632{633m.d = MUX_0;634m.b |= MUX_COMPLEMENT;635continue;636}637638if( m.a == m.d )639{640splitType[i] = CM_FMT_TYPE_A_B_C_A;641continue;642}643644//Type 9: (A-B)*C+D645splitType[i] = CM_FMT_TYPE_A_B_C_D;646}647648if( (splitType[0] == CM_FMT_TYPE_D && splitType[2]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 1 Color649(isUsedInCycle(MUX_COMBINED,1,COLOR_CHANNEL) == false && isUsedInCycle(MUX_COMBINED,1,ALPHA_CHANNEL) == false && splitType[2]!= CM_FMT_TYPE_NOT_USED) )650{651//Replace cycle 1 color with cycle 2 color because we have already replace cycle2's cmb652aRGB0 = aRGB1;653bRGB0 = bRGB1;654cRGB0 = cRGB1;655dRGB0 = dRGB1;656aRGB1 = MUX_0;657bRGB1 = MUX_0;658cRGB1 = MUX_0;659dRGB1 = MUX_COMBINED;660splitType[0] = splitType[2];661splitType[2] = CM_FMT_TYPE_NOT_USED;662}663664if( (splitType[1] == CM_FMT_TYPE_D && splitType[3]!= CM_FMT_TYPE_NOT_USED ) || //Cycle 2 Alpha665( 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) )666{667//Replace cycle 1 alpha with cycle 2 alpha because we have already replace cycle2's cmb668aA0 = aA1;669bA0 = bA1;670cA0 = cA1;671dA0 = dA1;672aA1 = MUX_0;673bA1 = MUX_0;674cA1 = MUX_0;675dA1 = MUX_COMBINED;676splitType[1] = splitType[3];677splitType[3] = CM_FMT_TYPE_NOT_USED;678}679680if( splitType[0] == CM_FMT_TYPE_A_MOD_C && splitType[2] == CM_FMT_TYPE_A_ADD_D )681{682m_n64Combiners[0].d = (m_n64Combiners[2].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[2].d : m_n64Combiners[2].a;683splitType[0] = CM_FMT_TYPE_A_MOD_C_ADD_D;684splitType[2] = CM_FMT_TYPE_NOT_USED;685m_n64Combiners[2].a = MUX_0;686m_n64Combiners[2].c = MUX_0;687m_n64Combiners[2].d = MUX_COMBINED;688}689690if( splitType[1] == CM_FMT_TYPE_A_MOD_C && splitType[3] == CM_FMT_TYPE_A_ADD_D )691{692m_n64Combiners[1].d = (m_n64Combiners[3].a & MUX_MASK) == MUX_COMBINED ? m_n64Combiners[3].d : m_n64Combiners[3].a;693splitType[1] = CM_FMT_TYPE_A_MOD_C_ADD_D;694splitType[3] = CM_FMT_TYPE_NOT_USED;695m_n64Combiners[3].a = MUX_0;696m_n64Combiners[3].c = MUX_0;697m_n64Combiners[3].d = MUX_COMBINED;698}699700mType = max(max(max(splitType[0], splitType[1]),splitType[2]),splitType[3]);701}702703const char* MuxGroupStr[4] =704{705"Color0",706"Alpha0",707"Color1",708"Alpha1",709};710711char* DecodedMux::FormatStr(uint8 val, char *buf)712{713if( val == CM_IGNORE_BYTE )714{715strcpy(buf," ");716}717else718{719strcpy(buf, translatedCombTypes[val&MUX_MASK]);720if( val&MUX_ALPHAREPLICATE )721strcat(buf,"|A");722if( val&MUX_COMPLEMENT )723strcat(buf,"|C");724if( val&MUX_NEG )725strcat(buf,"|N");726}727728return buf;729}730731void DecodedMux::Display(bool simplified,FILE *fp)732{733DecodedMux decodedMux;734DecodedMux *mux;735if( simplified )736{737mux = this;738}739else740{741decodedMux.Decode(m_dwMux0, m_dwMux1);742mux = &decodedMux;743}744745char buf0[30];746char buf1[30];747char buf2[30];748char buf3[30];749750for( int i=0; i<2; i++ )751{752for(int j=0;j<2;j++)753{754N64CombinerType &m = mux->m_n64Combiners[i+2*j];755if( fp )756{757fprintf(fp,"%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),758FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));759}760else761{762DebuggerAppendMsg("%s: (%s - %s) * %s + %s\n", MuxGroupStr[i+2*j], FormatStr(m.a,buf0),763FormatStr(m.b,buf1), FormatStr(m.c,buf2), FormatStr(m.d,buf3));764}765}766}767}768769int DecodedMux::HowManyConstFactors()770{771int n=0;772if( isUsed(MUX_PRIM) ) n++;773if( isUsed(MUX_ENV) ) n++;774if( isUsed(MUX_LODFRAC) ) n++;775if( isUsed(MUX_PRIMLODFRAC) ) n++;776return n;777}778779int DecodedMux::HowManyTextures()780{781int n=0;782if( isUsed(MUX_TEXEL0) ) n++;783if( isUsed(MUX_TEXEL1) ) n++;784return n;785}786787int DecodedMux::CountTexels(void)788{789int count=0;790791for( int i=0; i<4; i++ )792{793N64CombinerType &m = m_n64Combiners[i];794count = max(count, ::CountTexel1Cycle(m));795if( count == 2 )796break;797}798799return count;800}801802void DecodedMux::ReplaceVal(uint8 val1, uint8 val2, int cycle, uint8 mask)803{804int start = 0;805int end = 16;806807if( cycle >= 0 )808{809start = cycle*4;810end = start+4;811}812813uint8* pmux = m_bytes;814for( int i=start; i<end; i++ )815{816if( (pmux[i]&mask) == (val1&mask) )817{818pmux[i] &= (~mask);819pmux[i] |= val2;820}821}822}823824uint32 DecodedMux::GetCycle(int cycle, CombineChannel channel)825{826uint32* pmux = m_dWords;827if( channel == COLOR_CHANNEL )828{829return pmux[cycle*2];830}831else832{833return pmux[cycle*2+1];834}835836}837838uint32 DecodedMux::GetCycle(int cycle)839{840return m_dWords[cycle];841}842843enum ShadeConstMergeType844{845SHADE_DO_NOTHING,846SHADE_ADD_PRIM, // Shade+PRIM847SHADE_ADD_ENV, // Shade+ENV848SHADE_ADD_PRIM_ALPHA, // Shade+PRIM_ALPHA849SHADE_ADD_ENV_ALPHA, // Shade+ENV_ALPHA850SHADE_MINUS_PRIM_PLUS_ENV,851SHADE_MINUS_ENV_PLUS_PRIM,852SHADE_MOD_ENV,853};854855typedef struct856{857uint64 mux; // simplified858ShadeConstMergeType op;859} ShadeConstMergeMapType;860861ShadeConstMergeMapType MergeShadeWithConstantsMaps[] =862{863{0, SHADE_DO_NOTHING},864{0x0007000600070006LL, SHADE_MOD_ENV}, // SHADE * ENV865};866867// 0x05070501, 0x00070006 //(1 - PRIM) * ENV + PRIM868// 0x00050003, 0x00050003 //(TEXEL0 - 0) * PRIM + 0869870void DecodedMux::MergeShadeWithConstants(void)871{872// This function should be called afte the mux has been simplified873// The goal of this function is to merge as many as possible constants with shade874// so to reduce the totally number of constants to 0 or 1875// And at the same time, to reduce the complexity of the whole mux876// so we can implement the mux easiler when lower end video cards877878// We can only try to merge shade with constants for:879// 1 cycle mode or 2 cycle mode and shade is not used in the 2nd cycle880881if( m_bShadeIsUsed[0] ) MergeShadeWithConstantsInChannel(COLOR_CHANNEL);882if( m_bShadeIsUsed[1] ) MergeShadeWithConstantsInChannel(ALPHA_CHANNEL);883}884885void DecodedMux::MergeShadeWithConstantsInChannel(CombineChannel channel)886{887bool usedIn[2];888uint32 cycleVal;889int cycleNum;890891usedIn[0] = isUsedInCycle(MUX_SHADE,channel);892usedIn[1] = isUsedInCycle(MUX_SHADE,channel+2);893if( usedIn[0] && usedIn[1] && GetCycle(channel)!=GetCycle(channel+2) )894{895//Shade is used in more than 1 cycles, and the ways it is used are different896//in cycles, so we can not merge shade with const factors897return;898}899900if( usedIn[0] ) { cycleVal = GetCycle(channel);cycleNum=0;}901else {cycleVal = GetCycle(channel+2);cycleNum=1;}902903904//Update to here, Shade is either used only in 1 cycle, or the way it is used are totally905//the same in different cycles906907if( cycleVal == 0x06000000 || isUsedInCycle(MUX_COMBINED,channel+cycleNum*2) ) // (0-0)*0+Shade908{909return;910}911912//Now we can merge shade with consts913for( int i=0; i<2; i++ )914{915if( usedIn[i] )916{917N64CombinerType &m = m_n64Combiners[channel+i*2];918if( isUsedInCycle(MUX_TEXEL0,i*2+channel) || isUsedInCycle(MUX_TEXEL1,i*2+channel) )919{920if( (m.a&MUX_MASK) == MUX_TEXEL0 || (m.a&MUX_MASK) == MUX_TEXEL1 )921{922// m.a is texel, can not merge constant with shade923return;924}925else if( (m.b&MUX_MASK) == MUX_TEXEL0 || (m.b&MUX_MASK) == MUX_TEXEL1 )926{927// m.b is texel, can not merge constant with shade928return;929}930else if(( (m.c&MUX_MASK) == MUX_TEXEL0 || (m.c&MUX_MASK) == MUX_TEXEL1 ) )931{932if( (m.d&MUX_MASK) != MUX_SHADE )933{934cycleVal &= 0x0000FFFF; // A-B935}936else if( (m.a&MUX_MASK) == MUX_SHADE || (m.b&MUX_MASK) == MUX_SHADE )937{938return;939}940}941else if( (m.d&MUX_MASK) == MUX_TEXEL0 || (m.d&MUX_MASK) == MUX_TEXEL1 )942{943cycleVal &= 0x00FFFFFF; // (A-B)*C944}945}946else947{948m.a = m.b = m.c = MUX_0;949m.d = MUX_SHADE;950splitType[i*2+channel] = CM_FMT_TYPE_D;951}952}953}954955if( channel == COLOR_CHANNEL )956m_dwShadeColorChannelFlag = cycleVal;957else958m_dwShadeAlphaChannelFlag = cycleVal;959}960961962void DecodedMux::MergeConstants(void)963{964// This function should be called afte the mux has been simplified965// The goal of this function is to merge remain constants and to reduce the966// total number of constants, so we can implement the mux easiler967968// This function should be called after the MergeShadeWithConstants() function969}970971972void DecodedMux::UseShadeForConstant(void)973{974// If shade is not used in the mux, we can use it for constants975// This function should be called after constants have been merged976977bool doAlphaChannel = true;978uint8 mask = (uint8)~MUX_COMPLEMENT;979980int constants = 0;981if( isUsed(MUX_ENV) ) constants++;982if( isUsed(MUX_PRIM) ) constants++;983if( isUsed(MUX_LODFRAC) ) constants++;984if( isUsed(MUX_PRIMLODFRAC) ) constants++;985986bool forceToUsed = constants>m_maxConstants;987988if( !isUsedInColorChannel(MUX_SHADE) && (forceToUsed || max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D) )989{990int countEnv = Count(MUX_ENV, N64Cycle0RGB, mask) + Count(MUX_ENV, N64Cycle1RGB, mask);991int countPrim = Count(MUX_PRIM, N64Cycle0RGB, mask) + Count(MUX_PRIM, N64Cycle1RGB, mask);992if( countEnv+countPrim > 0 )993{994if( countPrim >= countEnv )995{996//TRACE0("Use Shade for PRIM in color channel");997ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0RGB);998ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1RGB);999m_dwShadeColorChannelFlag = MUX_PRIM;1000}1001else if( countEnv>0 )1002{1003//TRACE0("Use Shade for ENV in color channel");1004ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0RGB);1005ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1RGB);1006m_dwShadeColorChannelFlag = MUX_ENV;1007}10081009if( isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE, mask) )1010{1011m_dwShadeAlphaChannelFlag = m_dwShadeColorChannelFlag;1012ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle0Alpha);1013ReplaceVal((uint8)m_dwShadeColorChannelFlag, MUX_SHADE, N64Cycle1Alpha);1014doAlphaChannel = false;1015}1016}1017}10181019if( doAlphaChannel && !isUsedInAlphaChannel(MUX_SHADE) && !isUsedInColorChannel(MUX_SHADE|MUX_ALPHAREPLICATE,MUX_MASK_WITH_ALPHA))1020{1021int countEnv = Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1022int countPrim = Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);10231024if( forceToUsed || max(splitType[1], splitType[3]) >= CM_FMT_TYPE_A_MOD_C_ADD_D ||1025(max(splitType[0], splitType[2]) >= CM_FMT_TYPE_A_MOD_C_ADD_D && countEnv+countPrim > 0 ) )1026{1027countEnv = Count(MUX_ENV, N64Cycle0Alpha) + Count(MUX_ENV, N64Cycle1Alpha) +1028Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_ENV|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1029countPrim = Count(MUX_PRIM, N64Cycle0Alpha) + Count(MUX_PRIM, N64Cycle1Alpha) +1030Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask) + Count(MUX_PRIM|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1031if( countEnv+countPrim > 0 )1032{1033if( countPrim>0 && m_dwShadeColorChannelFlag == MUX_PRIM )1034{1035//TRACE0("Use Shade for PRIM in alpha channel");1036ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha);1037ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha);1038ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);1039ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1040m_dwShadeAlphaChannelFlag = MUX_PRIM;1041}1042else if( countEnv>0 && m_dwShadeColorChannelFlag == MUX_ENV )1043{1044//TRACE0("Use Shade for PRIM in alpha channel");1045ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha);1046ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha);1047ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);1048ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1049m_dwShadeAlphaChannelFlag = MUX_ENV;1050}1051else if( countPrim >= countEnv )1052{1053//TRACE0("Use Shade for PRIM in alpha channel");1054ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle0Alpha);1055ReplaceVal(MUX_PRIM, MUX_SHADE, N64Cycle1Alpha);1056ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);1057ReplaceVal(MUX_PRIM|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1058m_dwShadeAlphaChannelFlag = MUX_PRIM;1059}1060else if( countEnv>0 )1061{1062//TRACE0("Use Shade for ENV in alpha channel");1063ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle0Alpha);1064ReplaceVal(MUX_ENV, MUX_SHADE, N64Cycle1Alpha);1065ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle0RGB, mask);1066ReplaceVal(MUX_ENV|MUX_ALPHAREPLICATE, MUX_SHADE|MUX_ALPHAREPLICATE, N64Cycle1RGB, mask);1067m_dwShadeAlphaChannelFlag = MUX_ENV;1068}1069}1070}1071}1072}10731074void DecodedMux::UseTextureForConstant(void)1075{1076int numofconst = HowManyConstFactors();1077int numOftex = HowManyTextures();10781079if( numofconst > m_maxConstants && numOftex < m_maxTextures )1080{1081// We can use a texture for a constant1082for( int i=0; i<2 && numofconst > m_maxConstants ; i++ )1083{1084if( isUsed(MUX_TEXEL0+i) )1085{1086continue; // can not use this texture1087}10881089if( isUsed(MUX_PRIM) )1090{1091ReplaceVal(MUX_PRIM, MUX_TEXEL0+i);1092m_ColorTextureFlag[i] = MUX_PRIM;1093numofconst--;1094continue;1095}10961097if( isUsed(MUX_ENV) )1098{1099ReplaceVal(MUX_ENV, MUX_TEXEL0+i);1100m_ColorTextureFlag[i] = MUX_ENV;1101numofconst--;1102continue;1103}11041105if( isUsed(MUX_LODFRAC) )1106{1107ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i);1108m_ColorTextureFlag[i] = MUX_LODFRAC;1109numofconst--;1110continue;1111}11121113if( isUsed(MUX_PRIMLODFRAC) )1114{1115ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i);1116m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;1117numofconst--;1118continue;1119}1120}1121}1122}112311241125void DecodedMuxForOGL14V2::UseTextureForConstant(void)1126{1127bool envused = isUsed(MUX_ENV);1128bool lodused = isUsed(MUX_LODFRAC);11291130int numofconst = 0;1131if( envused ) numofconst++;1132if( lodused ) numofconst++;11331134int numOftex = HowManyTextures();11351136if( numofconst > 0 && numOftex < 2 )1137{1138// We can use a texture for a constant1139for( int i=0; i<2 && numofconst > 0 ; i++ )1140{1141if( isUsed(MUX_TEXEL0+i) )1142{1143continue; // can not use this texture1144}11451146if( envused )1147{1148ReplaceVal(MUX_ENV, MUX_TEXEL0+i);1149m_ColorTextureFlag[i] = MUX_ENV;1150numofconst--;1151envused = false;1152continue;1153}11541155if( isUsed(MUX_LODFRAC) )1156{1157ReplaceVal(MUX_LODFRAC, MUX_TEXEL0+i);1158m_ColorTextureFlag[i] = MUX_LODFRAC;1159numofconst--;1160continue;1161}11621163if( isUsed(MUX_PRIMLODFRAC) )1164{1165ReplaceVal(MUX_PRIMLODFRAC, MUX_TEXEL0+i);1166m_ColorTextureFlag[i] = MUX_PRIMLODFRAC;1167numofconst--;1168continue;1169}1170}1171}1172}11731174#ifdef DEBUGGER1175extern const char *translatedCombTypes[];1176void DecodedMux::DisplayMuxString(const char *prompt)1177{1178DebuggerAppendMsg("//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);1179Display(false);1180TRACE0("\n");1181}11821183void DecodedMux::DisplaySimpliedMuxString(const char *prompt)1184{1185DebuggerAppendMsg("//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);1186DebuggerAppendMsg("Simplied DWORDs=%08X, %08X, %08X, %08X", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);1187Display(true);1188DebuggerAppendMsg("Simplfied type: %s", muxTypeStrs[mType]);1189if( m_dwShadeColorChannelFlag != 0 )1190{1191if( m_dwShadeColorChannelFlag == MUX_ENV )1192TRACE0("Shade = ENV in color channel")1193else if( m_dwShadeColorChannelFlag == MUX_PRIM )1194TRACE0("Shade = PRIM in color channel")1195else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )1196TRACE0("Shade = MUX_LODFRAC in color channel")1197else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )1198TRACE0("Shade = MUX_PRIMLODFRAC in color channel")1199else1200DisplayConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL);1201}1202if( m_dwShadeAlphaChannelFlag != 0 )1203{1204if( m_dwShadeAlphaChannelFlag == MUX_ENV )1205TRACE0("Shade = ENV in alpha channel")1206else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )1207TRACE0("Shade = PRIM in alpha channel")1208else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )1209TRACE0("Shade = MUX_LODFRAC in alpha channel")1210else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )1211TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")1212else1213DisplayConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL);1214}12151216for( int i=0; i<2; i++ )1217{1218if( m_ColorTextureFlag[i] != 0 )1219{1220if( m_ColorTextureFlag[i] == MUX_ENV )1221TRACE1("Tex %d = ENV", i)1222else if( m_ColorTextureFlag[i] == MUX_PRIM )1223TRACE1("Tex %d = PRIM", i)1224else if( m_ColorTextureFlag[i] == MUX_LODFRAC )1225TRACE1("Tex %d = MUX_LODFRAC", i)1226else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )1227TRACE1("Tex %d = MUX_PRIMLODFRAC", i)1228}1229}123012311232TRACE0("\n");1233}12341235void DecodedMux::DisplayConstantsWithShade(uint32 flag,CombineChannel channel)1236{1237DebuggerAppendMsg("Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");1238}1239#else12401241extern const char *translatedCombTypes[];1242void DecodedMux::LogMuxString(const char *prompt, FILE *fp)1243{1244fprintf(fp,"//Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);1245Display(false,fp);1246TRACE0("\n");1247}12481249void DecodedMux::LogSimpliedMuxString(const char *prompt, FILE *fp)1250{1251fprintf(fp,"//Simplied Mux=0x%08x%08x\t%s in %s\n", m_dwMux0, m_dwMux1, prompt, g_curRomInfo.szGameName);1252fprintf(fp,"Simplied DWORDs=%08X, %08X, %08X, %08X\n", m_dWords[0],m_dWords[1],m_dWords[2],m_dWords[3]);1253Display(true,fp);1254fprintf(fp,"Simplfied type: %s", muxTypeStrs[mType]);1255if( m_dwShadeColorChannelFlag != 0 )1256{1257if( m_dwShadeColorChannelFlag == MUX_ENV )1258TRACE0("Shade = ENV in color channel")1259else if( m_dwShadeColorChannelFlag == MUX_PRIM )1260TRACE0("Shade = PRIM in color channel")1261else if( m_dwShadeColorChannelFlag == MUX_LODFRAC )1262TRACE0("Shade = MUX_LODFRAC in color channel")1263else if( m_dwShadeColorChannelFlag == MUX_PRIMLODFRAC )1264TRACE0("Shade = MUX_PRIMLODFRAC in color channel")1265else1266LogConstantsWithShade(m_dwShadeColorChannelFlag,COLOR_CHANNEL,fp);1267}1268if( m_dwShadeAlphaChannelFlag != 0 )1269{1270if( m_dwShadeAlphaChannelFlag == MUX_ENV )1271TRACE0("Shade = ENV in alpha channel")1272else if( m_dwShadeAlphaChannelFlag == MUX_PRIM )1273TRACE0("Shade = PRIM in alpha channel")1274else if( m_dwShadeAlphaChannelFlag == MUX_LODFRAC )1275TRACE0("Shade = MUX_LODFRAC in alpha channel")1276else if( m_dwShadeAlphaChannelFlag == MUX_PRIMLODFRAC )1277TRACE0("Shade = MUX_PRIMLODFRAC in alpha channel")1278else1279LogConstantsWithShade(m_dwShadeAlphaChannelFlag,ALPHA_CHANNEL,fp);1280}12811282for( int i=0; i<2; i++ )1283{1284if( m_ColorTextureFlag[i] != 0 )1285{1286if( m_ColorTextureFlag[i] == MUX_ENV )1287TRACE1("Tex %d = ENV", i)1288else if( m_ColorTextureFlag[i] == MUX_PRIM )1289TRACE1("Tex %d = PRIM", i)1290else if( m_ColorTextureFlag[i] == MUX_LODFRAC )1291TRACE1("Tex %d = MUX_LODFRAC", i)1292else if( m_ColorTextureFlag[i] == MUX_PRIMLODFRAC )1293TRACE1("Tex %d = MUX_PRIMLODFRAC", i)1294}1295}129612971298TRACE0("\n");1299}13001301void DecodedMux::LogConstantsWithShade(uint32 flag,CombineChannel channel, FILE *fp)1302{1303fprintf(fp,"Shade = %08X in %s channel",flag,channel==COLOR_CHANNEL?"color":"alpha");1304}1305#endif130613071308void DecodedMux::To_AB_Add_CD_Format(void) // Use by TNT,Geforce1309{1310// This function should be called after calling reformat1311// This function will not be called by default, can be called optionally1312// by TNT/Geforce combiner compilers13131314for( int i=0; i<2; i++ )1315{1316N64CombinerType &m0 = m_n64Combiners[i];1317N64CombinerType &m1 = m_n64Combiners[i+2];1318switch( splitType[i] )1319{1320case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage1321if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )1322{1323m1.a = m0.d;1324m1.d = MUX_COMBINED;1325splitType[i+2] = CM_FMT_TYPE_A_ADD_D;13261327m0.d = MUX_0;1328splitType[i] = CM_FMT_TYPE_A_SUB_B;1329}1330else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )1331{1332if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c);1333m1.b = m1.d = m1.c;1334m1.c = (m0.d | (m1.a & (~MUX_MASK)));1335splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;13361337m0.d = MUX_0;1338splitType[i] = CM_FMT_TYPE_A_SUB_B;1339}1340break;1341case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage1342m0.d = m0.b;1343m0.b = m0.c;1344splitType[i] = CM_FMT_TYPE_AB_SUB_CD;1345break;1346case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage1347m0.d = m0.b;1348m0.b = m0.c;1349splitType[i] = CM_FMT_TYPE_AB_ADD_CD;1350break;1351case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D1352case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+D1353if( splitType[i+2] == CM_FMT_TYPE_NOT_USED )1354{1355m1.a = m0.d;1356m1.d = MUX_COMBINED;1357splitType[i+2] = CM_FMT_TYPE_A_ADD_D;13581359m0.d = m0.b;1360m0.b = m0.c;1361splitType[i] = CM_FMT_TYPE_AB_SUB_CD;1362}1363else if( splitType[i+2] == CM_FMT_TYPE_A_MOD_C )1364{1365if( (m1.c&MUX_MASK) == MUX_COMBINED ) swap(m1.a, m1.c);1366m1.b = m1.d = m1.c;1367m1.c = (m0.d | (m1.a & (~MUX_MASK)));1368splitType[i+2] = CM_FMT_TYPE_AB_ADD_CD;13691370m0.d = m0.b;1371m0.b = m0.c;1372splitType[i] = CM_FMT_TYPE_AB_ADD_CD;1373}1374break;1375default:1376break;1377}1378}1379}13801381void DecodedMux::To_AB_Add_C_Format(void) // Use by ATI Radeon1382{1383// This function should be called after calling reformat1384// This function will not be called by default, can be called optionally1385// by ATI combiner compilers1386}13871388void DecodedMux::CheckCombineInCycle1(void)1389{1390if( isUsedInCycle(MUX_COMBINED,0,COLOR_CHANNEL) )1391{1392ReplaceVal(MUX_COMBINED, MUX_SHADE, 0);1393}13941395if( isUsedInCycle(MUX_COMBALPHA,0,COLOR_CHANNEL) )1396{1397ReplaceVal(MUX_COMBALPHA, MUX_SHADE|MUX_ALPHAREPLICATE, 0);1398}13991400if( isUsedInCycle(MUX_COMBINED,0,ALPHA_CHANNEL) )1401{1402if( cA0 == MUX_COMBINED && cRGB0 == MUX_LODFRAC && bRGB0 == dRGB0 && bA0 == dA0 )1403{1404cA0 = MUX_LODFRAC;1405}1406else1407{1408ReplaceVal(MUX_COMBINED, MUX_SHADE, 1);1409}1410}1411if( isUsedInCycle(MUX_COMBALPHA,0,ALPHA_CHANNEL) )1412{1413ReplaceVal(MUX_COMBALPHA, MUX_SHADE, 1);1414}1415}14161417void DecodedMux::SplitComplexStages()1418{1419for( int i=0; i<2; i++) // Color channel and alpha channel1420{1421if( splitType[i+2] != CM_FMT_TYPE_NOT_USED )1422continue;14231424N64CombinerType &m = m_n64Combiners[i];1425N64CombinerType &m2 = m_n64Combiners[i+2];14261427switch( splitType[i] )1428{1429case CM_FMT_TYPE_A_MOD_C_ADD_D: // = A*C+D can mapped to MULTIPLYADD(arg1,arg2,arg0)1430m2.a = m.d;1431m2.d = MUX_COMBINED;1432m2.c = MUX_1;1433m2.b = 0;1434splitType[i+2] = CM_FMT_TYPE_A_ADD_D;1435m.d = MUX_0;1436splitType[i] = CM_FMT_TYPE_A_MOD_C;1437break;1438case CM_FMT_TYPE_A_SUB_B_ADD_D: // = A-B+D can not map very well in 1 stage1439m2.a = m.d;1440m2.d = MUX_COMBINED;1441m2.c = MUX_1;1442m2.b=0;1443splitType[i+2] = CM_FMT_TYPE_A_ADD_D;1444m.d = MUX_0;1445splitType[i] = CM_FMT_TYPE_A_SUB_B;1446break;1447case CM_FMT_TYPE_A_SUB_B_MOD_C: // = (A-B)*C can not map very well in 1 stage1448m2.a = m.c;1449m2.c = MUX_COMBINED;1450m2.d = m2.b=0;1451splitType[i+2] = CM_FMT_TYPE_A_MOD_C;1452m.c = MUX_1;1453splitType[i] = CM_FMT_TYPE_A_SUB_B;1454break;1455case CM_FMT_TYPE_A_ADD_B_MOD_C: // = (A+B)*C can not map very well in 1 stage1456m2.a = m.c;1457m2.c = MUX_COMBINED;1458m2.d = m2.b = 0;1459splitType[i+2] = CM_FMT_TYPE_A_MOD_C;1460m.c = MUX_1;1461m.d = m.b;1462m.b = MUX_0;1463splitType[i] = CM_FMT_TYPE_A_ADD_D;1464break;1465case CM_FMT_TYPE_A_B_C_D: // = (A-B)*C+D can not map very well in 1 stage1466m2.a = m.d;1467m2.d = MUX_COMBINED;1468m2.c = MUX_1;1469m2.b = 0;1470splitType[i+2] = CM_FMT_TYPE_A_ADD_D;1471m.d = MUX_0;1472splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;1473break;1474case CM_FMT_TYPE_A_B_C_A: // = (A-B)*C+A can not map very well in 1 stage1475m2.a = m.d;1476m2.d = MUX_COMBINED;1477m2.c = MUX_1;1478m2.b = 0;1479splitType[i+2] = CM_FMT_TYPE_A_ADD_D;1480m.d = MUX_0;1481splitType[i] = CM_FMT_TYPE_A_SUB_B_MOD_C;1482break;1483default:1484break;1485}1486}1487//Reformat();1488//UseShadeForConstant();1489}149014911492void DecodedMux::ConvertLODFracTo0()1493{1494ReplaceVal(MUX_LODFRAC,MUX_0);1495ReplaceVal(MUX_PRIMLODFRAC,MUX_0);1496}149714981499void DecodedMux::Hack(void)1500{1501if( options.enableHackForGames == HACK_FOR_TONYHAWK )1502{1503if( gRSP.curTile == 1 )1504{1505ReplaceVal(MUX_TEXEL1, MUX_TEXEL0);1506}1507}1508else if( options.enableHackForGames == HACK_FOR_ZELDA || options.enableHackForGames == HACK_FOR_ZELDA_MM)1509{1510if( m_dwMux1 == 0xfffd9238 && m_dwMux0 == 0x00ffadff )1511{1512ReplaceVal(MUX_TEXEL1, MUX_TEXEL0);1513}1514else if( m_dwMux1 == 0xff5bfff8 && m_dwMux0 == 0x00121603 )1515{1516// The Zelda road trace1517ReplaceVal(MUX_TEXEL1, MUX_0);1518}1519}1520else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )1521{1522if( m_dwMux1 == 0xffebdbc0 && m_dwMux0 == 0x00ffb9ff )1523{1524// Player shadow1525//m_decodedMux.dRGB0 = MUX_TEXEL0;1526//m_decodedMux.dRGB1 = MUX_COMBINED;1527cA1 = MUX_TEXEL0;1528}1529}1530else if( options.enableHackForGames == HACK_FOR_MARIO_GOLF )1531{1532// Hack for Mario Golf1533if( m_dwMux1 == 0xf1ffca7e || m_dwMux0 == 0x00115407 )1534{1535// The grass1536ReplaceVal(MUX_TEXEL0, MUX_TEXEL1);1537}1538}1539else if( options.enableHackForGames == HACK_FOR_TOPGEARRALLY )1540{1541//Mux=0x00317e025ffef3fa Used in TOP GEAR RALLY1542//Color0: (PRIM - ENV) * TEXEL1 + ENV1543//Color1: (COMBINED - 0) * TEXEL1 + 01544//Alpha0: (0 - 0) * 0 + TEXEL01545//Alpha1: (0 - 0) * 0 + TEXEL11546if( m_dwMux1 == 0x5ffef3fa || m_dwMux0 == 0x00317e02 )1547{1548// The grass1549//ReplaceVal(MUX_TEXEL0, MUX_TEXEL1);1550dA1 = MUX_COMBINED;1551//aA1 = MUX_COMBINED;1552//cA1 = MUX_TEXEL1;1553//dA1 = MUX_0;1554cRGB1 = MUX_TEXEL0;1555}1556}1557}1558155915601561