Added aspect ratio option to RICE GLES2
[mupen64plus-pandora.git] / source / gles2rice / src / RSP_GBI2.h
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
20 #include "Render.h"
21 #include "Timing.h"
22
23 void RSP_GBI2_Vtx(Gfx *gfx)
24 {
25     uint32 addr = RSPSegmentAddr((gfx->gbi2vtx.addr));
26     int vend    = gfx->gbi2vtx.vend/2;
27     int n       = gfx->gbi2vtx.n;
28     int v0      = vend - n;
29
30     LOG_UCODE("    Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", addr, vend, v0, n);
31
32     if( vend > 64 )
33     {
34         DebuggerAppendMsg("Warning, attempting to load into invalid vertex positions, v0=%d, n=%d", v0, n);
35         return;
36     }
37
38     if ((addr + (n*16)) > g_dwRamSize)
39     {
40         DebuggerAppendMsg("ProcessVertexData: Address out of range (0x%08x)", addr);
41     }
42     else
43     {
44         ProcessVertexData(addr, v0, n);
45         status.dwNumVertices += n;
46         DisplayVertexInfo(addr, v0, n);
47     }
48 }
49
50 void RSP_GBI2_EndDL(Gfx *gfx)
51 {
52     SP_Timing(RSP_GBI1_EndDL);
53
54     RDP_GFX_PopDL();
55 }
56
57 void RSP_GBI2_CullDL(Gfx *gfx)
58 {
59     SP_Timing(RSP_GBI1_CullDL);
60
61 #ifdef DEBUGGER
62     if( !debuggerEnableCullFace )
63     {
64         return; //Disable Culling
65     }
66 #endif
67     if( g_curRomInfo.bDisableCulling )
68     {
69         return; //Disable Culling
70     }
71
72     uint32 dwVFirst = (((gfx->words.w0)) & 0xfff) / gRSP.vertexMult;
73     uint32 dwVLast  = (((gfx->words.w1)) & 0xfff) / gRSP.vertexMult;
74
75     LOG_UCODE("    Culling using verts %d to %d", dwVFirst, dwVLast);
76
77     // Mask into range
78     dwVFirst &= 0x1f;
79     dwVLast &= 0x1f;
80
81     if( dwVLast < dwVFirst ) return;
82     if( !gRSP.bRejectVtx )   return;
83
84     for (uint32 i = dwVFirst; i <= dwVLast; i++)
85     {
86         //if (g_dwVtxFlags[i] == 0)
87         if (g_clipFlag[i] == 0)
88         {
89             LOG_UCODE("    Vertex %d is visible, returning", i);
90             return;
91         }
92     }
93
94     status.dwNumDListsCulled++;
95
96     LOG_UCODE("    No vertices were visible, culling");
97
98     RDP_GFX_PopDL();
99 }
100
101 void RSP_GBI2_MoveWord(Gfx *gfx)
102 {
103     SP_Timing(RSP_GBI1_MoveWord);
104
105     switch (gfx->gbi2moveword.type)
106     {
107     case RSP_MOVE_WORD_MATRIX:
108         RSP_RDP_InsertMatrix(gfx);
109         break;
110     case RSP_MOVE_WORD_NUMLIGHT:
111         {
112             uint32 dwNumLights = gfx->gbi2moveword.value/24;
113             gRSP.ambientLightIndex = dwNumLights;
114             SetNumLights(dwNumLights);
115         }
116         break;
117
118     case RSP_MOVE_WORD_CLIP:
119         {
120             switch (gfx->gbi2moveword.offset)
121             {
122             case RSP_MV_WORD_OFFSET_CLIP_RNX:
123             case RSP_MV_WORD_OFFSET_CLIP_RNY:
124             case RSP_MV_WORD_OFFSET_CLIP_RPX:
125             case RSP_MV_WORD_OFFSET_CLIP_RPY:
126                 CRender::g_pRender->SetClipRatio(gfx->gbi2moveword.offset, gfx->gbi2moveword.value);
127             default:
128                 LOG_UCODE("     RSP_MOVE_WORD_CLIP  ?   : 0x%08x", gfx->words.w1);
129                 break;
130             }
131         }
132         break;
133
134     case RSP_MOVE_WORD_SEGMENT:
135         {
136             uint32 dwSeg     = gfx->gbi2moveword.offset / 4;
137             uint32 dwAddr = gfx->gbi2moveword.value & 0x00FFFFFF;           // Hack - convert to physical
138
139             LOG_UCODE("      RSP_MOVE_WORD_SEGMENT Segment[%d] = 0x%08x",   dwSeg, dwAddr);
140             if( dwAddr > g_dwRamSize )
141             {
142                 gRSP.segments[dwSeg] = dwAddr;
143 #ifdef DEBUGGER
144                 if( pauseAtNext )
145                     DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSeg, dwAddr);
146 #endif
147             }
148             else
149             {
150                 gRSP.segments[dwSeg] = dwAddr;
151             }
152         }
153         break;
154     case RSP_MOVE_WORD_FOG:
155         {
156             uint16 wMult = (uint16)((gfx->gbi2moveword.value >> 16) & 0xFFFF);
157             uint16 wOff  = (uint16)((gfx->gbi2moveword.value      ) & 0xFFFF);
158
159             float fMult = (float)(short)wMult;
160             float fOff = (float)(short)wOff;
161
162             float rng = 128000.0f / fMult;
163             float fMin = 500.0f - (fOff*rng/256.0f);
164             float fMax = rng + fMin;
165
166             FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff));
167             //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 )
168             if( fMult <= 0 || fMax < 0 )
169             {
170                 // Hack
171                 fMin = 996;
172                 fMax = 1000;
173                 fMult = 0;
174                 fOff = 1;
175             }
176
177             SetFogMinMax(fMin, fMax, fMult, fOff);
178             FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=0x%08X", fMin, fMax, gfx->gbi2moveword.value));
179         }
180         break;
181     case RSP_MOVE_WORD_LIGHTCOL:
182         {
183             uint32 dwLight = gfx->gbi2moveword.offset / 0x18;
184             uint32 dwField = (gfx->gbi2moveword.offset & 0x7);
185
186             switch (dwField)
187             {
188             case 0:
189                 if (dwLight == gRSP.ambientLightIndex)
190                 {
191                     SetAmbientLight( (gfx->gbi2moveword.value>>8) );
192                 }
193                 else
194                 {
195                     SetLightCol(dwLight, gfx->gbi2moveword.value);
196                 }
197                 break;
198
199             case 4:
200                 break;
201
202             default:
203                 DebuggerAppendMsg("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField);
204                 break;
205             }
206
207
208         }
209         break;
210
211     case RSP_MOVE_WORD_PERSPNORM:
212         LOG_UCODE("     RSP_MOVE_WORD_PERSPNORM 0x%04x", (short)gfx->words.w1);
213         break;
214
215     case RSP_MOVE_WORD_POINTS:
216         LOG_UCODE("     2nd cmd of Force Matrix");
217         break;
218
219     default:
220         {
221             LOG_UCODE("      Ignored!!");
222
223         }
224         break;
225     }
226 }
227
228 void RSP_GBI2_Tri1(Gfx *gfx)
229 {
230     if( gfx->words.w0 == 0x05000017 && gfx->gbi2tri1.flag == 0x80 )
231     {
232         // The ObjLoadTxtr / Tlut cmd for Evangelion.v64
233         RSP_S2DEX_SPObjLoadTxtr(gfx);
234         DebuggerAppendMsg("Fix me, SPObjLoadTxtr as RSP_GBI2_Tri2");
235     }
236     else
237     {
238         status.primitiveType = PRIM_TRI1;
239         bool bTrisAdded = false;
240         bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled();
241
242         // While the next command pair is Tri1, add vertices
243         uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
244         //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC);
245
246         do
247         {
248             uint32 dwV2 = gfx->gbi2tri1.v2/gRSP.vertexMult;
249             uint32 dwV1 = gfx->gbi2tri1.v1/gRSP.vertexMult;
250             uint32 dwV0 = gfx->gbi2tri1.v0/gRSP.vertexMult;
251
252             if (IsTriangleVisible(dwV0, dwV1, dwV2))
253             {
254                 DEBUG_DUMP_VERTEXES("ZeldaTri1", dwV0, dwV1, dwV2);
255                 LOG_UCODE("    ZeldaTri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2);
256                 if (!bTrisAdded)
257                 {
258                     if( bTexturesAreEnabled )
259                     {
260                         PrepareTextures();
261                         InitVertexTextureConstants();
262                     }
263
264                     CRender::g_pRender->SetCombinerAndBlender();
265                     bTrisAdded = true;
266                 }
267                 PrepareTriangle(dwV0, dwV1, dwV2);
268             }
269
270             gfx++;
271             dwPC += 8;
272
273 #ifdef DEBUGGER
274         } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI1);
275 #else
276         } while( gfx->words.cmd == (uint8)RSP_ZELDATRI1);
277 #endif
278
279         gDlistStack[gDlistStackPointer].pc = dwPC-8;
280
281         if (bTrisAdded) 
282         {
283             CRender::g_pRender->DrawTriangles();
284         }
285
286         DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI1"));
287     }
288 }
289
290 void RSP_GBI2_Tri2(Gfx *gfx)
291 {
292     if( gfx->words.w0 == 0x0600002f && gfx->gbi2tri2.flag == 0x80 )
293     {
294         // The ObjTxSprite cmd for Evangelion.v64
295         RSP_S2DEX_SPObjLoadTxSprite(gfx);
296         DebuggerAppendMsg("Fix me, SPObjLoadTxSprite as RSP_GBI2_Tri2");
297     }
298     else
299     {
300         status.primitiveType = PRIM_TRI2;
301         BOOL bTrisAdded = FALSE;
302
303         // While the next command pair is Tri2, add vertices
304         uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
305         bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled();
306
307         do {
308             uint32 dwV2 = gfx->gbi2tri2.v2;
309             uint32 dwV1 = gfx->gbi2tri2.v1;
310             uint32 dwV0 = gfx->gbi2tri2.v0;
311
312             uint32 dwV5 = gfx->gbi2tri2.v5;
313             uint32 dwV4 = gfx->gbi2tri2.v4;
314             uint32 dwV3 = gfx->gbi2tri2.v3;
315
316             LOG_UCODE("    ZeldaTri2: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1);
317             LOG_UCODE("           V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2);
318             LOG_UCODE("           V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5);
319
320             // Do first tri
321             if (IsTriangleVisible(dwV0, dwV1, dwV2))
322             {
323                 DEBUG_DUMP_VERTEXES("ZeldaTri2 1/2", dwV0, dwV1, dwV2);
324                 if (!bTrisAdded)
325                 {
326                     if( bTexturesAreEnabled )
327                     {
328                         PrepareTextures();
329                         InitVertexTextureConstants();
330                     }
331
332                     CRender::g_pRender->SetCombinerAndBlender();
333                     bTrisAdded = true;
334                 }
335
336                 PrepareTriangle(dwV0, dwV1, dwV2);
337             }
338
339             // Do second tri
340             if (IsTriangleVisible(dwV3, dwV4, dwV5))
341             {
342                 DEBUG_DUMP_VERTEXES("ZeldaTri2 2/2", dwV3, dwV4, dwV5);
343                 if (!bTrisAdded)
344                 {
345                     if( bTexturesAreEnabled )
346                     {
347                         PrepareTextures();
348                         InitVertexTextureConstants();
349                     }
350
351                     CRender::g_pRender->SetCombinerAndBlender();
352                     bTrisAdded = true;
353                 }
354
355                 PrepareTriangle(dwV3, dwV4, dwV5);
356             }
357             
358             gfx++;
359             dwPC += 8;
360
361 #ifdef DEBUGGER
362         } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_ZELDATRI2);
363 #else
364         } while ( gfx->words.cmd == (uint8)RSP_ZELDATRI2 );//&& status.dwNumTrisRendered < 50);
365 #endif
366
367
368         gDlistStack[gDlistStackPointer].pc = dwPC-8;
369
370         if (bTrisAdded) 
371         {
372             CRender::g_pRender->DrawTriangles();
373         }
374
375         DEBUG_TRIANGLE(TRACE0("Pause at GBI2 TRI2"));
376     }
377 }
378
379 void RSP_GBI2_Line3D(Gfx *gfx)
380 {
381     if( gfx->words.w0 == 0x0700002f && (gfx->words.w1>>24) == 0x80 )
382     {
383         // The ObjTxSprite cmd for Evangelion.v64
384         RSP_S2DEX_SPObjLoadTxRect(gfx);
385     }
386     else
387     {
388         status.primitiveType = PRIM_TRI3;
389
390         uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
391
392         BOOL bTrisAdded = FALSE;
393
394         do {
395             uint32 dwV0 = gfx->gbi2line3d.v0/gRSP.vertexMult;
396             uint32 dwV1 = gfx->gbi2line3d.v1/gRSP.vertexMult;
397             uint32 dwV2 = gfx->gbi2line3d.v2/gRSP.vertexMult;
398
399             uint32 dwV3 = gfx->gbi2line3d.v3/gRSP.vertexMult;
400             uint32 dwV4 = gfx->gbi2line3d.v4/gRSP.vertexMult;
401             uint32 dwV5 = gfx->gbi2line3d.v5/gRSP.vertexMult;
402
403             LOG_UCODE("    ZeldaTri3: 0x%08x 0x%08x", gfx->words.w0, gfx->words.w1);
404             LOG_UCODE("           V0: %d, V1: %d, V2: %d", dwV0, dwV1, dwV2);
405             LOG_UCODE("           V3: %d, V4: %d, V5: %d", dwV3, dwV4, dwV5);
406
407             // Do first tri
408             if (IsTriangleVisible(dwV0, dwV1, dwV2))
409             {
410                 DEBUG_DUMP_VERTEXES("ZeldaTri3 1/2", dwV0, dwV1, dwV2);
411                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
412                 {
413                     PrepareTextures();
414                     InitVertexTextureConstants();
415                 }
416
417                 if( !bTrisAdded )
418                 {
419                     CRender::g_pRender->SetCombinerAndBlender();
420                 }
421
422                 bTrisAdded = true;
423                 PrepareTriangle(dwV0, dwV1, dwV2);
424             }
425
426             // Do second tri
427             if (IsTriangleVisible(dwV3, dwV4, dwV5))
428             {
429                 DEBUG_DUMP_VERTEXES("ZeldaTri3 2/2", dwV3, dwV4, dwV5);
430                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
431                 {
432                     PrepareTextures();
433                     InitVertexTextureConstants();
434                 }
435
436                 if( !bTrisAdded )
437                 {
438                     CRender::g_pRender->SetCombinerAndBlender();
439                 }
440
441                 bTrisAdded = true;
442                 PrepareTriangle(dwV3, dwV4, dwV5);
443             }
444             
445             gfx++;
446             dwPC += 8;
447
448 #ifdef DEBUGGER
449         } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_LINE3D);
450 #else
451         } while ( gfx->words.cmd == (uint8)RSP_LINE3D);
452 #endif
453
454         gDlistStack[gDlistStackPointer].pc = dwPC-8;
455
456
457         if (bTrisAdded) 
458         {
459             CRender::g_pRender->DrawTriangles();
460         }
461
462         DEBUG_TRIANGLE(TRACE0("Pause at GBI2 Line3D"));
463     }
464 }
465
466 void RSP_GBI2_Texture(Gfx *gfx)
467 {
468     SP_Timing(RSP_GBI1_Texture);
469
470     float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f);
471     float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f);
472
473     if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF )
474     {
475         fTextureScaleS = 1/32.0f;
476     }
477     else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 )
478     {
479         fTextureScaleS = 1/64.0f;
480     }
481     if( (((gfx->words.w1)    )&0xFFFF) == 0xFFFF )
482     {
483         fTextureScaleT = 1/32.0f;
484     }
485     else if( (((gfx->words.w1)    )&0xFFFF) == 0x8000 )
486     {
487         fTextureScaleT = 1/64.0f;
488     }
489
490     CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT);
491
492     /*
493     if( g_curRomInfo.bTextureScaleHack )
494     {
495     // Hack, need to verify, refer to N64 programming manual
496     // that if scale = 0.5 (1/64), vtx s,t are also doubled
497
498         if( ((word1>>16)&0xFFFF) == 0x8000 )
499         {
500             fTextureScaleS = 1/128.0f;
501             if( ((word1)&0xFFFF) == 0xFFFF )
502             {
503                 fTextureScaleT = 1/64.0f;
504             }
505         }
506
507         if( ((word1    )&0xFFFF) == 0x8000 )
508         {
509             fTextureScaleT = 1/128.0f;
510             if( ((word1>>16)&0xFFFF) == 0xFFFF )
511             {
512                 fTextureScaleS = 1/64.0f;
513             }
514         }
515     }
516     */
517
518     CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi2, fTextureScaleS, fTextureScaleT);
519
520     LOG_TEXTURE(
521     {
522         DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled");
523         DebuggerAppendMsg("            ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f);
524     });
525
526     DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE);
527
528     LOG_UCODE("    Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi2 ? "enabled":"disabled");
529     LOG_UCODE("    ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f);
530 }
531
532
533
534 void RSP_GBI2_PopMtx(Gfx *gfx)
535 {
536     SP_Timing(RSP_GBI1_PopMtx);
537
538     uint8 nCommand = (uint8)(gfx->words.w0 & 0xFF);
539
540     LOG_UCODE("        PopMtx: 0x%02x (%s)",
541         nCommand, 
542         (nCommand & RSP_ZELDA_MTX_PROJECTION) ? "Projection" : "ModelView");
543
544
545 /*  if (nCommand & RSP_ZELDA_MTX_PROJECTION)
546     {
547         CRender::g_pRender->PopProjection();
548     }
549     else*/
550     {
551         CRender::g_pRender->PopWorldView();
552     }
553 #ifdef DEBUGGER
554     if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD )
555     {
556         pauseAtNext = false;
557         debuggerPause = true;
558         TRACE0("Pause after Pop GBI2_PopMtx:");
559     }
560     else
561     {
562         if( pauseAtNext && logMatrix ) 
563         {
564             TRACE0("Pause after Pop GBI2_PopMtx:");
565         }
566     }
567 #endif
568
569 }
570
571
572 #define RSP_ZELDA_ZBUFFER             0x00000001      // Guess
573 #define RSP_ZELDA_CULL_BACK           0x00000200
574 #define RSP_ZELDA_CULL_FRONT          0x00000400
575 #define RSP_ZELDA_FOG                 0x00010000
576 #define RSP_ZELDA_LIGHTING            0x00020000
577 #define RSP_ZELDA_TEXTURE_GEN         0x00040000
578 #define RSP_ZELDA_TEXTURE_GEN_LINEAR  0x00080000
579 #define RSP_ZELDA_SHADING_SMOOTH      0x00200000
580
581 void RSP_GBI2_GeometryMode(Gfx *gfx)
582 {
583     SP_Timing(RSP_GBI2_GeometryMode);
584
585     uint32 dwAnd = ((gfx->words.w0)) & 0x00FFFFFF;
586     uint32 dwOr  = ((gfx->words.w1)) & 0x00FFFFFF;
587
588 #ifdef DEBUGGER
589         LOG_UCODE("    0x%08x 0x%08x =(x & 0x%08x) | 0x%08x", gfx->words.w0, gfx->words.w1, dwAnd, dwOr);
590
591         if ((~dwAnd) & RSP_ZELDA_ZBUFFER)               LOG_UCODE("  Disabling ZBuffer");
592         //if ((~dwAnd) & RSP_ZELDA_TEXTURE_ENABLE)        LOG_UCODE("  Disabling Texture");
593         //if ((~dwAnd) & RSP_ZELDA_SHADE)                 LOG_UCODE("  Disabling Shade");
594         if ((~dwAnd) & RSP_ZELDA_SHADING_SMOOTH)        LOG_UCODE("  Disabling Flat Shading");
595         if ((~dwAnd) & RSP_ZELDA_CULL_FRONT)            LOG_UCODE("  Disabling Front Culling");
596         if ((~dwAnd) & RSP_ZELDA_CULL_BACK)             LOG_UCODE("  Disabling Back Culling");
597         if ((~dwAnd) & RSP_ZELDA_FOG)                   LOG_UCODE("  Disabling Fog");
598         if ((~dwAnd) & RSP_ZELDA_LIGHTING)              LOG_UCODE("  Disabling Lighting");
599         if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN)           LOG_UCODE("  Disabling Texture Gen");
600         if ((~dwAnd) & RSP_ZELDA_TEXTURE_GEN_LINEAR)    LOG_UCODE("  Disabling Texture Gen Linear");
601         //  if ((~dwAnd) & RSP_ZELDA_LOD)                       LOG_UCODE("  Disabling LOD (no impl)");
602
603         if (dwOr & RSP_ZELDA_ZBUFFER)                   LOG_UCODE("  Enabling ZBuffer");
604         //if (dwOr & RSP_ZELDA_TEXTURE_ENABLE)            LOG_UCODE("  Enabling Texture");
605         //if (dwOr & RSP_ZELDA_SHADE)                     LOG_UCODE("  Enabling Shade");
606         if (dwOr & RSP_ZELDA_SHADING_SMOOTH)            LOG_UCODE("  Enabling Flat Shading");
607         if (dwOr & RSP_ZELDA_CULL_FRONT)                LOG_UCODE("  Enabling Front Culling");
608         if (dwOr & RSP_ZELDA_CULL_BACK)                 LOG_UCODE("  Enabling Back Culling");
609         if (dwOr & RSP_ZELDA_FOG)                       LOG_UCODE("  Enabling Fog");
610         if (dwOr & RSP_ZELDA_LIGHTING)                  LOG_UCODE("  Enabling Lighting");
611         if (dwOr & RSP_ZELDA_TEXTURE_GEN)               LOG_UCODE("  Enabling Texture Gen");
612         if (dwOr & RSP_ZELDA_TEXTURE_GEN_LINEAR)        LOG_UCODE("  Enabling Texture Gen Linear");
613         ///if (dwOr & RSP_ZELDA_LOD)                       LOG_UCODE("  Enabling LOD (no impl)");
614 #endif // DEBUGGER
615
616         gRDP.geometryMode &= dwAnd;
617     gRDP.geometryMode |= dwOr;
618
619
620     bool bCullFront     = (gRDP.geometryMode & RSP_ZELDA_CULL_FRONT) ? true : false;
621     bool bCullBack      = (gRDP.geometryMode & RSP_ZELDA_CULL_BACK) ? true : false;
622     
623     //BOOL bShade         = (gRDP.geometryMode & G_SHADE) ? TRUE : FALSE;
624     //BOOL bFlatShade     = (gRDP.geometryMode & RSP_ZELDA_SHADING_SMOOTH) ? TRUE : FALSE;
625     BOOL bFlatShade     = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN_LINEAR) ? TRUE : FALSE;
626     if( options.enableHackForGames == HACK_FOR_TIGER_HONEY_HUNT )
627         bFlatShade      = FALSE;
628     
629     bool bFog           = (gRDP.geometryMode & RSP_ZELDA_FOG) ? true : false;
630     bool bTextureGen    = (gRDP.geometryMode & RSP_ZELDA_TEXTURE_GEN) ? true : false;
631
632     bool bLighting      = (gRDP.geometryMode & RSP_ZELDA_LIGHTING) ? true : false;
633     BOOL bZBuffer       = (gRDP.geometryMode & RSP_ZELDA_ZBUFFER)   ? TRUE : FALSE; 
634
635     CRender::g_pRender->SetCullMode(bCullFront, bCullBack);
636     
637     //if (bFlatShade||!bShade)  CRender::g_pRender->SetShadeMode( SHADE_FLAT );
638     if (bFlatShade) CRender::g_pRender->SetShadeMode( SHADE_FLAT );
639     else            CRender::g_pRender->SetShadeMode( SHADE_SMOOTH );
640     
641     SetTextureGen(bTextureGen);
642
643     SetLighting( bLighting );
644     CRender::g_pRender->ZBufferEnable( bZBuffer );
645     CRender::g_pRender->SetFogEnable( bFog );
646 }
647
648
649 int dlistMtxCount=0;
650 extern uint32 dwConkerVtxZAddr;
651
652 void RSP_GBI2_Mtx(Gfx *gfx)
653 {   
654     SP_Timing(RSP_GBI0_Mtx);
655     dwConkerVtxZAddr = 0;   // For Conker BFD
656
657     uint32 addr = RSPSegmentAddr((gfx->gbi2matrix.addr));
658
659     if( gfx->gbi2matrix.param == 0 && gfx->gbi2matrix.len == 0 )
660     {
661         DLParser_Bomberman2TextRect(gfx);
662         return;
663     }
664
665     LOG_UCODE("    Mtx: %s %s %s Length %d Address 0x%08x",
666         gfx->gbi2matrix.projection ? "Projection" : "ModelView",
667         gfx->gbi2matrix.load ? "Load" : "Mul",  
668         gfx->gbi2matrix.nopush==0 ? "Push" : "No Push",
669         gfx->gbi2matrix.len, addr);
670
671     if (addr + 64 > g_dwRamSize)
672     {
673         DebuggerAppendMsg("ZeldaMtx: Address invalid (0x%08x)", addr);
674         return;
675     }
676
677     LoadMatrix(addr);
678
679     if (gfx->gbi2matrix.projection)
680     {
681         // So far only Extreme-G seems to Push/Pop projection matrices  
682         CRender::g_pRender->SetProjection(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load);
683     }
684     else
685     {
686         CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi2matrix.nopush==0, gfx->gbi2matrix.load);
687
688         if( options.enableHackForGames == HACK_FOR_SOUTH_PARK_RALLY )
689         {
690             dlistMtxCount++;
691             if( dlistMtxCount == 2 )
692             {
693                 CRender::g_pRender->ClearZBuffer(1.0f);
694             }
695         }
696     }
697
698 #ifdef DEBUGGER
699     const char *loadstr = gfx->gbi2matrix.load?"Load":"Mul";
700     const char *pushstr = gfx->gbi2matrix.nopush==0?"Push":"Nopush";
701     int projlevel = CRender::g_pRender->GetProjectMatrixLevel();
702     int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel();
703     if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD )
704     {
705         pauseAtNext = false;
706         debuggerPause = true;
707         if (gfx->gbi2matrix.projection)
708         {
709             DebuggerAppendMsg("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel );
710         }
711         else
712         {
713             DebuggerAppendMsg("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel);
714         }
715     }
716     else
717     {
718         if( pauseAtNext && logMatrix ) 
719         {
720             if (gfx->gbi2matrix.projection)
721             {
722                 DebuggerAppendMsg("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel);
723             }
724             else
725             {
726                 DebuggerAppendMsg("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel);
727             }
728         }
729     }
730 #endif
731 }
732
733 void RSP_GBI2_MoveMem(Gfx *gfx)
734 {
735     SP_Timing(RSP_GBI1_MoveMem);
736
737     uint32 addr = RSPSegmentAddr((gfx->words.w1));
738     uint32 type    = ((gfx->words.w0)     ) & 0xFE;
739
740     //uint32 dwLen = ((gfx->words.w0) >> 16) & 0xFF;
741     //uint32 dwOffset = ((gfx->words.w0) >> 8) & 0xFFFF;
742
743     switch (type)
744     {
745     case RSP_GBI2_MV_MEM__VIEWPORT:
746         {
747             RSP_MoveMemViewport(addr);
748         }
749         break;
750     case RSP_GBI2_MV_MEM__LIGHT:
751         {
752             uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF;
753         switch (dwOffset2)
754         {
755         case 0x00:
756             {
757                 s8 * pcBase = g_pRDRAMs8 + addr;
758                 LOG_UCODE("    RSP_GBI1_MV_MEM_LOOKATX %f %f %f",
759                     (float)pcBase[8 ^ 0x3],
760                     (float)pcBase[9 ^ 0x3],
761                     (float)pcBase[10 ^ 0x3]);
762
763             }
764             break;
765         case 0x18:
766             {
767                 s8 * pcBase = g_pRDRAMs8 + addr;
768                 LOG_UCODE("    RSP_GBI1_MV_MEM_LOOKATY %f %f %f",
769                     (float)pcBase[8 ^ 0x3],
770                     (float)pcBase[9 ^ 0x3],
771                     (float)pcBase[10 ^ 0x3]);
772             }
773             break;
774         default:        //0x30/48/60
775             {
776                 uint32 dwLight = (dwOffset2 - 0x30)/0x18;
777                 LOG_UCODE("    Light %d:", dwLight);
778                     RSP_MoveMemLight(dwLight, addr);
779             }
780             break;
781         }
782         break;
783
784         }
785     case RSP_GBI2_MV_MEM__MATRIX:
786         LOG_UCODE("Force Matrix: addr=%08X", addr);
787         RSP_GFX_Force_Matrix(addr);
788         break;
789     case RSP_GBI2_MV_MEM_O_L0:
790     case RSP_GBI2_MV_MEM_O_L1:
791     case RSP_GBI2_MV_MEM_O_L2:
792     case RSP_GBI2_MV_MEM_O_L3:
793     case RSP_GBI2_MV_MEM_O_L4:
794     case RSP_GBI2_MV_MEM_O_L5:
795     case RSP_GBI2_MV_MEM_O_L6:
796     case RSP_GBI2_MV_MEM_O_L7:
797         LOG_UCODE("Zelda Move Light");
798         RDP_NOIMPL_WARN("Zelda Move Light");
799         break;
800
801     case RSP_GBI2_MV_MEM__POINT:
802         LOG_UCODE("Zelda Move Point");
803         void RDP_NOIMPL_WARN(const char* op);
804         RDP_NOIMPL_WARN("Zelda Move Point");
805         break;
806
807     case RSP_GBI2_MV_MEM_O_LOOKATX:
808         if( (gfx->words.w0) == 0xDC170000 && ((gfx->words.w1)&0xFF000000) == 0x80000000 )
809         {
810             // Ucode for Evangelion.v64, the ObjMatrix cmd
811             RSP_S2DEX_OBJ_MOVEMEM(gfx);
812         }
813         break;
814     case RSP_GBI2_MV_MEM_O_LOOKATY:
815         RSP_RDP_NOIMPL("Not implemented ZeldaMoveMem LOOKATY, Cmd0=0x%08X, Cmd1=0x%08X", gfx->words.w0, gfx->words.w1);
816         break;
817     case 0x02:
818         if( (gfx->words.w0) == 0xDC070002 && ((gfx->words.w1)&0xFF000000) == 0x80000000 )
819         {
820             RSP_S2DEX_OBJ_MOVEMEM(gfx);
821             break;
822         }
823     default:
824         LOG_UCODE("ZeldaMoveMem Type: Unknown");
825         RSP_RDP_NOIMPL("Unknown ZeldaMoveMem Type, type=0x%X, Addr=%08X", type, addr);
826         break;
827     }
828 }
829
830
831
832 void RSP_GBI2_DL(Gfx *gfx)
833 {
834     SP_Timing(RSP_GBI0_DL);
835
836     uint32 dwPush = ((gfx->words.w0) >> 16) & 0xFF;
837     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
838
839     if( dwAddr > g_dwRamSize )
840     {
841         RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc );
842         dwAddr &= (g_dwRamSize-1);
843         DebuggerPauseCountN( NEXT_DLIST );
844     }
845
846     LOG_UCODE("    DL: Push:0x%02x Addr: 0x%08x", dwPush, dwAddr);
847     
848     switch (dwPush)
849     {
850     case RSP_DLIST_PUSH:
851         LOG_UCODE("    Pushing ZeldaDisplayList 0x%08x", dwAddr);
852         gDlistStackPointer++;
853         gDlistStack[gDlistStackPointer].pc = dwAddr;
854         gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
855
856         break;
857     case RSP_DLIST_NOPUSH:
858         LOG_UCODE("    Jumping to ZeldaDisplayList 0x%08x", dwAddr);
859         if( gDlistStack[gDlistStackPointer].pc == dwAddr+8 )    //Is this a loop
860         {
861             //Hack for Gauntlet Legends
862             gDlistStack[gDlistStackPointer].pc = dwAddr+8;
863         }
864         else
865             gDlistStack[gDlistStackPointer].pc = dwAddr;
866         gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
867         break;
868     }
869
870     LOG_UCODE("");
871     LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/");
872     LOG_UCODE("#############################################");
873 }
874
875
876 void RSP_GBI2_SetOtherModeL(Gfx *gfx)
877 {
878     SP_Timing(RSP_GBI1_SetOtherModeL);
879
880     uint32 dwShift = ((gfx->words.w0)>>8)&0xFF;
881     uint32 dwLength= ((gfx->words.w0)   )&0xFF;
882     uint32 dwData  = (gfx->words.w1);
883
884     // Mask is constructed slightly differently
885     uint32 dwMask = (uint32)((s32)(0x80000000)>>dwLength)>>dwShift;
886     dwData &= dwMask;
887
888     uint32 modeL = gRDP.otherModeL;
889     modeL = (modeL&(~dwMask)) | dwData;
890
891     Gfx tempgfx;
892     tempgfx.words.w0 = gRDP.otherModeH;
893     tempgfx.words.w1 = modeL;
894     DLParser_RDPSetOtherMode(&tempgfx );
895 }
896
897
898 void RSP_GBI2_SetOtherModeH(Gfx *gfx)
899 {
900     SP_Timing(RSP_GBI1_SetOtherModeH);
901
902     uint32 dwLength= (((gfx->words.w0))&0xFF)+1;
903     uint32 dwShift = 32 - (((gfx->words.w0)>>8)&0xFF) - dwLength;
904     uint32 dwData  = (gfx->words.w1);
905
906     uint32 dwMask2 = ((1<<dwLength)-1)<<dwShift;
907     uint32 dwModeH = gRDP.otherModeH;
908     dwModeH = (dwModeH&(~dwMask2)) | dwData;
909
910     Gfx tempgfx;
911     tempgfx.words.w0 = dwModeH;
912     tempgfx.words.w1 = gRDP.otherModeL;
913     DLParser_RDPSetOtherMode(&tempgfx );
914 }
915
916
917 void RSP_GBI2_SubModule(Gfx *gfx)
918 {
919     SP_Timing(RSP_GBI2_SubModule);
920
921     RSP_RDP_NOIMPL("RDP: RSP_GBI2_SubModule (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1));
922 }
923