1 /*
2 Copyright (C) 2002 Rice1964
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 */
19 #include <stdint.h>
20 #include "Combiner.h"
21 #include "Config.h"
22 #include "RenderBase.h"
23 
24 #ifdef DEBUGGER
25 const char *constStrs[] = {
26     "MUX_0",
27     "MUX_1",
28     "MUX_COMBINED",
29     "MUX_TEXEL0",
30     "MUX_TEXEL1",
31     "MUX_PRIM",
32     "MUX_SHADE",
33     "MUX_ENV",
34     "MUX_COMBALPHA",
35     "MUX_T0_ALPHA",
36     "MUX_T1_ALPHA",
37     "MUX_PRIM_ALPHA",
38     "MUX_SHADE_ALPHA",
39     "MUX_ENV_ALPHA",
40     "MUX_LODFRAC",
41     "MUX_PRIMLODFRAC",
42     "MUX_K5",
43     "MUX_UNK",
44 };
45 
46 const char *cycleTypeStrs[] = {
47     "1 Cycle",
48     "2 Cycle",
49     "Copy Mode",
50     "Fill Mode"
51 };
52 
constStr(uint32_t op)53 const char* constStr(uint32_t op)
54 {
55     if (op <= MUX_UNK)
56         return constStrs[op];
57     return "Invalid-Const";
58 }
59 #endif
60 
61 //========================================================================
62 
63 //========================================================================
64 
GetIColor(uint8_t flag,uint32_t curCol)65 inline IColor GetIColor(uint8_t flag, uint32_t curCol)
66 {
67    IColor newc;
68    switch(flag & MUX_MASK)
69    {
70       case MUX_0:
71          newc = 0;
72          break;
73       case MUX_1:
74          newc = 0xFFFFFFFF;
75          break;
76       case MUX_PRIM:
77          newc = gRDP.primitiveColor;
78          break;
79       case MUX_ENV:
80          newc = gRDP.envColor;
81          break;
82       case MUX_COMBINED:
83       case MUX_SHADE:
84          newc = curCol;
85          break;
86       case MUX_K5:
87          newc = 0xFFFFFFFF;
88          break;
89       case MUX_UNK:
90          newc = curCol;
91          if (options.enableHackForGames == HACK_FOR_CONKER)
92             newc = 0xFFFFFFFF;
93          break;
94       default:
95          newc = curCol;
96          break;
97    }
98 
99    if (flag&MUX_COMPLEMENT)
100       newc.Complement();
101 
102    if (flag&MUX_ALPHAREPLICATE)
103       newc.AlphaReplicate();
104 
105    return newc;
106 }
107 
CalculateConstFactor(uint32_t colorOp,uint32_t alphaOp,uint32_t curCol)108 COLOR CalculateConstFactor(uint32_t colorOp, uint32_t alphaOp, uint32_t curCol)
109 {
110    N64CombinerType m;
111    IColor color(curCol);
112    IColor alpha(curCol);
113 
114    /* For color channel */
115    *(uint32_t*)&m = colorOp;
116    if (m.c != MUX_0 && m.a != m.b)
117    {
118       if (m.a != MUX_0) color = GetIColor(m.a, curCol);
119       if (m.b != MUX_0) color -= GetIColor(m.b, curCol);
120       if (m.c != MUX_1) color *= GetIColor(m.c, curCol);
121    }
122    if (m.d != MUX_0) color += GetIColor(m.d, curCol);
123 
124 
125    // For alpha channel
126    *(uint32_t*)&m = alphaOp;
127    if (m.c != MUX_0 && m.a != m.b)
128    {
129       if (m.a != MUX_0) alpha = GetIColor(m.a, curCol);
130       if (m.b != MUX_0) alpha -= GetIColor(m.b, curCol);
131       if (m.c != MUX_1) alpha *= GetIColor(m.c, curCol);
132    }
133    if (m.d != MUX_0) alpha += GetIColor(m.d, curCol);
134 
135    return (COLOR)(((uint32_t)color&0x00FFFFFF)|((uint32_t)alpha&0xFF000000));
136 }
137 
138 
GetConstFactor(uint32_t colorFlag,uint32_t alphaFlag,uint32_t defaultColor)139 COLOR CColorCombiner::GetConstFactor(uint32_t colorFlag, uint32_t alphaFlag, uint32_t defaultColor)
140 {
141    // Allows a combine mode to select what TFACTOR should be
142    uint32_t color = defaultColor;
143    uint32_t alpha = defaultColor;
144 
145    switch (colorFlag & MUX_MASK)
146    {
147       case MUX_0:
148          break;
149       case MUX_FORCE_0:
150          color = 0;
151          break;
152       case MUX_1:
153          color = 0xFFFFFFFF;
154          break;
155       case MUX_PRIM:
156          color = gRDP.primitiveColor;
157          break;
158       case MUX_ENV:
159          color = gRDP.envColor;
160          break;
161       case MUX_LODFRAC:
162          color = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac);
163          break;
164       case MUX_PRIMLODFRAC:
165          color = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac);
166          break;
167       case MUX_PRIM_ALPHA:
168          {
169             IColor col(gRDP.primitiveColor);
170             col.AlphaReplicate();
171             color = (COLOR)col;
172          }
173          break;
174       case MUX_ENV_ALPHA:
175          {
176             IColor col(gRDP.envColor);
177             col.AlphaReplicate();
178             color = (COLOR)col;
179          }
180          break;
181       case MUX_K5:
182          color = 0xFFFFFFFF;
183          break;
184       case MUX_UNK:
185          color = defaultColor;
186          if(options.enableHackForGames == HACK_FOR_CONKER)
187          {
188             color = 0xFFFFFFFF;
189          }
190          break;
191       default:
192          color = defaultColor;
193          break;
194    }
195 
196    if (colorFlag & MUX_COMPLEMENT)
197       color = 0xFFFFFFFF - color;
198 
199    if (colorFlag & MUX_ALPHAREPLICATE)
200    {
201       color = color>>24;
202       color = color | (color<<8) | (color <<16) | (color<<24);
203    }
204 
205    color &= 0x00FFFFFF;    // For color channel only, not the alpha channel
206 
207 
208    switch (alphaFlag & MUX_MASK)
209    {
210       case MUX_0:
211          break;
212       case MUX_FORCE_0:
213          alpha = 0;
214          break;
215       case MUX_1:
216          alpha = 0xFFFFFFFF;
217          break;
218       case MUX_PRIM:
219          alpha = gRDP.primitiveColor;
220          break;
221       case MUX_ENV:
222          alpha = gRDP.envColor;
223          break;
224       case MUX_LODFRAC:
225          alpha = COLOR_RGBA(gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac, gRDP.LODFrac);
226          break;
227       case MUX_PRIMLODFRAC:
228          alpha = COLOR_RGBA(gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac, gRDP.primLODFrac);
229          break;
230       case MUX_PRIM_ALPHA:
231          {
232             IColor col(gRDP.primitiveColor);
233             col.AlphaReplicate();
234             alpha = (COLOR)col;
235          }
236          break;
237       case MUX_ENV_ALPHA:
238          {
239             IColor col(gRDP.envColor);
240             col.AlphaReplicate();
241             alpha = (COLOR)col;
242          }
243          break;
244       default:
245          alpha = defaultColor;
246          break;
247    }
248 
249    if (alphaFlag & MUX_COMPLEMENT)
250       alpha = 0xFFFFFFFF - alpha;
251 
252    alpha &= 0xFF000000;
253 
254    return (color|alpha);
255 }
256 
257 //*****************************************************************************
258 //
259 //*****************************************************************************
260 bool    gUsingPrimColour = false;
261 bool    gUsingEnvColour = false;
262 
CountTexel1Cycle(N64CombinerType & m)263 int CountTexel1Cycle(N64CombinerType &m)
264 {
265    unsigned i;
266    int hasTexel[2];
267    uint8_t *p = (uint8_t*)&m;
268 
269    for (i=0; i<2; i++)
270    {
271       unsigned j;
272 
273       hasTexel[i]=0;
274       for (j=0; j<4; j++)
275       {
276          if ((p[j]&MUX_MASK) == MUX_TEXEL0+i)
277          {
278             hasTexel[i]=1;
279             break;
280          }
281       }
282    }
283 
284    return hasTexel[0]+hasTexel[1];
285 }
286 
GetTexelNumber(N64CombinerType & m)287 uint32_t GetTexelNumber(N64CombinerType &m)
288 {
289    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)
290       return TEX_1;
291    return TEX_0;
292 }
293 
IsTextureUsed(N64CombinerType & m)294 bool IsTextureUsed(N64CombinerType &m)
295 {
296     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)
297         return true;
298     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)
299         return true;
300     return false;
301 }
302 
303 //========================================================================
304 
InitCombinerMode(void)305 void CColorCombiner::InitCombinerMode(void)
306 {
307 #ifdef DEBUGGER
308     LOG_UCODE(cycleTypeStrs[gRDP.otherMode.cycle_type]);
309     if (debuggerDropDecodedMux)
310     {
311         UpdateCombiner(m_pDecodedMux->m_dwMux0, m_pDecodedMux->m_dwMux1);
312     }
313 #endif
314 
315     if (currentRomOptions.bNormalCombiner)
316         DisableCombiner();
317     else if (gRDP.otherMode.cycle_type  == G_CYC_COPY)
318     {
319         InitCombinerCycleCopy();
320         m_bCycleChanged = true;
321     }
322     else if (gRDP.otherMode.cycle_type == G_CYC_FILL)
323     {
324         InitCombinerCycleFill();
325         m_bCycleChanged = true;
326     }
327     else
328     {
329         InitCombinerCycle12();
330         m_bCycleChanged = false;
331     }
332 }
333 
334 
335 bool bConkerHideShadow=false;
336 
UpdateCombiner(uint32_t dwMux0,uint32_t dwMux1)337 void CColorCombiner::UpdateCombiner(uint32_t dwMux0, uint32_t dwMux1)
338 {
339 #ifdef DEBUGGER
340    if (debuggerDropDecodedMux)
341    {
342       debuggerDropDecodedMux = false;
343       m_pDecodedMux->m_dwMux0 = m_pDecodedMux->m_dwMux1 = 0;
344       m_DecodedMuxList.clear();
345    }
346 #endif
347 
348    DecodedMux &m_decodedMux = *m_pDecodedMux;
349    if (m_decodedMux.m_dwMux0 != dwMux0 || m_decodedMux.m_dwMux1 != dwMux1)
350    {
351       if (options.enableHackForGames == HACK_FOR_DR_MARIO)
352       {
353          /* Hack for Dr. Mario */
354          if (dwMux1 == 0xfffcf239 &&
355                ((m_decodedMux.m_dwMux0 == dwMux0 && dwMux0 == 0x00ffffff &&
356                  m_decodedMux.m_dwMux1 != dwMux1 && m_decodedMux.m_dwMux1 == 0xfffcf279) ||
357                 (m_decodedMux.m_dwMux0 == 0x00ffb3ff && m_decodedMux.m_dwMux1 == 0xff64fe7f && dwMux0 == 0x00ffffff )))
358          {
359             //dwMux1 = 0xffcf23A;
360             dwMux1 = 0xfffcf438;
361          }
362       }
363       uint64_t mux64 = (((uint64_t)dwMux1)<<32)+dwMux0;
364       int index=m_DecodedMuxList.find(mux64);
365 
366       if (options.enableHackForGames == HACK_FOR_CONKER)
367       {
368          // Conker's shadow, to disable the shadow
369          //Mux=0x00ffe9ff    Used in CONKER BFD
370          //Color0: (0 - 0) * 0 + SHADE
371          //Color1: (0 - 0) * 0 + SHADE
372          //Alpha0: (1 - TEXEL0) * SHADE + 0
373          //Alpha1: (1 - TEXEL0) * SHADE + 0
374          if (dwMux1 == 0xffd21f0f && dwMux0 == 0x00ffe9ff)
375             bConkerHideShadow = true;
376          else
377             bConkerHideShadow = false;
378       }
379 
380       if (index >= 0)
381       {
382          m_decodedMux = m_DecodedMuxList[index];
383       }
384       else
385       {
386          m_decodedMux.Decode(dwMux0, dwMux1);
387          m_decodedMux.splitType[0] = CM_FMT_TYPE_NOT_CHECKED;
388          m_decodedMux.splitType[1] = CM_FMT_TYPE_NOT_CHECKED;
389          m_decodedMux.splitType[2] = CM_FMT_TYPE_NOT_CHECKED;
390          m_decodedMux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED;
391 
392          m_decodedMux.Hack();
393 
394          m_decodedMux.Simplify();
395          if (m_supportedStages > 1)
396             m_decodedMux.SplitComplexStages();
397 
398          m_DecodedMuxList.add(m_decodedMux.m_u64Mux, *m_pDecodedMux);
399 #ifdef DEBUGGER
400          if (logCombiners)
401          {
402             TRACE0("Add a new mux");
403             DisplayMuxString();
404          }
405 #endif
406       }
407 
408       m_bTex0Enabled = m_decodedMux.m_bTexel0IsUsed;
409       m_bTex1Enabled = m_decodedMux.m_bTexel1IsUsed;
410       m_bTexelsEnable = m_bTex0Enabled||m_bTex1Enabled;
411 
412       gRSP.bProcessDiffuseColor = (m_decodedMux.m_dwShadeColorChannelFlag != MUX_0 || m_decodedMux.m_dwShadeAlphaChannelFlag != MUX_0);
413       gRSP.bProcessSpecularColor = false;
414    }
415 }
416 
417 
418 #ifdef DEBUGGER
DisplayMuxString(void)419 void CColorCombiner::DisplayMuxString(void)
420 {
421     if (gRDP.otherMode.cycle_type == G_CYC_COPY)
422     {
423         TRACE0("COPY Mode\n");
424     }
425     else if (gRDP.otherMode.cycle_type == G_CYC_FILL)
426     {
427         TRACE0("FILL Mode\n");
428     }
429 
430     m_pDecodedMux->DisplayMuxString("Used");
431 }
432 
DisplaySimpleMuxString(void)433 void CColorCombiner::DisplaySimpleMuxString(void)
434 {
435     m_pDecodedMux->DisplaySimpliedMuxString("Used");
436 }
437 #endif
438 
439