GLES2GLIDE: Some fixes from mupen64plus-ae
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / rdp.cpp
1 /*
2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002  Dave2001
4 * Copyright (c) 2003-2009  Sergey 'Gonetz' Lipski
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 //****************************************************************
22 //
23 // Glide64 - Glide Plugin for Nintendo 64 emulators
24 // Project started on December 29th, 2001
25 //
26 // Authors:
27 // Dave2001, original author, founded the project in 2001, left it in 2002
28 // Gugaman, joined the project in 2002, left it in 2002
29 // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30 // Hiroshi 'KoolSmoky' Morii, joined the project in 2007
31 //
32 //****************************************************************
33 //
34 // To modify Glide64:
35 // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
36 // * Do NOT send me the whole project or file that you modified.  Take out your modified code sections, and tell me where to put them.  If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
37 //
38 //****************************************************************
39
40 #include <math.h>
41 #include "Gfx_1.3.h"
42 #include "m64p.h"
43 #include "Ini.h"
44 #include "Config.h"
45 #include "3dmath.h"
46 #include "Util.h"
47 #include "Debugger.h"
48 #include "Combine.h"
49 #include "TexCache.h"
50 #include "TexBuffer.h"
51 #include "FBtoScreen.h"
52 #include "CRC.h"
53
54 #ifdef PAULSCODE
55 #include "FrameSkipper.h"
56 extern FrameSkipper frameSkipper;
57 #endif
58
59 #ifdef PERFORMANCE
60 #include "ticks.h"
61 #endif
62
63 #ifdef __ARM_NEON__
64 #include "arm_neon.h"
65 //#include "ticks.h"
66 #endif
67
68 /*
69 const int NumOfFormats = 3;
70 SCREEN_SHOT_FORMAT ScreenShotFormats[NumOfFormats] = { {wxT("BMP"), wxT("bmp"), wxBITMAP_TYPE_BMP}, {wxT("PNG"), wxT("png"), wxBITMAP_TYPE_PNG}, {wxT("JPEG"), wxT("jpeg"), wxBITMAP_TYPE_JPEG} };
71 */
72 const char *ACmp[] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" };
73
74 const char *Mode0[] = { "COMBINED",    "TEXEL0",
75             "TEXEL1",     "PRIMITIVE",
76             "SHADE",      "ENVIORNMENT",
77             "1",        "NOISE",
78             "0",        "0",
79             "0",        "0",
80             "0",        "0",
81             "0",        "0" };
82
83 const char *Mode1[] = { "COMBINED",    "TEXEL0",
84             "TEXEL1",     "PRIMITIVE",
85             "SHADE",      "ENVIORNMENT",
86             "CENTER",     "K4",
87             "0",        "0",
88             "0",        "0",
89             "0",        "0",
90             "0",        "0" };
91
92 const char *Mode2[] = { "COMBINED",    "TEXEL0",
93             "TEXEL1",     "PRIMITIVE",
94             "SHADE",      "ENVIORNMENT",
95             "SCALE",      "COMBINED_ALPHA",
96             "T0_ALPHA",     "T1_ALPHA",
97             "PRIM_ALPHA",   "SHADE_ALPHA",
98             "ENV_ALPHA",    "LOD_FRACTION",
99             "PRIM_LODFRAC",   "K5",
100             "0",        "0",
101             "0",        "0",
102             "0",        "0",
103             "0",        "0",
104             "0",        "0",
105             "0",        "0",
106             "0",        "0",
107             "0",        "0" };
108
109 const char *Mode3[] = { "COMBINED",    "TEXEL0",
110             "TEXEL1",     "PRIMITIVE",
111             "SHADE",      "ENVIORNMENT",
112             "1",        "0" };
113
114 const char *Alpha0[] = { "COMBINED",   "TEXEL0",
115             "TEXEL1",     "PRIMITIVE",
116             "SHADE",      "ENVIORNMENT",
117             "1",        "0" };
118
119 #define Alpha1 Alpha0
120 const char *Alpha2[] = { "LOD_FRACTION", "TEXEL0",
121             "TEXEL1",     "PRIMITIVE",
122             "SHADE",      "ENVIORNMENT",
123             "PRIM_LODFRAC",   "0" };
124 #define Alpha3 Alpha0
125
126 const char *FBLa[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG" };
127 const char *FBLb[] = { "G_BL_A_IN", "G_BL_A_FOG", "G_BL_A_SHADE", "G_BL_0" };
128 const char *FBLc[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG"};
129 const char *FBLd[] = { "G_BL_1MA", "G_BL_A_MEM", "G_BL_1", "G_BL_0" };
130
131 const char *str_zs[] = { "G_ZS_PIXEL", "G_ZS_PRIM" };
132
133 const char *str_yn[] = { "NO", "YES" };
134 const char *str_offon[] = { "OFF", "ON" };
135
136 const char *str_cull[] = { "DISABLE", "FRONT", "BACK", "BOTH" };
137
138 // I=intensity probably
139 const char *str_format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
140 const char *str_size[]   = { "4bit", "8bit", "16bit", "32bit" };
141 const char *str_cm[]     = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" };
142 const char *str_lod[]    = { "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048" };
143 const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" };
144
145 const char *str_filter[] = { "Point Sampled", "Average (box)", "Bilinear" };
146
147 const char *str_tlut[]   = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" };
148
149 const char *str_dither[] = { "Pattern", "~Pattern", "Noise", "None" };
150
151 const char *CIStatus[]   = { "ci_main", "ci_zimg", "ci_unknown",  "ci_useless",
152                             "ci_old_copy", "ci_copy", "ci_copy_self",
153                             "ci_zcopy", "ci_aux", "ci_aux_copy" };
154
155 //static variables
156
157 char out_buf[2048];
158
159 wxUint32 frame_count;  // frame counter
160
161 int ucode_error_report = TRUE;
162 int wrong_tile = -1;
163
164 // ** RDP graphics functions **
165 static void undef();
166 static void spnoop();
167
168 static void rdp_noop();
169 static void rdp_texrect();
170 //static void rdp_texrectflip();
171 static void rdp_loadsync();
172 static void rdp_pipesync();
173 static void rdp_tilesync();
174 static void rdp_fullsync();
175 static void rdp_setkeygb();
176 static void rdp_setkeyr();
177 static void rdp_setconvert();
178 static void rdp_setscissor();
179 static void rdp_setprimdepth();
180 static void rdp_setothermode();
181 static void rdp_loadtlut();
182 static void rdp_settilesize();
183 static void rdp_loadblock();
184 static void rdp_loadtile();
185 static void rdp_settile();
186 static void rdp_fillrect();
187 static void rdp_setfillcolor();
188 static void rdp_setfogcolor();
189 static void rdp_setblendcolor();
190 static void rdp_setprimcolor();
191 static void rdp_setenvcolor();
192 static void rdp_setcombine();
193 static void rdp_settextureimage();
194 static void rdp_setdepthimage();
195 static void rdp_setcolorimage();
196 static void rdp_trifill();
197 static void rdp_trishade();
198 static void rdp_tritxtr();
199 static void rdp_trishadetxtr();
200 static void rdp_trifillz();
201 static void rdp_trishadez();
202 static void rdp_tritxtrz();
203 static void rdp_trishadetxtrz();
204 static void rdphalf_1();
205 static void rdphalf_2();
206 static void rdphalf_cont();
207
208 static void rsp_reserved0();
209 static void rsp_reserved1();
210 static void rsp_reserved2();
211 static void rsp_reserved3();
212
213 static void ys_memrect();
214
215 wxUint8 microcode[4096];
216 wxUint32 uc_crc;
217 void microcheck ();
218
219 #ifdef PAULSCODE
220 #define Check_FrameSkip  if (frameSkipper.willSkipNext()) return
221 #else
222 #define Check_FrameSkip  {}
223 #endif
224
225 // ** UCODE FUNCTIONS **
226 #include "ucode00.h"
227 #include "ucode01.h"
228 #include "ucode02.h"
229 #include "ucode03.h"
230 #include "ucode04.h"
231 #include "ucode05.h"
232 #include "ucode06.h"
233 #include "ucode07.h"
234 #include "ucode08.h"
235 #include "ucode09.h"
236 #include "ucode.h"
237 #include "ucode09rdp.h"
238 #include "turbo3D.h"
239
240 static int reset = 0;
241 static int old_ucode = -1;
242
243 void RDP::Reset()
244 {
245   memset(this, 0, sizeof(RDP_Base));
246   // set all vertex numbers
247   for (int i=0; i<MAX_VTX; i++)
248     vtx[i].number = i;
249
250   scissor_o.ul_x = 0;
251   scissor_o.ul_y = 0;
252   scissor_o.lr_x = 320;
253   scissor_o.lr_y = 240;
254
255   vi_org_reg = *gfx.VI_ORIGIN_REG;
256   view_scale[2] = 32.0f * 511.0f;
257   view_trans[2] = 32.0f * 511.0f;
258   clip_ratio = 1.0f;
259
260   lookat[0][0] = lookat[1][1] = 1.0f;
261
262   cycle_mode = 2;
263   allow_combine = 1;
264   rdp.update = UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
265   fog_mode = RDP::fog_enabled;
266   maincimg[0].addr = maincimg[1].addr = last_drawn_ci_addr = 0x7FFFFFFF;
267
268   hotkey_info.hk_ref = 90;
269   hotkey_info.hk_motionblur = (settings.buff_clear == 0)?0:90;
270   hotkey_info.hk_filtering = hotkey_info.hk_motionblur;
271
272   CheckKeyPressed(G64_VK_BACK, 1); //BACK
273   CheckKeyPressed(G64_VK_B, 1);
274   CheckKeyPressed(G64_VK_V, 1);
275 }
276
277 RDP::RDP()
278 {
279   vtx1 = new VERTEX[256];
280   memset(vtx1, 0, sizeof(VERTEX)*256);
281   vtx2 = new VERTEX[256];
282   memset(vtx2, 0, sizeof(VERTEX)*256);
283   vtxbuf = vtxbuf2 = 0;
284   vtx_buffer = n_global = 0;
285
286   for (int i = 0; i < MAX_TMU; i++)
287   {
288     cache[i] = new CACHE_LUT[MAX_CACHE];
289     cur_cache[i] = 0;
290     cur_cache_n[i] = 0;
291   };
292
293   vtx = new VERTEX[MAX_VTX];
294   memset(vtx, 0, sizeof(VERTEX)*MAX_VTX);
295   v0 = vn = 0;
296
297   frame_buffers = new COLOR_IMAGE[NUMTEXBUF+2];
298 }
299
300 RDP::~RDP()
301 {
302   delete[] vtx1;
303   delete[] vtx2;
304   for (int i = 0; i < MAX_TMU; i++)
305     delete[] cache[i];
306
307   delete[] vtx;
308   delete[] frame_buffers;
309 }
310
311 void rdp_reset ()
312 {
313   reset = 1;
314   rdp.Reset();
315 }
316
317 void microcheck ()
318 {
319   wxUint32 i;
320   uc_crc = 0;
321
322   // Check first 3k of ucode, because the last 1k sometimes contains trash
323   for (i=0; i<3072>>2; i++)
324   {
325     uc_crc += ((wxUint32*)microcode)[i];
326   }
327
328   FRDP_E ("crc: %08lx\n", uc_crc);
329
330 #ifdef LOG_UCODE
331   std::ofstream ucf;
332   ucf.open ("ucode.txt", std::ios::out | std::ios::binary);
333   char d;
334   for (i=0; i<0x400000; i++)
335   {
336     d = ((char*)gfx.RDRAM)[i^3];
337     ucf.write (&d, 1);
338   }
339   ucf.close ();
340 #endif
341
342   FRDP("ucode = %08lx\n", uc_crc);
343
344   Ini * ini = Ini::OpenIni();
345   ini->SetPath("UCODE");
346   char str[9];
347   sprintf (str, "%08lx", (unsigned long)uc_crc);
348   int uc = ini->Read(str, -2);
349
350   if (uc == -2 && ucode_error_report)
351   {
352     settings.ucode = Config_ReadInt("ucode", "Force microcode", 0, TRUE, FALSE);
353
354     ReleaseGfx ();
355     ERRLOG("Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc);
356
357     ucode_error_report = FALSE; // don't report any more ucode errors from this game
358   }
359   else if (uc == -1 && ucode_error_report)
360   {
361     settings.ucode = ini->Read(_T("/SETTINGS/ucode"), 0);
362
363     ReleaseGfx ();
364     ERRLOG("Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc);
365
366     ucode_error_report = FALSE; // don't report any more ucode errors from this game
367   }
368   else
369   {
370     old_ucode = settings.ucode;
371     settings.ucode = uc;
372     FRDP("microcheck: old ucode: %d,  new ucode: %d\n", old_ucode, uc);
373     if (uc_crc == 0x8d5735b2 || uc_crc == 0xb1821ed3 || uc_crc == 0x1118b3e0) //F3DLP.Rej ucode. perspective texture correction is not implemented
374     {
375       rdp.Persp_en = 1;
376       rdp.persp_supported = FALSE;
377     }
378     else if (settings.texture_correction)
379       rdp.persp_supported = TRUE;
380   }
381 }
382
383 #ifdef __WINDOWS__
384 static void GetClientSize(int * width, int * height)
385 {
386 #ifdef __WINDOWS__
387   RECT win_rect;
388   GetClientRect (gfx.hWnd, &win_rect);
389   *width = win_rect.right;
390   *height = win_rect.bottom;
391 #else
392   GFXWindow->GetClientSize(width, height);
393 #endif
394 }
395 #endif
396
397 void drawNoFullscreenMessage()
398 {
399 //need to find, how to do it on non-windows OS
400 //the code below will compile on any OS
401 //but it works only on windows, because
402 //I don't know, how to initialize GFXWindow on other OS
403 #ifdef __WINDOWS__
404   LOG ("drawNoFullscreenMessage ()\n");
405   if (rdp.window_changed)
406   {
407     rdp.window_changed = FALSE;
408     int width, height;
409     GetClientSize(&width, &height);
410
411     wxClientDC dc(GFXWindow);
412     dc.SetBrush(*wxMEDIUM_GREY_BRUSH);
413     dc.SetTextForeground(*wxWHITE);
414     dc.SetBackgroundMode(wxTRANSPARENT);
415     dc.DrawRectangle(0, 0, width, height);
416
417     wxCoord w, h;
418     wxString text = wxT("Glide64mk2");
419     dc.GetTextExtent(text, &w, &h);
420     wxCoord x = (width - w)/2;
421     wxCoord y = height/2 - h*4;
422     dc.DrawText(text, x, y);
423
424     text = wxT("Gfx cannot be drawn in windowed mode");
425     dc.GetTextExtent(text, &w, &h);
426     x = (width - w)/2;
427     y = height/2 - h;
428     dc.DrawText(text, x, y);
429
430     text = wxT("Press Alt+Enter to switch to fullscreen");
431     dc.GetTextExtent(text, &w, &h);
432     x = (width - w)/2;
433     y = (height - h)/2 + h*2;
434     dc.DrawText(text, x, y);
435   }
436 #endif
437 }
438
439 static wxUint32 d_ul_x, d_ul_y, d_lr_x, d_lr_y;
440
441 static void DrawPartFrameBufferToScreen()
442 {
443   FB_TO_SCREEN_INFO fb_info;
444   fb_info.addr   = rdp.cimg;
445   fb_info.size   = rdp.ci_size;
446   fb_info.width  = rdp.ci_width;
447   fb_info.height = rdp.ci_height;
448   fb_info.ul_x = d_ul_x;
449   fb_info.lr_x = d_lr_x;
450   fb_info.ul_y = d_ul_y;
451   fb_info.lr_y = d_lr_y;
452   fb_info.opaque = 0;
453   DrawFrameBufferToScreen(fb_info);
454   memset(gfx.RDRAM+rdp.cimg, 0, (rdp.ci_width*rdp.ci_height)<<rdp.ci_size>>1);
455 }
456
457 #define RGBA16TO32(color) \
458   ((color&1)?0xFF:0) | \
459   ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \
460   ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \
461   ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8)
462
463 static void CopyFrameBuffer (GrBuffer_t buffer = GR_BUFFER_BACKBUFFER)
464 {
465   if (!fullscreen)
466     return;
467   FRDP ("CopyFrameBuffer: %08lx... ", rdp.cimg);
468
469   // don't bother to write the stuff in asm... the slow part is the read from video card,
470   //   not the copy.
471
472   wxUint32 width = rdp.ci_width;//*gfx.VI_WIDTH_REG;
473   wxUint32 height;
474   if (fb_emulation_enabled && !(settings.hacks&hack_PPL))
475   {
476     int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0;
477     height = rdp.frame_buffers[ind].height;
478   }
479   else
480   {
481     height = rdp.ci_lower_bound;
482     if (settings.hacks&hack_PPL)
483       height -= rdp.ci_upper_bound;
484   }
485   FRDP ("width: %d, height: %d...  ", width, height);
486 //printf("CopyFrameBuffer width: %d, height: %d...  ", width, height);
487
488   if (rdp.scale_x < 1.1f)
489   {
490     wxUint16 * ptr_src = new wxUint16[width*height];
491     if (grLfbReadRegion(buffer,
492       (wxUint32)rdp.offset_x,
493       (wxUint32)rdp.offset_y,//rdp.ci_upper_bound,
494       width,
495       height,
496       width<<1,
497       ptr_src))
498     {
499       wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg);
500       wxUint32 *ptr_dst32 = (wxUint32*)(gfx.RDRAM+rdp.cimg);
501       wxUint16 c;
502
503       for (wxUint32 y=0; y<height; y++)
504       {
505         for (wxUint32 x=0; x<width; x++)
506         {
507           c = ptr_src[x + y * width];
508           if (settings.frame_buffer&fb_read_alpha)
509           {
510             if (c > 0)
511               c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
512           }
513           else
514           {
515             c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
516           }
517           if (rdp.ci_size == 2)
518             ptr_dst[(x + y * width)^1] = c;
519           else
520             ptr_dst32[x + y * width] = RGBA16TO32(c);
521         }
522       }
523       LRDP("ReadRegion.  Framebuffer copy complete.\n");
524     }
525     else
526     {
527       LRDP("Framebuffer copy failed.\n");
528     }
529     delete[] ptr_src;
530   }
531   else
532   {
533     if (rdp.motionblur && fb_hwfbe_enabled)
534     {
535       return;
536     }
537     else
538     {
539       float scale_x = (settings.scr_res_x - rdp.offset_x*2.0f)  / max(width, rdp.vi_width);
540       float scale_y = (settings.scr_res_y - rdp.offset_y*2.0f) / max(height, rdp.vi_height);
541
542       FRDP("width: %d, height: %d, ul_y: %d, lr_y: %d, scale_x: %f, scale_y: %f, ci_width: %d, ci_height: %d\n",width, height, rdp.ci_upper_bound, rdp.ci_lower_bound, scale_x, scale_y, rdp.ci_width, rdp.ci_height);
543 //printf("CopyFrameBuffer width: %d, height: %d, ul_y: %d, lr_y: %d, scale_x: %f, scale_y: %f, ci_width: %d, ci_height: %d\n",width, height, rdp.ci_upper_bound, rdp.ci_lower_bound, scale_x, scale_y, rdp.ci_width, rdp.ci_height);
544       GrLfbInfo_t info;
545       info.size = sizeof(GrLfbInfo_t);
546
547       if (grLfbLock (GR_LFB_READ_ONLY,
548         buffer,
549         GR_LFBWRITEMODE_565,
550         GR_ORIGIN_UPPER_LEFT,
551         FXFALSE,
552         &info))
553       {
554         wxUint16 *ptr_src = (wxUint16*)info.lfbPtr;
555         wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg);
556         wxUint32 *ptr_dst32 = (wxUint32*)(gfx.RDRAM+rdp.cimg);
557         wxUint16 c;
558         wxUint32 stride = info.strideInBytes>>1;
559
560         int read_alpha = settings.frame_buffer & fb_read_alpha;
561         if ((settings.hacks&hack_PMario) && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux)
562           read_alpha = FALSE;
563         int x_start = 0, y_start = 0, x_end = width, y_end = height;
564         if (settings.hacks&hack_BAR)
565         {
566           x_start = 80, y_start = 24, x_end = 240, y_end = 86;
567         }
568         for (int y=y_start; y<y_end; y++)
569         {
570           for (int x=x_start; x<x_end; x++)
571           {
572             c = ptr_src[int(x*scale_x + rdp.offset_x) + int(y * scale_y + rdp.offset_y) * stride];
573             c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
574             if (read_alpha && c == 1)
575               c = 0;
576             if (rdp.ci_size <= 2)
577               ptr_dst[(x + y * width)^1] = c;
578             else
579               ptr_dst32[x + y * width] = RGBA16TO32(c);
580           }
581         }
582
583         // Unlock the backbuffer
584         grLfbUnlock (GR_LFB_READ_ONLY, buffer);
585         LRDP("LfbLock.  Framebuffer copy complete.\n");
586       }
587       else
588       {
589         LRDP("Framebuffer copy failed.\n");
590       }
591     }
592   }
593 }
594
595 void GoToFullScreen()
596 {
597     //if (!InitGfx ())
598     {
599       LOG ("FAILED!!!\n");
600       return;
601     }
602 }
603
604 class SoftLocker
605 {
606 public:
607   // lock the mutex in the ctor
608   SoftLocker(SDL_sem *mutex)
609     : _isOk(false), _mutex(mutex)
610   { _isOk = ( SDL_SemTryWait(_mutex) == 0 ); }
611
612   // returns true if mutex was successfully locked in ctor
613   bool IsOk() const
614   { return _isOk; }
615
616   // unlock the mutex in dtor
617   ~SoftLocker()
618   { if ( IsOk() ) SDL_SemPost(_mutex); }
619
620 private:
621   bool     _isOk;
622   SDL_sem *_mutex;
623 };
624
625
626 /******************************************************************
627 Function: ProcessDList
628 Purpose:  This function is called when there is a Dlist to be
629 processed. (High level GFX list)
630 input:    none
631 output:   none
632 *******************************************************************/
633 void DetectFrameBufferUsage ();
634 wxUint32 fbreads_front = 0;
635 wxUint32 fbreads_back = 0;
636 int cpu_fb_read_called = FALSE;
637 int cpu_fb_write_called = FALSE;
638 int cpu_fb_write = FALSE;
639 int cpu_fb_ignore = FALSE;
640 int CI_SET = TRUE;
641 wxUint32 ucode5_texshiftaddr = 0;
642 wxUint32 ucode5_texshiftcount = 0;
643 wxUint16 ucode5_texshift = 0;
644 int depth_buffer_fog;
645
646 #ifdef __cplusplus
647 extern "C" {
648 #endif
649
650
651 EXPORT void CALL ProcessDList(void)
652 {
653 //  SoftLocker lock(mutexProcessDList);
654 #ifdef PAULSCODE
655 //printf("ProcessDList()\n");
656 //  frameSkipper.newFrame();
657   if (0)
658 //  if (frameSkipper.willSkipNext())
659 #else
660   if (/*!lock.IsOk()*/0) //mutex is busy
661 #endif
662   {
663 // printf("Frameskip, reason=%s\n", (lock.IsOk())?"lock":"frameskip");
664  /*   if (!fullscreen)
665       drawNoFullscreenMessage();*/
666     // Set an interrupt to allow the game to continue
667     *(gfx.MI_INTR_REG) |= 0x20;
668     gfx.CheckInterrupts();
669         *(gfx.MI_INTR_REG) |= 0x01;
670         gfx.CheckInterrupts();
671 //      rdp.updatescreen = 1;
672 //      no_dlist = true;
673 //    rdp_fullsync();
674     return;
675   }
676
677   no_dlist = false;
678   update_screen_count = 0;
679   ChangeSize ();
680
681 #ifdef ALTTAB_FIX
682   if (!hhkLowLevelKybd)
683   {
684     hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
685       LowLevelKeyboardProc, NULL, 0);
686   }
687 #endif
688
689   VLOG ("ProcessDList ()\n");
690 /*
691   if (!fullscreen)
692   {
693     drawNoFullscreenMessage();
694     // Set an interrupt to allow the game to continue
695     *gfx.MI_INTR_REG |= 0x20;
696     gfx.CheckInterrupts();
697   }
698 */
699   if (reset)
700   {
701     reset = 0;
702     if (settings.autodetect_ucode)
703     {
704       // Thanks to ZeZu for ucode autodetection!!!
705       wxUint32 startUcode = *(wxUint32*)(gfx.DMEM+0xFD0);
706       memcpy (microcode, gfx.RDRAM+startUcode, 4096);
707       microcheck ();
708     }
709     else
710       memset (microcode, 0, 4096);
711   }
712   else if ( ((old_ucode == ucode_S2DEX) && (settings.ucode == ucode_F3DEX)) || settings.force_microcheck)
713   {
714     wxUint32 startUcode = *(wxUint32*)(gfx.DMEM+0xFD0);
715     memcpy (microcode, gfx.RDRAM+startUcode, 4096);
716     microcheck ();
717   }
718
719   if (exception)
720     return;
721
722   // Switch to fullscreen?
723   if (to_fullscreen)
724     GoToFullScreen();
725
726   if (!fullscreen && !settings.run_in_window)
727     return;
728
729   // Clear out the RDP log
730 #ifdef RDP_LOGGING
731   if (settings.logging && settings.log_clear)
732   {
733     CLOSE_RDP_LOG ();
734     OPEN_RDP_LOG ();
735   }
736 #endif
737
738 #ifdef UNIMP_LOG
739   if (settings.log_unk && settings.unk_clear)
740   {
741     std::ofstream unimp;
742     unimp.open("unimp.txt");
743     unimp.close();
744   }
745 #endif
746
747   //* Set states *//
748   if (settings.swapmode > 0)
749     SwapOK = TRUE;
750   rdp.updatescreen = 1;
751
752   rdp.tri_n = 0;  // 0 triangles so far this frame
753   rdp.debug_n = 0;
754
755   rdp.model_i = 0; // 0 matrices so far in stack
756   //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin!
757   rdp.model_stack_size = min(32, (*(wxUint32*)(gfx.DMEM+0x0FE4))>>6);
758   if (rdp.model_stack_size == 0)
759     rdp.model_stack_size = 32;
760   rdp.Persp_en = TRUE;
761   rdp.fb_drawn = rdp.fb_drawn_front = FALSE;
762   rdp.update = 0x7FFFFFFF;  // All but clear cache
763   rdp.geom_mode = 0;
764   rdp.acmp = 0;
765   rdp.maincimg[1] = rdp.maincimg[0];
766   rdp.skip_drawing = FALSE;
767   rdp.s2dex_tex_loaded = FALSE;
768   rdp.bg_image_height = 0xFFFF;
769   fbreads_front = fbreads_back = 0;
770   rdp.fog_multiplier = rdp.fog_offset = 0;
771   rdp.zsrc = 0;
772   if (rdp.vi_org_reg != *gfx.VI_ORIGIN_REG)
773     rdp.tlut_mode = 0; //is it correct?
774   rdp.scissor_set = FALSE;
775   ucode5_texshiftaddr = ucode5_texshiftcount = 0;
776   cpu_fb_write = FALSE;
777   cpu_fb_read_called = FALSE;
778   cpu_fb_write_called = FALSE;
779   cpu_fb_ignore = FALSE;
780   d_ul_x = 0xffff;
781   d_ul_y = 0xffff;
782   d_lr_x = 0;
783   d_lr_y = 0;
784   depth_buffer_fog = TRUE;
785 //printf("ProcessDList\n");
786   //analize possible frame buffer usage
787   if (fb_emulation_enabled)
788     DetectFrameBufferUsage();
789   if (!(settings.hacks&hack_Lego) || rdp.num_of_ci > 1)
790     rdp.last_bg = 0;
791   //* End of set states *//
792
793   // Get the start of the display list and the length of it
794   wxUint32 dlist_start = *(wxUint32*)(gfx.DMEM+0xFF0);
795   wxUint32 dlist_length = *(wxUint32*)(gfx.DMEM+0xFF4);
796   FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_length: %d, x_scale: %f, y_scale: %f\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length, (*gfx.VI_X_SCALE_REG & 0xFFF)/1024.0f, (*gfx.VI_Y_SCALE_REG & 0xFFF)/1024.0f);
797   FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
798
799   if (cpu_fb_write == TRUE)
800     DrawPartFrameBufferToScreen();
801   if ((settings.hacks&hack_Tonic) && dlist_length < 16)
802   {
803     rdp_fullsync();
804     FRDP_E("DLIST is too short!\n");
805     return;
806   }
807
808   // Start executing at the start of the display list
809   rdp.pc_i = 0;
810   rdp.pc[rdp.pc_i] = dlist_start;
811   rdp.dl_count = -1;
812   rdp.halt = 0;
813   wxUint32 a;
814   
815
816   // catches exceptions so that it doesn't freeze
817 #ifdef CATCH_EXCEPTIONS
818   try {
819 #endif
820     if (settings.ucode == ucode_Turbo3d)
821     {
822       Turbo3D();
823     }
824     else
825     {
826       // MAIN PROCESSING LOOP
827       do {
828
829         // Get the address of the next command
830         a = rdp.pc[rdp.pc_i] & BMASK;
831
832         // Load the next command and its input
833         rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2];   // \ Current command, 64 bit
834         rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // /
835         // cmd2 and cmd3 are filled only when needed, by the function that needs them
836
837         // Output the address before the command
838 #ifdef LOG_COMMANDS
839         FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1);
840 #else
841         FRDP ("%08lx: ", a);
842 #endif
843
844         // Go to the next instruction
845         rdp.pc[rdp.pc_i] = (a+8) & BMASK;
846
847 #ifdef PERFORMANCE
848         perf_cur = ticksGetTicks();
849 #endif
850         // Process this instruction
851         gfx_instruction[settings.ucode][rdp.cmd0>>24] ();
852
853         // check DL counter
854         if (rdp.dl_count != -1)
855         {
856           rdp.dl_count --;
857           if (rdp.dl_count == 0)
858           {
859             rdp.dl_count = -1;
860
861             LRDP("End of DL\n");
862             rdp.pc_i --;
863           }
864         }
865
866 #ifdef PERFORMANCE
867         perf_next = ticksGetTicks();
868         sprintf (out_buf, "perf %08x: %lli\n", a-8, (perf_next-perf_cur));
869 #ifdef RDP_LOGGING
870         rdp_log << out_buf;
871 #else
872                 printf(out_buf);
873 #endif
874 #endif
875
876       } while (!rdp.halt);
877     }
878 #ifdef CATCH_EXCEPTIONS
879   } catch (...) {
880
881     if (fullscreen)
882     {
883       ReleaseGfx ();
884       rdp_reset ();
885 #ifdef TEXTURE_FILTER
886       if (settings.ghq_use)
887       {
888         ext_ghq_shutdown();
889         settings.ghq_use = 0;
890       }
891 #endif
892     }
893     ERRLOG("The GFX plugin caused an exception and has been disabled.");
894       exception = TRUE;
895     return;
896   }
897 #endif
898
899   if (fb_emulation_enabled)
900   {
901     rdp.scale_x = rdp.scale_x_bak;
902     rdp.scale_y = rdp.scale_y_bak;
903   }
904 #ifdef PAULSCODE
905   if (!frameSkipper.willSkipNext())
906 #endif
907   if (settings.frame_buffer & fb_ref)
908     CopyFrameBuffer ();
909   if (rdp.cur_image)
910     CloseTextureBuffer(rdp.read_whole_frame && ((settings.hacks&hack_PMario) || rdp.swap_ci_index >= 0));
911
912   if ((settings.hacks&hack_TGR2) && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
913   {
914     newSwapBuffers ();
915     CI_SET = FALSE;
916   }
917   LRDP("ProcessDList end\n");
918 }
919
920 #ifdef __cplusplus
921 }
922 #endif
923
924 // undef - undefined instruction, always ignore
925 static void undef()
926 {
927   FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0);
928   FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0);
929 #ifdef _ENDUSER_RELEASE_
930   *gfx.MI_INTR_REG |= 0x20;
931   gfx.CheckInterrupts();
932   rdp.halt = 1;
933 #endif
934 }
935
936 // spnoop - no operation, always ignore
937 static void spnoop()
938 {
939   LRDP("spnoop\n");
940 }
941
942 // noop - no operation, always ignore
943 static void rdp_noop()
944 {
945   LRDP("noop\n");
946 }
947
948 static void ys_memrect ()
949 {
950   wxUint32 tile = (wxUint16)((rdp.cmd1 & 0x07000000) >> 24);
951
952   wxUint32 lr_x = (wxUint16)((rdp.cmd0 & 0x00FFF000) >> 14);
953   wxUint32 lr_y = (wxUint16)((rdp.cmd0 & 0x00000FFF) >> 2);
954   wxUint32 ul_x = (wxUint16)((rdp.cmd1 & 0x00FFF000) >> 14);
955   wxUint32 ul_y = (wxUint16)((rdp.cmd1 & 0x00000FFF) >> 2);
956
957   if (lr_y > rdp.scissor_o.lr_y)
958     lr_y = rdp.scissor_o.lr_y;
959   wxUint32 off_x = ((rdp.cmd2 & 0xFFFF0000) >> 16) >> 5;
960   wxUint32 off_y = (rdp.cmd2 & 0x0000FFFF) >> 5;
961
962   FRDP ("memrect (%d, %d, %d, %d), ci_width: %d", ul_x, ul_y, lr_x, lr_y, rdp.ci_width);
963   if (off_x > 0)
964     FRDP ("  off_x: %d", off_x);
965   if (off_y > 0)
966     FRDP ("  off_y: %d", off_y);
967   LRDP("\n");
968
969   wxUint32 y, width = lr_x - ul_x;
970   wxUint32 tex_width = rdp.tiles[tile].line << 3;
971   wxUint8 * texaddr = gfx.RDRAM + rdp.addr[rdp.tiles[tile].t_mem] + tex_width*off_y + off_x;
972   wxUint8 * fbaddr = gfx.RDRAM + rdp.cimg + ul_x;
973
974   for (y = ul_y; y < lr_y; y++) {
975     wxUint8 *src = texaddr + (y - ul_y) * tex_width;
976     wxUint8 *dst = fbaddr + y * rdp.ci_width;
977     memcpy (dst, src, width);
978   }
979 }
980
981 static void pm_palette_mod ()
982 {
983   wxUint8 envr = (wxUint8)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f);
984   wxUint8 envg = (wxUint8)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f);
985   wxUint8 envb = (wxUint8)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f);
986   wxUint16 env16 = (wxUint16)((envr<<11)|(envg<<6)|(envb<<1)|1);
987   wxUint8 prmr = (wxUint8)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f);
988   wxUint8 prmg = (wxUint8)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f);
989   wxUint8 prmb = (wxUint8)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f);
990   wxUint16 prim16 = (wxUint16)((prmr<<11)|(prmg<<6)|(prmb<<1)|1);
991   wxUint16 * dst = (wxUint16*)(gfx.RDRAM+rdp.cimg);
992   for (int i = 0; i < 16; i++)
993   {
994     dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16;
995   }
996   LRDP("Texrect palette modification\n");
997 }
998
999 static void pd_zcopy ()
1000 {
1001   wxUint16 ul_x = (wxUint16)((rdp.cmd1 & 0x00FFF000) >> 14);
1002   wxUint16 lr_x = (wxUint16)((rdp.cmd0 & 0x00FFF000) >> 14) + 1;
1003   wxUint16 ul_u = (wxUint16)((rdp.cmd2 & 0xFFFF0000) >> 21) + 1;
1004   wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg);
1005   wxUint16 width = lr_x - ul_x;
1006   wxUint16 * ptr_src = ((wxUint16*)rdp.tmem)+ul_u;
1007   wxUint16 c;
1008   for (wxUint16 x=0; x<width; x++)
1009   {
1010     c = ptr_src[x];
1011     c = ((c<<8)&0xFF00) | (c >> 8);
1012     ptr_dst[(ul_x+x)^1] = c;
1013     //      FRDP("dst[%d]=%04lx \n", (x + ul_x)^1, c);
1014   }
1015 }
1016
1017 static void DrawDepthBufferFog()
1018 {
1019   if (rdp.zi_width < 200)
1020     return;
1021   FB_TO_SCREEN_INFO fb_info;
1022   fb_info.addr   = rdp.zimg;
1023   fb_info.size   = 2;
1024   fb_info.width  = rdp.zi_width;
1025   fb_info.height = rdp.ci_height;
1026   fb_info.ul_x = rdp.scissor_o.ul_x;
1027   fb_info.lr_x = rdp.scissor_o.lr_x;
1028   fb_info.ul_y = rdp.scissor_o.ul_y;
1029   fb_info.lr_y = rdp.scissor_o.lr_y;
1030   fb_info.opaque = 0;
1031   DrawDepthBufferToScreen(fb_info);
1032 }
1033
1034 static void rdp_texrect()
1035 {
1036   if (!rdp.LLE)
1037   {
1038     wxUint32 a = rdp.pc[rdp.pc_i];
1039     wxUint8 cmdHalf1 = gfx.RDRAM[a+3];
1040     wxUint8 cmdHalf2 = gfx.RDRAM[a+11];
1041     a >>= 2;
1042     if ((cmdHalf1 == 0xE1 && cmdHalf2 == 0xF1) || (cmdHalf1 == 0xB4 && cmdHalf2 == 0xB3) || (cmdHalf1 == 0xB3 && cmdHalf2 == 0xB2))
1043     {
1044       //gSPTextureRectangle
1045       rdp.cmd2 = ((wxUint32*)gfx.RDRAM)[a+1];
1046       rdp.cmd3 = ((wxUint32*)gfx.RDRAM)[a+3];
1047       rdp.pc[rdp.pc_i] += 16;
1048     }
1049     else
1050     {
1051       //gDPTextureRectangle
1052       if (settings.hacks&hack_ASB)
1053         rdp.cmd2 = 0;
1054       else
1055         rdp.cmd2 = ((wxUint32*)gfx.RDRAM)[a+0];
1056       rdp.cmd3 = ((wxUint32*)gfx.RDRAM)[a+1];
1057       rdp.pc[rdp.pc_i] += 8;
1058     }
1059   }
1060   if ((settings.hacks&hack_Yoshi) && settings.ucode == ucode_S2DEX)
1061   {
1062     ys_memrect();
1063     return;
1064   }
1065
1066   if (rdp.skip_drawing || (!fb_emulation_enabled && (rdp.cimg == rdp.zimg)))
1067   {
1068     if ((settings.hacks&hack_PMario) && rdp.ci_status == ci_useless)
1069     {
1070       pm_palette_mod ();
1071     }
1072     else
1073     {
1074       LRDP("Texrect skipped\n");
1075     }
1076     return;
1077   }
1078
1079   if ((settings.ucode == ucode_CBFD) && rdp.cur_image && rdp.cur_image->format)
1080   {
1081     //FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1].addr, rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size);
1082     LRDP("Shadow texrect is skipped.\n");
1083     rdp.tri_n += 2;
1084     return;
1085   }
1086
1087   if ((settings.ucode == ucode_PerfectDark) && (rdp.frame_buffers[rdp.ci_count-1].status == ci_zcopy))
1088   {
1089     pd_zcopy ();
1090     LRDP("Depth buffer copied.\n");
1091     rdp.tri_n += 2;
1092     return;
1093   }
1094
1095   if ((rdp.othermode_l >> 16) == 0x3c18 && rdp.cycle1 == 0x03ffffff && rdp.cycle2 == 0x01ff1fff) //depth image based fog
1096   {
1097     if (!depth_buffer_fog)
1098       return;
1099     if (settings.fog)
1100       DrawDepthBufferFog();
1101     depth_buffer_fog = FALSE;
1102     return;
1103   }
1104
1105   //  FRDP ("rdp.cycle1 %08lx, rdp.cycle2 %08lx\n", rdp.cycle1, rdp.cycle2);
1106
1107   float ul_x, ul_y, lr_x, lr_y;
1108   if (rdp.cycle_mode == 2)
1109   {
1110     ul_x = max(0.0f, (short)((rdp.cmd1 & 0x00FFF000) >> 14));
1111     ul_y = max(0.0f, (short)((rdp.cmd1 & 0x00000FFF) >> 2));
1112     lr_x = max(0.0f, (short)((rdp.cmd0 & 0x00FFF000) >> 14));
1113     lr_y = max(0.0f, (short)((rdp.cmd0 & 0x00000FFF) >> 2));
1114   }
1115   else
1116   {
1117     ul_x = max(0.0f, ((short)((rdp.cmd1 & 0x00FFF000) >> 12)) / 4.0f);
1118     ul_y = max(0.0f, ((short)(rdp.cmd1 & 0x00000FFF)) / 4.0f);
1119     lr_x = max(0.0f, ((short)((rdp.cmd0 & 0x00FFF000) >> 12)) / 4.0f);
1120     lr_y = max(0.0f, ((short)(rdp.cmd0 & 0x00000FFF)) / 4.0f);
1121   }
1122
1123   if (ul_x >= lr_x)
1124   {
1125     FRDP("Wrong Texrect: ul_x: %f, lr_x: %f\n", ul_x, lr_x);
1126     return;
1127   }
1128
1129   if (rdp.cycle_mode > 1)
1130   {
1131     lr_x += 1.0f;
1132     lr_y += 1.0f;
1133   } else if (lr_y - ul_y < 1.0f)
1134     lr_y = ceil(lr_y);
1135
1136   if (settings.increase_texrect_edge)
1137   {
1138     if (floor(lr_x) != lr_x)
1139       lr_x = ceil(lr_x);
1140     if (floor(lr_y) != lr_y)
1141       lr_y = ceil(lr_y);
1142   }
1143
1144   //*
1145   if (rdp.tbuff_tex && (settings.frame_buffer & fb_optimize_texrect))
1146   {
1147     LRDP("Attempt to optimize texrect\n");
1148     if (!rdp.tbuff_tex->drawn)
1149     {
1150       DRAWIMAGE d;
1151       d.imageX  = 0;
1152       d.imageW  = (wxUint16)rdp.tbuff_tex->width;
1153       d.frameX  = (wxUint16)ul_x;
1154       d.frameW  = (wxUint16)(rdp.tbuff_tex->width);
1155
1156       d.imageY  = 0;
1157       d.imageH  = (wxUint16)rdp.tbuff_tex->height;
1158       d.frameY  = (wxUint16)ul_y;
1159       d.frameH  = (wxUint16)(rdp.tbuff_tex->height);
1160       FRDP("texrect. ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d, width: %d, height: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.tbuff_tex->width, rdp.tbuff_tex->height);
1161       d.scaleX  = 1.0f;
1162       d.scaleY  = 1.0f;
1163       DrawHiresImage(d, rdp.tbuff_tex->width == rdp.ci_width);
1164       rdp.tbuff_tex->drawn = TRUE;
1165     }
1166     return;
1167   }
1168   //*/
1169   // framebuffer workaround for Zelda: MM LOT
1170   if ((rdp.othermode_l & 0xFFFF0000) == 0x0f5a0000)
1171     return;
1172
1173   /*Gonetz*/
1174   //hack for Zelda MM. it removes black texrects which cover all geometry in "Link meets Zelda" cut scene
1175   if ((settings.hacks&hack_Zelda) && rdp.timg.addr >= rdp.cimg && rdp.timg.addr < rdp.ci_end)
1176   {
1177     FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.cur_cache[0]->addr, rdp.cimg, rdp.cimg+rdp.ci_width*rdp.ci_height*2);
1178     rdp.tri_n += 2;
1179     return;
1180   }
1181   //*
1182   //hack for Banjo2. it removes black texrects under Banjo
1183   if (!fb_hwfbe_enabled && ((rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF)) == 0xFFFFFFFF && (rdp.othermode_l & 0xFFFF0000) == 0x00500000)
1184   {
1185     rdp.tri_n += 2;
1186     return;
1187   }
1188   //*/
1189   //*
1190   //remove motion blur in night vision
1191   if ((settings.ucode == ucode_PerfectDark) && (rdp.maincimg[1].addr != rdp.maincimg[0].addr) && (rdp.timg.addr >= rdp.maincimg[1].addr) && (rdp.timg.addr < (rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size)))
1192   {
1193     if (fb_emulation_enabled)
1194       if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self)
1195       {
1196         //FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1], rdp.maincimg[1]+rdp.ci_width*rdp.ci_height*rdp.ci_size);
1197         LRDP("Wrong Texrect.\n");
1198         rdp.tri_n += 2;
1199         return;
1200       }
1201   }
1202   //*/
1203
1204   int i;
1205
1206   wxUint32 tile = (wxUint16)((rdp.cmd1 & 0x07000000) >> 24);
1207
1208   rdp.texrecting = 1;
1209
1210   wxUint32 prev_tile = rdp.cur_tile;
1211   rdp.cur_tile = tile;
1212
1213   const float Z = set_sprite_combine_mode ();
1214
1215   rdp.texrecting = 0;
1216
1217   if (!rdp.cur_cache[0])
1218   {
1219     rdp.cur_tile = prev_tile;
1220     rdp.tri_n += 2;
1221     return;
1222   }
1223   // ****
1224   // ** Texrect offset by Gugaman **
1225   //
1226   //integer representation of texture coordinate.
1227   //needed to detect and avoid overflow after shifting
1228   wxInt32 off_x_i = (rdp.cmd2 >> 16) & 0xFFFF;
1229   wxInt32 off_y_i = rdp.cmd2 & 0xFFFF;
1230   float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f;
1231   float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f;
1232   if (off_x_i & 0x8000) //check for sign bit
1233     off_x_i |= ~0xffff; //make it negative
1234   //the same as for off_x_i
1235   if (off_y_i & 0x8000)
1236     off_y_i |= ~0xffff;
1237
1238   if (rdp.cycle_mode == 2)
1239     dsdx /= 4.0f;
1240
1241   float s_ul_x = ul_x * rdp.scale_x + rdp.offset_x;
1242   float s_lr_x = lr_x * rdp.scale_x + rdp.offset_x;
1243   float s_ul_y = ul_y * rdp.scale_y + rdp.offset_y;
1244   float s_lr_y = lr_y * rdp.scale_y + rdp.offset_y;
1245
1246   FRDP("texrect (%.2f, %.2f, %.2f, %.2f), tile: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, tile, rdp.tri_n, rdp.tri_n+1);
1247   FRDP ("(%f, %f) -> (%f, %f), s: (%d, %d) -> (%d, %d)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y, rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y);
1248   FRDP("\toff_x: %f, off_y: %f, dsdx: %f, dtdy: %f\n", off_x_i/32.0f, off_y_i/32.0f, dsdx, dtdy);
1249
1250   float off_size_x;
1251   float off_size_y;
1252
1253   if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1254   {
1255 #ifdef TEXTURE_FILTER
1256     if (rdp.cur_cache[0]->is_hires_tex)
1257     {
1258       off_size_x = (float)((lr_y - ul_y) * dsdx);
1259       off_size_y = (float)((lr_x - ul_x) * dtdy);
1260     }
1261     else
1262 #endif
1263     {
1264       off_size_x = (lr_y - ul_y - 1) * dsdx;
1265       off_size_y = (lr_x - ul_x - 1) * dtdy;
1266     }
1267   }
1268   else
1269   {
1270 #ifdef TEXTURE_FILTER
1271     if (rdp.cur_cache[0]->is_hires_tex)
1272     {
1273       off_size_x = (float)((lr_x - ul_x) * dsdx);
1274       off_size_y = (float)((lr_y - ul_y) * dtdy);
1275     }
1276     else
1277 #endif
1278     {
1279       off_size_x = (lr_x - ul_x - 1) * dsdx;
1280       off_size_y = (lr_y - ul_y - 1) * dtdy;
1281     }
1282   }
1283
1284   struct {
1285     float ul_u, ul_v, lr_u, lr_v;
1286   } texUV[2]; //struct for texture coordinates
1287   //angrylion's macro, helps to cut overflowed values.
1288   #define SIGN16(x) (((x) & 0x8000) ? ((x) | ~0xffff) : ((x) & 0xffff))
1289
1290   //calculate texture coordinates
1291   for (int i = 0; i < 2; i++)
1292   {
1293     if (rdp.cur_cache[i] && (rdp.tex & (i+1)))
1294     {
1295       float sx = 1, sy = 1;
1296       int x_i = off_x_i, y_i = off_y_i;
1297       TILE & tile = rdp.tiles[rdp.cur_tile + i];
1298       //shifting
1299       if (tile.shift_s)
1300       {
1301         if (tile.shift_s > 10)
1302         {
1303           wxUint8 iShift = (16 - tile.shift_s);
1304           x_i <<= iShift;
1305           sx = (float)(1 << iShift);
1306         }
1307         else
1308         {
1309           wxUint8 iShift = tile.shift_s;
1310           x_i >>= iShift;
1311           sx = 1.0f/(float)(1 << iShift);
1312         }
1313       }
1314       if (tile.shift_t)
1315       {
1316         if (tile.shift_t > 10)
1317         {
1318           wxUint8 iShift = (16 - tile.shift_t);
1319           y_i <<= iShift;
1320           sy = (float)(1 << iShift);
1321         }
1322         else
1323         {
1324           wxUint8 iShift = tile.shift_t;
1325           y_i >>= iShift;
1326           sy = 1.0f/(float)(1 << iShift);
1327         }
1328       }
1329
1330       if (rdp.aTBuffTex[i]) //hwfbe texture
1331       {
1332         float t0_off_x;
1333         float t0_off_y;
1334         if (off_x_i + off_y_i == 0)
1335         {
1336           t0_off_x = tile.ul_s;
1337           t0_off_y = tile.ul_t;
1338         }
1339         else
1340         {
1341           t0_off_x = off_x_i/32.0f;
1342           t0_off_y = off_y_i/32.0f;
1343         }
1344         t0_off_x += rdp.aTBuffTex[i]->u_shift;// + tile.ul_s; //commented for Paper Mario motion blur
1345         t0_off_y += rdp.aTBuffTex[i]->v_shift;// + tile.ul_t;
1346         texUV[i].ul_u = t0_off_x * sx;
1347         texUV[i].ul_v = t0_off_y * sy;
1348
1349         texUV[i].lr_u = texUV[i].ul_u + off_size_x * sx;
1350         texUV[i].lr_v = texUV[i].ul_v + off_size_y * sy;
1351
1352         texUV[i].ul_u *= rdp.aTBuffTex[i]->u_scale;
1353         texUV[i].ul_v *= rdp.aTBuffTex[i]->v_scale;
1354         texUV[i].lr_u *= rdp.aTBuffTex[i]->u_scale;
1355         texUV[i].lr_v *= rdp.aTBuffTex[i]->v_scale;
1356         FRDP("tbuff_tex[%d] ul_u: %f, ul_v: %f, lr_u: %f, lr_v: %f\n",
1357           i, texUV[i].ul_u, texUV[i].ul_v, texUV[i].lr_u, texUV[i].lr_v);
1358       }
1359       else //common case
1360       {
1361         //kill 10.5 format overflow by SIGN16 macro
1362         texUV[i].ul_u = SIGN16(x_i) / 32.0f;
1363         texUV[i].ul_v = SIGN16(y_i) / 32.0f;
1364
1365         texUV[i].ul_u -= tile.f_ul_s;
1366         texUV[i].ul_v -= tile.f_ul_t;
1367
1368         texUV[i].lr_u = texUV[i].ul_u + off_size_x * sx;
1369         texUV[i].lr_v = texUV[i].ul_v + off_size_y * sy;
1370
1371         texUV[i].ul_u = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_x * texUV[i].ul_u;
1372         texUV[i].lr_u = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_x * texUV[i].lr_u;
1373         texUV[i].ul_v = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_y * texUV[i].ul_v;
1374         texUV[i].lr_v = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_y * texUV[i].lr_v;
1375       }
1376     }
1377     else
1378     {
1379       texUV[i].ul_u = texUV[i].ul_v = texUV[i].lr_u = texUV[i].lr_v = 0;
1380     }
1381   }
1382   rdp.cur_tile = prev_tile;
1383
1384   // ****
1385
1386   FRDP ("  scissor: (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y);
1387
1388   CCLIP2 (s_ul_x, s_lr_x, texUV[0].ul_u, texUV[0].lr_u, texUV[1].ul_u, texUV[1].lr_u, (float)rdp.scissor.ul_x, (float)rdp.scissor.lr_x);
1389   CCLIP2 (s_ul_y, s_lr_y, texUV[0].ul_v, texUV[0].lr_v, texUV[1].ul_v, texUV[1].lr_v, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y);
1390
1391   FRDP ("  draw at: (%f, %f) -> (%f, %f)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
1392
1393   VERTEX vstd[4] = {
1394     { s_ul_x, s_ul_y, Z, 1.0f, texUV[0].ul_u, texUV[0].ul_v, texUV[1].ul_u, texUV[1].ul_v, {0, 0, 0, 0}, 255 },
1395     { s_lr_x, s_ul_y, Z, 1.0f, texUV[0].lr_u, texUV[0].ul_v, texUV[1].lr_u, texUV[1].ul_v, {0, 0, 0, 0}, 255 },
1396     { s_ul_x, s_lr_y, Z, 1.0f, texUV[0].ul_u, texUV[0].lr_v, texUV[1].ul_u, texUV[1].lr_v, {0, 0, 0, 0}, 255 },
1397     { s_lr_x, s_lr_y, Z, 1.0f, texUV[0].lr_u, texUV[0].lr_v, texUV[1].lr_u, texUV[1].lr_v, {0, 0, 0, 0}, 255 } };
1398
1399     if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1400     {
1401       vstd[1].u0 = texUV[0].ul_u;
1402       vstd[1].v0 = texUV[0].lr_v;
1403       vstd[1].u1 = texUV[1].ul_u;
1404       vstd[1].v1 = texUV[1].lr_v;
1405
1406       vstd[2].u0 = texUV[0].lr_u;
1407       vstd[2].v0 = texUV[0].ul_v;
1408       vstd[2].u1 = texUV[1].lr_u;
1409       vstd[2].v1 = texUV[1].ul_v;
1410     }
1411
1412     VERTEX *vptr = vstd;
1413     int n_vertices = 4;
1414
1415     VERTEX *vnew = 0;
1416     //          for (int j =0; j < 4; j++)
1417     //            FRDP("v[%d]  u0: %f, v0: %f, u1: %f, v1: %f\n", j, vstd[j].u0, vstd[j].v0, vstd[j].u1, vstd[j].v1);
1418
1419
1420     if (!rdp.aTBuffTex[0] && rdp.cur_cache[0]->splits != 1)
1421     {
1422       // ** LARGE TEXTURE HANDLING **
1423       // *VERY* simple algebra for texrects
1424       float min_u, min_x, max_u, max_x;
1425       if (vstd[0].u0 < vstd[1].u0)
1426       {
1427         min_u = vstd[0].u0;
1428         min_x = vstd[0].x;
1429         max_u = vstd[1].u0;
1430         max_x = vstd[1].x;
1431       }
1432       else
1433       {
1434         min_u = vstd[1].u0;
1435         min_x = vstd[1].x;
1436         max_u = vstd[0].u0;
1437         max_x = vstd[0].x;
1438       }
1439
1440       int start_u_256, end_u_256;
1441       start_u_256 = (int)min_u >> 8;
1442       end_u_256 = (int)max_u >> 8;
1443       //FRDP(" min_u: %f, max_u: %f start: %d, end: %d\n", min_u, max_u, start_u_256, end_u_256);
1444
1445       int splitheight = rdp.cur_cache[0]->splitheight;
1446
1447       int num_verts_line = 2 + ((end_u_256-start_u_256)<<1);
1448       n_vertices = num_verts_line << 1;
1449       vnew = new VERTEX [n_vertices];
1450       vptr = vnew;
1451
1452       vnew[0] = vstd[0];
1453       vnew[0].u0 -= 256.0f * start_u_256;
1454       vnew[0].v0 += splitheight * start_u_256;
1455       vnew[0].u1 -= 256.0f * start_u_256;
1456       vnew[0].v1 += splitheight * start_u_256;
1457       vnew[1] = vstd[2];
1458       vnew[1].u0 -= 256.0f * start_u_256;
1459       vnew[1].v0 += splitheight * start_u_256;
1460       vnew[1].u1 -= 256.0f * start_u_256;
1461       vnew[1].v1 += splitheight * start_u_256;
1462       vnew[n_vertices-2] = vstd[1];
1463       vnew[n_vertices-2].u0 -= 256.0f * end_u_256;
1464       vnew[n_vertices-2].v0 += splitheight * end_u_256;
1465       vnew[n_vertices-2].u1 -= 256.0f * end_u_256;
1466       vnew[n_vertices-2].v1 += splitheight * end_u_256;
1467       vnew[n_vertices-1] = vstd[3];
1468       vnew[n_vertices-1].u0 -= 256.0f * end_u_256;
1469       vnew[n_vertices-1].v0 += splitheight * end_u_256;
1470       vnew[n_vertices-1].u1 -= 256.0f * end_u_256;
1471       vnew[n_vertices-1].v1 += splitheight * end_u_256;
1472
1473       // find the equation of the line of u,x
1474       float m = (max_x - min_x) / (max_u - min_u);  // m = delta x / delta u
1475       float b = min_x - m * min_u;          // b = y - m * x
1476
1477       for (i=start_u_256; i<end_u_256; i++)
1478       {
1479         // Find where x = current 256 multiple
1480         float x = m * ((i<<8)+256) + b;
1481
1482         int vn = 2 + ((i-start_u_256)<<2);
1483         vnew[vn] = vstd[0];
1484         vnew[vn].x = x;
1485         vnew[vn].u0 = 255.5f;
1486         vnew[vn].v0 += (float)splitheight * i;
1487         vnew[vn].u1 = 255.5f;
1488         vnew[vn].v1 += (float)splitheight * i;
1489
1490         vn ++;
1491         vnew[vn] = vstd[2];
1492         vnew[vn].x = x;
1493         vnew[vn].u0 = 255.5f;
1494         vnew[vn].v0 += (float)splitheight * i;
1495         vnew[vn].u1 = 255.5f;
1496         vnew[vn].v1 += (float)splitheight * i;
1497
1498         vn ++;
1499         vnew[vn] = vnew[vn-2];
1500         vnew[vn].u0 = 0.5f;
1501         vnew[vn].v0 += (float)splitheight;
1502         vnew[vn].u1 = 0.5f;
1503         vnew[vn].v1 += (float)splitheight;
1504
1505         vn ++;
1506         vnew[vn] = vnew[vn-2];
1507         vnew[vn].u0 = 0.5f;
1508         vnew[vn].v0 += (float)splitheight;
1509         vnew[vn].u1 = 0.5f;
1510         vnew[vn].v1 += (float)splitheight;
1511       }
1512       //*
1513       if (n_vertices > 12)
1514       {
1515         float texbound = (float)(splitheight << 1);
1516         for (int k = 0; k < n_vertices; k ++)
1517         {
1518           if (vnew[k].v0 > texbound)
1519             vnew[k].v0 = (float)fmod(vnew[k].v0, texbound);
1520         }
1521       }
1522       //*/
1523     }
1524
1525     AllowShadeMods (vptr, n_vertices);
1526     for (i=0; i<n_vertices; i++)
1527     {
1528       apply_shade_mods (&vptr[i]);
1529     }
1530
1531     if (fullscreen)
1532     {
1533       if (rdp.fog_mode >= RDP::fog_blend)
1534       {
1535         float fog;
1536         if (rdp.fog_mode == RDP::fog_blend)
1537           fog = 1.0f/max(1, rdp.fog_color&0xFF);
1538         else
1539           fog = 1.0f/max(1, (~rdp.fog_color)&0xFF);
1540         for (i = 0; i < n_vertices; i++)
1541         {
1542           vptr[i].f = fog;
1543         }
1544         grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
1545       }
1546
1547       ConvertCoordsConvert (vptr, n_vertices);
1548
1549       if (settings.wireframe)
1550       {
1551         SetWireframeCol ();
1552         grDrawLine (&vstd[0], &vstd[2]);
1553         grDrawLine (&vstd[2], &vstd[1]);
1554         grDrawLine (&vstd[1], &vstd[0]);
1555         grDrawLine (&vstd[2], &vstd[3]);
1556         grDrawLine (&vstd[3], &vstd[1]);
1557       }
1558       else
1559       {
1560         grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, n_vertices, vptr, sizeof(VERTEX));
1561       }
1562
1563       if (_debugger.capture)
1564       {
1565         VERTEX vl[3];
1566         vl[0] = vstd[0];
1567         vl[1] = vstd[2];
1568         vl[2] = vstd[1];
1569         add_tri (vl, 3, TRI_TEXRECT);
1570         rdp.tri_n ++;
1571         vl[0] = vstd[2];
1572         vl[1] = vstd[3];
1573         vl[2] = vstd[1];
1574         add_tri (vl, 3, TRI_TEXRECT);
1575         rdp.tri_n ++;
1576       }
1577       else
1578         rdp.tri_n += 2;
1579     }
1580     else
1581     {
1582       rdp.tri_n += 2;
1583     }
1584
1585     delete[] vnew;
1586 }
1587
1588 static void rdp_loadsync()
1589 {
1590   LRDP("loadsync - ignored\n");
1591 }
1592
1593 static void rdp_pipesync()
1594 {
1595   LRDP("pipesync - ignored\n");
1596 }
1597
1598 static void rdp_tilesync()
1599 {
1600   LRDP("tilesync - ignored\n");
1601 }
1602
1603 static void rdp_fullsync()
1604 {
1605   // Set an interrupt to allow the game to continue
1606   *gfx.MI_INTR_REG |= 0x20;
1607   gfx.CheckInterrupts();
1608   LRDP("fullsync\n");
1609 }
1610
1611 static void rdp_setkeygb()
1612 {
1613   wxUint32 sB = rdp.cmd1&0xFF;
1614   wxUint32 cB = (rdp.cmd1>>8)&0xFF;
1615   wxUint32 sG = (rdp.cmd1>>16)&0xFF;
1616   wxUint32 cG = (rdp.cmd1>>24)&0xFF;
1617   rdp.SCALE = (rdp.SCALE&0xFF0000FF) | (sG<<16) | (sB<<8);
1618   rdp.CENTER = (rdp.CENTER&0xFF0000FF) | (cG<<16) | (cB<<8);
1619   FRDP("setkeygb. cG=%02lx, sG=%02lx, cB=%02lx, sB=%02lx\n", cG, sG, cB, sB);
1620 }
1621
1622 static void rdp_setkeyr()
1623 {
1624   wxUint32 sR = rdp.cmd1&0xFF;
1625   wxUint32 cR = (rdp.cmd1>>8)&0xFF;
1626   rdp.SCALE = (rdp.SCALE&0x00FFFFFF) | (sR<<24);
1627   rdp.CENTER = (rdp.CENTER&0x00FFFFFF) | (cR<<24);
1628   FRDP("setkeyr. cR=%02lx, sR=%02lx\n", cR, sR);
1629 }
1630
1631 static void rdp_setconvert()
1632 {
1633   /*
1634   rdp.YUV_C0 = 1.1647f  ;
1635   rdp.YUV_C1 = 0.79931f ;
1636   rdp.YUV_C2 = -0.1964f ;
1637   rdp.YUV_C3 = -0.40651f;
1638   rdp.YUV_C4 = 1.014f   ;
1639   */
1640   rdp.K4 = (wxUint8)(rdp.cmd1>>9)&0x1FF;
1641   rdp.K5 = (wxUint8)(rdp.cmd1&0x1FF);
1642   //  RDP_E("setconvert - IGNORED\n");
1643   FRDP("setconvert. K4=%02lx K5=%02lx\n", rdp.K4, rdp.K5);
1644 }
1645
1646 //
1647 // setscissor - sets the screen clipping rectangle
1648 //
1649
1650 static void rdp_setscissor()
1651 {
1652   // clipper resolution is 320x240, scale based on computer resolution
1653   rdp.scissor_o.ul_x = /*min(*/(wxUint32)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/;
1654   rdp.scissor_o.ul_y = /*min(*/(wxUint32)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/;
1655   rdp.scissor_o.lr_x = /*min(*/(wxUint32)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/;
1656   rdp.scissor_o.lr_y = /*min(*/(wxUint32)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/;
1657
1658   rdp.ci_upper_bound = rdp.scissor_o.ul_y;
1659   rdp.ci_lower_bound = rdp.scissor_o.lr_y;
1660   rdp.scissor_set = TRUE;
1661
1662   FRDP("setscissor: (%d,%d) -> (%d,%d)\n", rdp.scissor_o.ul_x, rdp.scissor_o.ul_y,
1663     rdp.scissor_o.lr_x, rdp.scissor_o.lr_y);
1664
1665   rdp.update |= UPDATE_SCISSOR;
1666
1667   if (rdp.view_scale[0] == 0) //viewport is not set?
1668   {
1669     rdp.view_scale[0] = (rdp.scissor_o.lr_x>>1)*rdp.scale_x;
1670     rdp.view_scale[1] = (rdp.scissor_o.lr_y>>1)*-rdp.scale_y;
1671     rdp.view_trans[0] = rdp.view_scale[0];
1672     rdp.view_trans[1] = -rdp.view_scale[1];
1673     rdp.update |= UPDATE_VIEWPORT;
1674   }
1675 }
1676
1677 static void rdp_setprimdepth()
1678 {
1679   rdp.prim_depth = (wxUint16)((rdp.cmd1 >> 16) & 0x7FFF);
1680   rdp.prim_dz = (wxUint16)(rdp.cmd1 & 0x7FFF);
1681
1682   FRDP("setprimdepth: %d\n", rdp.prim_depth);
1683 }
1684
1685 static void rdp_setothermode()
1686 {
1687 #define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \
1688   rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \
1689   rdp.cmd1 = data; \
1690   gfx_instruction[settings.ucode][cmd] (); \
1691 }
1692 #define SETOTHERMODE(cmd,sft,len,data) { \
1693   rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \
1694   rdp.cmd1 = data; \
1695   gfx_instruction[settings.ucode][cmd] (); \
1696 }
1697
1698   LRDP("rdp_setothermode\n");
1699
1700   if ((settings.ucode == ucode_F3DEX2) || (settings.ucode == ucode_CBFD))
1701   {
1702     int cmd0 = rdp.cmd0;
1703     F3DEX2_SETOTHERMODE(0xE2, 0, 32, rdp.cmd1);         // SETOTHERMODE_L
1704     F3DEX2_SETOTHERMODE(0xE3, 0, 32, cmd0 & 0x00FFFFFF);    // SETOTHERMODE_H
1705   }
1706   else
1707   {
1708     int cmd0 = rdp.cmd0;
1709     SETOTHERMODE(0xB9, 0, 32, rdp.cmd1);            // SETOTHERMODE_L
1710     SETOTHERMODE(0xBA, 0, 32, cmd0 & 0x00FFFFFF);       // SETOTHERMODE_H
1711   }
1712 }
1713
1714 void load_palette (wxUint32 addr, wxUint16 start, wxUint16 count)
1715 {
1716   LRDP("Loading palette... ");
1717   wxUint16 *dpal = rdp.pal_8 + start;
1718   wxUint16 end = start+count;
1719 #ifdef TEXTURE_FILTER
1720   wxUint16 *spal = (wxUint16*)(gfx.RDRAM + (addr & BMASK));
1721 #endif
1722
1723   for (wxUint16 i=start; i<end; i++)
1724   {
1725     *(dpal++) = *(wxUint16 *)(gfx.RDRAM + (addr^2));
1726     addr += 2;
1727
1728 #ifdef TLUT_LOGGING
1729     FRDP ("%d: %08lx\n", i, *(wxUint16 *)(gfx.RDRAM + (addr^2)));
1730 #endif
1731   }
1732 #ifdef TEXTURE_FILTER
1733   if (settings.ghq_hirs)
1734     memcpy((wxUint8*)(rdp.pal_8_rice+start), spal, count<<1);
1735 #endif
1736   start >>= 4;
1737   end = start + (count >> 4);
1738   if (end == start) // it can be if count < 16
1739     end = start + 1;
1740   for (wxUint16 p = start; p < end; p++)
1741   {
1742     rdp.pal_8_crc[p] = CRC32( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 );
1743   }
1744   rdp.pal_256_crc = CRC32( 0xFFFFFFFF, rdp.pal_8_crc, 64 );
1745   LRDP("Done.\n");
1746 }
1747
1748 static void rdp_loadtlut()
1749 {
1750   wxUint32 tile = (rdp.cmd1 >> 24) & 0x07;
1751   wxUint16 start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes
1752   //  wxUint16 start = ((wxUint16)(rdp.cmd1 >> 2) & 0x3FF) + 1;
1753   wxUint16 count = ((wxUint16)(rdp.cmd1 >> 14) & 0x3FF) + 1;    // number to copy
1754
1755   if (rdp.timg.addr + (count<<1) > BMASK)
1756     count = (wxUint16)((BMASK - rdp.timg.addr) >> 1);
1757
1758   if (start+count > 256) count = 256-start;
1759
1760   FRDP("loadtlut: tile: %d, start: %d, count: %d, from: %08lx\n", tile, start, count,
1761     rdp.timg.addr);
1762
1763   load_palette (rdp.timg.addr, start, count);
1764
1765   rdp.timg.addr += count << 1;
1766
1767   if (rdp.tbuff_tex) //paranoid check.
1768   {
1769     //the buffer is definitely wrong, as there must be no CI frame buffers
1770     //find and remove it
1771     for (int i = 0; i < voodoo.num_tmu; i++)
1772     {
1773       for (int j = 0; j < rdp.texbufs[i].count; j++)
1774       {
1775         if (&(rdp.texbufs[i].images[j]) == rdp.tbuff_tex)
1776         {
1777           rdp.texbufs[i].count--;
1778           if (j < rdp.texbufs[i].count)
1779             memcpy(&(rdp.texbufs[i].images[j]), &(rdp.texbufs[i].images[j+1]), sizeof(TBUFF_COLOR_IMAGE)*(rdp.texbufs[i].count-j));
1780           return;
1781         }
1782       }
1783     }
1784   }
1785 }
1786
1787 int tile_set = 0;
1788 static void rdp_settilesize()
1789 {
1790   wxUint32 tile = (rdp.cmd1 >> 24) & 0x07;
1791   rdp.last_tile_size = tile;
1792
1793   rdp.tiles[tile].f_ul_s = (float)((rdp.cmd0 >> 12) & 0xFFF) / 4.0f;
1794   rdp.tiles[tile].f_ul_t = (float)(rdp.cmd0 & 0xFFF) / 4.0f;
1795
1796   int ul_s = (((wxUint16)(rdp.cmd0 >> 14)) & 0x03ff);
1797   int ul_t = (((wxUint16)(rdp.cmd0 >> 2 )) & 0x03ff);
1798   int lr_s = (((wxUint16)(rdp.cmd1 >> 14)) & 0x03ff);
1799   int lr_t = (((wxUint16)(rdp.cmd1 >> 2 )) & 0x03ff);
1800
1801   if (lr_s == 0 && ul_s == 0)  //pokemon puzzle league set such tile size
1802     wrong_tile = tile;
1803   else if (wrong_tile == (int)tile)
1804     wrong_tile = -1;
1805
1806   if (settings.use_sts1_only)
1807   {
1808     // ** USE FIRST SETTILESIZE ONLY **
1809     // This option helps certain textures while using the 'Alternate texture size method',
1810     //  but may break others.  (should help more than break)
1811
1812     if (tile_set)
1813     {
1814       // coords in 10.2 format
1815       rdp.tiles[tile].ul_s = ul_s;
1816       rdp.tiles[tile].ul_t = ul_t;
1817       rdp.tiles[tile].lr_s = lr_s;
1818       rdp.tiles[tile].lr_t = lr_t;
1819       tile_set = 0;
1820     }
1821   }
1822   else
1823   {
1824     // coords in 10.2 format
1825     rdp.tiles[tile].ul_s = ul_s;
1826     rdp.tiles[tile].ul_t = ul_t;
1827     rdp.tiles[tile].lr_s = lr_s;
1828     rdp.tiles[tile].lr_t = lr_t;
1829   }
1830
1831   // handle wrapping
1832   if (rdp.tiles[tile].lr_s < rdp.tiles[tile].ul_s) rdp.tiles[tile].lr_s += 0x400;
1833   if (rdp.tiles[tile].lr_t < rdp.tiles[tile].ul_t) rdp.tiles[tile].lr_t += 0x400;
1834
1835   rdp.update |= UPDATE_TEXTURE;
1836
1837   rdp.first = 1;
1838
1839   FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d, f_ul_s: %f, f_ul_t: %f\n",
1840     tile, ul_s, ul_t, lr_s, lr_t, rdp.tiles[tile].f_ul_s, rdp.tiles[tile].f_ul_t);
1841 }
1842
1843 void setTBufTex(wxUint16 t_mem, wxUint32 cnt)
1844 {
1845   FRDP("setTBufTex t_mem=%d, cnt=%d\n", t_mem, cnt);
1846   TBUFF_COLOR_IMAGE * pTbufTex = rdp.tbuff_tex;
1847   for (int i = 0; i < 2; i++)
1848   {
1849     LRDP("Before: ");
1850     if (rdp.aTBuffTex[i]) {
1851       FRDP("rdp.aTBuffTex[%d]: tmu=%d t_mem=%d tile=%d\n", i, rdp.aTBuffTex[i]->tmu, rdp.aTBuffTex[i]->t_mem, rdp.aTBuffTex[i]->tile);
1852     } else {
1853       FRDP("rdp.aTBuffTex[%d]=0\n", i);
1854     }
1855     if ((rdp.aTBuffTex[i] == 0 && rdp.aTBuffTex[i^1] != pTbufTex) || (rdp.aTBuffTex[i] && rdp.aTBuffTex[i]->t_mem >= t_mem && rdp.aTBuffTex[i]->t_mem < t_mem + cnt))
1856     {
1857       if (pTbufTex)
1858       {
1859         rdp.aTBuffTex[i] = pTbufTex;
1860         rdp.aTBuffTex[i]->t_mem = t_mem;
1861         pTbufTex = 0;
1862         FRDP("rdp.aTBuffTex[%d] tmu=%d t_mem=%d\n", i, rdp.aTBuffTex[i]->tmu, rdp.aTBuffTex[i]->t_mem);
1863       }
1864       else
1865       {
1866         rdp.aTBuffTex[i] = 0;
1867         FRDP("rdp.aTBuffTex[%d]=0\n", i);
1868       }
1869     }
1870   }
1871 }
1872
1873 static inline void loadBlock(uint32_t *src, uint32_t *dst, uint32_t off, int dxt, int cnt)
1874 {
1875   uint32_t *v5;
1876   int v6;
1877   uint32_t *v7;
1878   uint32_t v8;
1879   int v9;
1880   uint32_t v10;
1881   uint32_t *v11;
1882   uint32_t v12;
1883   uint32_t v13;
1884   uint32_t v14;
1885   int v15;
1886   int v16;
1887   uint32_t *v17;
1888   int v18;
1889   uint32_t v19;
1890   uint32_t v20;
1891   int i;
1892
1893   v5 = dst;
1894   v6 = cnt;
1895   if ( cnt )
1896   {
1897     v7 = (uint32_t *)((char *)src + (off & 0xFFFFFFFC));
1898     v8 = off & 3;
1899     if ( !(off & 3) )
1900       goto LABEL_23;
1901     v9 = 4 - v8;
1902     v10 = *v7;
1903     v11 = v7 + 1;
1904     do
1905     {
1906       v10 = __ROL__(v10, 8);
1907       --v8;
1908     }
1909     while ( v8 );
1910     do
1911     {
1912       v10 = __ROL__(v10, 8);
1913       *(uint8_t *)v5 = v10;
1914       v5 = (uint32_t *)((char *)v5 + 1);
1915       --v9;
1916     }
1917     while ( v9 );
1918     v12 = *v11;
1919     v7 = v11 + 1;
1920     *v5 = bswap32(v12);
1921     ++v5;
1922     v6 = cnt - 1;
1923     if ( cnt != 1 )
1924     {
1925 LABEL_23:
1926       do
1927       {
1928         *v5 = bswap32(*v7);
1929         v5[1] = bswap32(v7[1]);
1930         v7 += 2;
1931         v5 += 2;
1932         --v6;
1933       }
1934       while ( v6 );
1935     }
1936     v13 = off & 3;
1937     if ( off & 3 )
1938     {
1939       v14 = *(uint32_t *)((char *)src + ((8 * cnt + off) & 0xFFFFFFFC));
1940       do
1941       {
1942         v14 = __ROL__(v14, 8);
1943         *(uint8_t *)v5 = v14;
1944         v5 = (uint32_t *)((char *)v5 + 1);
1945         --v13;
1946       }
1947       while ( v13 );
1948     }
1949   }
1950   v15 = cnt;
1951   v16 = 0;
1952   v17 = dst;
1953   v18 = 0;
1954 dxt_test:
1955   while ( 1 )
1956   {
1957     v17 += 2;
1958     --v15;
1959     if ( !v15 )
1960       break;
1961     v16 += dxt;
1962     if ( v16 < 0 )
1963     {
1964       while ( 1 )
1965       {
1966         ++v18;
1967         --v15;
1968         if ( !v15 )
1969           goto end_dxt_test;
1970         v16 += dxt;
1971         if ( v16 >= 0 )
1972         {
1973           for ( i = v15; v18; --v18 )
1974           {
1975             v19 = *v17;
1976             *v17 = v17[1];
1977             v17[1] = v19;
1978             v17 += 2;
1979           }
1980           v15 = i;
1981           goto dxt_test;
1982         }
1983       }
1984     }
1985   }
1986 end_dxt_test:
1987   while ( v18 )
1988   {
1989     v20 = *v17;
1990     *v17 = v17[1];
1991     v17[1] = v20;
1992     v17 += 2;
1993     --v18;
1994   }
1995 }
1996
1997 void LoadBlock32b(wxUint32 tile, wxUint32 ul_s, wxUint32 ul_t, wxUint32 lr_s, wxUint32 dxt);
1998 static void rdp_loadblock()
1999 {
2000   if (rdp.skip_drawing)
2001   {
2002     LRDP("loadblock skipped\n");
2003     return;
2004   }
2005   wxUint32 tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07);
2006   wxUint32 dxt = (wxUint32)(rdp.cmd1 & 0x0FFF);
2007   wxUint16 lr_s = (wxUint16)(rdp.cmd1 >> 14) & 0x3FF;
2008   if (ucode5_texshiftaddr)
2009   {
2010     if (ucode5_texshift % ((lr_s+1)<<3))
2011     {
2012       rdp.timg.addr -= ucode5_texshift;
2013       ucode5_texshiftaddr = 0;
2014       ucode5_texshift = 0;
2015       ucode5_texshiftcount = 0;
2016     }
2017     else
2018       ucode5_texshiftcount++;
2019   }
2020
2021   rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2022
2023   // ** DXT is used for swapping every other line
2024   /*  double fdxt = (double)0x8000000F/(double)((wxUint32)(2047/(dxt-1))); // F for error
2025   wxUint32 _dxt = (wxUint32)fdxt;*/
2026
2027   // 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit)
2028   wxUint32 _dxt = dxt << 20;
2029
2030   wxUint32 addr = segoffset(rdp.timg.addr) & BMASK;
2031
2032   // lr_s specifies number of 64-bit words to copy
2033   // 10.2 format
2034   wxUint16 ul_s = (wxUint16)(rdp.cmd0 >> 14) & 0x3FF;
2035   wxUint16 ul_t = (wxUint16)(rdp.cmd0 >>  2) & 0x3FF;
2036
2037   rdp.tiles[tile].ul_s = ul_s;
2038   rdp.tiles[tile].ul_t = ul_t;
2039   rdp.tiles[tile].lr_s = lr_s;
2040
2041   rdp.timg.set_by = 0;  // load block
2042
2043 #ifdef TEXTURE_FILTER
2044   LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[tile].t_mem];
2045   info.tile_width = lr_s;
2046   info.dxt = dxt;
2047 #endif
2048
2049   // do a quick boundary check before copying to eliminate the possibility for exception
2050   if (ul_s >= 512) {
2051     lr_s = 1;   // 1 so that it doesn't die on memcpy
2052     ul_s = 511;
2053   }
2054   if (ul_s+lr_s > 512)
2055     lr_s = 512-ul_s;
2056
2057   if (addr+(lr_s<<3) > BMASK+1)
2058     lr_s = (wxUint16)((BMASK-addr)>>3);
2059
2060   //angrylion's advice to use ul_s in texture image offset and cnt calculations.
2061   //Helps to fix Vigilante 8 jpeg backgrounds and logos
2062   wxUint32 off = rdp.timg.addr + (ul_s << rdp.tiles[tile].size >> 1);
2063   unsigned char *dst = ((unsigned char *)rdp.tmem) + (rdp.tiles[tile].t_mem<<3);
2064   wxUint32 cnt = lr_s-ul_s+1;
2065   if (rdp.tiles[tile].size == 3)
2066     cnt <<= 1;
2067
2068   if (((rdp.tiles[tile].t_mem + cnt) << 3) > sizeof(rdp.tmem)) {
2069     WriteLog(M64MSG_INFO, "rdp_loadblock wanted to write %u bytes after the end of tmem", ((rdp.tiles[tile].t_mem + cnt) << 3) - sizeof(rdp.tmem));
2070     cnt = (sizeof(rdp.tmem) >> 3) - (rdp.tiles[tile].t_mem);
2071   }
2072
2073   if (rdp.timg.size == 3)
2074     LoadBlock32b(tile, ul_s, ul_t, lr_s, dxt);
2075   else
2076     loadBlock((uint32_t *)gfx.RDRAM, (uint32_t *)dst, off, _dxt, cnt);
2077
2078   rdp.timg.addr += cnt << 3;
2079   rdp.tiles[tile].lr_t = ul_t + ((dxt*cnt)>>11);
2080
2081   rdp.update |= UPDATE_TEXTURE;
2082
2083   FRDP ("loadblock: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, dxt: %08lx -> %08lx\n",
2084     tile, ul_s, ul_t, lr_s,
2085     dxt, _dxt);
2086
2087   if (fb_hwfbe_enabled)
2088     setTBufTex(rdp.tiles[tile].t_mem, cnt);
2089 }
2090
2091
2092 static inline void loadTile(uint32_t *src, uint32_t *dst, int width, int height, int line, int off, uint32_t *end)
2093 {
2094   uint32_t *v7;
2095   int v8;
2096   uint32_t *v9;
2097   int v10;
2098   int v11;
2099   int v12;
2100   uint32_t *v13;
2101   int v14;
2102   int v15;
2103   uint32_t v16;
2104   uint32_t *v17;
2105   uint32_t v18;
2106   int v19;
2107   uint32_t v20;
2108   int v21;
2109   uint32_t v22;
2110   int v23;
2111   uint32_t *v24;
2112   int v25;
2113   int v26;
2114   uint32_t *v27;
2115   int v28;
2116   int v29;
2117   int v30;
2118   uint32_t *v31;
2119
2120   v7 = dst;
2121   v8 = width;
2122   v9 = src;
2123   v10 = off;
2124   v11 = 0;
2125   v12 = height;
2126   do
2127   {
2128     if ( end < v7 )
2129       break;
2130     v31 = v7;
2131     v30 = v8;
2132     v29 = v12;
2133     v28 = v11;
2134     v27 = v9;
2135     v26 = v10;
2136     if ( v8 )
2137     {
2138       v25 = v8;
2139       v24 = v9;
2140       v23 = v10;
2141       v13 = (uint32_t *)((char *)v9 + (v10 & 0xFFFFFFFC));
2142       v14 = v10 & 3;
2143       if ( !(v10 & 3) )
2144         goto LABEL_20;
2145       v15 = 4 - v14;
2146       v16 = *v13;
2147       v17 = v13 + 1;
2148       do
2149       {
2150         v16 = __ROL__(v16, 8);
2151         --v14;
2152       }
2153       while ( v14 );
2154       do
2155       {
2156         v16 = __ROL__(v16, 8);
2157         *(uint8_t *)v7 = v16;
2158         v7 = (uint32_t *)((char *)v7 + 1);
2159         --v15;
2160       }
2161       while ( v15 );
2162       v18 = *v17;
2163       v13 = v17 + 1;
2164       *v7 = bswap32(v18);
2165       ++v7;
2166       --v8;
2167       if ( v8 )
2168       {
2169 LABEL_20:
2170         do
2171         {
2172           *v7 = bswap32(*v13);
2173           v7[1] = bswap32(v13[1]);
2174           v13 += 2;
2175           v7 += 2;
2176           --v8;
2177         }
2178         while ( v8 );
2179       }
2180       v19 = v23 & 3;
2181       if ( v23 & 3 )
2182       {
2183         v20 = *(uint32_t *)((char *)v24 + ((8 * v25 + v23) & 0xFFFFFFFC));
2184         do
2185         {
2186           v20 = __ROL__(v20, 8);
2187           *(uint8_t *)v7 = v20;
2188           v7 = (uint32_t *)((char *)v7 + 1);
2189           --v19;
2190         }
2191         while ( v19 );
2192       }
2193     }
2194     v9 = v27;
2195     v21 = v29;
2196     v8 = v30;
2197     v11 = v28 ^ 1;
2198     if ( v28 == 1 )
2199     {
2200       v7 = v31;
2201       if ( v30 )
2202       {
2203         do
2204         {
2205           v22 = *v7;
2206           *v7 = v7[1];
2207           v7[1] = v22;
2208           v7 += 2;
2209           --v8;
2210         }
2211         while ( v8 );
2212       }
2213       v21 = v29;
2214       v8 = v30;
2215     }
2216     v10 = line + v26;
2217     v12 = v21 - 1;
2218   }
2219   while ( v12 );
2220 }
2221
2222 void LoadTile32b (wxUint32 tile, wxUint32 ul_s, wxUint32 ul_t, wxUint32 width, wxUint32 height);
2223 static void rdp_loadtile()
2224 {
2225   if (rdp.skip_drawing)
2226   {
2227     LRDP("loadtile skipped\n");
2228     return;
2229   }
2230   rdp.timg.set_by = 1;  // load tile
2231
2232   wxUint32 tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07);
2233
2234   rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2235
2236   wxUint16 ul_s = (wxUint16)((rdp.cmd0 >> 14) & 0x03FF);
2237   wxUint16 ul_t = (wxUint16)((rdp.cmd0 >> 2 ) & 0x03FF);
2238   wxUint16 lr_s = (wxUint16)((rdp.cmd1 >> 14) & 0x03FF);
2239   wxUint16 lr_t = (wxUint16)((rdp.cmd1 >> 2 ) & 0x03FF);
2240
2241   if (lr_s < ul_s || lr_t < ul_t) return;
2242
2243   if (wrong_tile >= 0)  //there was a tile with zero length
2244   {
2245     rdp.tiles[wrong_tile].lr_s = lr_s;
2246
2247     if (rdp.tiles[tile].size > rdp.tiles[wrong_tile].size)
2248       rdp.tiles[wrong_tile].lr_s <<= (rdp.tiles[tile].size - rdp.tiles[wrong_tile].size);
2249     else if (rdp.tiles[tile].size < rdp.tiles[wrong_tile].size)
2250       rdp.tiles[wrong_tile].lr_s >>= (rdp.tiles[wrong_tile].size - rdp.tiles[tile].size);
2251     rdp.tiles[wrong_tile].lr_t = lr_t;
2252     rdp.tiles[wrong_tile].mask_s = rdp.tiles[wrong_tile].mask_t = 0;
2253     //     wrong_tile = -1;
2254   }
2255
2256   if (rdp.tbuff_tex)// && (rdp.tiles[tile].format == 0))
2257   {
2258     FRDP("loadtile: tbuff_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t);
2259     rdp.tbuff_tex->tile_uls = ul_s;
2260     rdp.tbuff_tex->tile_ult = ul_t;
2261   }
2262
2263   if ((settings.hacks&hack_Tonic) && tile == 7)
2264   {
2265     rdp.tiles[0].ul_s = ul_s;
2266     rdp.tiles[0].ul_t = ul_t;
2267     rdp.tiles[0].lr_s = lr_s;
2268     rdp.tiles[0].lr_t = lr_t;
2269   }
2270
2271   wxUint32 height = lr_t - ul_t + 1;   // get height
2272   wxUint32 width = lr_s - ul_s + 1;
2273
2274 #ifdef TEXTURE_FILTER
2275   LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[tile].t_mem];
2276   info.tile_ul_s = ul_s;
2277   info.tile_ul_t = ul_t;
2278   info.tile_width = (rdp.tiles[tile].mask_s ? min((wxUint16)width, 1<<rdp.tiles[tile].mask_s) : (wxUint16)width);
2279   info.tile_height = (rdp.tiles[tile].mask_t ? min((wxUint16)height, 1<<rdp.tiles[tile].mask_t) : (wxUint16)height);
2280   if (settings.hacks&hack_MK64) {
2281     if (info.tile_width%2)
2282       info.tile_width--;
2283     if (info.tile_height%2)
2284       info.tile_height--;
2285   }
2286   info.tex_width = rdp.timg.width;
2287   info.tex_size = rdp.timg.size;
2288 #endif
2289
2290   int line_n = rdp.timg.width << rdp.tiles[tile].size >> 1;
2291   wxUint32 offs = ul_t * line_n;
2292   offs += ul_s << rdp.tiles[tile].size >> 1;
2293   offs += rdp.timg.addr;
2294   if (offs >= BMASK)
2295     return;
2296
2297   if (rdp.timg.size == 3)
2298   {
2299     LoadTile32b(tile, ul_s, ul_t, width, height);
2300   }
2301   else
2302   {
2303     // check if points to bad location
2304     if (offs + line_n*height > BMASK)
2305       height = (BMASK - offs) / line_n;
2306     if (height == 0)
2307       return;
2308
2309     wxUint32 wid_64 = rdp.tiles[tile].line;
2310     unsigned char *dst = ((unsigned char *)rdp.tmem) + (rdp.tiles[tile].t_mem<<3);
2311     unsigned char *end = ((unsigned char *)rdp.tmem) + 4096 - (wid_64<<3);
2312     loadTile((uint32_t *)gfx.RDRAM, (uint32_t *)dst, wid_64, height, line_n, offs, (uint32_t *)end);
2313   }
2314   FRDP("loadtile: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile,
2315     ul_s, ul_t, lr_s, lr_t);
2316
2317   if (fb_hwfbe_enabled)
2318     setTBufTex(rdp.tiles[tile].t_mem, rdp.tiles[tile].line*height);
2319 }
2320
2321 static void rdp_settile()
2322 {
2323   tile_set = 1; // used to check if we only load the first settilesize
2324
2325   rdp.first = 0;
2326
2327   rdp.last_tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07);
2328   TILE *tile = &rdp.tiles[rdp.last_tile];
2329
2330   tile->format = (wxUint8)((rdp.cmd0 >> 21) & 0x07);
2331   tile->size = (wxUint8)((rdp.cmd0 >> 19) & 0x03);
2332   tile->line = (wxUint16)((rdp.cmd0 >> 9) & 0x01FF);
2333   tile->t_mem = (wxUint16)(rdp.cmd0 & 0x1FF);
2334   tile->palette = (wxUint8)((rdp.cmd1 >> 20) & 0x0F);
2335   tile->clamp_t = (wxUint8)((rdp.cmd1 >> 19) & 0x01);
2336   tile->mirror_t = (wxUint8)((rdp.cmd1 >> 18) & 0x01);
2337   tile->mask_t = (wxUint8)((rdp.cmd1 >> 14) & 0x0F);
2338   tile->shift_t = (wxUint8)((rdp.cmd1 >> 10) & 0x0F);
2339   tile->clamp_s = (wxUint8)((rdp.cmd1 >> 9) & 0x01);
2340   tile->mirror_s = (wxUint8)((rdp.cmd1 >> 8) & 0x01);
2341   tile->mask_s = (wxUint8)((rdp.cmd1 >> 4) & 0x0F);
2342   tile->shift_s = (wxUint8)(rdp.cmd1 & 0x0F);
2343
2344   rdp.update |= UPDATE_TEXTURE;
2345
2346   FRDP ("settile: tile: %d, format: %s, size: %s, line: %d, "
2347     "t_mem: %08lx, palette: %d, clamp_t/mirror_t: %s, mask_t: %d, "
2348     "shift_t: %d, clamp_s/mirror_s: %s, mask_s: %d, shift_s: %d\n",
2349     rdp.last_tile, str_format[tile->format], str_size[tile->size], tile->line,
2350     tile->t_mem, tile->palette, str_cm[(tile->clamp_t<<1)|tile->mirror_t], tile->mask_t,
2351     tile->shift_t, str_cm[(tile->clamp_s<<1)|tile->mirror_s], tile->mask_s, tile->shift_s);
2352
2353   if (fb_hwfbe_enabled && rdp.last_tile < rdp.cur_tile + 2)
2354   {
2355     for (int i = 0; i < 2; i++)
2356     {
2357       if (rdp.aTBuffTex[i])
2358       {
2359         if (rdp.aTBuffTex[i]->t_mem == tile->t_mem)
2360         {
2361           if (rdp.aTBuffTex[i]->size == tile->size)
2362           {
2363             rdp.aTBuffTex[i]->tile = rdp.last_tile;
2364             rdp.aTBuffTex[i]->info.format = tile->format == 0 ? GR_TEXFMT_RGB_565 : GR_TEXFMT_ALPHA_INTENSITY_88;
2365             FRDP("rdp.aTBuffTex[%d] tile=%d, format=%s\n", i, rdp.last_tile, tile->format == 0 ? "RGB565" : "Alpha88");
2366           }
2367           else
2368             rdp.aTBuffTex[i] = 0;
2369           break;
2370         }
2371         else if (rdp.aTBuffTex[i]->tile == rdp.last_tile) //wrong! t_mem must be the same
2372           rdp.aTBuffTex[i] = 0;
2373       }
2374     }
2375   }
2376 }
2377
2378 //
2379 // fillrect - fills a rectangle
2380 //
2381
2382 static void rdp_fillrect()
2383 {
2384   wxUint32 ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14);
2385   wxUint32 ul_y = (rdp.cmd1 & 0x00000FFF) >> 2;
2386   wxUint32 lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1;
2387   wxUint32 lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1;
2388   if ((ul_x > lr_x) || (ul_y > lr_y))
2389   {
2390     LRDP("Fillrect. Wrong coordinates. Skipped\n");
2391     return;
2392   }
2393   int pd_multiplayer = (settings.ucode == ucode_PerfectDark) && (rdp.cycle_mode == 3) && (rdp.fill_color == 0xFFFCFFFC);
2394   if ((rdp.cimg == rdp.zimg) || (fb_emulation_enabled && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg) || pd_multiplayer)
2395   {
2396     LRDP("Fillrect - cleared the depth buffer\n");
2397     if (fullscreen)
2398     {
2399       if (!(settings.hacks&hack_Hyperbike) || rdp.ci_width > 64) //do not clear main depth buffer for aux depth buffers
2400       {
2401         update_scissor ();
2402         grDepthMask (FXTRUE);
2403         grColorMask (FXFALSE, FXFALSE);
2404         grBufferClear (0, 0, rdp.fill_color ? rdp.fill_color&0xFFFF : 0xFFFF);
2405         grColorMask (FXTRUE, FXTRUE);
2406         rdp.update |= UPDATE_ZBUF_ENABLED;
2407       }
2408       //if (settings.frame_buffer&fb_depth_clear)
2409       {
2410         ul_x = min(max(ul_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2411         lr_x = min(max(lr_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2412         ul_y = min(max(ul_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2413         lr_y = min(max(lr_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2414         wxUint32 zi_width_in_dwords = rdp.ci_width >> 1;
2415         ul_x >>= 1;
2416         lr_x >>= 1;
2417         wxUint32 * dst = (wxUint32*)(gfx.RDRAM+rdp.cimg);
2418         dst += ul_y * zi_width_in_dwords;
2419         for (wxUint32 y = ul_y; y < lr_y; y++)
2420         {
2421           for (wxUint32 x = ul_x; x < lr_x; x++)
2422           {
2423             dst[x] = rdp.fill_color;
2424           }
2425           dst += zi_width_in_dwords;
2426         }
2427       }
2428     }
2429     return;
2430   }
2431
2432   if (rdp.skip_drawing)
2433   {
2434     LRDP("Fillrect skipped\n");
2435     return;
2436   }
2437
2438   if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x - ul_x) && (rdp.cur_image->height == lr_y - ul_y))
2439   {
2440     wxUint32 color = rdp.fill_color;
2441     if (rdp.ci_size < 3)
2442     {
2443           color = ((color&1)?0xFF:0) |
2444                 ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2445                 ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2446                 ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2447     }
2448     grDepthMask (FXFALSE);
2449     grBufferClear (color, 0, 0xFFFF);
2450     grDepthMask (FXTRUE);
2451     rdp.update |= UPDATE_ZBUF_ENABLED;
2452     LRDP("Fillrect - cleared the texture buffer\n");
2453     return;
2454   }
2455
2456   // Update scissor
2457   if (fullscreen)
2458     update_scissor ();
2459
2460   if (settings.decrease_fillrect_edge && rdp.cycle_mode == 0)
2461   {
2462     lr_x--; lr_y--;
2463   }
2464   FRDP("fillrect (%d,%d) -> (%d,%d), cycle mode: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, rdp.cycle_mode,
2465     rdp.tri_n, rdp.tri_n+1);
2466
2467   FRDP("scissor (%d,%d) -> (%d,%d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x,
2468     rdp.scissor.lr_y);
2469
2470   // KILL the floating point error with 0.01f
2471   wxInt32 s_ul_x = (wxUint32)min(max(ul_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
2472   wxInt32 s_lr_x = (wxUint32)min(max(lr_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
2473   wxInt32 s_ul_y = (wxUint32)min(max(ul_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y);
2474   wxInt32 s_lr_y = (wxUint32)min(max(lr_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y);
2475
2476   if (s_lr_x < 0) s_lr_x = 0;
2477   if (s_lr_y < 0) s_lr_y = 0;
2478   if ((wxUint32)s_ul_x > settings.res_x) s_ul_x = settings.res_x;
2479   if ((wxUint32)s_ul_y > settings.res_y) s_ul_y = settings.res_y;
2480
2481   FRDP (" - %d, %d, %d, %d\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
2482
2483   if (fullscreen)
2484   {
2485     grFogMode (GR_FOG_DISABLE);
2486
2487     const float Z = (rdp.cycle_mode == 3) ? 0.0f : set_sprite_combine_mode();
2488
2489     // Draw the rectangle
2490     VERTEX v[4] = {
2491       { (float)s_ul_x, (float)s_ul_y, Z, 1.0f,  0,0,0,0,  {0,0,0,0}, 0,0, 0,0,0,0},
2492       { (float)s_lr_x, (float)s_ul_y, Z, 1.0f,  0,0,0,0,  {0,0,0,0}, 0,0, 0,0,0,0},
2493       { (float)s_ul_x, (float)s_lr_y, Z, 1.0f,  0,0,0,0,  {0,0,0,0}, 0,0, 0,0,0,0},
2494       { (float)s_lr_x, (float)s_lr_y, Z, 1.0f,  0,0,0,0,  {0,0,0,0}, 0,0, 0,0,0,0} };
2495
2496       if (rdp.cycle_mode == 3)
2497       {
2498         wxUint32 color = rdp.fill_color;
2499
2500         if ((settings.hacks&hack_PMario) && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux)
2501         {
2502           //background of auxiliary frame buffers must have zero alpha.
2503           //make it black, set 0 alpha to plack pixels on frame buffer read
2504           color = 0;
2505         }
2506         else if (rdp.ci_size < 3)
2507         {
2508           color = ((color&1)?0xFF:0) |
2509             ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2510             ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2511             ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2512         }
2513
2514         grConstantColorValue (color);
2515
2516         grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
2517           GR_COMBINE_FACTOR_NONE,
2518           GR_COMBINE_LOCAL_CONSTANT,
2519           GR_COMBINE_OTHER_NONE,
2520           FXFALSE);
2521
2522         grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
2523           GR_COMBINE_FACTOR_NONE,
2524           GR_COMBINE_LOCAL_CONSTANT,
2525           GR_COMBINE_OTHER_NONE,
2526           FXFALSE);
2527
2528         grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO);
2529
2530         grAlphaTestFunction (GR_CMP_ALWAYS);
2531         if (grStippleModeExt)
2532         grStippleModeExt(GR_STIPPLE_DISABLE);
2533
2534         grCullMode(GR_CULL_DISABLE);
2535         grFogMode (GR_FOG_DISABLE);
2536         grDepthBufferFunction (GR_CMP_ALWAYS);
2537         grDepthMask (FXFALSE);
2538
2539         rdp.update |= UPDATE_COMBINE | UPDATE_CULL_MODE | UPDATE_FOG_ENABLED | UPDATE_ZBUF_ENABLED;
2540       }
2541       else
2542       {
2543         wxUint32 cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF);
2544         wxUint32 cmb_mode_a = (rdp.cycle1 & 0x0FFF0000) | ((rdp.cycle2 >> 16) & 0x00000FFF);
2545         if (cmb_mode_c == 0x9fff9fff || cmb_mode_a == 0x09ff09ff) //shade
2546         {
2547           AllowShadeMods (v, 4);
2548           for (int k = 0; k < 4; k++)
2549             apply_shade_mods (&v[k]);
2550         }
2551         if ((rdp.othermode_l & 0x4000) && ((rdp.othermode_l >> 16) == 0x0550)) //special blender mode for Bomberman64
2552         {
2553           grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
2554             GR_COMBINE_FACTOR_NONE,
2555             GR_COMBINE_LOCAL_CONSTANT,
2556             GR_COMBINE_OTHER_NONE,
2557             FXFALSE);
2558           grConstantColorValue((cmb.ccolor&0xFFFFFF00)|(rdp.fog_color&0xFF));
2559           rdp.update |= UPDATE_COMBINE;
2560         }
2561       }
2562
2563       if (settings.wireframe)
2564       {
2565         SetWireframeCol ();
2566         grDrawLine (&v[0], &v[2]);
2567         grDrawLine (&v[2], &v[1]);
2568         grDrawLine (&v[1], &v[0]);
2569         grDrawLine (&v[2], &v[3]);
2570         grDrawLine (&v[3], &v[1]);
2571         //grDrawLine (&v[1], &v[2]);
2572       }
2573       else
2574       {
2575         grDrawTriangle (&v[0], &v[2], &v[1]);
2576         grDrawTriangle (&v[2], &v[3], &v[1]);
2577       }
2578
2579       if (_debugger.capture)
2580       {
2581         VERTEX v1[3];
2582         v1[0] = v[0];
2583         v1[1] = v[2];
2584         v1[2] = v[1];
2585         add_tri (v1, 3, TRI_FILLRECT);
2586         rdp.tri_n ++;
2587         v1[0] = v[2];
2588         v1[1] = v[3];
2589         add_tri (v1, 3, TRI_FILLRECT);
2590         rdp.tri_n ++;
2591       }
2592       else
2593         rdp.tri_n += 2;
2594   }
2595   else
2596   {
2597     rdp.tri_n += 2;
2598   }
2599 }
2600
2601 //
2602 // setfillcolor - sets the filling color
2603 //
2604
2605 static void rdp_setfillcolor()
2606 {
2607   rdp.fill_color = rdp.cmd1;
2608   rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
2609
2610   FRDP("setfillcolor: %08lx\n", rdp.cmd1);
2611 }
2612
2613 static void rdp_setfogcolor()
2614 {
2615   rdp.fog_color = rdp.cmd1;
2616   rdp.update |= UPDATE_COMBINE | UPDATE_FOG_ENABLED;
2617
2618   FRDP("setfogcolor - %08lx\n", rdp.cmd1);
2619 }
2620
2621 static void rdp_setblendcolor()
2622 {
2623   rdp.blend_color = rdp.cmd1;
2624   rdp.update |= UPDATE_COMBINE;
2625
2626   FRDP("setblendcolor: %08lx\n", rdp.cmd1);
2627 }
2628
2629 static void rdp_setprimcolor()
2630 {
2631   rdp.prim_color = rdp.cmd1;
2632   rdp.prim_lodmin = (rdp.cmd0 >> 8) & 0xFF;
2633   rdp.prim_lodfrac = max(rdp.cmd0 & 0xFF, rdp.prim_lodmin);
2634   rdp.update |= UPDATE_COMBINE;
2635
2636   FRDP("setprimcolor: %08lx, lodmin: %d, lodfrac: %d\n", rdp.cmd1, rdp.prim_lodmin,
2637     rdp.prim_lodfrac);
2638 }
2639
2640 static void rdp_setenvcolor()
2641 {
2642   rdp.env_color = rdp.cmd1;
2643   rdp.update |= UPDATE_COMBINE;
2644
2645   FRDP("setenvcolor: %08lx\n", rdp.cmd1);
2646 }
2647
2648 static void rdp_setcombine()
2649 {
2650   rdp.c_a0  = (wxUint8)((rdp.cmd0 >> 20) & 0xF);
2651   rdp.c_b0  = (wxUint8)((rdp.cmd1 >> 28) & 0xF);
2652   rdp.c_c0  = (wxUint8)((rdp.cmd0 >> 15) & 0x1F);
2653   rdp.c_d0  = (wxUint8)((rdp.cmd1 >> 15) & 0x7);
2654   rdp.c_Aa0 = (wxUint8)((rdp.cmd0 >> 12) & 0x7);
2655   rdp.c_Ab0 = (wxUint8)((rdp.cmd1 >> 12) & 0x7);
2656   rdp.c_Ac0 = (wxUint8)((rdp.cmd0 >> 9)  & 0x7);
2657   rdp.c_Ad0 = (wxUint8)((rdp.cmd1 >> 9)  & 0x7);
2658
2659   rdp.c_a1  = (wxUint8)((rdp.cmd0 >> 5)  & 0xF);
2660   rdp.c_b1  = (wxUint8)((rdp.cmd1 >> 24) & 0xF);
2661   rdp.c_c1  = (wxUint8)((rdp.cmd0 >> 0)  & 0x1F);
2662   rdp.c_d1  = (wxUint8)((rdp.cmd1 >> 6)  & 0x7);
2663   rdp.c_Aa1 = (wxUint8)((rdp.cmd1 >> 21) & 0x7);
2664   rdp.c_Ab1 = (wxUint8)((rdp.cmd1 >> 3)  & 0x7);
2665   rdp.c_Ac1 = (wxUint8)((rdp.cmd1 >> 18) & 0x7);
2666   rdp.c_Ad1 = (wxUint8)((rdp.cmd1 >> 0)  & 0x7);
2667
2668   rdp.cycle1 = (rdp.c_a0<<0)  | (rdp.c_b0<<4)  | (rdp.c_c0<<8)  | (rdp.c_d0<<13)|
2669     (rdp.c_Aa0<<16)| (rdp.c_Ab0<<19)| (rdp.c_Ac0<<22)| (rdp.c_Ad0<<25);
2670   rdp.cycle2 = (rdp.c_a1<<0)  | (rdp.c_b1<<4)  | (rdp.c_c1<<8)  | (rdp.c_d1<<13)|
2671     (rdp.c_Aa1<<16)| (rdp.c_Ab1<<19)| (rdp.c_Ac1<<22)| (rdp.c_Ad1<<25);
2672
2673   rdp.update |= UPDATE_COMBINE;
2674
2675   FRDP("setcombine\na0=%s b0=%s c0=%s d0=%s\nAa0=%s Ab0=%s Ac0=%s Ad0=%s\na1=%s b1=%s c1=%s d1=%s\nAa1=%s Ab1=%s Ac1=%s Ad1=%s\n",
2676     Mode0[rdp.c_a0], Mode1[rdp.c_b0], Mode2[rdp.c_c0], Mode3[rdp.c_d0],
2677     Alpha0[rdp.c_Aa0], Alpha1[rdp.c_Ab0], Alpha2[rdp.c_Ac0], Alpha3[rdp.c_Ad0],
2678     Mode0[rdp.c_a1], Mode1[rdp.c_b1], Mode2[rdp.c_c1], Mode3[rdp.c_d1],
2679     Alpha0[rdp.c_Aa1], Alpha1[rdp.c_Ab1], Alpha2[rdp.c_Ac1], Alpha3[rdp.c_Ad1]);
2680 }
2681
2682 //
2683 // settextureimage - sets the source for an image copy
2684 //
2685
2686 static void rdp_settextureimage()
2687 {
2688   static const char *format[]   = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
2689   static const char *size[]     = { "4bit", "8bit", "16bit", "32bit" };
2690
2691   rdp.timg.format = (wxUint8)((rdp.cmd0 >> 21) & 0x07);
2692   rdp.timg.size = (wxUint8)((rdp.cmd0 >> 19) & 0x03);
2693   rdp.timg.width = (wxUint16)(1 + (rdp.cmd0 & 0x00000FFF));
2694   rdp.timg.addr = segoffset(rdp.cmd1);
2695   if (ucode5_texshiftaddr)
2696   {
2697     if (rdp.timg.format == 0)
2698     {
2699       wxUint16 * t = (wxUint16*)(gfx.RDRAM+ucode5_texshiftaddr);
2700       ucode5_texshift = t[ucode5_texshiftcount^1];
2701       rdp.timg.addr += ucode5_texshift;
2702     }
2703     else
2704     {
2705       ucode5_texshiftaddr = 0;
2706       ucode5_texshift = 0;
2707       ucode5_texshiftcount = 0;
2708     }
2709   }
2710   rdp.s2dex_tex_loaded = TRUE;
2711   rdp.update |= UPDATE_TEXTURE;
2712
2713   if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self && (rdp.timg.addr >= rdp.cimg) && (rdp.timg.addr < rdp.ci_end))
2714   {
2715     if (!rdp.fb_drawn)
2716     {
2717       if (!rdp.cur_image)
2718         CopyFrameBuffer();
2719       else
2720         CloseTextureBuffer(TRUE);
2721       rdp.fb_drawn = TRUE;
2722     }
2723   }
2724
2725   if (fb_hwfbe_enabled) //search this texture among drawn texture buffers
2726     FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
2727
2728   FRDP("settextureimage: format: %s, size: %s, width: %d, addr: %08lx\n",
2729     format[rdp.timg.format], size[rdp.timg.size],
2730     rdp.timg.width, rdp.timg.addr);
2731 }
2732
2733 static void rdp_setdepthimage()
2734 {
2735   rdp.zimg = segoffset(rdp.cmd1) & BMASK;
2736   rdp.zi_width = rdp.ci_width;
2737   FRDP("setdepthimage - %08lx\n", rdp.zimg);
2738 }
2739
2740 int SwapOK = TRUE;
2741 static void RestoreScale()
2742 {
2743   FRDP("Return to original scale: x = %f, y = %f\n", rdp.scale_x_bak, rdp.scale_y_bak);
2744   rdp.scale_x = rdp.scale_x_bak;
2745   rdp.scale_y = rdp.scale_y_bak;
2746   //    update_scissor();
2747   rdp.view_scale[0] *= rdp.scale_x;
2748   rdp.view_scale[1] *= rdp.scale_y;
2749   rdp.view_trans[0] *= rdp.scale_x;
2750   rdp.view_trans[1] *= rdp.scale_y;
2751   rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR;
2752   //*
2753   if (fullscreen)
2754   {
2755     grDepthMask (FXFALSE);
2756     grBufferClear (0, 0, 0xFFFF);
2757     grDepthMask (FXTRUE);
2758   }
2759   //*/
2760 }
2761
2762 static wxUint32 swapped_addr = 0;
2763
2764 static void rdp_setcolorimage()
2765 {
2766 //unsigned int ticks = ticksGetTicks();
2767 //bool showdeb = false;
2768   if (fb_emulation_enabled && (rdp.num_of_ci < NUMTEXBUF))
2769   {
2770     COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count];
2771     COLOR_IMAGE & prev_fb = rdp.frame_buffers[rdp.ci_count?rdp.ci_count-1:0];
2772     COLOR_IMAGE & next_fb = rdp.frame_buffers[rdp.ci_count+1];
2773 //if (cur_fb.status==ci_aux) showdeb = true;
2774 //if (showdeb) printf("rp_setcolorimage, status=%i\n", cur_fb.status);
2775     switch (cur_fb.status)
2776     {
2777     case ci_main:
2778       {
2779
2780         if (rdp.ci_count == 0)
2781         {
2782           if ((rdp.ci_status == ci_aux)) //for PPL
2783           {
2784             float sx = rdp.scale_x;
2785             float sy = rdp.scale_y;
2786             rdp.scale_x = 1.0f;
2787             rdp.scale_y = 1.0f;
2788             CopyFrameBuffer ();
2789             rdp.scale_x = sx;
2790             rdp.scale_y = sy;
2791           }
2792           if (!fb_hwfbe_enabled)
2793           {
2794             if ((rdp.num_of_ci > 1) &&
2795               (next_fb.status == ci_aux) &&
2796               (next_fb.width >= cur_fb.width))
2797             {
2798               rdp.scale_x = 1.0f;
2799               rdp.scale_y = 1.0f;
2800             }
2801           }
2802           else if (rdp.copy_ci_index && (settings.hacks&hack_PMario)) //tidal wave
2803             OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2804         }
2805         else if (!rdp.motionblur && fb_hwfbe_enabled && !SwapOK && (rdp.ci_count <= rdp.copy_ci_index))
2806         {
2807           if (next_fb.status == ci_aux_copy)
2808             OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2809           else
2810             OpenTextureBuffer(rdp.frame_buffers[rdp.copy_ci_index]);
2811         }
2812         else if (fb_hwfbe_enabled && prev_fb.status == ci_aux)
2813         {
2814           if (rdp.motionblur)
2815           {
2816             rdp.cur_image = &(rdp.texbufs[rdp.cur_tex_buf].images[0]);
2817             grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
2818             grTextureBufferExt( rdp.cur_image->tmu, rdp.cur_image->tex_addr, rdp.cur_image->info.smallLodLog2, rdp.cur_image->info.largeLodLog2,
2819               rdp.cur_image->info.aspectRatioLog2, rdp.cur_image->info.format, GR_MIPMAPLEVELMASK_BOTH );
2820           }
2821           else if (rdp.read_whole_frame)
2822           {
2823             OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2824           }
2825         }
2826         //else if (rdp.ci_status == ci_aux && !rdp.copy_ci_index)
2827         //  CloseTextureBuffer();
2828
2829         rdp.skip_drawing = FALSE;
2830       }
2831       break;
2832     case ci_copy:
2833       {
2834         if (!rdp.motionblur || (settings.frame_buffer&fb_motionblur))
2835         {
2836           if (cur_fb.width == rdp.ci_width)
2837           {
2838             if (CopyTextureBuffer(prev_fb, cur_fb))
2839             {
2840               //                      if (CloseTextureBuffer(TRUE))
2841               //*
2842               if ((settings.hacks&hack_Zelda) && (rdp.frame_buffers[rdp.ci_count+2].status == ci_aux) && !rdp.fb_drawn) //hack for photo camera in Zelda MM
2843               {
2844                 CopyFrameBuffer (GR_BUFFER_TEXTUREBUFFER_EXT);
2845                 rdp.fb_drawn = TRUE;
2846                 memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2847               }
2848               //*/
2849             }
2850             else
2851             {
2852               if (!rdp.fb_drawn || prev_fb.status == ci_copy_self)
2853               {
2854                 CopyFrameBuffer ();
2855                 rdp.fb_drawn = TRUE;
2856               }
2857               memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2858             }
2859           }
2860           else
2861           {
2862             CloseTextureBuffer(TRUE);
2863           }
2864         }
2865         else
2866         {
2867           memset(gfx.RDRAM+cur_fb.addr, 0, cur_fb.width*cur_fb.height*rdp.ci_size);
2868         }
2869         rdp.skip_drawing = TRUE;
2870       }
2871       break;
2872     case ci_aux_copy:
2873       {
2874         rdp.skip_drawing = FALSE;
2875         if (CloseTextureBuffer(prev_fb.status != ci_aux_copy))
2876           ;
2877         else if (!rdp.fb_drawn)
2878         {
2879           CopyFrameBuffer ();
2880           rdp.fb_drawn = TRUE;
2881         }
2882         if (fb_hwfbe_enabled)
2883           OpenTextureBuffer(cur_fb);
2884       }
2885       break;
2886     case ci_old_copy:
2887       {
2888         if (!rdp.motionblur || (settings.frame_buffer&fb_motionblur))
2889         {
2890           if (cur_fb.width == rdp.ci_width)
2891           {
2892             memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.maincimg[1].addr, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2893           }
2894           //rdp.skip_drawing = TRUE;
2895         }
2896         else
2897         {
2898           memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<<rdp.ci_size>>1);
2899         }
2900       }
2901       break;
2902       /*
2903       else if (rdp.frame_buffers[rdp.ci_count].status == ci_main_i)
2904       {
2905       //       CopyFrameBuffer ();
2906       rdp.scale_x = rdp.scale_x_bak;
2907       rdp.scale_y = rdp.scale_y_bak;
2908       rdp.skip_drawing = FALSE;
2909       }
2910       */
2911     case ci_aux:
2912       {
2913 //unsigned int tticks = ticksGetTicks();
2914         if (!fb_hwfbe_enabled && cur_fb.format != 0)
2915           rdp.skip_drawing = TRUE;
2916         else
2917         {
2918           rdp.skip_drawing = FALSE;
2919           if (fb_hwfbe_enabled && OpenTextureBuffer(cur_fb))
2920             ;
2921           else
2922           {
2923             if (cur_fb.format != 0)
2924               rdp.skip_drawing = TRUE;
2925             if (rdp.ci_count == 0)
2926             {
2927               //           if (rdp.num_of_ci > 1)
2928               //           {
2929               rdp.scale_x = 1.0f;
2930               rdp.scale_y = 1.0f;
2931               //           }
2932             }
2933             else if (!fb_hwfbe_enabled && (prev_fb.status == ci_main) &&
2934               (prev_fb.width == cur_fb.width)) // for Pokemon Stadium
2935               CopyFrameBuffer ();
2936           }
2937         }
2938         cur_fb.status = ci_aux;
2939 //tticks = ticksGetTicks() - ticks;
2940 //printf("intermediary: %u ms\n", tticks);
2941       }
2942       break;
2943     case ci_zimg:
2944       if (settings.ucode != ucode_PerfectDark)
2945       {
2946         if (fb_hwfbe_enabled && !rdp.copy_ci_index && (rdp.copy_zi_index || (settings.hacks&hack_BAR)))
2947         {
2948           GrLOD_t LOD = GR_LOD_LOG2_1024;
2949           if (settings.scr_res_x > 1024)
2950             LOD = GR_LOD_LOG2_2048;
2951           grTextureAuxBufferExt( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, LOD, LOD,
2952             GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
2953           grAuxBufferExt( GR_BUFFER_TEXTUREAUXBUFFER_EXT );
2954           LRDP("rdp_setcolorimage - set texture depth buffer to TMU0\n");
2955         }
2956       }
2957       rdp.skip_drawing = TRUE;
2958       break;
2959     case ci_zcopy:
2960       if (settings.ucode != ucode_PerfectDark)
2961       {
2962         if (fb_hwfbe_enabled && !rdp.copy_ci_index && rdp.copy_zi_index == rdp.ci_count)
2963         {
2964           CopyDepthBuffer();
2965         }
2966         rdp.skip_drawing = TRUE;
2967       }
2968       break;
2969     case ci_useless:
2970       rdp.skip_drawing = TRUE;
2971       break;
2972     case ci_copy_self:
2973       if (fb_hwfbe_enabled && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2))
2974         OpenTextureBuffer(cur_fb);
2975       rdp.skip_drawing = FALSE;
2976       break;
2977     default:
2978       rdp.skip_drawing = FALSE;
2979     }
2980
2981     if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium
2982     {
2983       if (!fb_hwfbe_enabled && prev_fb.format == 0)
2984         CopyFrameBuffer ();
2985       else if ((settings.hacks&hack_Knockout) && prev_fb.width < 100)
2986         CopyFrameBuffer (GR_BUFFER_TEXTUREBUFFER_EXT);
2987     }
2988     if (!fb_hwfbe_enabled && cur_fb.status == ci_copy)
2989     {
2990       if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux))
2991       {
2992         RestoreScale();
2993       }
2994     }
2995     if (!fb_hwfbe_enabled && cur_fb.status == ci_aux)
2996     {
2997       if (cur_fb.format == 0)
2998       {
2999         if ((settings.hacks&hack_PPL) && (rdp.scale_x < 1.1f))  //need to put current image back to frame buffer
3000         {
3001           int width = cur_fb.width;
3002           int height = cur_fb.height;
3003           wxUint16 *ptr_dst = new wxUint16[width*height];
3004           wxUint16 *ptr_src = (wxUint16*)(gfx.RDRAM+cur_fb.addr);
3005           wxUint16 c;
3006
3007           for (int y=0; y<height; y++)
3008           {
3009             for (int x=0; x<width; x++)
3010             {
3011               c = ((ptr_src[(x + y * width)^1]) >> 1) | 0x8000;
3012               ptr_dst[x + y * width] = c;
3013             }
3014           }
3015           grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
3016             (wxUint32)rdp.offset_x,
3017             (wxUint32)rdp.offset_y,
3018             GR_LFB_SRC_FMT_555,
3019             width,
3020             height,
3021             FXFALSE,
3022             width<<1,
3023             ptr_dst);
3024           delete[] ptr_dst;
3025         }
3026         /*
3027         else  //just clear buffer
3028         {
3029
3030         grColorMask(FXTRUE, FXTRUE);
3031         grBufferClear (0, 0, 0xFFFF);
3032         }
3033         */
3034       }
3035     }
3036
3037     if ((cur_fb.status == ci_main) && (rdp.ci_count > 0))
3038     {
3039       int to_org_res = TRUE;
3040       for (int i = rdp.ci_count + 1; i < rdp.num_of_ci; i++)
3041       {
3042         if ((rdp.frame_buffers[i].status != ci_main) && (rdp.frame_buffers[i].status != ci_zimg) && (rdp.frame_buffers[i].status != ci_zcopy))
3043         {
3044           to_org_res = FALSE;
3045           break;
3046         }
3047       }
3048       if (to_org_res)
3049       {
3050         LRDP("return to original scale\n");
3051         rdp.scale_x = rdp.scale_x_bak;
3052         rdp.scale_y = rdp.scale_y_bak;
3053         if (fb_hwfbe_enabled && !rdp.read_whole_frame)
3054           CloseTextureBuffer();
3055       }
3056       if (fb_hwfbe_enabled && !rdp.read_whole_frame && (prev_fb.status >= ci_aux) && (rdp.ci_count > rdp.copy_ci_index))
3057         CloseTextureBuffer();
3058
3059     }
3060     rdp.ci_status = cur_fb.status;
3061     rdp.ci_count++;
3062   }
3063
3064   rdp.ocimg = rdp.cimg;
3065   rdp.cimg = segoffset(rdp.cmd1) & BMASK;
3066   rdp.ci_width = (rdp.cmd0 & 0xFFF) + 1;
3067   if (fb_emulation_enabled)
3068     rdp.ci_height = rdp.frame_buffers[rdp.ci_count-1].height;
3069   else if (rdp.ci_width == 32)
3070     rdp.ci_height = 32;
3071   else
3072     rdp.ci_height = rdp.scissor_o.lr_y;
3073   if (rdp.zimg == rdp.cimg)
3074   {
3075     rdp.zi_width = rdp.ci_width;
3076     //    int zi_height = min((int)rdp.zi_width*3/4, (int)rdp.vi_height);
3077     //    rdp.zi_words = rdp.zi_width * zi_height;
3078   }
3079   wxUint32 format = (rdp.cmd0 >> 21) & 0x7;
3080   rdp.ci_size = (rdp.cmd0 >> 19) & 0x3;
3081   rdp.ci_end = rdp.cimg + ((rdp.ci_width*rdp.ci_height)<<(rdp.ci_size-1));
3082   FRDP("setcolorimage - %08lx, width: %d,  height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size);
3083   FRDP("cimg: %08lx, ocimg: %08lx, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK);
3084   
3085 //if (showdeb) printf("setcolorimage - %08x, width: %d,  height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size);
3086 //if (showdeb) printf("cimg: %08x, ocimg: %08x, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK);
3087
3088   if (format != 0) //can't draw into non RGBA buffer
3089   {
3090     if (!rdp.cur_image)
3091     {
3092       if (fb_hwfbe_enabled && rdp.ci_width <= 64)
3093         OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]);
3094       else if (format > 2)
3095         rdp.skip_drawing = TRUE;
3096       return;
3097     }
3098   }
3099   else
3100   {
3101     if (!fb_emulation_enabled)
3102       rdp.skip_drawing = FALSE;
3103   }
3104
3105   CI_SET = TRUE;
3106   if (settings.swapmode > 0)
3107   {
3108     if (rdp.zimg == rdp.cimg)
3109       rdp.updatescreen = 1;
3110
3111     int viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE;
3112     if ((rdp.zimg != rdp.cimg) && (rdp.ocimg != rdp.cimg) && SwapOK && viSwapOK && !rdp.cur_image)
3113     {
3114       if (fb_emulation_enabled)
3115         rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3116       else
3117         rdp.maincimg[0].addr = rdp.cimg;
3118       rdp.last_drawn_ci_addr = (settings.swapmode == 2) ? swapped_addr : rdp.maincimg[0].addr;
3119       swapped_addr = rdp.cimg;
3120       newSwapBuffers();
3121       rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
3122       SwapOK = FALSE;
3123       if (fb_hwfbe_enabled)
3124       {
3125         if (rdp.copy_ci_index && (rdp.frame_buffers[rdp.ci_count-1].status != ci_zimg))
3126         {
3127           int idx = (rdp.frame_buffers[rdp.ci_count].status == ci_aux_copy) ? rdp.main_ci_index : rdp.copy_ci_index;
3128           FRDP("attempt open tex buffer. status: %s, addr: %08lx\n", CIStatus[rdp.frame_buffers[idx].status], rdp.frame_buffers[idx].addr);
3129           OpenTextureBuffer(rdp.frame_buffers[idx]);
3130           if (rdp.frame_buffers[rdp.copy_ci_index].status == ci_main) //tidal wave
3131             rdp.copy_ci_index = 0;
3132         }
3133         else if (rdp.read_whole_frame && !rdp.cur_image)
3134         {
3135           OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3136         }
3137       }
3138     }
3139   }
3140 //ticks = ticksGetTicks() - ticks;
3141 //if (showdeb) printf("time = %u\n", ticks);
3142 }
3143
3144 static void rsp_reserved0()
3145 {
3146   if (settings.ucode == ucode_DiddyKong)
3147   {
3148     ucode5_texshiftaddr = segoffset(rdp.cmd1);
3149     ucode5_texshiftcount = 0;
3150     FRDP("uc5_texshift. addr: %08lx\n", ucode5_texshiftaddr);
3151   }
3152   else
3153   {
3154     RDP_E("reserved0 - IGNORED\n");
3155     LRDP("reserved0 - IGNORED\n");
3156   }
3157 }
3158
3159 static void rsp_reserved1()
3160 {
3161   LRDP("reserved1 - ignored\n");
3162 }
3163
3164 static void rsp_reserved2()
3165 {
3166   LRDP("reserved2\n");
3167 }
3168
3169 static void rsp_reserved3()
3170 {
3171   LRDP("reserved3 - ignored\n");
3172 }
3173
3174 void SetWireframeCol ()
3175 {
3176   if (!fullscreen) return;
3177
3178   switch (settings.wfmode)
3179   {
3180     //case 0: // normal colors, don't do anything
3181   case 1: // vertex colors
3182     grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3183       GR_COMBINE_FACTOR_NONE,
3184       GR_COMBINE_LOCAL_ITERATED,
3185       GR_COMBINE_OTHER_NONE,
3186       FXFALSE);
3187     grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3188       GR_COMBINE_FACTOR_NONE,
3189       GR_COMBINE_LOCAL_ITERATED,
3190       GR_COMBINE_OTHER_NONE,
3191       FXFALSE);
3192     grAlphaBlendFunction (GR_BLEND_ONE,
3193       GR_BLEND_ZERO,
3194       GR_BLEND_ZERO,
3195       GR_BLEND_ZERO);
3196     grTexCombine (GR_TMU0,
3197       GR_COMBINE_FUNCTION_ZERO,
3198       GR_COMBINE_FACTOR_NONE,
3199       GR_COMBINE_FUNCTION_ZERO,
3200       GR_COMBINE_FACTOR_NONE,
3201       FXFALSE, FXFALSE);
3202     grTexCombine (GR_TMU1,
3203       GR_COMBINE_FUNCTION_ZERO,
3204       GR_COMBINE_FACTOR_NONE,
3205       GR_COMBINE_FUNCTION_ZERO,
3206       GR_COMBINE_FACTOR_NONE,
3207       FXFALSE, FXFALSE);
3208     break;
3209   case 2: // red only
3210     grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3211       GR_COMBINE_FACTOR_NONE,
3212       GR_COMBINE_LOCAL_CONSTANT,
3213       GR_COMBINE_OTHER_NONE,
3214       FXFALSE);
3215     grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3216       GR_COMBINE_FACTOR_NONE,
3217       GR_COMBINE_LOCAL_CONSTANT,
3218       GR_COMBINE_OTHER_NONE,
3219       FXFALSE);
3220     grConstantColorValue (0xFF0000FF);
3221     grAlphaBlendFunction (GR_BLEND_ONE,
3222       GR_BLEND_ZERO,
3223       GR_BLEND_ZERO,
3224       GR_BLEND_ZERO);
3225     grTexCombine (GR_TMU0,
3226       GR_COMBINE_FUNCTION_ZERO,
3227       GR_COMBINE_FACTOR_NONE,
3228       GR_COMBINE_FUNCTION_ZERO,
3229       GR_COMBINE_FACTOR_NONE,
3230       FXFALSE, FXFALSE);
3231     grTexCombine (GR_TMU1,
3232       GR_COMBINE_FUNCTION_ZERO,
3233       GR_COMBINE_FACTOR_NONE,
3234       GR_COMBINE_FUNCTION_ZERO,
3235       GR_COMBINE_FACTOR_NONE,
3236       FXFALSE, FXFALSE);
3237     break;
3238   }
3239
3240   grAlphaTestFunction (GR_CMP_ALWAYS);
3241   grCullMode (GR_CULL_DISABLE);
3242
3243   rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE;
3244 }
3245
3246 /******************************************************************
3247 Function: FrameBufferRead
3248 Purpose:  This function is called to notify the dll that the
3249 frame buffer memory is beening read at the given address.
3250 DLL should copy content from its render buffer to the frame buffer
3251 in N64 RDRAM
3252 DLL is responsible to maintain its own frame buffer memory addr list
3253 DLL should copy 4KB block content back to RDRAM frame buffer.
3254 Emulator should not call this function again if other memory
3255 is read within the same 4KB range
3256 input:    addr          rdram address
3257 val                     val
3258 size            1 = wxUint8, 2 = wxUint16, 4 = wxUint32
3259 output:   none
3260 *******************************************************************/
3261
3262 #ifdef __cplusplus
3263 extern "C" {
3264 #endif
3265
3266 EXPORT void CALL FBRead(wxUint32 addr)
3267 {
3268   LOG ("FBRead ()\n");
3269
3270   if (cpu_fb_ignore)
3271     return;
3272   if (cpu_fb_write_called)
3273   {
3274     cpu_fb_ignore = TRUE;
3275     cpu_fb_write = FALSE;
3276     return;
3277   }
3278   cpu_fb_read_called = TRUE;
3279   wxUint32 a = segoffset(addr);
3280   FRDP("FBRead. addr: %08lx\n", a);
3281   if (!rdp.fb_drawn && (a >= rdp.cimg) && (a < rdp.ci_end))
3282   {
3283     fbreads_back++;
3284     //if (fbreads_back > 2) //&& (rdp.ci_width <= 320))
3285     {
3286       CopyFrameBuffer ();
3287       rdp.fb_drawn = TRUE;
3288     }
3289   }
3290   if (!rdp.fb_drawn_front && (a >= rdp.maincimg[1].addr) && (a < rdp.maincimg[1].addr + rdp.ci_width*rdp.ci_height*2))
3291   {
3292     fbreads_front++;
3293     //if (fbreads_front > 2)//&& (rdp.ci_width <= 320))
3294     {
3295       wxUint32 cimg = rdp.cimg;
3296       rdp.cimg = rdp.maincimg[1].addr;
3297       if (fb_emulation_enabled)
3298       {
3299         rdp.ci_width = rdp.maincimg[1].width;
3300         rdp.ci_count = 0;
3301         wxUint32 h = rdp.frame_buffers[0].height;
3302         rdp.frame_buffers[0].height = rdp.maincimg[1].height;
3303         CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3304         rdp.frame_buffers[0].height = h;
3305       }
3306       else
3307       {
3308         CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3309       }
3310       rdp.cimg = cimg;
3311       rdp.fb_drawn_front = TRUE;
3312     }
3313   }
3314 }
3315
3316 #if 0
3317 /******************************************************************
3318 Function: FrameBufferWriteList
3319 Purpose:  This function is called to notify the dll that the
3320 frame buffer has been modified by CPU at the given address.
3321 input:    FrameBufferModifyEntry *plist
3322 size = size of the plist, max = 1024
3323 output:   none
3324 *******************************************************************/
3325 EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, wxUint32 size)
3326 {
3327   LOG ("FBWList ()\n");
3328   FRDP("FBWList. size: %d\n", size);
3329 }
3330 #endif
3331
3332 /******************************************************************
3333 Function: FrameBufferWrite
3334 Purpose:  This function is called to notify the dll that the
3335 frame buffer has been modified by CPU at the given address.
3336 input:    addr          rdram address
3337 val                     val
3338 size            1 = wxUint8, 2 = wxUint16, 4 = wxUint32
3339 output:   none
3340 *******************************************************************/
3341 EXPORT void CALL FBWrite(wxUint32 addr, wxUint32 size)
3342 {
3343   LOG ("FBWrite ()\n");
3344   if (cpu_fb_ignore)
3345     return;
3346   if (cpu_fb_read_called)
3347   {
3348     cpu_fb_ignore = TRUE;
3349     cpu_fb_write = FALSE;
3350     return;
3351   }
3352   cpu_fb_write_called = TRUE;
3353   wxUint32 a = segoffset(addr);
3354   FRDP("FBWrite. addr: %08lx\n", a);
3355   if (a < rdp.cimg || a > rdp.ci_end)
3356     return;
3357   cpu_fb_write = TRUE;
3358   wxUint32 shift_l = (a-rdp.cimg) >> 1;
3359   wxUint32 shift_r = shift_l+2;
3360
3361   d_ul_x = min(d_ul_x, shift_l%rdp.ci_width);
3362   d_ul_y = min(d_ul_y, shift_l/rdp.ci_width);
3363   d_lr_x = max(d_lr_x, shift_r%rdp.ci_width);
3364   d_lr_y = max(d_lr_y, shift_r/rdp.ci_width);
3365 }
3366
3367
3368 /************************************************************************
3369 Function: FBGetFrameBufferInfo
3370 Purpose:  This function is called by the emulator core to retrieve frame
3371 buffer information from the video plugin in order to be able
3372 to notify the video plugin about CPU frame buffer read/write
3373 operations
3374
3375 size:
3376 = 1           byte
3377 = 2           word (16 bit) <-- this is N64 default depth buffer format
3378 = 4           dword (32 bit)
3379
3380 when frame buffer information is not available yet, set all values
3381 in the FrameBufferInfo structure to 0
3382
3383 input:    FrameBufferInfo pinfo[6]
3384 pinfo is pointed to a FrameBufferInfo structure which to be
3385 filled in by this function
3386 output:   Values are return in the FrameBufferInfo structure
3387 Plugin can return up to 6 frame buffer info
3388 ************************************************************************/
3389 ///*
3390 #if 0
3391 typedef struct
3392 {
3393   wxUint32 addr;
3394   wxUint32 size;
3395   wxUint32 width;
3396   wxUint32 height;
3397 } FrameBufferInfo;
3398 #endif
3399 EXPORT void CALL FBGetFrameBufferInfo(void *p)
3400 {
3401   VLOG ("FBGetFrameBufferInfo ()\n");
3402   FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
3403   memset(pinfo,0,sizeof(FrameBufferInfo)*6);
3404   if (!(settings.frame_buffer&fb_get_info))
3405     return;
3406   LRDP("FBGetFrameBufferInfo ()\n");
3407   //*
3408   if (fb_emulation_enabled)
3409   {
3410     pinfo[0].addr   = rdp.maincimg[1].addr;
3411     pinfo[0].size   = rdp.maincimg[1].size;
3412     pinfo[0].width  = rdp.maincimg[1].width;
3413     pinfo[0].height = rdp.maincimg[1].height;
3414     int info_index = 1;
3415     for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++)
3416     {
3417       COLOR_IMAGE & cur_fb = rdp.frame_buffers[i];
3418       if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self ||
3419         cur_fb.status == ci_old_copy)
3420       {
3421         pinfo[info_index].addr   = cur_fb.addr;
3422         pinfo[info_index].size   = cur_fb.size;
3423         pinfo[info_index].width  = cur_fb.width;
3424         pinfo[info_index].height = cur_fb.height;
3425         info_index++;
3426       }
3427     }
3428   }
3429   else
3430   {
3431     pinfo[0].addr   = rdp.maincimg[0].addr;
3432     pinfo[0].size   = rdp.ci_size;
3433     pinfo[0].width  = rdp.ci_width;
3434     pinfo[0].height = rdp.ci_width*3/4;
3435     pinfo[1].addr   = rdp.maincimg[1].addr;
3436     pinfo[1].size   = rdp.ci_size;
3437     pinfo[1].width  = rdp.ci_width;
3438     pinfo[1].height = rdp.ci_width*3/4;
3439   }
3440   //*/
3441 }
3442 #ifdef __cplusplus
3443 }
3444 #endif
3445 //*/
3446 #include "ucodeFB.h"
3447
3448 void DetectFrameBufferUsage ()
3449 {
3450   LRDP("DetectFrameBufferUsage\n");
3451
3452   wxUint32 dlist_start = *(wxUint32*)(gfx.DMEM+0xFF0);
3453   wxUint32 a;
3454
3455   int tidal = FALSE;
3456   if ((settings.hacks&hack_PMario) && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self))
3457     tidal = TRUE;
3458   wxUint32 ci = rdp.cimg, zi = rdp.zimg;
3459   wxUint32 ci_height = rdp.frame_buffers[(rdp.ci_count > 0)?rdp.ci_count-1:0].height;
3460   rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0;
3461   rdp.main_ci_index = rdp.copy_ci_index = rdp.copy_zi_index = 0;
3462   rdp.zimg_end = 0;
3463   rdp.tmpzimg = 0;
3464   rdp.motionblur = FALSE;
3465   rdp.main_ci_last_tex_addr = 0;
3466   int previous_ci_was_read = rdp.read_previous_ci;
3467   rdp.read_previous_ci = FALSE;
3468   rdp.read_whole_frame = FALSE;
3469   rdp.swap_ci_index = rdp.black_ci_index = -1;
3470   SwapOK = TRUE;
3471
3472   // Start executing at the start of the display list
3473   rdp.pc_i = 0;
3474   rdp.pc[rdp.pc_i] = dlist_start;
3475   rdp.dl_count = -1;
3476   rdp.halt = 0;
3477   rdp.scale_x_bak = rdp.scale_x;
3478   rdp.scale_y_bak = rdp.scale_y;
3479
3480   // MAIN PROCESSING LOOP
3481   do {
3482
3483     // Get the address of the next command
3484     a = rdp.pc[rdp.pc_i] & BMASK;
3485
3486     // Load the next command and its input
3487     rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2];   // \ Current command, 64 bit
3488     rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // /
3489
3490     // Output the address before the command
3491
3492     // Go to the next instruction
3493     rdp.pc[rdp.pc_i] = (a+8) & BMASK;
3494
3495     if (wxPtrToUInt(reinterpret_cast<void*>(gfx_instruction_lite[settings.ucode][rdp.cmd0>>24])))
3496       gfx_instruction_lite[settings.ucode][rdp.cmd0>>24] ();
3497
3498     // check DL counter
3499     if (rdp.dl_count != -1)
3500     {
3501       rdp.dl_count --;
3502       if (rdp.dl_count == 0)
3503       {
3504         rdp.dl_count = -1;
3505
3506         LRDP("End of DL\n");
3507         rdp.pc_i --;
3508       }
3509     }
3510
3511   } while (!rdp.halt);
3512   SwapOK = TRUE;
3513   if (rdp.ci_count > NUMTEXBUF) //overflow
3514   {
3515     rdp.cimg = ci;
3516     rdp.zimg = zi;
3517     rdp.num_of_ci = rdp.ci_count;
3518     rdp.scale_x = rdp.scale_x_bak;
3519     rdp.scale_y = rdp.scale_y_bak;
3520     return;
3521   }
3522
3523   if (rdp.black_ci_index > 0 && rdp.black_ci_index < rdp.copy_ci_index)
3524     rdp.frame_buffers[rdp.black_ci_index].status = ci_main;
3525
3526   if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown)
3527   {
3528     if (rdp.ci_count > 1)
3529       rdp.frame_buffers[rdp.ci_count-1].status = ci_aux;
3530     else
3531       rdp.frame_buffers[rdp.ci_count-1].status = ci_main;
3532   }
3533
3534   if ((rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) &&
3535     (rdp.frame_buffers[rdp.main_ci_index].width < 320) &&
3536     (rdp.frame_buffers[rdp.ci_count-1].width > rdp.frame_buffers[rdp.main_ci_index].width))
3537   {
3538     for (int i = 0; i < rdp.ci_count; i++)
3539     {
3540       if (rdp.frame_buffers[i].status == ci_main)
3541         rdp.frame_buffers[i].status = ci_aux;
3542       else if (rdp.frame_buffers[i].addr == rdp.frame_buffers[rdp.ci_count-1].addr)
3543         rdp.frame_buffers[i].status = ci_main;
3544       //                        FRDP("rdp.frame_buffers[%d].status = %d\n", i, rdp.frame_buffers[i].status);
3545     }
3546     rdp.main_ci_index = rdp.ci_count-1;
3547   }
3548
3549   int all_zimg = TRUE;
3550   int i;
3551   for (i = 0; i < rdp.ci_count; i++)
3552   {
3553     if (rdp.frame_buffers[i].status != ci_zimg)
3554     {
3555       all_zimg = FALSE;
3556       break;
3557     }
3558   }
3559   if (all_zimg)
3560   {
3561     for (i = 0; i < rdp.ci_count; i++)
3562       rdp.frame_buffers[i].status = ci_main;
3563   }
3564
3565   LRDP("detect fb final results: \n");
3566   for (i = 0; i < rdp.ci_count; i++)
3567   {
3568     FRDP("rdp.frame_buffers[%d].status = %s, addr: %08lx, height: %d\n", i, CIStatus[rdp.frame_buffers[i].status], rdp.frame_buffers[i].addr, rdp.frame_buffers[i].height);
3569   }
3570
3571   rdp.cimg = ci;
3572   rdp.zimg = zi;
3573   rdp.num_of_ci = rdp.ci_count;
3574   if (rdp.read_previous_ci && previous_ci_was_read)
3575   {
3576     if (!fb_hwfbe_enabled || !rdp.copy_ci_index)
3577       rdp.motionblur = TRUE;
3578   }
3579   if (rdp.motionblur || fb_hwfbe_enabled || (rdp.frame_buffers[rdp.copy_ci_index].status == ci_aux_copy))
3580   {
3581     rdp.scale_x = rdp.scale_x_bak;
3582     rdp.scale_y = rdp.scale_y_bak;
3583   }
3584
3585   if ((rdp.read_previous_ci || previous_ci_was_read) && !rdp.copy_ci_index)
3586     rdp.read_whole_frame = TRUE;
3587   if (rdp.read_whole_frame)
3588   {
3589     if (fb_hwfbe_enabled)
3590     {
3591       if (rdp.read_previous_ci && !previous_ci_was_read && (settings.swapmode != 2) && (settings.ucode != ucode_PerfectDark))
3592       {
3593         int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0;
3594         wxUint32 height = rdp.frame_buffers[ind].height;
3595         rdp.frame_buffers[ind].height = ci_height;
3596         CopyFrameBuffer();
3597         rdp.frame_buffers[ind].height = height;
3598       }
3599       if (rdp.swap_ci_index < 0)
3600       {
3601         rdp.texbufs[0].clear_allowed = rdp.texbufs[1].clear_allowed = TRUE;
3602         OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3603       }
3604     }
3605     else
3606     {
3607       if (rdp.motionblur)
3608       {
3609         if (settings.frame_buffer&fb_motionblur)
3610           CopyFrameBuffer();
3611         else
3612           memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
3613       }
3614       else //if (ci_width == rdp.frame_buffers[rdp.main_ci_index].width)
3615       {
3616         if (rdp.maincimg[0].height > 65) //for 1080
3617         {
3618           rdp.cimg = rdp.maincimg[0].addr;
3619           rdp.ci_width = rdp.maincimg[0].width;
3620           rdp.ci_count = 0;
3621           wxUint32 h = rdp.frame_buffers[0].height;
3622           rdp.frame_buffers[0].height = rdp.maincimg[0].height;
3623           CopyFrameBuffer();
3624           rdp.frame_buffers[0].height = h;
3625         }
3626         else //conker
3627         {
3628           CopyFrameBuffer();
3629         }
3630       }
3631     }
3632   }
3633
3634   if (fb_hwfbe_enabled)
3635   {
3636     for (i = 0; i < voodoo.num_tmu; i++)
3637     {
3638       rdp.texbufs[i].clear_allowed = TRUE;
3639       for (int j = 0; j < 256; j++)
3640       {
3641         rdp.texbufs[i].images[j].drawn = FALSE;
3642         rdp.texbufs[i].images[j].clear = TRUE;
3643       }
3644     }
3645     if (tidal)
3646     {
3647       //LRDP("Tidal wave!\n");
3648       rdp.copy_ci_index = rdp.main_ci_index;
3649     }
3650   }
3651   rdp.ci_count = 0;
3652   if (settings.hacks&hack_Banjo2)
3653     rdp.cur_tex_buf = 0;
3654   rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3655   //    rdp.scale_x = rdp.scale_x_bak;
3656   //    rdp.scale_y = rdp.scale_y_bak;
3657   LRDP("DetectFrameBufferUsage End\n");
3658 }
3659
3660 /*******************************************
3661  *          ProcessRDPList                 *
3662  *******************************************
3663  *    based on sources of ziggy's z64      *
3664  *******************************************/
3665
3666 static wxUint32 rdp_cmd_ptr = 0;
3667 static wxUint32 rdp_cmd_cur = 0;
3668 static wxUint32 rdp_cmd_data[0x1000];
3669
3670 void lle_triangle(wxUint32 w1, wxUint32 w2, int shade, int texture, int zbuffer,
3671                   wxUint32 * rdp_cmd)
3672 {
3673   rdp.cur_tile = (w1 >> 16) & 0x7;
3674   int j;
3675   int xleft, xright, xleft_inc, xright_inc;
3676   int r, g, b, a, z, s, t, w;
3677   int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0;
3678   int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0;
3679   int flip = (w1 & 0x800000) ? 1 : 0;
3680
3681   wxInt32 yl, ym, yh;
3682   wxInt32 xl, xm, xh;
3683   wxInt32 dxldy, dxhdy, dxmdy;
3684   wxUint32 w3, w4, w5, w6, w7, w8;
3685
3686   wxUint32 * shade_base = rdp_cmd + 8;
3687   wxUint32 * texture_base = rdp_cmd + 8;
3688   wxUint32 * zbuffer_base = rdp_cmd + 8;
3689
3690   if (shade)
3691   {
3692     texture_base += 16;
3693     zbuffer_base += 16;
3694   }
3695   if (texture)
3696   {
3697     zbuffer_base += 16;
3698   }
3699
3700   w3 = rdp_cmd[2];
3701   w4 = rdp_cmd[3];
3702   w5 = rdp_cmd[4];
3703   w6 = rdp_cmd[5];
3704   w7 = rdp_cmd[6];
3705   w8 = rdp_cmd[7];
3706
3707   yl = (w1 & 0x3fff);
3708   ym = ((w2 >> 16) & 0x3fff);
3709   yh = ((w2 >>  0) & 0x3fff);
3710   xl = (wxInt32)(w3);
3711   xh = (wxInt32)(w5);
3712   xm = (wxInt32)(w7);
3713   dxldy = (wxInt32)(w4);
3714   dxhdy = (wxInt32)(w6);
3715   dxmdy = (wxInt32)(w8);
3716
3717   if (yl & (0x800<<2)) yl |= 0xfffff000<<2;
3718   if (ym & (0x800<<2)) ym |= 0xfffff000<<2;
3719   if (yh & (0x800<<2)) yh |= 0xfffff000<<2;
3720
3721   yh &= ~3;
3722
3723   r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0xffff0000; s = 0;  t = 0;  w = 0x30000;
3724
3725   if (shade)
3726   {
3727     r    = (shade_base[0] & 0xffff0000) | ((shade_base[+4 ] >> 16) & 0x0000ffff);
3728     g    = ((shade_base[0 ] << 16) & 0xffff0000) | (shade_base[4 ] & 0x0000ffff);
3729     b    = (shade_base[1 ] & 0xffff0000) | ((shade_base[5 ] >> 16) & 0x0000ffff);
3730     a    = ((shade_base[1 ] << 16) & 0xffff0000) | (shade_base[5 ] & 0x0000ffff);
3731     drdx = (shade_base[2 ] & 0xffff0000) | ((shade_base[6 ] >> 16) & 0x0000ffff);
3732     dgdx = ((shade_base[2 ] << 16) & 0xffff0000) | (shade_base[6 ] & 0x0000ffff);
3733     dbdx = (shade_base[3 ] & 0xffff0000) | ((shade_base[7 ] >> 16) & 0x0000ffff);
3734     dadx = ((shade_base[3 ] << 16) & 0xffff0000) | (shade_base[7 ] & 0x0000ffff);
3735     drde = (shade_base[8 ] & 0xffff0000) | ((shade_base[12] >> 16) & 0x0000ffff);
3736     dgde = ((shade_base[8 ] << 16) & 0xffff0000) | (shade_base[12] & 0x0000ffff);
3737     dbde = (shade_base[9 ] & 0xffff0000) | ((shade_base[13] >> 16) & 0x0000ffff);
3738     dade = ((shade_base[9 ] << 16) & 0xffff0000) | (shade_base[13] & 0x0000ffff);
3739   }
3740   if (texture)
3741   {
3742     s    = (texture_base[0 ] & 0xffff0000) | ((texture_base[4 ] >> 16) & 0x0000ffff);
3743     t    = ((texture_base[0 ] << 16) & 0xffff0000)      | (texture_base[4 ] & 0x0000ffff);
3744     w    = (texture_base[1 ] & 0xffff0000) | ((texture_base[5 ] >> 16) & 0x0000ffff);
3745     //    w = abs(w);
3746     dsdx = (texture_base[2 ] & 0xffff0000) | ((texture_base[6 ] >> 16) & 0x0000ffff);
3747     dtdx = ((texture_base[2 ] << 16) & 0xffff0000)      | (texture_base[6 ] & 0x0000ffff);
3748     dwdx = (texture_base[3 ] & 0xffff0000) | ((texture_base[7 ] >> 16) & 0x0000ffff);
3749     dsde = (texture_base[8 ] & 0xffff0000) | ((texture_base[12] >> 16) & 0x0000ffff);
3750     dtde = ((texture_base[8 ] << 16) & 0xffff0000)      | (texture_base[12] & 0x0000ffff);
3751     dwde = (texture_base[9 ] & 0xffff0000) | ((texture_base[13] >> 16) & 0x0000ffff);
3752   }
3753   if (zbuffer)
3754   {
3755     z    = zbuffer_base[0];
3756     dzdx = zbuffer_base[1];
3757     dzde = zbuffer_base[2];
3758   }
3759
3760   xh <<= 2;  xm <<= 2;  xl <<= 2;
3761   r <<= 2;  g <<= 2;  b <<= 2;  a <<= 2;
3762   dsde >>= 2;  dtde >>= 2;  dsdx >>= 2;  dtdx >>= 2;
3763   dzdx >>= 2;  dzde >>= 2;
3764   dwdx >>= 2;  dwde >>= 2;
3765
3766 #define XSCALE(x) (float(x)/(1<<18))
3767 #define YSCALE(y) (float(y)/(1<<2))
3768 #define ZSCALE(z) ((rdp.zsrc == 1)? float(rdp.prim_depth) : float(wxUint32(z))/0xffff0000)
3769   //#define WSCALE(w) (rdp.Persp_en? (float(wxUint32(w) + 0x10000)/0xffff0000) : 1.0f)
3770   //#define WSCALE(w) (rdp.Persp_en? 4294901760.0/(w + 65536) : 1.0f)
3771 #define WSCALE(w) (rdp.Persp_en? 65536.0f/float((w+ 0xffff)>>16) : 1.0f)
3772 #define CSCALE(c) (((c)>0x3ff0000? 0x3ff0000:((c)<0? 0 : (c)))>>18)
3773 #define _PERSP(w) ( w )
3774 #define PERSP(s, w) ( ((int64_t)(s) << 20) / (_PERSP(w)? _PERSP(w):1) )
3775 #define SSCALE(s, _w) (rdp.Persp_en? float(PERSP(s, _w))/(1 << 10) : float(s)/(1<<21))
3776 #define TSCALE(s, w) (rdp.Persp_en? float(PERSP(s, w))/(1 << 10) : float(s)/(1<<21))
3777
3778   int nbVtxs = 0;
3779   VERTEX vtxbuf[12];
3780   VERTEX * vtx = &vtxbuf[nbVtxs++];
3781
3782   xleft = xm;
3783   xright = xh;
3784   xleft_inc = dxmdy;
3785   xright_inc = dxhdy;
3786
3787   while (yh<ym &&
3788     !((!flip && xleft < xright+0x10000) ||
3789     (flip && xleft > xright-0x10000))) {
3790       xleft += xleft_inc;
3791       xright += xright_inc;
3792       s += dsde;    t += dtde;    w += dwde;
3793       r += drde;    g += dgde;    b += dbde;    a += dade;
3794       z += dzde;
3795       yh++;
3796   }
3797
3798   j = ym-yh;
3799   if (j > 0)
3800   {
3801     int dx = (xleft-xright)>>16;
3802     if ((!flip && xleft < xright) ||
3803       (flip/* && xleft > xright*/))
3804     {
3805       if (shade) {
3806         vtx->r = CSCALE(r+drdx*dx);
3807         vtx->g = CSCALE(g+dgdx*dx);
3808         vtx->b = CSCALE(b+dbdx*dx);
3809         vtx->a = CSCALE(a+dadx*dx);
3810       }
3811       if (texture) {
3812         vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx);
3813         vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx);
3814       }
3815       vtx->x = XSCALE(xleft);
3816       vtx->y = YSCALE(yh);
3817       vtx->z = ZSCALE(z+dzdx*dx);
3818       vtx->w = WSCALE(w+dwdx*dx);
3819       vtx = &vtxbuf[nbVtxs++];
3820     }
3821     if ((!flip/* && xleft < xright*/) ||
3822       (flip && xleft > xright))
3823     {
3824       if (shade) {
3825         vtx->r = CSCALE(r);
3826         vtx->g = CSCALE(g);
3827         vtx->b = CSCALE(b);
3828         vtx->a = CSCALE(a);
3829       }
3830       if (texture) {
3831         vtx->ou = SSCALE(s, w);
3832         vtx->ov = TSCALE(t, w);
3833       }
3834       vtx->x = XSCALE(xright);
3835       vtx->y = YSCALE(yh);
3836       vtx->z = ZSCALE(z);
3837       vtx->w = WSCALE(w);
3838       vtx = &vtxbuf[nbVtxs++];
3839     }
3840     xleft += xleft_inc*j;  xright += xright_inc*j;
3841     s += dsde*j;  t += dtde*j;
3842     if (w + dwde*j) w += dwde*j;
3843     else w += dwde*(j-1);
3844     r += drde*j;  g += dgde*j;  b += dbde*j;  a += dade*j;
3845     z += dzde*j;
3846     // render ...
3847   }
3848
3849   if (xl != xh)
3850     xleft = xl;
3851
3852   //if (yl-ym > 0)
3853   {
3854     int dx = (xleft-xright)>>16;
3855     if ((!flip && xleft <= xright) ||
3856       (flip/* && xleft >= xright*/))
3857     {
3858       if (shade) {
3859         vtx->r = CSCALE(r+drdx*dx);
3860         vtx->g = CSCALE(g+dgdx*dx);
3861         vtx->b = CSCALE(b+dbdx*dx);
3862         vtx->a = CSCALE(a+dadx*dx);
3863       }
3864       if (texture) {
3865         vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx);
3866         vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx);
3867       }
3868       vtx->x = XSCALE(xleft);
3869       vtx->y = YSCALE(ym);
3870       vtx->z = ZSCALE(z+dzdx*dx);
3871       vtx->w = WSCALE(w+dwdx*dx);
3872       vtx = &vtxbuf[nbVtxs++];
3873     }
3874     if ((!flip/* && xleft <= xright*/) ||
3875       (flip && xleft >= xright))
3876     {
3877       if (shade) {
3878         vtx->r = CSCALE(r);
3879         vtx->g = CSCALE(g);
3880         vtx->b = CSCALE(b);
3881         vtx->a = CSCALE(a);
3882       }
3883       if (texture) {
3884         vtx->ou = SSCALE(s, w);
3885         vtx->ov = TSCALE(t, w);
3886       }
3887       vtx->x = XSCALE(xright);
3888       vtx->y = YSCALE(ym);
3889       vtx->z = ZSCALE(z);
3890       vtx->w = WSCALE(w);
3891       vtx = &vtxbuf[nbVtxs++];
3892     }
3893   }
3894   xleft_inc = dxldy;
3895   xright_inc = dxhdy;
3896
3897   j = yl-ym;
3898   //j--; // ?
3899   xleft += xleft_inc*j;  xright += xright_inc*j;
3900   s += dsde*j;  t += dtde*j;  w += dwde*j;
3901   r += drde*j;  g += dgde*j;  b += dbde*j;  a += dade*j;
3902   z += dzde*j;
3903
3904   while (yl>ym &&
3905     !((!flip && xleft < xright+0x10000) ||
3906     (flip && xleft > xright-0x10000))) {
3907       xleft -= xleft_inc;    xright -= xright_inc;
3908       s -= dsde;    t -= dtde;    w -= dwde;
3909       r -= drde;    g -= dgde;    b -= dbde;    a -= dade;
3910       z -= dzde;
3911       j--;
3912       yl--;
3913   }
3914
3915   // render ...
3916   if (j >= 0) {
3917     int dx = (xleft-xright)>>16;
3918     if ((!flip && xleft <= xright) ||
3919       (flip/* && xleft >= xright*/))
3920     {
3921       if (shade) {
3922         vtx->r = CSCALE(r+drdx*dx);
3923         vtx->g = CSCALE(g+dgdx*dx);
3924         vtx->b = CSCALE(b+dbdx*dx);
3925         vtx->a = CSCALE(a+dadx*dx);
3926       }
3927       if (texture) {
3928         vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx);
3929         vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx);
3930       }
3931       vtx->x = XSCALE(xleft);
3932       vtx->y = YSCALE(yl);
3933       vtx->z = ZSCALE(z+dzdx*dx);
3934       vtx->w = WSCALE(w+dwdx*dx);
3935       vtx = &vtxbuf[nbVtxs++];
3936     }
3937     if ((!flip/* && xleft <= xright*/) ||
3938       (flip && xleft >= xright))
3939     {
3940       if (shade) {
3941         vtx->r = CSCALE(r);
3942         vtx->g = CSCALE(g);
3943         vtx->b = CSCALE(b);
3944         vtx->a = CSCALE(a);
3945       }
3946       if (texture) {
3947         vtx->ou = SSCALE(s, w);
3948         vtx->ov = TSCALE(t, w);
3949       }
3950       vtx->x = XSCALE(xright);
3951       vtx->y = YSCALE(yl);
3952       vtx->z = ZSCALE(z);
3953       vtx->w = WSCALE(w);
3954       vtx = &vtxbuf[nbVtxs++];
3955     }
3956   }
3957
3958   if (fullscreen)
3959   {
3960     update ();
3961     for (int k = 0; k < nbVtxs-1; k++)
3962     {
3963       VERTEX * v = &vtxbuf[k];
3964       v->x = v->x * rdp.scale_x + rdp.offset_x;
3965       v->y = v->y * rdp.scale_y + rdp.offset_y;
3966       //    v->z = 1.0f;///v->w;
3967       v->q = 1.0f/v->w;
3968       v->u1 = v->u0 = v->ou;
3969       v->v1 = v->v0 = v->ov;
3970       if (rdp.tex >= 1 && rdp.cur_cache[0])
3971       {
3972         if (rdp.tiles[rdp.cur_tile].shift_s)
3973         {
3974           if (rdp.tiles[rdp.cur_tile].shift_s > 10)
3975             v->u0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s));
3976           else
3977             v->u0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_s);
3978         }
3979         if (rdp.tiles[rdp.cur_tile].shift_t)
3980         {
3981           if (rdp.tiles[rdp.cur_tile].shift_t > 10)
3982             v->v0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t));
3983           else
3984             v->v0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_t);
3985         }
3986
3987         v->u0 -= rdp.tiles[rdp.cur_tile].f_ul_s;
3988         v->v0 -= rdp.tiles[rdp.cur_tile].f_ul_t;
3989         v->u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * v->u0;
3990         v->v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * v->v0;
3991         v->u0 /= v->w;
3992         v->v0 /= v->w;
3993       }
3994
3995       if (rdp.tex >= 2 && rdp.cur_cache[1])
3996       {
3997         if (rdp.tiles[rdp.cur_tile+1].shift_s)
3998         {
3999           if (rdp.tiles[rdp.cur_tile+1].shift_s > 10)
4000             v->u1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s));
4001           else
4002             v->u1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_s);
4003         }
4004         if (rdp.tiles[rdp.cur_tile+1].shift_t)
4005         {
4006           if (rdp.tiles[rdp.cur_tile+1].shift_t > 10)
4007             v->v1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t));
4008           else
4009             v->v1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_t);
4010         }
4011
4012         v->u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s;
4013         v->v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t;
4014         v->u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * v->u1;
4015         v->v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * v->v1;
4016         v->u1 /= v->w;
4017         v->v1 /= v->w;
4018       }
4019       apply_shade_mods (v);
4020     }
4021     ConvertCoordsConvert (vtxbuf, nbVtxs);
4022     grCullMode (GR_CULL_DISABLE);
4023     grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, nbVtxs-1, vtxbuf, sizeof(VERTEX));
4024     if (_debugger.capture)
4025     {
4026       VERTEX vl[3];
4027       vl[0] = vtxbuf[0];
4028       vl[1] = vtxbuf[2];
4029       vl[2] = vtxbuf[1];
4030       add_tri (vl, 3, TRI_TRIANGLE);
4031       rdp.tri_n++;
4032       if (nbVtxs > 4)
4033       {
4034         vl[0] = vtxbuf[2];
4035         vl[1] = vtxbuf[3];
4036         vl[2] = vtxbuf[1];
4037         add_tri (vl, 3, TRI_TRIANGLE);
4038         rdp.tri_n++;
4039       }
4040     }
4041   }
4042 }
4043
4044 static void rdp_triangle(int shade, int texture, int zbuffer)
4045 {
4046   lle_triangle(rdp.cmd0, rdp.cmd1, shade, texture, zbuffer, rdp_cmd_data + rdp_cmd_cur);
4047 }
4048
4049 static void rdp_trifill()
4050 {
4051   rdp_triangle(0, 0, 0);
4052   LRDP("trifill\n");
4053 }
4054
4055 static void rdp_trishade()
4056 {
4057   rdp_triangle(1, 0, 0);
4058   LRDP("trishade\n");
4059 }
4060
4061 static void rdp_tritxtr()
4062 {
4063   rdp_triangle(0, 1, 0);
4064   LRDP("tritxtr\n");
4065 }
4066
4067 static void rdp_trishadetxtr()
4068 {
4069   rdp_triangle(1, 1, 0);
4070   LRDP("trishadetxtr\n");
4071 }
4072
4073 static void rdp_trifillz()
4074 {
4075   rdp_triangle(0, 0, 1);
4076   LRDP("trifillz\n");
4077 }
4078
4079 static void rdp_trishadez()
4080 {
4081   rdp_triangle(1, 0, 1);
4082   LRDP("trishadez\n");
4083 }
4084
4085 static void rdp_tritxtrz()
4086 {
4087   rdp_triangle(0, 1, 1);
4088   LRDP("tritxtrz\n");
4089 }
4090
4091 static void rdp_trishadetxtrz()
4092 {
4093   rdp_triangle(1, 1, 1);
4094   LRDP("trishadetxtrz\n");
4095 }
4096
4097
4098 static rdp_instr rdp_command_table[64] =
4099 {
4100   /* 0x00 */
4101   spnoop,             undef,                  undef,                  undef,
4102   undef,              undef,                  undef,                  undef,
4103   rdp_trifill,        rdp_trifillz,           rdp_tritxtr,            rdp_tritxtrz,
4104   rdp_trishade,       rdp_trishadez,          rdp_trishadetxtr,       rdp_trishadetxtrz,
4105   /* 0x10 */
4106   undef,              undef,                  undef,                  undef,
4107   undef,              undef,                  undef,                  undef,
4108   undef,              undef,                  undef,                  undef,
4109   undef,              undef,                  undef,                  undef,
4110   /* 0x20 */
4111   undef,              undef,                  undef,                  undef,
4112   rdp_texrect,        rdp_texrect,            rdp_loadsync,           rdp_pipesync,
4113   rdp_tilesync,       rdp_fullsync,           rdp_setkeygb,           rdp_setkeyr,
4114   rdp_setconvert,     rdp_setscissor,         rdp_setprimdepth,       rdp_setothermode,
4115   /* 0x30 */
4116   rdp_loadtlut,           undef,                  rdp_settilesize,        rdp_loadblock,
4117   rdp_loadtile,           rdp_settile,            rdp_fillrect,           rdp_setfillcolor,
4118   rdp_setfogcolor,        rdp_setblendcolor,      rdp_setprimcolor,       rdp_setenvcolor,
4119   rdp_setcombine,         rdp_settextureimage,    rdp_setdepthimage,      rdp_setcolorimage
4120 };
4121
4122 static const wxUint32 rdp_command_length[64] =
4123 {
4124   8,                      // 0x00, No Op
4125   8,                      // 0x01, ???
4126   8,                      // 0x02, ???
4127   8,                      // 0x03, ???
4128   8,                      // 0x04, ???
4129   8,                      // 0x05, ???
4130   8,                      // 0x06, ???
4131   8,                      // 0x07, ???
4132   32,                     // 0x08, Non-Shaded Triangle
4133   32+16,          // 0x09, Non-Shaded, Z-Buffered Triangle
4134   32+64,          // 0x0a, Textured Triangle
4135   32+64+16,       // 0x0b, Textured, Z-Buffered Triangle
4136   32+64,          // 0x0c, Shaded Triangle
4137   32+64+16,       // 0x0d, Shaded, Z-Buffered Triangle
4138   32+64+64,       // 0x0e, Shaded+Textured Triangle
4139   32+64+64+16,// 0x0f, Shaded+Textured, Z-Buffered Triangle
4140   8,                      // 0x10, ???
4141   8,                      // 0x11, ???
4142   8,                      // 0x12, ???
4143   8,                      // 0x13, ???
4144   8,                      // 0x14, ???
4145   8,                      // 0x15, ???
4146   8,                      // 0x16, ???
4147   8,                      // 0x17, ???
4148   8,                      // 0x18, ???
4149   8,                      // 0x19, ???
4150   8,                      // 0x1a, ???
4151   8,                      // 0x1b, ???
4152   8,                      // 0x1c, ???
4153   8,                      // 0x1d, ???
4154   8,                      // 0x1e, ???
4155   8,                      // 0x1f, ???
4156   8,                      // 0x20, ???
4157   8,                      // 0x21, ???
4158   8,                      // 0x22, ???
4159   8,                      // 0x23, ???
4160   16,                     // 0x24, Texture_Rectangle
4161   16,                     // 0x25, Texture_Rectangle_Flip
4162   8,                      // 0x26, Sync_Load
4163   8,                      // 0x27, Sync_Pipe
4164   8,                      // 0x28, Sync_Tile
4165   8,                      // 0x29, Sync_Full
4166   8,                      // 0x2a, Set_Key_GB
4167   8,                      // 0x2b, Set_Key_R
4168   8,                      // 0x2c, Set_Convert
4169   8,                      // 0x2d, Set_Scissor
4170   8,                      // 0x2e, Set_Prim_Depth
4171   8,                      // 0x2f, Set_Other_Modes
4172   8,                      // 0x30, Load_TLUT
4173   8,                      // 0x31, ???
4174   8,                      // 0x32, Set_Tile_Size
4175   8,                      // 0x33, Load_Block
4176   8,                      // 0x34, Load_Tile
4177   8,                      // 0x35, Set_Tile
4178   8,                      // 0x36, Fill_Rectangle
4179   8,                      // 0x37, Set_Fill_Color
4180   8,                      // 0x38, Set_Fog_Color
4181   8,                      // 0x39, Set_Blend_Color
4182   8,                      // 0x3a, Set_Prim_Color
4183   8,                      // 0x3b, Set_Env_Color
4184   8,                      // 0x3c, Set_Combine
4185   8,                      // 0x3d, Set_Texture_Image
4186   8,                      // 0x3e, Set_Mask_Image
4187   8                       // 0x3f, Set_Color_Image
4188 };
4189
4190 #define rdram ((wxUint32*)gfx.RDRAM)
4191 #define rsp_dmem ((wxUint32*)gfx.DMEM)
4192
4193 #define dp_start (*(wxUint32*)gfx.DPC_START_REG)
4194 #define dp_end (*(wxUint32*)gfx.DPC_END_REG)
4195 #define dp_current (*(wxUint32*)gfx.DPC_CURRENT_REG)
4196 #define dp_status (*(wxUint32*)gfx.DPC_STATUS_REG)
4197
4198 inline wxUint32 READ_RDP_DATA(wxUint32 address)
4199 {
4200   if (dp_status & 0x1)          // XBUS_DMEM_DMA enabled
4201     return rsp_dmem[(address & 0xfff)>>2];
4202   else
4203     return rdram[address>>2];
4204 }
4205
4206 static void rdphalf_1()
4207 {
4208   wxUint32 cmd = rdp.cmd1 >> 24;
4209   if (cmd >= 0xc8 && cmd <=0xcf) //triangle command
4210   {
4211     LRDP("rdphalf_1 - lle triangle\n");
4212     rdp_cmd_ptr = 0;
4213     rdp_cmd_cur = 0;
4214     wxUint32 a;
4215
4216     do
4217     {
4218       rdp_cmd_data[rdp_cmd_ptr++] = rdp.cmd1;
4219       // check DL counter
4220       if (rdp.dl_count != -1)
4221       {
4222         rdp.dl_count --;
4223         if (rdp.dl_count == 0)
4224         {
4225           rdp.dl_count = -1;
4226
4227           LRDP("End of DL\n");
4228           rdp.pc_i --;
4229         }
4230       }
4231
4232       // Get the address of the next command
4233       a = rdp.pc[rdp.pc_i] & BMASK;
4234
4235       // Load the next command and its input
4236       rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2];   // \ Current command, 64 bit
4237       rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // /
4238
4239       // Go to the next instruction
4240       rdp.pc[rdp.pc_i] = (a+8) & BMASK;
4241
4242     }while ((rdp.cmd0 >> 24) != 0xb3);
4243     rdp_cmd_data[rdp_cmd_ptr++] = rdp.cmd1;
4244     cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f;
4245     rdp.cmd0 = rdp_cmd_data[rdp_cmd_cur+0];
4246     rdp.cmd1 = rdp_cmd_data[rdp_cmd_cur+1];
4247     /*
4248     wxUint32 cmd3 = ((wxUint32*)gfx.RDRAM)[(a>>2)+2];
4249     if ((cmd3>>24) == 0xb4)
4250     rglSingleTriangle = TRUE;
4251     else
4252     rglSingleTriangle = FALSE;
4253     */
4254     rdp_command_table[cmd]();
4255   }
4256   else
4257   {
4258 #ifdef EXTREME_LOGGING
4259     LRDP("rdphalf_1 - IGNORED\n");
4260 #endif
4261   }
4262 }
4263
4264 static void rdphalf_2()
4265 {
4266   RDP_E("rdphalf_2 - IGNORED\n");
4267 }
4268
4269 static void rdphalf_cont()
4270 {
4271   RDP_E("rdphalf_cont - IGNORED\n");
4272 }
4273
4274 /******************************************************************
4275 Function: ProcessRDPList
4276 Purpose:  This function is called when there is a Dlist to be
4277 processed. (Low level GFX list)
4278 input:    none
4279 output:   none
4280 *******************************************************************/
4281 #ifdef __cplusplus
4282 extern "C" {
4283 #endif
4284 EXPORT void CALL ProcessRDPList(void)
4285 {
4286 #ifdef EXTREME_LOGGING
4287   LRDP("ProcessRDPList ()\n");
4288 #endif
4289
4290  // SoftLocker lock(mutexProcessDList);
4291   if (/*!lock.IsOk()*/0) //mutex is busy
4292   {
4293     if (!fullscreen)
4294       drawNoFullscreenMessage();
4295     // Set an interrupt to allow the game to continue
4296     *gfx.MI_INTR_REG |= 0x20;
4297     gfx.CheckInterrupts();
4298     return;
4299   }
4300
4301   wxUint32 i;
4302   wxUint32 cmd, length, cmd_length;
4303   rdp_cmd_ptr = 0;
4304   rdp_cmd_cur = 0;
4305
4306   if (dp_end <= dp_current) return;
4307   length = dp_end - dp_current;
4308
4309   // load command data
4310   for (i=0; i < length; i += 4)
4311   {
4312     rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(dp_current + i);
4313     if (rdp_cmd_ptr >= 0x1000)
4314     {
4315       FRDP("rdp_process_list: rdp_cmd_ptr overflow %x %x --> %x\n", length, dp_current, dp_end);
4316     }
4317   }
4318
4319   dp_current = dp_end;
4320
4321   cmd = (rdp_cmd_data[0] >> 24) & 0x3f;
4322   cmd_length = (rdp_cmd_ptr + 1) * 4;
4323
4324   // check if more data is needed
4325   if (cmd_length < rdp_command_length[cmd])
4326     return;
4327   rdp.LLE = TRUE;
4328   while (rdp_cmd_cur < rdp_cmd_ptr)
4329   {
4330     cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f;
4331
4332     if (((rdp_cmd_ptr-rdp_cmd_cur) * 4) < rdp_command_length[cmd])
4333       return;
4334
4335     // execute the command
4336     rdp.cmd0 = rdp_cmd_data[rdp_cmd_cur+0];
4337     rdp.cmd1 = rdp_cmd_data[rdp_cmd_cur+1];
4338     rdp.cmd2 = rdp_cmd_data[rdp_cmd_cur+2];
4339     rdp.cmd3 = rdp_cmd_data[rdp_cmd_cur+3];
4340     rdp_command_table[cmd]();
4341
4342     rdp_cmd_cur += rdp_command_length[cmd] / 4;
4343   };
4344   rdp.LLE = FALSE;
4345
4346   dp_start = dp_end;
4347
4348   dp_status &= ~0x0002;
4349
4350   //}
4351 }
4352
4353 #ifdef __cplusplus
4354 }
4355 #endif
4356