Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
[mupen64plus-pandora.git] / source / gles2rice / src / RSP_GBI0.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 <cmath>
21 #include "Render.h"
22 #include "Timing.h"
23
24 void RSP_GBI1_SpNoop(Gfx *gfx)
25 {
26     SP_Timing(RSP_GBI1_SpNoop);
27
28     if( (gfx+1)->words.cmd == 0x00 && gRSP.ucode >= 17 )
29     {
30         RSP_RDP_NOIMPL("Double SPNOOP, Skip remain ucodes, PC=%08X, Cmd1=%08X", gDlistStack[gDlistStackPointer].pc, gfx->words.w1);
31         RDP_GFX_PopDL();
32         //if( gRSP.ucode < 17 ) TriggerDPInterrupt();
33     }
34 }
35
36 void RSP_GBI0_Mtx(Gfx *gfx)
37 {   
38     SP_Timing(RSP_GBI0_Mtx);
39
40     uint32 addr = RSPSegmentAddr((gfx->gbi0matrix.addr));
41
42     LOG_UCODE("    Command: %s %s %s Length %d Address 0x%08x",
43         gfx->gbi0matrix.projection == 1 ? "Projection" : "ModelView",
44         gfx->gbi0matrix.load == 1 ? "Load" : "Mul", 
45         gfx->gbi0matrix.push == 1 ? "Push" : "NoPush",
46         gfx->gbi0matrix.len, addr);
47
48     if (addr + 64 > g_dwRamSize)
49     {
50         TRACE1("Mtx: Address invalid (0x%08x)", addr);
51         return;
52     }
53
54     LoadMatrix(addr);
55     
56     if (gfx->gbi0matrix.projection)
57     {
58         CRender::g_pRender->SetProjection(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load);
59     }
60     else
61     {
62         CRender::g_pRender->SetWorldView(matToLoad, gfx->gbi0matrix.push, gfx->gbi0matrix.load);
63     }
64
65 #ifdef DEBUGGER
66     const char *loadstr = gfx->gbi0matrix.load == 1 ? "Load" : "Mul";
67     const char *pushstr = gfx->gbi0matrix.push == 1 ? "Push" : "Nopush";
68     int projlevel = CRender::g_pRender->GetProjectMatrixLevel();
69     int worldlevel = CRender::g_pRender->GetWorldViewMatrixLevel();
70     if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD )
71     {
72         pauseAtNext = false;
73         debuggerPause = true;
74         if (gfx->gbi0matrix.projection)
75         {
76             TRACE3("Pause after %s and %s Matrix: Projection, level=%d\n", loadstr, pushstr, projlevel );
77         }
78         else
79         {
80             TRACE3("Pause after %s and %s Matrix: WorldView level=%d\n", loadstr, pushstr, worldlevel);
81         }
82     }
83     else
84     {
85         if( pauseAtNext && logMatrix ) 
86         {
87             if (gfx->gbi0matrix.projection)
88             {
89                 TRACE3("Matrix: %s and %s Projection level=%d\n", loadstr, pushstr, projlevel);
90             }
91             else
92             {
93                 TRACE3("Matrix: %s and %s WorldView\n level=%d", loadstr, pushstr, worldlevel);
94             }
95         }
96     }
97 #endif
98 }
99
100
101 void RSP_GBI1_Reserved(Gfx *gfx)
102 {
103     SP_Timing(RSP_GBI1_Reserved);
104     RSP_RDP_NOIMPL("RDP: Reserved (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1));
105 }
106
107
108 void RSP_GBI1_MoveMem(Gfx *gfx)
109 {
110     SP_Timing(RSP_GBI1_MoveMem);
111
112     uint32 type    = ((gfx->words.w0)>>16)&0xFF;
113     uint32 dwLength  = ((gfx->words.w0))&0xFFFF;
114     uint32 addr = RSPSegmentAddr((gfx->words.w1));
115
116     switch (type) 
117     {
118         case RSP_GBI1_MV_MEM_VIEWPORT:
119             {
120                 LOG_UCODE("    RSP_GBI1_MV_MEM_VIEWPORT. Address: 0x%08x, Length: 0x%04x", addr, dwLength);
121                 RSP_MoveMemViewport(addr);
122             }
123             break;
124         case RSP_GBI1_MV_MEM_LOOKATY:
125             LOG_UCODE("    RSP_GBI1_MV_MEM_LOOKATY");
126             break;
127         case RSP_GBI1_MV_MEM_LOOKATX:
128             LOG_UCODE("    RSP_GBI1_MV_MEM_LOOKATX");
129             break;
130         case RSP_GBI1_MV_MEM_L0:
131         case RSP_GBI1_MV_MEM_L1:
132         case RSP_GBI1_MV_MEM_L2:
133         case RSP_GBI1_MV_MEM_L3:
134         case RSP_GBI1_MV_MEM_L4:
135         case RSP_GBI1_MV_MEM_L5:
136         case RSP_GBI1_MV_MEM_L6:
137         case RSP_GBI1_MV_MEM_L7:
138             {
139                 uint32 dwLight = (type-RSP_GBI1_MV_MEM_L0)/2;
140                 LOG_UCODE("    RSP_GBI1_MV_MEM_L%d", dwLight);
141                 LOG_UCODE("    Light%d: Length:0x%04x, Address: 0x%08x", dwLight, dwLength, addr);
142
143                 RSP_MoveMemLight(dwLight, addr);
144             }
145             break;
146         case RSP_GBI1_MV_MEM_TXTATT:
147             LOG_UCODE("    RSP_GBI1_MV_MEM_TXTATT");
148             break;
149         case RSP_GBI1_MV_MEM_MATRIX_1:
150             RSP_GFX_Force_Matrix(addr);
151             break;
152         case RSP_GBI1_MV_MEM_MATRIX_2:
153             break;
154         case RSP_GBI1_MV_MEM_MATRIX_3:
155             break;
156         case RSP_GBI1_MV_MEM_MATRIX_4:
157             break;
158         default:
159             RSP_RDP_NOIMPL("MoveMem: Unknown Move Type, cmd=%08X, %08X", gfx->words.w0, gfx->words.w1);
160             break;
161     }
162 }
163
164
165 void RSP_GBI0_Vtx(Gfx *gfx)
166 {
167     SP_Timing(RSP_GBI0_Vtx);
168
169     int n = gfx->gbi0vtx.n + 1;
170     int v0 = gfx->gbi0vtx.v0;
171     uint32 addr = RSPSegmentAddr((gfx->gbi0vtx.addr));
172
173     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", addr, v0, n, gfx->gbi0vtx.len);
174
175     if ((v0 + n) > 80)
176     {
177         TRACE3("Warning, invalid vertex positions, N=%d, v0=%d, Addr=0x%08X", n, v0, addr);
178         n = 32 - v0;
179     }
180
181     // Check that address is valid...
182     if ((addr + n*16) > g_dwRamSize)
183     {
184         TRACE1("Vertex Data: Address out of range (0x%08x)", addr);
185     }
186     else
187     {
188         ProcessVertexData(addr, v0, n);
189         status.dwNumVertices += n;
190         DisplayVertexInfo(addr, v0, n);
191     }
192 }
193
194
195 void RSP_GBI0_DL(Gfx *gfx)
196 {
197     SP_Timing(RSP_GBI0_DL);
198
199     uint32 addr = RSPSegmentAddr((gfx->gbi0dlist.addr)) & (g_dwRamSize-1);
200
201     LOG_UCODE("    Address=0x%08x Push: 0x%02x", addr, gfx->gbi0dlist.param);
202     if( addr > g_dwRamSize )
203     {
204         RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", addr, gDlistStack[gDlistStackPointer].pc );
205         addr &= (g_dwRamSize-1);
206         DebuggerPauseCountN( NEXT_DLIST );
207     }
208
209     if( gfx->gbi0dlist.param == RSP_DLIST_PUSH )
210         gDlistStackPointer++;
211
212     gDlistStack[gDlistStackPointer].pc = addr;
213     gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
214
215     LOG_UCODE("Level=%d", gDlistStackPointer+1);
216     LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
217 }
218
219
220 void RSP_GBI1_RDPHalf_Cont(Gfx *gfx)    
221 {
222     SP_Timing(RSP_GBI1_RDPHalf_Cont);
223
224     LOG_UCODE("RDPHalf_Cont: (Ignored)"); 
225 }
226 void RSP_GBI1_RDPHalf_2(Gfx *gfx)       
227
228     SP_Timing(RSP_GBI1_RDPHalf_2);
229
230     LOG_UCODE("RDPHalf_2: (Ignored)"); 
231 }
232
233 void RSP_GBI1_RDPHalf_1(Gfx *gfx)       
234 {
235     SP_Timing(RSP_GBI1_RDPHalf_1);
236
237     LOG_UCODE("RDPHalf_1: (Ignored)"); 
238 }
239
240 void RSP_GBI1_Line3D(Gfx *gfx)
241 {
242     status.primitiveType = PRIM_LINE3D;
243
244     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
245
246     BOOL bTrisAdded = FALSE;
247
248     if( gfx->ln3dtri2.v3 == 0 )
249     {
250         // Flying Dragon
251         uint32 dwV0     = gfx->ln3dtri2.v0/gRSP.vertexMult;
252         uint32 dwV1     = gfx->ln3dtri2.v1/gRSP.vertexMult;
253         uint32 dwWidth  = gfx->ln3dtri2.v2;
254         //uint32 dwFlag = gfx->ln3dtri2.v3/gRSP.vertexMult; 
255         
256         CRender::g_pRender->SetCombinerAndBlender();
257
258         status.dwNumTrisRendered++;
259
260         CRender::g_pRender->Line3D(dwV0, dwV1, dwWidth);
261         SP_Timing(RSP_GBI1_Line3D);
262         DP_Timing(RSP_GBI1_Line3D);
263     }
264     else
265     {
266         do {
267             uint32 dwV3  = gfx->ln3dtri2.v3/gRSP.vertexMult;        
268             uint32 dwV0  = gfx->ln3dtri2.v0/gRSP.vertexMult;
269             uint32 dwV1  = gfx->ln3dtri2.v1/gRSP.vertexMult;
270             uint32 dwV2  = gfx->ln3dtri2.v2/gRSP.vertexMult;
271
272             LOG_UCODE("    Line3D: V0: %d, V1: %d, V2: %d, V3: %d", dwV0, dwV1, dwV2, dwV3);
273
274             // Do first tri
275             if (IsTriangleVisible(dwV0, dwV1, dwV2))
276             {
277                 DEBUG_DUMP_VERTEXES("Line3D 1/2", dwV0, dwV1, dwV2);
278                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
279                 {
280                     PrepareTextures();
281                     InitVertexTextureConstants();
282                 }
283
284                 if( !bTrisAdded )
285                 {
286                     CRender::g_pRender->SetCombinerAndBlender();
287                 }
288
289                 bTrisAdded = true;
290                 PrepareTriangle(dwV0, dwV1, dwV2);
291             }
292
293             // Do second tri
294             if (IsTriangleVisible(dwV2, dwV3, dwV0))
295             {
296                 DEBUG_DUMP_VERTEXES("Line3D 2/2", dwV0, dwV1, dwV2);
297                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
298                 {
299                     PrepareTextures();
300                     InitVertexTextureConstants();
301                 }
302
303                 if( !bTrisAdded )
304                 {
305                     CRender::g_pRender->SetCombinerAndBlender();
306                 }
307
308                 bTrisAdded = true;
309                 PrepareTriangle(dwV2, dwV3, dwV0);
310             }
311
312             gfx++;
313             dwPC += 8;
314 #ifdef DEBUGGER
315         } while (gfx->words.cmd == (uint8)RSP_LINE3D && !(pauseAtNext && eventToPause==NEXT_FLUSH_TRI));
316 #else
317         } while (gfx->words.cmd == (uint8)RSP_LINE3D);
318 #endif
319
320         gDlistStack[gDlistStackPointer].pc = dwPC-8;
321
322         if (bTrisAdded) 
323         {
324             CRender::g_pRender->DrawTriangles();
325         }
326     }
327 }
328
329
330 void RSP_GBI1_ClearGeometryMode(Gfx *gfx)
331 {
332     SP_Timing(RSP_GBI1_ClearGeometryMode);
333     uint32 dwMask = ((gfx->words.w1));
334
335 #ifdef DEBUGGER
336     LOG_UCODE("    Mask=0x%08x", dwMask);
337     if (dwMask & G_ZBUFFER)                 LOG_UCODE("  Disabling ZBuffer");
338     if (dwMask & G_TEXTURE_ENABLE)          LOG_UCODE("  Disabling Texture");
339     if (dwMask & G_SHADE)                   LOG_UCODE("  Disabling Shade");
340     if (dwMask & G_SHADING_SMOOTH)          LOG_UCODE("  Disabling Smooth Shading");
341     if (dwMask & G_CULL_FRONT)              LOG_UCODE("  Disabling Front Culling");
342     if (dwMask & G_CULL_BACK)               LOG_UCODE("  Disabling Back Culling");
343     if (dwMask & G_FOG)                     LOG_UCODE("  Disabling Fog");
344     if (dwMask & G_LIGHTING)                LOG_UCODE("  Disabling Lighting");
345     if (dwMask & G_TEXTURE_GEN)             LOG_UCODE("  Disabling Texture Gen");
346     if (dwMask & G_TEXTURE_GEN_LINEAR)      LOG_UCODE("  Disabling Texture Gen Linear");
347     if (dwMask & G_LOD)                     LOG_UCODE("  Disabling LOD (no impl)");
348 #endif
349
350     gRDP.geometryMode &= ~dwMask;
351     RSP_GFX_InitGeometryMode();
352 }
353
354
355
356 void RSP_GBI1_SetGeometryMode(Gfx *gfx)
357 {
358     SP_Timing(RSP_GBI1_SetGeometryMode);
359     uint32 dwMask = ((gfx->words.w1));
360
361 #ifdef DEBUGGER
362     LOG_UCODE("    Mask=0x%08x", dwMask);
363     if (dwMask & G_ZBUFFER)                 LOG_UCODE("  Enabling ZBuffer");
364     if (dwMask & G_TEXTURE_ENABLE)          LOG_UCODE("  Enabling Texture");
365     if (dwMask & G_SHADE)                   LOG_UCODE("  Enabling Shade");
366     if (dwMask & G_SHADING_SMOOTH)          LOG_UCODE("  Enabling Smooth Shading");
367     if (dwMask & G_CULL_FRONT)              LOG_UCODE("  Enabling Front Culling");
368     if (dwMask & G_CULL_BACK)               LOG_UCODE("  Enabling Back Culling");
369     if (dwMask & G_FOG)                     LOG_UCODE("  Enabling Fog");
370     if (dwMask & G_LIGHTING)                LOG_UCODE("  Enabling Lighting");
371     if (dwMask & G_TEXTURE_GEN)             LOG_UCODE("  Enabling Texture Gen");
372     if (dwMask & G_TEXTURE_GEN_LINEAR)      LOG_UCODE("  Enabling Texture Gen Linear");
373     if (dwMask & G_LOD)                     LOG_UCODE("  Enabling LOD (no impl)");
374 #endif // DEBUGGER
375     gRDP.geometryMode |= dwMask;
376     RSP_GFX_InitGeometryMode();
377 }
378
379
380 void RSP_GBI1_EndDL(Gfx *gfx)
381 {
382     SP_Timing(RSP_GBI1_EndDL);
383     RDP_GFX_PopDL();
384 }
385
386
387 //static const char * sc_szBlClr[4] = { "In", "Mem", "Bl", "Fog" };
388 //static const char * sc_szBlA1[4] = { "AIn", "AFog", "AShade", "0" };
389 //static const char * sc_szBlA2[4] = { "1-A", "AMem", "1", "?" };
390
391 void RSP_GBI1_SetOtherModeL(Gfx *gfx)
392 {
393     SP_Timing(RSP_GBI1_SetOtherModeL);
394
395     uint32 dwShift = ((gfx->words.w0)>>8)&0xFF;
396     uint32 dwLength= ((gfx->words.w0)   )&0xFF;
397     uint32 dwData  = (gfx->words.w1);
398
399     uint32 dwMask = ((1<<dwLength)-1)<<dwShift;
400
401     uint32 modeL = gRDP.otherModeL;
402     modeL = (modeL&(~dwMask)) | dwData;
403
404     Gfx tempgfx;
405     tempgfx.words.w0 = gRDP.otherModeH;
406     tempgfx.words.w1 = modeL;
407     DLParser_RDPSetOtherMode(&tempgfx);
408 }
409
410
411 void RSP_GBI1_SetOtherModeH(Gfx *gfx)
412 {
413     SP_Timing(RSP_GBI1_SetOtherModeH);
414
415     uint32 dwShift = ((gfx->words.w0)>>8)&0xFF;
416     uint32 dwLength= ((gfx->words.w0)   )&0xFF;
417     uint32 dwData  = (gfx->words.w1);
418
419     uint32 dwMask = ((1<<dwLength)-1)<<dwShift;
420     uint32 dwModeH = gRDP.otherModeH;
421
422     dwModeH = (dwModeH&(~dwMask)) | dwData;
423     Gfx tempgfx;
424     tempgfx.words.w0 = dwModeH;
425     tempgfx.words.w1 = gRDP.otherModeL;
426     DLParser_RDPSetOtherMode(&tempgfx );
427 }
428
429
430 void RSP_GBI1_Texture(Gfx *gfx)
431 {
432     SP_Timing(RSP_GBI1_Texture);
433
434     float fTextureScaleS = (float)(gfx->texture.scaleS) / (65536.0f * 32.0f);
435     float fTextureScaleT = (float)(gfx->texture.scaleT) / (65536.0f * 32.0f);
436
437     if( (((gfx->words.w1)>>16)&0xFFFF) == 0xFFFF )
438     {
439         fTextureScaleS = 1/32.0f;
440     }
441     else if( (((gfx->words.w1)>>16)&0xFFFF) == 0x8000 )
442     {
443         fTextureScaleS = 1/64.0f;
444     }
445 #ifdef DEBUGGER
446     else if( ((gfx->words.w1>>16)&0xFFFF) != 0 )
447     {
448         //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1>>16)&0xFFFF);
449     }
450 #endif
451
452     if( (((gfx->words.w1)    )&0xFFFF) == 0xFFFF )
453     {
454         fTextureScaleT = 1/32.0f;
455     }
456     else if( (((gfx->words.w1)    )&0xFFFF) == 0x8000 )
457     {
458         fTextureScaleT = 1/64.0f;
459     }
460 #ifdef DEBUGGER
461     else if( (gfx->words.w1&0xFFFF) != 0 )
462     {
463         //DebuggerAppendMsg("Warning, texture scale = %08X is not integer", (word1)&0xFFFF);
464     }
465 #endif
466
467     if( gRSP.ucode == 6 )
468     {
469         if( fTextureScaleS == 0 )   fTextureScaleS = 1.0f/32.0f;
470         if( fTextureScaleT == 0 )   fTextureScaleT = 1.0f/32.0f;
471     }
472
473     CRender::g_pRender->SetTextureEnableAndScale(gfx->texture.tile, gfx->texture.enable_gbi0, fTextureScaleS, fTextureScaleT);
474
475     // What happens if these are 0? Interpret as 1.0f?
476
477     LOG_TEXTURE(
478     {
479         DebuggerAppendMsg("SetTexture: Level: %d Tile: %d %s\n", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled");
480         DebuggerAppendMsg("            ScaleS: %f, ScaleT: %f\n", fTextureScaleS*32.0f, fTextureScaleT*32.0f);
481     });
482
483     DEBUGGER_PAUSE_COUNT_N(NEXT_SET_TEXTURE);
484     LOG_UCODE("    Level: %d Tile: %d %s", gfx->texture.level, gfx->texture.tile, gfx->texture.enable_gbi0 ? "enabled":"disabled");
485     LOG_UCODE("    ScaleS: %f, ScaleT: %f", fTextureScaleS*32.0f, fTextureScaleT*32.0f);
486 }
487
488 extern void RSP_RDP_InsertMatrix(uint32 word0, uint32 word1);
489 void RSP_GBI1_MoveWord(Gfx *gfx)
490 {
491     SP_Timing(RSP_GBI1_MoveWord);
492
493     switch (gfx->gbi0moveword.type)
494     {
495     case RSP_MOVE_WORD_MATRIX:
496         RSP_RDP_InsertMatrix(gfx);
497         break;
498     case RSP_MOVE_WORD_NUMLIGHT:
499         {
500             uint32 dwNumLights = (((gfx->gbi0moveword.value)-0x80000000)/32)-1;
501             LOG_UCODE("    RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights);
502
503             gRSP.ambientLightIndex = dwNumLights;
504             SetNumLights(dwNumLights);
505         }
506         break;
507     case RSP_MOVE_WORD_CLIP:
508         {
509             switch (gfx->gbi0moveword.offset)
510             {
511             case RSP_MV_WORD_OFFSET_CLIP_RNX:
512             case RSP_MV_WORD_OFFSET_CLIP_RNY:
513             case RSP_MV_WORD_OFFSET_CLIP_RPX:
514             case RSP_MV_WORD_OFFSET_CLIP_RPY:
515                 CRender::g_pRender->SetClipRatio(gfx->gbi0moveword.offset, gfx->gbi0moveword.value);
516                 break;
517             default:
518                 LOG_UCODE("    RSP_MOVE_WORD_CLIP  ?   : 0x%08x", gfx->words.w1);
519                 break;
520             }
521         }
522         break;
523     case RSP_MOVE_WORD_SEGMENT:
524         {
525             uint32 dwSegment = (gfx->gbi0moveword.offset >> 2) & 0xF;
526             uint32 dwBase = (gfx->gbi0moveword.value)&0x00FFFFFF;
527             LOG_UCODE("    RSP_MOVE_WORD_SEGMENT Seg[%d] = 0x%08x", dwSegment, dwBase);
528             if( dwBase > g_dwRamSize )
529             {
530                 gRSP.segments[dwSegment] = dwBase;
531 #ifdef DEBUGGER
532                 if( pauseAtNext )
533                     DebuggerAppendMsg("warning: Segment %d addr is %8X", dwSegment, dwBase);
534 #endif
535             }
536             else
537             {
538                 gRSP.segments[dwSegment] = dwBase;
539             }
540         }
541         break;
542     case RSP_MOVE_WORD_FOG:
543         {
544             uint16 wMult = (uint16)(((gfx->gbi0moveword.value) >> 16) & 0xFFFF);
545             uint16 wOff  = (uint16)(((gfx->gbi0moveword.value)      ) & 0xFFFF);
546
547             float fMult = (float)(short)wMult;
548             float fOff = (float)(short)wOff;
549
550             float rng = 128000.0f / fMult;
551             float fMin = 500.0f - (fOff*rng/256.0f);
552             float fMax = rng + fMin;
553
554             FOG_DUMP(TRACE4("Set Fog: Min=%f, Max=%f, Mul=%f, Off=%f", fMin, fMax, fMult, fOff));
555             //if( fMult <= 0 || fMin > fMax || fMax < 0 || fMin > 1000 )
556             if( fMult <= 0 || fMax < 0 )
557             {
558                 // Hack
559                 fMin = 996;
560                 fMax = 1000;
561                 fMult = 0;
562                 fOff = 1;
563             }
564
565             LOG_UCODE("    RSP_MOVE_WORD_FOG/Mul=%d: Off=%d", wMult, wOff);
566             FOG_DUMP(TRACE3("Set Fog: Min=%f, Max=%f, Data=%08X", fMin, fMax, gfx->gbi0moveword.value));
567             SetFogMinMax(fMin, fMax, fMult, fOff);
568         }
569         break;
570     case RSP_MOVE_WORD_LIGHTCOL:
571         {
572             uint32 dwLight = gfx->gbi0moveword.offset / 0x20;
573             uint32 dwField = (gfx->gbi0moveword.offset & 0x7);
574
575             LOG_UCODE("    RSP_MOVE_WORD_LIGHTCOL/0x%08x: 0x%08x", gfx->gbi0moveword.offset, gfx->words.w1);
576
577             switch (dwField)
578             {
579             case 0:
580                 if (dwLight == gRSP.ambientLightIndex)
581                 {
582                     SetAmbientLight( ((gfx->gbi0moveword.value)>>8) );
583                 }
584                 else
585                 {
586                     SetLightCol(dwLight, gfx->gbi0moveword.value);
587                 }
588                 break;
589
590             case 4:
591                 break;
592
593             default:
594                 TRACE1("RSP_MOVE_WORD_LIGHTCOL with unknown offset 0x%08x", dwField);
595                 break;
596             }
597         }
598         break;
599     case RSP_MOVE_WORD_POINTS:
600         {
601             uint32 vtx = gfx->gbi0moveword.offset/40;
602             uint32 where = gfx->gbi0moveword.offset - vtx*40;
603             ModifyVertexInfo(where, vtx, gfx->gbi0moveword.value);
604         }
605         break;
606     case RSP_MOVE_WORD_PERSPNORM:
607         LOG_UCODE("    RSP_MOVE_WORD_PERSPNORM");
608         //if( word1 != 0x1A ) DebuggerAppendMsg("PerspNorm: 0x%04x", (short)word1); 
609         break;
610     default:
611         RSP_RDP_NOIMPL("Unknown MoveWord, %08X, %08X", gfx->words.w0, gfx->words.w1);
612         break;
613     }
614
615 }
616
617
618 void RSP_GBI1_PopMtx(Gfx *gfx)
619 {
620     SP_Timing(RSP_GBI1_PopMtx);
621
622     LOG_UCODE("    Command: (%s)",  gfx->gbi0popmatrix.projection ? "Projection" : "ModelView");
623
624     // Do any of the other bits do anything?
625     // So far only Extreme-G seems to Push/Pop projection matrices
626
627     if (gfx->gbi0popmatrix.projection)
628     {
629         CRender::g_pRender->PopProjection();
630     }
631     else
632     {
633         CRender::g_pRender->PopWorldView();
634     }
635 #ifdef DEBUGGER
636     if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD )
637     {
638         pauseAtNext = false;
639         debuggerPause = true;
640         DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World");
641     }
642     else
643     {
644         if( pauseAtNext && logMatrix ) 
645         {
646             DebuggerAppendMsg("Pause after Pop Matrix: %s\n", gfx->gbi0popmatrix.projection ? "Proj":"World");
647         }
648     }
649 #endif
650 }
651
652
653 void RSP_GBI1_CullDL(Gfx *gfx)
654 {
655     SP_Timing(RSP_GBI1_CullDL);
656
657 #ifdef DEBUGGER
658     if( !debuggerEnableCullFace )
659     {
660         return; //Disable Culling
661     }
662 #endif
663     if( g_curRomInfo.bDisableCulling )
664     {
665         return; //Disable Culling
666     }
667
668     uint32 dwVFirst = ((gfx->words.w0) & 0xFFF) / gRSP.vertexMult;
669     uint32 dwVLast  = (((gfx->words.w1)) & 0xFFF) / gRSP.vertexMult;
670
671     LOG_UCODE("    Culling using verts %d to %d", dwVFirst, dwVLast);
672
673     // Mask into range
674     dwVFirst &= 0x1f;
675     dwVLast &= 0x1f;
676
677     if( dwVLast < dwVFirst )    return;
678     if( !gRSP.bRejectVtx )  return;
679
680     for (uint32 i = dwVFirst; i <= dwVLast; i++)
681     {
682         if (g_clipFlag[i] == 0)
683         {
684             LOG_UCODE("    Vertex %d is visible, continuing with display list processing", i);
685             return;
686         }
687     }
688
689     status.dwNumDListsCulled++;
690
691     LOG_UCODE("    No vertices were visible, culling rest of display list");
692
693     RDP_GFX_PopDL();
694 }
695
696
697
698 void RSP_GBI1_Tri1(Gfx *gfx)
699 {
700     status.primitiveType = PRIM_TRI1;
701     bool bTrisAdded = false;
702     bool bTexturesAreEnabled = CRender::g_pRender->IsTextureEnabled();
703
704     // While the next command pair is Tri1, add vertices
705     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
706     //uint32 * pCmdBase = (uint32 *)(g_pRDRAMu8 + dwPC);
707     
708     do
709     {
710         uint32 dwV0 = gfx->tri1.v0/gRSP.vertexMult;
711         uint32 dwV1 = gfx->tri1.v1/gRSP.vertexMult;
712         uint32 dwV2 = gfx->tri1.v2/gRSP.vertexMult;
713
714         if (IsTriangleVisible(dwV0, dwV1, dwV2))
715         {
716             DEBUG_DUMP_VERTEXES("Tri1", dwV0, dwV1, dwV2);
717             LOG_UCODE("    Tri1: 0x%08x 0x%08x %d,%d,%d", gfx->words.w0, gfx->words.w1, dwV0, dwV1, dwV2);
718
719             if (!bTrisAdded)
720             {
721                 if( bTexturesAreEnabled )
722                 {
723                     PrepareTextures();
724                     InitVertexTextureConstants();
725                 }
726                 CRender::g_pRender->SetCombinerAndBlender();
727                 bTrisAdded = true;
728             }
729             PrepareTriangle(dwV0, dwV1, dwV2);
730         }
731
732         gfx++;
733         dwPC += 8;
734
735 #ifdef DEBUGGER
736     } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && gfx->words.cmd == (uint8)RSP_TRI1);
737 #else
738     } while (gfx->words.cmd == (uint8)RSP_TRI1);
739 #endif
740
741     gDlistStack[gDlistStackPointer].pc = dwPC-8;
742
743     if (bTrisAdded) 
744     {
745         CRender::g_pRender->DrawTriangles();
746     }
747
748     DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI1"));
749 }
750
751
752 void RSP_GBI0_Tri4(Gfx *gfx)
753 {
754     uint32 w0 = gfx->words.w0;
755     uint32 w1 = gfx->words.w1;
756
757     status.primitiveType = PRIM_TRI2;
758
759     // While the next command pair is Tri2, add vertices
760     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
761
762     BOOL bTrisAdded = FALSE;
763
764     do {
765         uint32 dwFlag = (w0>>16)&0xFF;
766         LOG_UCODE("    PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", gfx->words.w0, gfx->words.w1, dwFlag);
767
768         BOOL bVisible;
769         for( int i=0; i<4; i++)
770         {
771             uint32 v0 = (w1>>(4+(i<<3))) & 0xF;
772             uint32 v1 = (w1>>(  (i<<3))) & 0xF;
773             uint32 v2 = (w0>>(  (i<<2))) & 0xF;
774             bVisible = IsTriangleVisible(v0, v2, v1);
775             LOG_UCODE("       (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)");
776             if (bVisible)
777             {
778                 DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2);
779                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
780                 {
781                     PrepareTextures();
782                     InitVertexTextureConstants();
783                 }
784
785                 if( !bTrisAdded )
786                 {
787                     CRender::g_pRender->SetCombinerAndBlender();
788                 }
789
790                 bTrisAdded = true;
791                 PrepareTriangle(v0, v2, v1);
792             }
793         }
794         
795         w0  = *(uint32 *)(g_pRDRAMu8 + dwPC+0);
796         w1  = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
797         dwPC += 8;
798
799 #ifdef DEBUGGER
800     } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2);
801 #else
802     } while (((w0)>>24) == (uint8)RSP_TRI2);
803 #endif
804
805
806     gDlistStack[gDlistStackPointer].pc = dwPC-8;
807
808     if (bTrisAdded) 
809     {
810         CRender::g_pRender->DrawTriangles();
811     }
812     
813     DEBUG_TRIANGLE(TRACE0("Pause at GBI0 TRI4"));
814
815     gRSP.DKRVtxCount=0;
816 }
817
818 //Nintro64 uses Sprite2d 
819
820
821 void RSP_RDP_Nothing(Gfx *gfx)
822 {
823     SP_Timing(RSP_RDP_Nothing);
824
825 #ifdef DEBUGGER
826     if( logWarning )
827     {
828         TRACE0("Stack Trace");
829         for( int i=0; i<gDlistStackPointer; i++ )
830         {
831             DebuggerAppendMsg("  %08X", gDlistStack[i].pc);
832         }
833
834         uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
835         DebuggerAppendMsg("PC=%08X",dwPC);
836         DebuggerAppendMsg("Warning, unknown ucode PC=%08X: 0x%08x 0x%08x\n", dwPC, gfx->words.w0, gfx->words.w1);
837     }
838     DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_UNKNOWN_OP, {TRACE0("Paused at unknown ucode\n");})
839     if( debuggerContinueWithUnknown )
840     {
841         return;
842     }
843 #endif
844         
845     if( options.bEnableHacks )
846         return;
847     
848     gDlistStackPointer=-1;
849 }
850
851
852 void RSP_RDP_InsertMatrix(Gfx *gfx)
853 {
854     float fraction;
855
856     UpdateCombinedMatrix();
857
858     if ((gfx->words.w0) & 0x20)
859     {
860         int x = ((gfx->words.w0) & 0x1F) >> 1;
861         int y = x >> 2;
862         x &= 3;
863
864         fraction = ((gfx->words.w1)>>16)/65536.0f;
865         gRSPworldProject.m[y][x] = (float)(int)gRSPworldProject.m[y][x];
866         gRSPworldProject.m[y][x] += fraction;
867
868         fraction = ((gfx->words.w1)&0xFFFF)/65536.0f;
869         gRSPworldProject.m[y][x+1] = (float)(int)gRSPworldProject.m[y][x+1];
870         gRSPworldProject.m[y][x+1] += fraction;
871     }
872     else
873     {
874         int x = ((gfx->words.w0) & 0x1F) >> 1;
875         int y = x >> 2;
876         x &= 3;
877
878         fraction = (float)fabs(gRSPworldProject.m[y][x] - (int)gRSPworldProject.m[y][x]);
879         gRSPworldProject.m[y][x] = (short)((gfx->words.w1)>>16) + fraction;
880
881         fraction = (float)fabs(gRSPworldProject.m[y][x+1] - (int)gRSPworldProject.m[y][x+1]);
882         gRSPworldProject.m[y][x+1] = (short)((gfx->words.w1)&0xFFFF) + fraction;
883     }
884
885     gRSP.bMatrixIsUpdated = false;
886     gRSP.bCombinedMatrixIsUpdated = true;
887
888 #ifdef DEBUGGER
889     if( pauseAtNext && eventToPause == NEXT_MATRIX_CMD )
890     {
891         pauseAtNext = false;
892         debuggerPause = true;
893         DebuggerAppendMsg("Pause after insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1);
894     }
895     else
896     {
897         if( pauseAtNext && logMatrix ) 
898         {
899             DebuggerAppendMsg("insert matrix: %08X, %08X", gfx->words.w0, gfx->words.w1);
900         }
901     }
902 #endif
903 }
904