Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
[mupen64plus-pandora.git] / source / gles2rice / src / RSP_GBI_Others.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 // A few ucode used in DKR and Others Special games
21
22 #include <algorithm>
23
24 #include "Render.h"
25 #include "Timing.h"
26 #include "osal_preproc.h"
27
28 uint32 dwConkerVtxZAddr=0;
29
30 static void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN);
31
32 void RDP_GFX_DLInMem(Gfx *gfx)
33 {
34     uint32 dwLimit = ((gfx->words.w0) >> 16) & 0xFF;
35     uint32 dwPush = RSP_DLIST_PUSH; //((gfx->words.w0) >> 16) & 0xFF;
36     uint32 dwAddr = 0x00000000 | (gfx->words.w1); //RSPSegmentAddr((gfx->words.w1));
37
38     LOG_UCODE("    Address=0x%08x Push: 0x%02x", dwAddr, dwPush);
39
40     switch (dwPush)
41     {
42     case RSP_DLIST_PUSH:
43         LOG_UCODE("    Pushing DisplayList 0x%08x", dwAddr);
44         gDlistStackPointer++;
45         gDlistStack[gDlistStackPointer].pc = dwAddr;
46         gDlistStack[gDlistStackPointer].countdown = dwLimit;
47
48         break;
49     case RSP_DLIST_NOPUSH:
50         LOG_UCODE("    Jumping to DisplayList 0x%08x", dwAddr);
51         gDlistStack[gDlistStackPointer].pc = dwAddr;
52         gDlistStack[gDlistStackPointer].countdown = dwLimit;
53         break;
54     }
55
56     LOG_UCODE("");
57     LOG_UCODE("\\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/");
58     LOG_UCODE("#############################################");
59 }
60
61 extern Matrix ALIGN(16, dkrMatrixTransposed)
62 void RSP_Mtx_DKR(Gfx *gfx)
63 {   
64     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
65     uint32 dwCommand = ((gfx->words.w0)>>16)&0xFF;
66     //uint32 dwLength  = ((gfx->words.w0))    &0xFFFF;
67
68     dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRMatrixAddr);
69
70     //gRSP.DKRCMatrixIndex = ((gfx->words.w0)>>22)&3;
71     bool mul=false;
72     int index = 0;
73     switch( dwCommand )
74     {
75     case 0xC0:  // DKR
76         gRSP.DKRCMatrixIndex = index = 3;
77         break;
78     case 0x80:  // DKR
79         gRSP.DKRCMatrixIndex = index = 2;
80         break;
81     case 0x40:  // DKR
82         gRSP.DKRCMatrixIndex = index = 1;
83         break;
84     case 0x20:  // DKR
85         gRSP.DKRCMatrixIndex = index = 0;
86         break;
87     case 0x00:
88         gRSP.DKRCMatrixIndex = index = 0;
89         break;
90     case 0x01:
91         //mul = true;
92         gRSP.DKRCMatrixIndex = index = 1;
93         break;
94     case 0x02:
95         //mul = true;
96         gRSP.DKRCMatrixIndex = index = 2;
97         break;
98     case 0x03:
99         //mul = true;
100         gRSP.DKRCMatrixIndex = index = 3;
101         break;
102     case 0x81:
103         index = 1;
104         mul = true;
105         break;
106     case 0x82:
107         index = 2;
108         mul = true;
109         break;
110     case 0x83:
111         index = 3;
112         mul = true;
113         break;
114     default:
115         DebuggerAppendMsg("Fix me, mtx DKR, cmd=%08X", dwCommand);
116         break;
117     }
118
119     // Load matrix from dwAddr
120     Matrix &mat = gRSP.DKRMatrixes[index];
121     LoadMatrix(dwAddr);
122
123     if( mul )
124     {
125         mat = matToLoad*gRSP.DKRMatrixes[0];
126     }
127     else
128     {
129         mat = matToLoad;
130     }
131
132     if( status.isSSEEnabled )
133         MatrixTranspose(&dkrMatrixTransposed, &mat);
134
135     DEBUGGER_IF_DUMP(logMatrix,TRACE3("DKR Matrix: cmd=0x%X, idx = %d, mul=%d", dwCommand, index, mul));
136     LOG_UCODE("    DKR Loading Mtx: %d, command=%d", index, dwCommand);
137     DEBUGGER_PAUSE_AND_DUMP(NEXT_MATRIX_CMD,{TRACE0("Paused at DKR Matrix Cmd");});
138 }
139
140 void RSP_Vtx_DKR(Gfx *gfx)
141 {
142     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
143     uint32 dwV0 = (((gfx->words.w0) >> 9 )&0x1F);
144     uint32 dwN  = (((gfx->words.w0) >>19 )&0x1F)+1;
145
146     if( gfx->words.w0 & 0x00010000 )
147     {
148         if( gRSP.DKRBillBoard )
149             gRSP.DKRVtxCount = 1;
150     }
151     else
152     {
153         gRSP.DKRVtxCount = 0;
154     }
155
156     dwV0 += gRSP.DKRVtxCount;
157
158     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN);
159     DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));});
160
161     VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1)));
162     VTX_DUMP(TRACE2("Vtx_DKR, v0=%d n=%d", dwV0, dwN));
163
164     if (dwV0 >= 32)
165         dwV0 = 31;
166     
167     if ((dwV0 + dwN) > 32)
168     {
169         WARNING(TRACE0("Warning, attempting to load into invalid vertex positions"));
170         dwN = 32 - dwV0;
171     }
172
173     
174     //if( dwAddr == 0 || dwAddr < 0x2000)
175     {
176         dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr);
177     }
178
179     // Check that address is valid...
180     if ((dwAddr + (dwN*16)) > g_dwRamSize)
181     {
182         WARNING(TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr));
183     }
184     else
185     {
186         ProcessVertexDataDKR(dwAddr, dwV0, dwN);
187
188         status.dwNumVertices += dwN;
189
190         RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN);
191     }
192 }
193
194
195 void RSP_Vtx_Gemini(Gfx *gfx)
196 {
197     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
198     uint32 dwV0 =  (((gfx->words.w0)>>9)&0x1F);
199     uint32 dwN  = (((gfx->words.w0) >>19 )&0x1F);
200
201     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN);
202     DEBUGGER_ONLY_IF( (pauseAtNext && (eventToPause==NEXT_VERTEX_CMD||eventToPause==NEXT_MATRIX_CMD)), {DebuggerAppendMsg("DKR Vtx: Cmd0=%08X, Cmd1=%08X", (gfx->words.w0), (gfx->words.w1));});
203
204     VTX_DUMP(TRACE2("Vtx_DKR, cmd0=%08X cmd1=%08X", (gfx->words.w0), (gfx->words.w1)));
205
206     if (dwV0 >= 32)
207         dwV0 = 31;
208
209     if ((dwV0 + dwN) > 32)
210     {
211         TRACE0("Warning, attempting to load into invalid vertex positions");
212         dwN = 32 - dwV0;
213     }
214
215
216     //if( dwAddr == 0 || dwAddr < 0x2000)
217     {
218         dwAddr = (gfx->words.w1)+RSPSegmentAddr(gRSP.dwDKRVtxAddr);
219     }
220
221     // Check that address is valid...
222     if ((dwAddr + (dwN*16)) > g_dwRamSize)
223     {
224         TRACE1("ProcessVertexData: Address out of range (0x%08x)", dwAddr);
225     }
226     else
227     {
228         ProcessVertexDataDKR(dwAddr, dwV0, dwN);
229
230         status.dwNumVertices += dwN;
231
232         RDP_GFX_DumpVtxInfoDKR(dwAddr, dwV0, dwN);
233     }
234 }
235
236 // DKR verts are extra 4 bytes
237 void RDP_GFX_DumpVtxInfoDKR(uint32 dwAddr, uint32 dwV0, uint32 dwN)
238 {
239 #ifdef DEBUGGER
240         uint32 dwV;
241         int i;
242
243         short * psSrc = (short *)(g_pRDRAMu8 + dwAddr);
244
245         i = 0;
246         for (dwV = dwV0; dwV < dwV0 + dwN; dwV++)
247         {
248             float x = (float)psSrc[(i + 0) ^ 1];
249             float y = (float)psSrc[(i + 1) ^ 1];
250             float z = (float)psSrc[(i + 2) ^ 1];
251
252             //uint16 wFlags = CRender::g_pRender->m_dwVecFlags[dwV]; //(uint16)psSrc[3^0x1];
253
254             uint16 wA = psSrc[(i + 3) ^ 1];
255             uint16 wB = psSrc[(i + 4) ^ 1];
256
257             uint8 a = wA>>8;
258             uint8 b = (uint8)wA;
259             uint8 c = wB>>8;
260             uint8 d = (uint8)wB;
261
262             XVECTOR4 & t = g_vecProjected[dwV];
263
264
265             LOG_UCODE(" #%02d Pos: {% 6f,% 6f,% 6f} Extra: %02x %02x %02x %02x (transf: {% 6f,% 6f,% 6f})",
266                 dwV, x, y, z, a, b, c, d, t.x, t.y, t.z );
267
268             i+=5;
269         }
270
271
272         uint16 * pwSrc = (uint16 *)(g_pRDRAMu8 + dwAddr);
273         i = 0;
274         for (dwV = dwV0; dwV < dwV0 + dwN; dwV++)
275         {
276             LOG_UCODE(" #%02d %04x %04x %04x %04x %04x",
277                 dwV, pwSrc[(i + 0) ^ 1],
278                 pwSrc[(i + 1) ^ 1],
279                 pwSrc[(i + 2) ^ 1],
280                 pwSrc[(i + 3) ^ 1],
281                 pwSrc[(i + 4) ^ 1]);
282
283             i += 5;
284         }
285
286 #endif // DEBUGGER
287 }
288
289 void DLParser_Set_Addr_Ucode6(Gfx *gfx)
290 {
291     gRSP.dwDKRMatrixAddr = (gfx->words.w0)&0x00FFFFFF;
292     gRSP.dwDKRVtxAddr = (gfx->words.w1)&0x00FFFFFF;
293     gRSP.DKRVtxCount=0;
294 }
295
296
297
298 void RSP_Vtx_WRUS(Gfx *gfx)
299 {
300     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
301     uint32 dwLength = ((gfx->words.w0))&0xFFFF;
302
303     uint32 dwN= (dwLength + 1) / 0x210;
304     //uint32 dwN= (dwLength >> 9);
305     //uint32 dwV0 = (((gfx->words.w0)>>16)&0x3f)/5;
306     uint32 dwV0 = (((gfx->words.w0)>>16)&0xFF)/5;
307
308     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength);
309
310     if (dwV0 >= 32)
311         dwV0 = 31;
312     
313     if ((dwV0 + dwN) > 32)
314     {
315         TRACE0("Warning, attempting to load into invalid vertex positions");
316         dwN = 32 - dwV0;
317     }
318
319     ProcessVertexData(dwAddr, dwV0, dwN);
320
321     status.dwNumVertices += dwN;
322
323     DisplayVertexInfo(dwAddr, dwV0, dwN);
324 }
325
326 void RSP_Vtx_ShadowOfEmpire(Gfx *gfx)
327 {
328     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
329     uint32 dwLength = ((gfx->words.w0))&0xFFFF;
330
331     uint32 dwN= (((gfx->words.w0) >> 4) & 0xFFF) / 33 + 1;
332     uint32 dwV0 = 0;
333
334     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d, Length: 0x%04x", dwAddr, dwV0, dwN, dwLength);
335
336     if (dwV0 >= 32)
337         dwV0 = 31;
338
339     if ((dwV0 + dwN) > 32)
340     {
341         TRACE0("Warning, attempting to load into invalid vertex positions");
342         dwN = 32 - dwV0;
343     }
344
345     ProcessVertexData(dwAddr, dwV0, dwN);
346
347     status.dwNumVertices += dwN;
348
349     DisplayVertexInfo(dwAddr, dwV0, dwN);
350 }
351
352
353 void RSP_DL_In_MEM_DKR(Gfx *gfx)
354 {
355     // This cmd is likely to execute number of ucode at the given address
356     uint32 dwAddr = (gfx->words.w1);//RSPSegmentAddr((gfx->words.w1));
357     {
358         gDlistStackPointer++;
359         gDlistStack[gDlistStackPointer].pc = dwAddr;
360         gDlistStack[gDlistStackPointer].countdown = (((gfx->words.w0)>>16)&0xFF);
361     }
362 }
363 uint16 ConvertYUVtoR5G5B5X1(int y, int u, int v)
364 {
365     float r = y + (1.370705f * (v-128));
366     float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128));
367     float b = y + (1.732446f * (u-128));
368     r *= 0.125f;
369     g *= 0.125f;
370     b *= 0.125f;
371
372     //clipping the result
373     if (r > 32) r = 32;
374     if (g > 32) g = 32;
375     if (b > 32) b = 32;
376     if (r < 0) r = 0;
377     if (g < 0) g = 0;
378     if (b < 0) b = 0;
379
380     uint16 c = (uint16)(((uint16)(r) << 11) |
381                         ((uint16)(g) << 6)  |
382                         ((uint16)(b) << 1)  | 1);
383     return c;
384 }
385
386 void TexRectToN64FrameBuffer_YUV_16b(uint32 x0, uint32 y0, uint32 width, uint32 height)
387 {
388     // Convert YUV image at TImg and Copy the texture into the N64 RDRAM framebuffer memory
389
390     uint32 n64CIaddr = g_CI.dwAddr;
391     uint32 n64CIwidth = g_CI.dwWidth;
392
393     for (uint32 y = 0; y < height; y++)
394     {
395         uint32* pN64Src = (uint32*)(g_pRDRAMu8+(g_TI.dwAddr&(g_dwRamSize-1)))+y*(g_TI.dwWidth>>1);
396         uint16* pN64Dst = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth;
397
398         for (uint32 x = 0; x < width; x+=2)
399         {
400             uint32 val = *pN64Src++;
401             int y0 = (uint8)val&0xFF;
402             int v  = (uint8)(val>>8)&0xFF;
403             int y1 = (uint8)(val>>16)&0xFF;
404             int u  = (uint8)(val>>24)&0xFF;
405
406             pN64Dst[x+x0] = ConvertYUVtoR5G5B5X1(y0,u,v);
407             pN64Dst[x+x0+1] = ConvertYUVtoR5G5B5X1(y1,u,v);
408         }
409     }
410 }
411
412 extern uObjMtxReal gObjMtxReal;
413 void DLParser_OgreBatter64BG(Gfx *gfx)
414 {
415 #ifdef DEBUGGER
416 uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
417 uObjTxSprite *ptr = (uObjTxSprite*)(g_pRDRAMu8+dwAddr);
418 #endif
419
420 PrepareTextures();
421
422 CTexture *ptexture = g_textures[0].m_pCTexture;
423 TexRectToN64FrameBuffer_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, ptexture->m_dwWidth, ptexture->m_dwHeight, gRSP.curTile);
424
425 #ifdef DEBUGGER
426 CRender::g_pRender->DrawSpriteR(*ptr, false);
427
428 DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && 
429 (eventToPause==NEXT_OBJ_TXT_CMD|| eventToPause==NEXT_FLUSH_TRI)),
430 {DebuggerAppendMsg("OgreBatter 64 BG: Addr=%08X\n", dwAddr);});
431 #endif
432 }
433
434 void DLParser_Bomberman2TextRect(Gfx *gfx)
435 {
436     // Bomberman 64 - The Second Attack! (U) [!]
437     // The 0x02 cmd, list a TexRect cmd
438
439     if( options.enableHackForGames == HACK_FOR_OGRE_BATTLE && gRDP.tiles[7].dwFormat == TXT_FMT_YUV )
440     {
441         TexRectToN64FrameBuffer_YUV_16b( (uint32)gObjMtxReal.X, (uint32)gObjMtxReal.Y, 16, 16);
442         //DLParser_OgreBatter64BG((gfx->words.w0), (gfx->words.w1));
443         return;
444     }
445
446     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
447     uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr);
448
449     uint32 dwTile   = gRSP.curTile;
450
451     PrepareTextures();
452     
453     //CRender::g_pRender->SetCombinerAndBlender();
454
455     uObjTxSprite drawinfo;
456     memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite));
457     CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32);
458
459     DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((pauseAtNext && (eventToPause==NEXT_TRIANGLE|| eventToPause==NEXT_FLUSH_TRI)),
460         {
461             DebuggerAppendMsg("Bomberman 64 - TextRect: Addr=%08X\n", dwAddr);
462             dwAddr &= (g_dwRamSize-1);
463             DebuggerAppendMsg("%08X-%08X-%08X-%08X-%08X-%08X\n", RDRAM_UWORD(dwAddr), RDRAM_UWORD(dwAddr+4),
464                 RDRAM_UWORD(dwAddr+8), RDRAM_UWORD(dwAddr+12), RDRAM_UWORD(dwAddr+16), RDRAM_UWORD(dwAddr+20) );
465         }
466     );
467 }
468
469
470 void RSP_MoveWord_DKR(Gfx *gfx)
471 {
472     SP_Timing(RSP_GBI1_MoveWord);
473     uint32 dwNumLights;
474
475     switch ((gfx->words.w0) & 0xFF)
476     {
477     case RSP_MOVE_WORD_NUMLIGHT:
478         dwNumLights = (gfx->words.w1)&0x7;
479         LOG_UCODE("    RSP_MOVE_WORD_NUMLIGHT: Val:%d", dwNumLights);
480
481         gRSP.ambientLightIndex = dwNumLights;
482         SetNumLights(dwNumLights);
483         //gRSP.DKRBillBoard = (gfx->words.w1)&0x1 ? true : false;
484         gRSP.DKRBillBoard = (gfx->words.w1)&0x7 ? true : false;
485
486         LOG_UCODE("    gRSP.DKRBillBoard = %d", gRSP.DKRBillBoard);
487         DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select gRSP.DKRBillBoard %s, cmd0=%08X, cmd1=%08X", gRSP.DKRBillBoard?"true":"false", (gfx->words.w0), (gfx->words.w1));});
488         break;
489     case RSP_MOVE_WORD_LIGHTCOL:
490         gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&7;
491         //gRSP.DKRCMatrixIndex = ((gfx->words.w1)>>6)&3;
492         LOG_UCODE("    gRSP.DKRCMatrixIndex = %d", gRSP.DKRCMatrixIndex);
493         DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_MATRIX_CMD, {DebuggerAppendMsg("DKR Moveword, select matrix %d, cmd0=%08X, cmd1=%08X", gRSP.DKRCMatrixIndex, (gfx->words.w0), (gfx->words.w1));});
494         break;
495     default:
496         RSP_GBI1_MoveWord(gfx);
497         break;
498     }
499 }
500
501
502 void RSP_DMA_Tri_DKR(Gfx *gfx)
503 {
504     BOOL bTrisAdded = FALSE;
505     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
506     uint32 flag = ((gfx->words.w0) & 0xFF0000) >> 16;
507     if (flag&1) 
508         CRender::g_pRender->SetCullMode(false,true);
509     else
510         CRender::g_pRender->SetCullMode(false,false);
511
512     uint32 dwNum = (((gfx->words.w0) &  0xFFF0) >>4 );
513     uint32 * pData = (uint32*)&g_pRDRAMu32[dwAddr/4];
514
515     if( dwAddr+16*dwNum >= g_dwRamSize )
516     {
517         TRACE0("DMATRI invalid memory pointer");
518         return;
519     }
520
521     TRI_DUMP(TRACE2("DMATRI, addr=%08X, Cmd0=%08X\n", dwAddr, (gfx->words.w0)));
522
523     status.primitiveType = PRIM_DMA_TRI;
524
525     for (uint32 i = 0; i < dwNum; i++)
526     {
527         LOG_UCODE("    0x%08x: %08x %08x %08x %08x", dwAddr + i*16,
528             pData[0], pData[1], pData[2], pData[3]);
529
530         uint32 dwInfo = pData[0];
531
532         uint32 dwV0 = (dwInfo >> 16) & 0x1F;
533         uint32 dwV1 = (dwInfo >>  8) & 0x1F;
534         uint32 dwV2 = (dwInfo      ) & 0x1F;
535
536         TRI_DUMP(TRACE5("DMATRI: %d, %d, %d (%08X-%08X)", dwV0,dwV1,dwV2,(gfx->words.w0),(gfx->words.w1)));
537
538         //if (IsTriangleVisible(dwV0, dwV1, dwV2))
539         {
540             DEBUG_DUMP_VERTEXES("DmaTri", dwV0, dwV1, dwV2);
541             LOG_UCODE("   Tri: %d,%d,%d", dwV0, dwV1, dwV2);
542             if (!bTrisAdded )//&& CRender::g_pRender->IsTextureEnabled())
543             {
544                 PrepareTextures();
545                 InitVertexTextureConstants();
546             }
547
548             // Generate texture coordinates
549             short s0 = ((short)(pData[1]>>16));
550             short t0 = ((short)(pData[1]&0xFFFF));
551             short s1 = ((short)(pData[2]>>16));
552             short t1 = ((short)(pData[2]&0xFFFF));
553             short s2 = ((short)(pData[3]>>16));
554             short t2 = ((short)(pData[3]&0xFFFF));
555
556             TRI_DUMP( 
557             {
558                 DebuggerAppendMsg(" (%d,%d), (%d,%d), (%d,%d)",s0,t0,s1,t1,s2,t2);
559                 DebuggerAppendMsg(" (%08X), (%08X), (%08X), (%08X)",pData[0],pData[1],pData[2],pData[3]);
560             });
561             CRender::g_pRender->SetVtxTextureCoord(dwV0, s0, t0);
562             CRender::g_pRender->SetVtxTextureCoord(dwV1, s1, t1);
563             CRender::g_pRender->SetVtxTextureCoord(dwV2, s2, t2);
564
565             if( !bTrisAdded )
566             {
567                 CRender::g_pRender->SetCombinerAndBlender();
568             }
569
570             bTrisAdded = true;
571             PrepareTriangle(dwV0, dwV1, dwV2);
572         }
573
574         pData += 4;
575
576     }
577
578     if (bTrisAdded) 
579     {
580         CRender::g_pRender->DrawTriangles();
581     }
582     gRSP.DKRVtxCount=0;
583 }
584
585 uint32 dwPDCIAddr = 0;
586 void ProcessVertexDataPD(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
587 void RSP_Vtx_PD(Gfx *gfx)
588 {
589     SP_Timing(RSP_GBI0_Vtx);
590
591     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
592     uint32 dwV0 =  ((gfx->words.w0)>>16)&0x0F;
593     uint32 dwN  = (((gfx->words.w0)>>20)&0x0F)+1;
594     //uint32 dwLength = ((gfx->words.w0))&0xFFFF;
595
596     LOG_UCODE("    Address 0x%08x, v0: %d, Num: %d", dwAddr, dwV0, dwN);
597
598     ProcessVertexDataPD(dwAddr, dwV0, dwN);
599     status.dwNumVertices += dwN;
600 }
601
602 void RSP_Set_Vtx_CI_PD(Gfx *gfx)
603 {
604     // Color index buf address
605     dwPDCIAddr = RSPSegmentAddr((gfx->words.w1));
606 }
607
608 void RSP_Tri4_PD(Gfx *gfx)
609 {
610     uint32 w0 = gfx->words.w0;
611     uint32 w1 = gfx->words.w1;
612
613     status.primitiveType = PRIM_TRI2;
614
615     // While the next command pair is Tri2, add vertices
616     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
617
618     BOOL bTrisAdded = FALSE;
619
620     do {
621         uint32 dwFlag = (w0>>16)&0xFF;
622         LOG_UCODE("    PD Tri4: 0x%08x 0x%08x Flag: 0x%02x", w0, w1, dwFlag);
623
624         BOOL bVisible;
625         for( uint32 i=0; i<4; i++)
626         {
627             uint32 v0 = (w1>>(4+(i<<3))) & 0xF;
628             uint32 v1 = (w1>>(  (i<<3))) & 0xF;
629             uint32 v2 = (w0>>(  (i<<2))) & 0xF;
630             bVisible = IsTriangleVisible(v0, v2, v1);
631             LOG_UCODE("       (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)");
632             if (bVisible)
633             {
634                 DEBUG_DUMP_VERTEXES("Tri4_PerfectDark 1/2", v0, v1, v2);
635                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
636                 {
637                     PrepareTextures();
638                     InitVertexTextureConstants();
639                 }
640
641                 if( !bTrisAdded )
642                 {
643                     CRender::g_pRender->SetCombinerAndBlender();
644                 }
645
646                 bTrisAdded = true;
647                 PrepareTriangle(v0, v2, v1);
648             }
649         }
650
651         w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0);
652         w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
653         dwPC += 8;
654
655 #ifdef DEBUGGER
656     } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>24) == (uint8)RSP_TRI2);
657 #else
658     } while ((w0>>24) == (uint8)RSP_TRI2);
659 #endif
660
661     gDlistStack[gDlistStackPointer].pc = dwPC-8;
662
663     if (bTrisAdded) 
664     {
665         CRender::g_pRender->DrawTriangles();
666     }
667
668     DEBUG_TRIANGLE(TRACE0("Pause at PD Tri4"));
669 }
670
671
672 void DLParser_Tri4_Conker(Gfx *gfx)
673 {
674     uint32 w0 = gfx->words.w0;
675     uint32 w1 = gfx->words.w1;
676
677     status.primitiveType = PRIM_TRI2;
678
679     // While the next command pair is Tri2, add vertices
680     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
681
682     BOOL bTrisAdded = FALSE;
683
684     do {
685         LOG_UCODE("    Conker Tri4: 0x%08x 0x%08x", w0, w1);
686         uint32 idx[12];
687         idx[0] = (w1   )&0x1F;
688         idx[1] = (w1>> 5)&0x1F;
689         idx[2] = (w1>>10)&0x1F;
690         idx[3] = (w1>>15)&0x1F;
691         idx[4] = (w1>>20)&0x1F;
692         idx[5] = (w1>>25)&0x1F;
693
694         idx[6] = (w0    )&0x1F;
695         idx[7] = (w0>> 5)&0x1F;
696         idx[8] = (w0>>10)&0x1F;
697
698         idx[ 9] = (((w0>>15)&0x7)<<2)|(w1>>30);
699         idx[10] = (w0>>18)&0x1F;
700         idx[11] = (w0>>23)&0x1F;
701
702         BOOL bVisible;
703         for( uint32 i=0; i<4; i++)
704         {
705             uint32 v0=idx[i*3  ];
706             uint32 v1=idx[i*3+1];
707             uint32 v2=idx[i*3+2];
708             bVisible = IsTriangleVisible(v0, v1, v2);
709             LOG_UCODE("       (%d, %d, %d) %s", v0, v1, v2, bVisible ? "": "(clipped)");
710             if (bVisible)
711             {
712                 DEBUG_DUMP_VERTEXES("Tri4 Conker:", v0, v1, v2);
713                 if (!bTrisAdded && CRender::g_pRender->IsTextureEnabled())
714                 {
715                     PrepareTextures();
716                     InitVertexTextureConstants();
717                 }
718
719                 if( !bTrisAdded )
720                 {
721                     CRender::g_pRender->SetCombinerAndBlender();
722                 }
723
724                 bTrisAdded = true;
725                 PrepareTriangle(v0, v1, v2);
726             }
727         }
728
729         w0 = *(uint32 *)(g_pRDRAMu8 + dwPC+0);
730         w1 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
731         dwPC += 8;
732
733 #ifdef DEBUGGER
734     } while (!(pauseAtNext && eventToPause==NEXT_TRIANGLE) && (w0>>28) == 1 );
735 #else
736     } while ((w0>>28) == 1);
737 #endif
738
739     gDlistStack[gDlistStackPointer].pc = dwPC-8;
740
741     if (bTrisAdded) 
742     {
743         CRender::g_pRender->DrawTriangles();
744     }
745
746     DEBUG_TRIANGLE(TRACE0("Pause at Conker Tri4"));
747 }
748
749 void RDP_GFX_Force_Vertex_Z_Conker(uint32 dwAddr)
750 {
751     VTX_DUMP( 
752     {
753         s8 * pcBase = g_pRDRAMs8 + (dwAddr&(g_dwRamSize-1));
754         uint32 * pdwBase = (uint32 *)pcBase;
755
756         for (int i = 0; i < 4; i++)
757         {
758             DebuggerAppendMsg("    %08x %08x %08x %08x", pdwBase[0], pdwBase[1], pdwBase[2], pdwBase[3]);
759             pdwBase+=4;
760         }
761     });
762
763     dwConkerVtxZAddr = dwAddr;
764     DEBUGGER_PAUSE_AND_DUMP(NEXT_VERTEX_CMD,{TRACE0("Paused at RDP_GFX_Force_Matrix_Conker Cmd");});
765 }
766
767
768
769 void DLParser_MoveMem_Conker(Gfx *gfx)
770 {
771     uint32 dwType    = ((gfx->words.w0)     ) & 0xFE;
772     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
773     if( dwType == RSP_GBI2_MV_MEM__MATRIX )
774     {
775         LOG_UCODE("    DLParser_MoveMem_Conker");
776         RDP_GFX_Force_Vertex_Z_Conker(dwAddr);
777     }
778     else if( dwType == RSP_GBI2_MV_MEM__LIGHT )
779     {
780         LOG_UCODE("    MoveMem Light Conker");
781         uint32 dwOffset2 = ((gfx->words.w0) >> 5) & 0x3FFF;
782         uint32 dwLight=0xFF;
783         if( dwOffset2 >= 0x30 )
784         {
785             dwLight = (dwOffset2 - 0x30)/0x30;
786             LOG_UCODE("    Light %d:", dwLight);
787             RSP_MoveMemLight(dwLight, dwAddr);
788         }
789         else
790         {
791             // fix me
792             //TRACE0("Check me in DLParser_MoveMem_Conker - MoveMem Light");
793         }
794         DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, 
795         {
796             DebuggerAppendMsg("RSP_MoveMemLight: %d, Addr=%08X, cmd0=%08X", dwLight, dwAddr, (gfx->words.w0));
797             TRACE0("Pause after MoveMemLight");
798         });
799     }
800     else
801     {
802         RSP_GBI2_MoveMem(gfx);
803     }
804 }
805
806 extern void ProcessVertexDataConker(uint32 dwAddr, uint32 dwV0, uint32 dwNum);
807 void RSP_Vtx_Conker(Gfx *gfx)
808 {
809     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
810     uint32 dwVEnd    = (((gfx->words.w0)   )&0xFFF)/2;
811     uint32 dwN      = (((gfx->words.w0)>>12)&0xFFF);
812     uint32 dwV0     = dwVEnd - dwN;
813
814     LOG_UCODE("    Vtx: Address 0x%08x, vEnd: %d, v0: %d, Num: %d", dwAddr, dwVEnd, dwV0, dwN);
815
816     ProcessVertexDataConker(dwAddr, dwV0, dwN);
817     status.dwNumVertices += dwN;
818     DisplayVertexInfo(dwAddr, dwV0, dwN);
819 }
820
821
822 void DLParser_MoveWord_Conker(Gfx *gfx)
823 {
824     uint32 dwType   = ((gfx->words.w0) >> 16) & 0xFF;
825     if( dwType != RSP_MOVE_WORD_NUMLIGHT )
826     {
827         RSP_GBI2_MoveWord(gfx);
828     }
829     else
830     {
831         uint32 dwNumLights = ((gfx->words.w1)/48);
832         LOG_UCODE("Conker RSP_MOVE_WORD_NUMLIGHT: %d", dwNumLights);
833         gRSP.ambientLightIndex = dwNumLights+1;
834         SetNumLights(dwNumLights);
835         DEBUGGER_PAUSE_AND_DUMP_COUNT_N( NEXT_SET_LIGHT, 
836         {
837             DebuggerAppendMsg("SetNumLights: %d", dwNumLights);
838             TRACE0("Pause after SetNumLights");
839         });
840     }
841 }
842
843 void DLParser_Ucode8_0x0(Gfx *gfx)
844 {
845     LOG_UCODE("DLParser_Ucode8_0x0");
846
847     if( (gfx->words.w0) == 0 && (gfx->words.w1) )
848     {
849         uint32 newaddr = RSPSegmentAddr((gfx->words.w1));
850
851         if( newaddr && newaddr < g_dwRamSize)
852         {
853             if( gDlistStackPointer < MAX_DL_STACK_SIZE-1 )
854             {
855                 gDlistStackPointer++;
856                 gDlistStack[gDlistStackPointer].pc = newaddr+8; // Always skip the first 2 entries
857                 gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
858             }
859             else
860             {
861                 DebuggerAppendMsg("Error, gDlistStackPointer overflow");
862             }
863         }
864     }
865     else
866     {
867         LOG_UCODE("DLParser_Ucode8_0x0, skip 0x%08X, 0x%08x", (gfx->words.w0), (gfx->words.w1));
868         gDlistStack[gDlistStackPointer].pc += 8;
869     }
870 }
871
872
873 uint32 Rogue_Squadron_Vtx_XYZ_Cmd;
874 uint32 Rogue_Squadron_Vtx_XYZ_Addr;
875 uint32 Rogue_Squadron_Vtx_Color_Cmd;
876 uint32 Rogue_Squadron_Vtx_Color_Addr;
877 uint32 GSBlkAddrSaves[100][2];
878
879 void ProcessVertexData_Rogue_Squadron(uint32 dwXYZAddr, uint32 dwColorAddr, uint32 dwXYZCmd, uint32 dwColorCmd);
880
881 void DLParser_RS_Color_Buffer(Gfx *gfx)
882 {
883     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
884     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
885
886     if( dwAddr > g_dwRamSize )
887     {
888         TRACE0("DL, addr is wrong");
889         dwAddr = (gfx->words.w1)&(g_dwRamSize-1);
890     }
891
892     Rogue_Squadron_Vtx_Color_Cmd = (gfx->words.w0);
893     Rogue_Squadron_Vtx_Color_Addr = dwAddr;
894
895     LOG_UCODE("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
896 #ifdef DEBUGGER
897     if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) )
898     {
899         DebuggerAppendMsg("Vtx_Color at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
900         if( dwAddr < g_dwRamSize )
901         {
902             DumpHex(dwAddr, min(64, g_dwRamSize-dwAddr));
903         }
904     }
905 #endif
906
907     ProcessVertexData_Rogue_Squadron(Rogue_Squadron_Vtx_XYZ_Addr, Rogue_Squadron_Vtx_Color_Addr, Rogue_Squadron_Vtx_XYZ_Cmd, Rogue_Squadron_Vtx_Color_Cmd);
908
909 }
910
911
912 void DLParser_RS_Vtx_Buffer(Gfx *gfx)
913 {
914     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
915     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
916     if( dwAddr > g_dwRamSize )
917     {
918         TRACE0("DL, addr is wrong");
919         dwAddr = (gfx->words.w1)&(g_dwRamSize-1);
920     }
921
922     LOG_UCODE("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
923     Rogue_Squadron_Vtx_XYZ_Cmd = (gfx->words.w0);
924     Rogue_Squadron_Vtx_XYZ_Addr = dwAddr;
925
926 #ifdef DEBUGGER
927     if( pauseAtNext && (eventToPause == NEXT_VERTEX_CMD ) )
928     {
929         DebuggerAppendMsg("Vtx_XYZ at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
930         if( dwAddr < g_dwRamSize )
931         {
932             DumpHex(dwAddr, min(64, g_dwRamSize-dwAddr));
933         }
934     }
935 #endif
936 }
937
938
939 void DLParser_RS_Block(Gfx *gfx)
940 {
941     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
942     LOG_UCODE("ucode 0x80 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
943 }
944
945 void DLParser_RS_MoveMem(Gfx *gfx)
946 {
947     //uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
948     //uint32 cmd1 = ((dwPC)&0x00FFFFFF)|0x80000000;
949     RSP_GBI1_MoveMem(gfx);
950     /*
951     LOG_UCODE("RS_MoveMem", ((gfx->words.w0)>>24));
952     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
953     dwPC+=8;
954     uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC);
955     uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
956     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, dwCmd2, dwCmd3);
957     dwPC+=8;
958     uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + dwPC);
959     uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
960     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd4, dwCmd5);
961     */
962     gDlistStack[gDlistStackPointer].pc += 16;
963
964     //DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, {
965     //  DebuggerAppendMsg("Pause after RS_MoveMem at: %08X\n", dwPC-8);
966     //});
967
968 }
969
970 void DLParser_RS_0xbe(Gfx *gfx)
971 {
972     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
973     LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24));
974     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
975     dwPC+=8;
976     uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC);
977     uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
978     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, dwCmd2, dwCmd3);
979     gDlistStack[gDlistStackPointer].pc += 8;
980
981     DEBUGGER_PAUSE_AND_DUMP(NEXT_SET_MODE_CMD, {
982         DebuggerAppendMsg("Pause after RS_0xbe at: %08X\n", dwPC-8);
983         DebuggerAppendMsg("\t0x%08x 0x%08x", (gfx->words.w0), (gfx->words.w1));
984         DebuggerAppendMsg("\t0x%08x 0x%08x", dwCmd2, dwCmd3);
985     });
986 }
987
988
989 void DLParser_Ucode8_EndDL(Gfx *gfx)
990 {
991 #ifdef DEBUGGER
992     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
993 #endif
994
995     RDP_GFX_PopDL();
996     DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, DebuggerAppendMsg("PC=%08X: EndDL, return to %08X\n\n", dwPC, gDlistStack[gDlistStackPointer].pc));
997 }
998
999 void DLParser_Ucode8_DL(Gfx *gfx)   // DL Function Call
1000 {
1001 #ifdef DEBUGGER
1002     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1003 #endif
1004
1005     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
1006     uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr);
1007     uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4);
1008
1009     if( dwAddr > g_dwRamSize )
1010     {
1011         TRACE0("DL, addr is wrong");
1012         dwAddr = (gfx->words.w1)&(g_dwRamSize-1);
1013     }
1014
1015     // Detect looping
1016     /*if(gDlistStackPointer>0 )
1017        {
1018        for( int i=0; i<gDlistStackPointer; i++ )
1019            {
1020            if(gDlistStack[i].addr == dwAddr+8)
1021                {
1022                TRACE1("Detected DL looping, PC=%08X", dwPC );
1023                DLParser_Ucode8_EndDL(0,0);
1024                return;
1025                }
1026            }
1027         }*/
1028
1029     if( gDlistStackPointer < MAX_DL_STACK_SIZE-1 )
1030     {
1031         gDlistStackPointer++;
1032         gDlistStack[gDlistStackPointer].pc = dwAddr+16;
1033         gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
1034     }
1035     else
1036     {
1037         DebuggerAppendMsg("Error, gDlistStackPointer overflow");
1038         RDP_GFX_PopDL();
1039     }
1040
1041     GSBlkAddrSaves[gDlistStackPointer][0]=GSBlkAddrSaves[gDlistStackPointer][1]=0;
1042     if( (dwCmd2>>24) == 0x80 )
1043     {
1044         GSBlkAddrSaves[gDlistStackPointer][0] = dwCmd2;
1045         GSBlkAddrSaves[gDlistStackPointer][1] = dwCmd3;
1046     }
1047
1048     DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, 
1049     DebuggerAppendMsg("\nPC=%08X: Call DL at Address %08X - %08X, %08X\n\n", 
1050     dwPC, dwAddr, dwCmd2, dwCmd3));
1051 }
1052
1053 void DLParser_Ucode8_JUMP(Gfx *gfx) // DL Function Call
1054 {
1055     if( ((gfx->words.w0)&0x00FFFFFF) == 0 )
1056     {
1057 #ifdef DEBUGGER
1058         uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1059 #endif
1060
1061         uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
1062
1063         if( dwAddr > g_dwRamSize )
1064         {
1065             TRACE0("DL, addr is wrong");
1066             dwAddr = (gfx->words.w1)&(g_dwRamSize-1);
1067         }
1068
1069 #ifdef DEBUGGER
1070         uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwAddr);
1071         uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwAddr+4);
1072 #endif
1073
1074         gDlistStack[gDlistStackPointer].pc = dwAddr+8; // Jump to new address
1075         DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, 
1076             DebuggerAppendMsg("\nPC=%08X: Jump to Address %08X - %08X, %08X\n\n", dwPC, dwAddr, dwCmd2, dwCmd3));
1077     }
1078     else
1079     {
1080         uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1081         LOG_UCODE("ucode 0x07 at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1082     }
1083 }
1084
1085 void DLParser_Ucode8_Unknown(Gfx *gfx)
1086 {
1087     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1088     LOG_UCODE("ucode %02X at PC=%08X: 0x%08x 0x%08x\n", ((gfx->words.w0)>>24), dwPC, (gfx->words.w0), (gfx->words.w1));
1089 }
1090
1091 void DLParser_Unknown_Skip1(Gfx *gfx)
1092 {
1093     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1094     LOG_UCODE("ucode %02X, skip 1", ((gfx->words.w0)>>24));
1095     gfx++;
1096     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1097     dwPC+=8;
1098     gfx++;
1099     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1100     gDlistStack[gDlistStackPointer].pc += 8;
1101 }
1102
1103 void DLParser_Unknown_Skip2(Gfx *gfx)
1104 {
1105     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1106     LOG_UCODE("ucode %02X, skip 2", ((gfx->words.w0)>>24));
1107     gfx++;
1108     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1109     dwPC+=8;
1110     gfx++;
1111     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1112     dwPC+=8;
1113     gfx++;
1114     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1115     gDlistStack[gDlistStackPointer].pc += 16;
1116 }
1117
1118 void DLParser_Unknown_Skip3(Gfx *gfx)
1119 {
1120     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1121     LOG_UCODE("ucode %02X, skip 3", ((gfx->words.w0)>>24));
1122     gfx++;
1123     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1124     dwPC+=8;
1125     gfx++;
1126     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1127     dwPC+=8;
1128     gfx++;
1129     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1130     dwPC+=8;
1131     gfx++;
1132     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1133     gDlistStack[gDlistStackPointer].pc += 24;
1134 }
1135
1136 void DLParser_Unknown_Skip4(Gfx *gfx)
1137 {
1138     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1139     LOG_UCODE("ucode %02X, skip 4", ((gfx->words.w0)>>24));
1140     gfx++;
1141     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1142     dwPC+=8;
1143     gfx++;
1144     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1145     dwPC+=8;
1146     gfx++;
1147     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1148     dwPC+=8;
1149     gfx++;
1150     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1151     dwPC+=8;
1152     gfx++;
1153     LOG_UCODE("\tPC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1154     gDlistStack[gDlistStackPointer].pc += 32;
1155 }
1156
1157 void DLParser_Ucode8_0x05(Gfx *gfx)
1158 {
1159     // Be careful, 0x05 is variable length ucode
1160     /*
1161     0028E4E0: 05020088, 04D0000F - Reserved1
1162     0028E4E8: 6BDC0306, 00000000 - G_NOTHING
1163     0028E4F0: 05010130, 01B0000F - Reserved1
1164     0028E4F8: 918A01CA, 1EC5FF3B - G_NOTHING
1165     0028E500: 05088C68, F5021809 - Reserved1
1166     0028E508: 04000405, 00000000 - RSP_VTX
1167     0028E510: 102ECE60, 202F2AA0 - G_NOTHING
1168     0028E518: 05088C90, F5021609 - Reserved1
1169     0028E520: 04050405, F0F0F0F0 - RSP_VTX
1170     0028E528: 102ED0C0, 202F2D00 - G_NOTHING
1171     0028E530: B5000000, 00000000 - RSP_LINE3D
1172     0028E538: 8028E640, 8028E430 - G_NOTHING
1173     0028E540: 00000000, 00000000 - RSP_SPNOOP
1174     */
1175
1176     if((gfx->words.w1) == 0)
1177         return;
1178     else
1179         DLParser_Unknown_Skip4(gfx);
1180 }
1181
1182 void DLParser_Ucode8_0xb4(Gfx *gfx)
1183 {
1184 #ifdef DEBUGGER
1185     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
1186 #endif
1187
1188     if(((gfx->words.w0)&0xFF) == 0x06)
1189         DLParser_Unknown_Skip3(gfx);
1190     else if(((gfx->words.w0)&0xFF) == 0x04)
1191         DLParser_Unknown_Skip1(gfx);
1192     else if(((gfx->words.w0)&0xFFF) == 0x600)
1193         DLParser_Unknown_Skip3(gfx);
1194     else
1195     {
1196 #ifdef DEBUGGER
1197         if(pauseAtNext)
1198         {
1199             DebuggerAppendMsg("ucode 0xb4 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8,
1200                 (gfx->words.w0), (gfx->words.w1));
1201         }
1202 #endif
1203         DLParser_Unknown_Skip3(gfx);
1204     }
1205 }
1206
1207 void DLParser_Ucode8_0xb5(Gfx *gfx)
1208 {
1209     uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1210     LOG_UCODE("ucode 0xB5 at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
1211
1212     uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8);
1213     uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+12);
1214     LOG_UCODE("     : 0x%08x 0x%08x\n", dwCmd2, dwCmd3);
1215
1216     //if( dwCmd2 == 0 && dwCmd3 == 0 )
1217     {
1218         DLParser_Ucode8_EndDL(gfx); // Check me
1219         return;
1220     }
1221
1222     gDlistStack[gDlistStackPointer].pc += 8;
1223     return;
1224
1225
1226     if( GSBlkAddrSaves[gDlistStackPointer][0] == 0 || GSBlkAddrSaves[gDlistStackPointer][1] == 0 )
1227     {
1228 #ifdef DEBUGGER
1229         if( pauseAtNext && eventToPause == NEXT_DLIST)
1230         {
1231             DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, no next blk\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1232         }
1233 #endif
1234         DLParser_Ucode8_EndDL(gfx); // Check me
1235         return;
1236     }
1237
1238     if( ((dwCmd2>>24)!=0x80 && (dwCmd2>>24)!=0x00 ) || ((dwCmd3>>24)!=0x80 && (dwCmd3>>24)!=0x00 ) )
1239     {
1240 #ifdef DEBUGGER
1241         if( pauseAtNext && eventToPause == NEXT_DLIST)
1242         {
1243             DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1244         }
1245 #endif
1246         DLParser_Ucode8_EndDL(gfx); // Check me
1247         return;
1248     }
1249
1250     if( (dwCmd2>>24)!= (dwCmd3>>24) )
1251     {
1252 #ifdef DEBUGGER
1253         if( pauseAtNext && eventToPause == NEXT_DLIST)
1254         {
1255             DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, Unknown\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1256         }
1257 #endif
1258         DLParser_Ucode8_EndDL(gfx); // Check me
1259         return;
1260     }
1261
1262
1263     if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 )
1264     {
1265         if( dwCmd2 < dwCmd3  )
1266         {
1267             // All right, the next block is not ucode, but data
1268 #ifdef DEBUGGER
1269             if( pauseAtNext && eventToPause == NEXT_DLIST)
1270             {
1271                 DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1272             }
1273 #endif
1274             DLParser_Ucode8_EndDL(gfx); // Check me
1275             return;
1276         }
1277
1278         uint32 dwCmd4 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF));
1279         uint32 dwCmd5 = *(uint32 *)(g_pRDRAMu8 + (dwCmd2&0x00FFFFFF)+4);
1280         uint32 dwCmd6 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF));
1281         uint32 dwCmd7 = *(uint32 *)(g_pRDRAMu8 + (dwCmd3&0x00FFFFFF)+4);
1282         if( (dwCmd4>>24) != 0x80 || (dwCmd5>>24) != 0x80 || (dwCmd6>>24) != 0x80 || (dwCmd7>>24) != 0x80 || dwCmd4 < dwCmd5 || dwCmd6 < dwCmd7 )
1283         {
1284             // All right, the next block is not ucode, but data
1285 #ifdef DEBUGGER
1286             if( pauseAtNext && eventToPause == NEXT_DLIST)
1287             {
1288                 DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1289                 DebuggerAppendMsg("%08X, %08X     %08X,%08X\n", dwCmd4, dwCmd5, dwCmd6, dwCmd7);
1290             }
1291 #endif
1292             DLParser_Ucode8_EndDL(gfx); // Check me
1293             return;
1294         }
1295
1296         gDlistStack[gDlistStackPointer].pc += 8;
1297         DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, 
1298             DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1299             );
1300         return;
1301     }
1302     else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 )
1303     {
1304 #ifdef DEBUGGER
1305         if( pauseAtNext && eventToPause == NEXT_DLIST)
1306         {
1307             DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1308         }
1309 #endif
1310         DLParser_Ucode8_EndDL(gfx); // Check me
1311         return;
1312     }
1313     else if( (dwCmd2>>24)==0x00 && (dwCmd3>>24)==0x00 )
1314     {
1315         dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+16);
1316         dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+20);
1317         if( (dwCmd2>>24)==0x80 && (dwCmd3>>24)==0x80 && dwCmd2 < dwCmd3 )
1318         {
1319             // All right, the next block is not ucode, but data
1320 #ifdef DEBUGGER
1321             if( pauseAtNext && eventToPause == NEXT_DLIST)
1322             {
1323                 DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, EndDL, next blk is data\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1324             }
1325 #endif
1326             DLParser_Ucode8_EndDL(gfx); // Check me
1327             return;
1328         }
1329         else
1330         {
1331             gDlistStack[gDlistStackPointer].pc += 8;
1332             DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, 
1333                 DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3)
1334                 );
1335             return;
1336         }
1337     }
1338
1339 #ifdef DEBUGGER
1340 uint32 dwAddr1 = RSPSegmentAddr(dwCmd2);
1341 uint32 dwAddr2 = RSPSegmentAddr(dwCmd3);
1342
1343     if( (gfx->words.w1) != 0 )
1344     {
1345         DebuggerAppendMsg("!!!! PC=%08X: 0xB5 - %08X : %08X, %08X\n", dwPC, (gfx->words.w1), dwCmd2, dwCmd3);
1346     }
1347 #endif
1348
1349     DEBUGGER_PAUSE_AND_DUMP(NEXT_DLIST, 
1350         DebuggerAppendMsg("PC=%08X: 0xB5 - %08X : %08X, %08X, continue\n", dwPC, (gfx->words.w1), dwAddr1, dwAddr2)
1351         );
1352
1353     return;
1354 }
1355
1356 void DLParser_Ucode8_0xbc(Gfx *gfx)
1357 {
1358     if( ((gfx->words.w0)&0xFFF) == 0x58C )
1359     {
1360         DLParser_Ucode8_DL(gfx);
1361     }
1362     else
1363     {
1364         uint32 dwPC = gDlistStack[gDlistStackPointer].pc-8;
1365         LOG_UCODE("ucode 0xBC at PC=%08X: 0x%08x 0x%08x\n", dwPC, (gfx->words.w0), (gfx->words.w1));
1366     }
1367 }
1368
1369 void DLParser_Ucode8_0xbd(Gfx *gfx)
1370 {
1371     /*
1372     00359A68: BD000000, DB5B0077 - RSP_POPMTX
1373     00359A70: C8C0A000, 00240024 - RDP_TriFill
1374     00359A78: 01000100, 00000000 - RSP_MTX
1375     00359A80: BD000501, DB5B0077 - RSP_POPMTX
1376     00359A88: C8C0A000, 00240024 - RDP_TriFill
1377     00359A90: 01000100, 00000000 - RSP_MTX
1378     00359A98: BD000A02, DB5B0077 - RSP_POPMTX
1379     00359AA0: C8C0A000, 00240024 - RDP_TriFill
1380     00359AA8: 01000100, 00000000 - RSP_MTX
1381     00359AB0: BD000F04, EB6F0087 - RSP_POPMTX
1382     00359AB8: C8C0A000, 00280028 - RDP_TriFill
1383     00359AC0: 01000100, 00000000 - RSP_MTX
1384     00359AC8: BD001403, DB5B0077 - RSP_POPMTX
1385     00359AD0: C8C0A000, 00240024 - RDP_TriFill
1386     00359AD8: 01000100, 00000000 - RSP_MTX
1387     00359AE0: B5000000, 00000000 - RSP_LINE3D
1388     00359AE8: 1A000000, 16000200 - G_NOTHING
1389      */
1390
1391     if( (gfx->words.w1) != 0 )
1392     {
1393         DLParser_Unknown_Skip2(gfx);
1394         return;
1395     }
1396
1397     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;
1398     LOG_UCODE("ucode 0xbd at PC=%08X: 0x%08x 0x%08x\n", dwPC-8, (gfx->words.w0), (gfx->words.w1));
1399 }
1400
1401 void DLParser_Ucode8_0xbf(Gfx *gfx)
1402 {
1403     if( ((gfx->words.w0)&0xFF) == 0x02 )
1404         DLParser_Unknown_Skip3(gfx);
1405     else
1406         DLParser_Unknown_Skip1(gfx);
1407 }
1408
1409 void PD_LoadMatrix_0xb4(uint32 addr)
1410 {
1411     const float fRecip = 1.0f / 65536.0f;
1412
1413     uint32 data[16];
1414     data[0] =  *(uint32*)(g_pRDRAMu8+addr+4+ 0);
1415     data[1] =  *(uint32*)(g_pRDRAMu8+addr+4+ 8);
1416     data[2] =  *(uint32*)(g_pRDRAMu8+addr+4+16);
1417     data[3] =  *(uint32*)(g_pRDRAMu8+addr+4+24);
1418
1419     data[8] =  *(uint32*)(g_pRDRAMu8+addr+4+32);
1420     data[9] =  *(uint32*)(g_pRDRAMu8+addr+4+40);
1421     data[10] = *(uint32*)(g_pRDRAMu8+addr+4+48);
1422     data[11] = *(uint32*)(g_pRDRAMu8+addr+4+56);
1423
1424     data[4] =  *(uint32*)(g_pRDRAMu8+addr+4+ 0+64);
1425     data[5] =  *(uint32*)(g_pRDRAMu8+addr+4+ 8+64);
1426     data[6] =  *(uint32*)(g_pRDRAMu8+addr+4+16+64);
1427     data[7] =  *(uint32*)(g_pRDRAMu8+addr+4+24+64);
1428
1429     data[12] = *(uint32*)(g_pRDRAMu8+addr+4+32+64);
1430     data[13] = *(uint32*)(g_pRDRAMu8+addr+4+40+64);
1431     data[14] = *(uint32*)(g_pRDRAMu8+addr+4+48+64);
1432     data[15] = *(uint32*)(g_pRDRAMu8+addr+4+56+64);
1433
1434
1435     for (int i = 0; i < 4; i++)
1436     {
1437         for (int j = 0; j < 4; j++) 
1438         {
1439             int  hi = *(short *)((unsigned char*)data + (((i<<3)+(j<<1)     )^0x2));
1440             int  lo = *(uint16*)((unsigned char*)data + (((i<<3)+(j<<1) + 32)^0x2));
1441             matToLoad.m[i][j] = (float)((hi<<16) | lo) * fRecip;
1442         }
1443     }
1444
1445
1446 #ifdef DEBUGGER
1447     LOG_UCODE(
1448         " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n"
1449         " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n"
1450         " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n"
1451         " %#+12.5f %#+12.5f %#+12.5f %#+12.5f\r\n",
1452         matToLoad.m[0][0], matToLoad.m[0][1], matToLoad.m[0][2], matToLoad.m[0][3],
1453         matToLoad.m[1][0], matToLoad.m[1][1], matToLoad.m[1][2], matToLoad.m[1][3],
1454         matToLoad.m[2][0], matToLoad.m[2][1], matToLoad.m[2][2], matToLoad.m[2][3],
1455         matToLoad.m[3][0], matToLoad.m[3][1], matToLoad.m[3][2], matToLoad.m[3][3]);
1456 #endif // DEBUGGER
1457 }   
1458
1459 void DLParser_RDPHalf_1_0xb4_GoldenEye(Gfx *gfx)        
1460 {
1461     SP_Timing(RSP_GBI1_RDPHalf_1);
1462     if( ((gfx->words.w1)>>24) == 0xce )
1463     {
1464         PrepareTextures();
1465         CRender::g_pRender->SetCombinerAndBlender();
1466
1467         uint32 dwPC = gDlistStack[gDlistStackPointer].pc;       // This points to the next instruction
1468
1469         //PD_LoadMatrix_0xb4(dwPC + 8*16 - 8);
1470
1471         uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*0+4);
1472         //uint32 dw2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*1+4);
1473         //uint32 dw3 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*2+4);
1474         //uint32 dw4 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*3+4);
1475         //uint32 dw5 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*4+4);
1476         //uint32 dw6 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*5+4);
1477         //uint32 dw7 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*6+4);
1478         uint32 dw8 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*7+4);
1479         uint32 dw9 = *(uint32 *)(g_pRDRAMu8 + dwPC+8*8+4);
1480
1481         uint32 r = (dw8>>16)&0xFF;
1482         uint32 g = (dw8    )&0xFF;
1483         uint32 b = (dw9>>16)&0xFF;
1484         uint32 a = (dw9    )&0xFF;
1485         uint32 color = COLOR_RGBA(r, g, b, a);
1486
1487         //int x0 = 0;
1488         //int x1 = gRDP.scissor.right;
1489         int x0 = gRSP.nVPLeftN;
1490         int x1 = gRSP.nVPRightN;
1491         int y0 = int(dw1&0xFFFF)/4;
1492         int y1 = int(dw1>>16)/4;
1493
1494         float xscale = g_textures[0].m_pCTexture->m_dwWidth / (float)(x1-x0);
1495         float yscale = g_textures[0].m_pCTexture->m_dwHeight / (float)(y1-y0);
1496         //float fs0 = (short)(dw3&0xFFFF)/32768.0f*g_textures[0].m_pCTexture->m_dwWidth;
1497         //float ft0 = (short)(dw3>>16)/32768.0f*256;
1498         CRender::g_pRender->TexRect(x0,y0,x1,y1,0,0,xscale,yscale,true,color);
1499
1500         gDlistStack[gDlistStackPointer].pc += 312;
1501
1502 #ifdef DEBUGGER
1503         if( logUcodes)
1504         {
1505             dwPC -= 8;
1506             LOG_UCODE("GoldenEye Sky at PC=%08X: 0x%08x 0x%08x", dwPC, (gfx->words.w0), (gfx->words.w1));
1507             uint32 *ptr = (uint32 *)(g_pRDRAMu8 + dwPC);
1508             for( int i=0; i<21; i++, dwPC+=16,ptr+=4 )
1509             {
1510                 LOG_UCODE("%08X: %08X %08X %08X %08X", dwPC, ptr[0], ptr[1], ptr[2], ptr[3]);
1511             }
1512         }
1513 #endif
1514
1515         DEBUGGER_PAUSE_AND_DUMP_COUNT_N(NEXT_FLUSH_TRI, {
1516             TRACE0("Pause after Golden Sky Drawing\n");
1517         });
1518     }
1519 }
1520
1521 void DLParser_RSP_DL_WorldDriver(Gfx *gfx)
1522 {
1523     uint32 dwAddr = RSPSegmentAddr((gfx->words.w1));
1524     if( dwAddr > g_dwRamSize )
1525     {
1526         RSP_RDP_NOIMPL("Error: DL addr = %08X out of range, PC=%08X", dwAddr, gDlistStack[gDlistStackPointer].pc );
1527         dwAddr &= (g_dwRamSize-1);
1528         DebuggerPauseCountN( NEXT_DLIST );
1529     }
1530
1531     LOG_UCODE("    WorldDriver DisplayList 0x%08x", dwAddr);
1532     gDlistStackPointer++;
1533     gDlistStack[gDlistStackPointer].pc = dwAddr;
1534     gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
1535
1536     LOG_UCODE("Level=%d", gDlistStackPointer+1);
1537     LOG_UCODE("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
1538 }
1539
1540 void DLParser_RSP_Pop_DL_WorldDriver(Gfx *gfx)
1541 {
1542     RDP_GFX_PopDL();
1543 }
1544
1545 void DLParser_RSP_Last_Legion_0x80(Gfx *gfx)
1546 {
1547     gDlistStack[gDlistStackPointer].pc += 16;
1548     LOG_UCODE("DLParser_RSP_Last_Legion_0x80");
1549 }
1550
1551 void DLParser_RSP_Last_Legion_0x00(Gfx *gfx)
1552 {
1553     LOG_UCODE("DLParser_RSP_Last_Legion_0x00");
1554     gDlistStack[gDlistStackPointer].pc += 16;
1555
1556     if( (gfx->words.w0) == 0 && (gfx->words.w1) )
1557     {
1558         uint32 newaddr = RSPSegmentAddr((gfx->words.w1));
1559         if( newaddr >= g_dwRamSize )
1560         {
1561             RDP_GFX_PopDL();
1562             return;
1563         }
1564
1565         //uint32 dw1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*0+4);
1566         uint32 pc1 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*1+4);
1567         uint32 pc2 = *(uint32 *)(g_pRDRAMu8 + newaddr+8*4+4);
1568         pc1 = RSPSegmentAddr(pc1);
1569         pc2 = RSPSegmentAddr(pc2);
1570
1571         if( pc1 && pc1 != 0xffffff && pc1 < g_dwRamSize)
1572         {
1573             // Need to call both DL
1574             gDlistStackPointer++;
1575             gDlistStack[gDlistStackPointer].pc = pc1;
1576             gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
1577         }
1578
1579         if( pc2 && pc2 != 0xffffff && pc2 < g_dwRamSize )
1580         {
1581             gDlistStackPointer++;
1582             gDlistStack[gDlistStackPointer].pc = pc2;
1583             gDlistStack[gDlistStackPointer].countdown = MAX_DL_COUNT;
1584         }
1585     }
1586     else if( (gfx->words.w1) == 0 )
1587     {
1588         RDP_GFX_PopDL();
1589     }
1590     else
1591     {
1592         // (gfx->words.w0) != 0
1593         RSP_RDP_Nothing(gfx);
1594         RDP_GFX_PopDL();
1595     }
1596 }
1597
1598 void DLParser_TexRect_Last_Legion(Gfx *gfx)
1599 {
1600     if( !status.bCIBufferIsRendered )
1601         g_pFrameBufferManager->ActiveTextureBuffer();
1602
1603     status.primitiveType = PRIM_TEXTRECT;
1604
1605     // This command used 128bits, and not 64 bits. This means that we have to look one 
1606     // Command ahead in the buffer, and update the PC.
1607     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;       // This points to the next instruction
1608     uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC);
1609     uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
1610
1611     gDlistStack[gDlistStackPointer].pc += 8;
1612
1613
1614     LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4));
1615
1616     uint32 dwXH     = (((gfx->words.w0)>>12)&0x0FFF)/4;
1617     uint32 dwYH     = (((gfx->words.w0)    )&0x0FFF)/4;
1618     uint32 tileno   = ((gfx->words.w1)>>24)&0x07;
1619     uint32 dwXL     = (((gfx->words.w1)>>12)&0x0FFF)/4;
1620     uint32 dwYL     = (((gfx->words.w1)    )&0x0FFF)/4;
1621
1622
1623     if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top )
1624     {
1625         // Clipping
1626         return;
1627     }
1628
1629     uint16 uS  = (uint16)(  dwCmd2>>16)&0xFFFF;
1630     uint16 uT  = (uint16)(  dwCmd2    )&0xFFFF;
1631     short s16S = *(short*)(&uS);
1632     short s16T = *(short*)(&uT);
1633
1634     uint16 uDSDX   = (uint16)((  dwCmd3>>16)&0xFFFF);
1635     uint16 uDTDY   = (uint16)((  dwCmd3    )&0xFFFF);
1636     short s16DSDX  = *(short*)(&uDSDX);
1637     short s16DTDY  = *(short*)(&uDTDY);
1638
1639     uint32 curTile = gRSP.curTile;
1640     ForceMainTextureIndex(tileno);
1641
1642     float fS0 = s16S / 32.0f;
1643     float fT0 = s16T / 32.0f;
1644
1645     float fDSDX = s16DSDX / 1024.0f;
1646     float fDTDY = s16DTDY / 1024.0f;
1647
1648     uint32 cycletype = gRDP.otherMode.cycle_type;
1649
1650     if (cycletype == CYCLE_TYPE_COPY)
1651     {
1652         fDSDX /= 4.0f;  // In copy mode 4 pixels are copied at once.
1653         dwXH++;
1654         dwYH++;
1655     }
1656     else if (cycletype == CYCLE_TYPE_FILL)
1657     {
1658         dwXH++;
1659         dwYH++;
1660     }
1661
1662     if( fDSDX == 0 )  fDSDX = 1;
1663     if( fDTDY == 0 )  fDTDY = 1;
1664
1665     float fS1 = fS0 + (fDSDX * (dwXH - dwXL));
1666     float fT1 = fT0 + (fDTDY * (dwYH - dwYL));
1667
1668     LOG_UCODE("    Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH);
1669     LOG_UCODE("           Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)",
1670         fS0, fT0, fS1, fT1, fDSDX, fDTDY);
1671     LOG_UCODE("");
1672
1673     float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS;
1674     float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT;
1675     float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS;
1676     float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT;
1677
1678     if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 &&
1679         t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 )
1680     {
1681         //Using TextRect to clear the screen
1682     }
1683     else
1684     {
1685         if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM && 
1686             g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat && 
1687             g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize && 
1688             gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b )
1689         {
1690             if( options.enableHackForGames == HACK_FOR_YOSHI )
1691             {
1692                 // Hack for Yoshi background image
1693                 PrepareTextures();
1694                 TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
1695                 DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), {
1696                     DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n",
1697                         gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1698                     DebuggerAppendMsg("Pause after TexRect for Yoshi\n");
1699                 });
1700             }
1701             else
1702             {
1703                 if( frameBufferOptions.bUpdateCIInfo )
1704                 {
1705                     PrepareTextures();
1706                     TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
1707                 }
1708
1709                 if( !status.bDirectWriteIntoRDRAM )
1710                 {
1711                     CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1712
1713                     status.dwNumTrisRendered += 2;
1714                 }
1715             }
1716         }
1717         else
1718         {
1719             CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1720             status.bFrameBufferDrawnByTriangles = true;
1721
1722             status.dwNumTrisRendered += 2;
1723         }
1724     }
1725
1726     if( status.bHandleN64RenderTexture ) 
1727         g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH);
1728
1729     ForceMainTextureIndex(curTile);
1730 }
1731