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