Replace Tmem_nasm.asm with C++ code. Patch by pyro.
[Glide64.git] / rdp.cpp
blob158cfd3090167b9a156eef048ce5afd2a55a4db3
1 /*
2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002 Dave2001
4 * Copyright (c) 2008 Günther <guenther.emu@freenet.de>
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.
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.
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
21 //****************************************************************
23 // Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
24 // Project started on December 29th, 2001
26 // To modify Glide64:
27 // * 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.
28 // * 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.
30 // Official Glide64 development channel: #Glide64 on EFnet
32 // Original author: Dave2001 (Dave2999@hotmail.com)
33 // Other authors: Gonetz, Gugaman
35 //****************************************************************
37 #include "Gfx1.3.h"
38 #include "3dmath.h"
39 #include "Util.h"
40 #include "Debugger.h"
41 #include "Combine.h"
42 #include "Util.h"
43 #include "Ini.h"
44 #include "Tmem.h"
45 #include "TexCache.h"
46 #include "TexCache.h"
47 #include "TexBuffer.h"
48 #include "CRC.h"
50 #ifndef _WIN32
51 #include "messagebox.h"
52 #include <sys/time.h>
53 #endif // _WIN32
55 char out_buf[2048];
57 DWORD frame_count; // frame counter
59 BOOL ucode_error_report = TRUE;
60 int wrong_tile = -1;
62 #define BYTESWAP1(s1) asm volatile (" bswap %0; " : "+r" (s1) : :);
63 #define BYTESWAP2(s1,s2) asm volatile (" bswap %0; bswap %1; " : "+r" (s1), "+r" (s2) : :);
65 // global strings
66 const char *ACmp[4] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" };
68 const char *Mode0[16] = { "COMBINED", "TEXEL0",
69 "TEXEL1", "PRIMITIVE",
70 "SHADE", "ENVIORNMENT",
71 "1", "NOISE",
72 "0", "0",
73 "0", "0",
74 "0", "0",
75 "0", "0" };
76 const char *Mode1[16] = { "COMBINED", "TEXEL0",
77 "TEXEL1", "PRIMITIVE",
78 "SHADE", "ENVIORNMENT",
79 "CENTER", "K4",
80 "0", "0",
81 "0", "0",
82 "0", "0",
83 "0", "0" };
84 const char *Mode2[32] = { "COMBINED", "TEXEL0",
85 "TEXEL1", "PRIMITIVE",
86 "SHADE", "ENVIORNMENT",
87 "SCALE", "COMBINED_ALPHA",
88 "T0_ALPHA", "T1_ALPHA",
89 "PRIM_ALPHA", "SHADE_ALPHA",
90 "ENV_ALPHA", "LOD_FRACTION",
91 "PRIM_LODFRAC", "K5",
92 "0", "0",
93 "0", "0",
94 "0", "0",
95 "0", "0",
96 "0", "0",
97 "0", "0",
98 "0", "0",
99 "0", "0" };
100 const char *Mode3[8] = { "COMBINED", "TEXEL0",
101 "TEXEL1", "PRIMITIVE",
102 "SHADE", "ENVIORNMENT",
103 "1", "0" };
105 const char *Alpha0[8] = { "COMBINED", "TEXEL0",
106 "TEXEL1", "PRIMITIVE",
107 "SHADE", "ENVIORNMENT",
108 "1", "0" };
109 const char *Alpha2[8] = { "LOD_FRACTION", "TEXEL0",
110 "TEXEL1", "PRIMITIVE",
111 "SHADE", "ENVIORNMENT",
112 "PRIM_LODFRAC", "0" };
114 //FIXME:unused?
115 //const char *FBLa[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG" };
116 //const char *FBLb[] = { "G_BL_A_IN", "G_BL_A_FOG", "G_BL_A_SHADE", "G_BL_0" };
117 //const char *FBLc[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG"};
118 //const char *FBLd[] = { "G_BL_1MA", "G_BL_A_MEM", "G_BL_1", "G_BL_0" };
120 const char *str_zs[2] = { "G_ZS_PIXEL", "G_ZS_PRIM" };
122 const char *str_yn[2] = { "NO", "YES" };
123 const char *str_offon[2] = { "OFF", "ON" };
125 const char *str_cull[4] = { "DISABLE", "FRONT", "BACK", "BOTH" };
127 // I=intensity probably
128 const char *str_format[8] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
129 const char *str_size[4] = { "4bit", "8bit", "16bit", "32bit" };
130 const char *str_cm[4] = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" };
132 //const char *str_lod[] = { "1", "2", "4", "8", "16", "32", "64", "128", "256" };
133 //const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" };
135 const char *str_filter[3] = { "Point Sampled", "Average (box)", "Bilinear" };
137 const char *str_tlut[4] = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" };
139 const char *CIStatus[10] = { "ci_main", "ci_zimg", "ci_unknown", "ci_useless",
140 "ci_old_copy", "ci_copy", "ci_copy_self",
141 "ci_zcopy", "ci_aux", "ci_aux_copy" };
144 // ZIGGY
145 // depth save/restore variables
146 // 0 : normal mode
147 // 1 : writing in normal depth buffer
148 // 2 : writing in alternate depth buffer
149 static int render_depth_mode;
151 // ** RDP graphics functions **
152 static void undef();
153 static void spnoop();
155 static void rdp_noop();
156 static void rdp_texrect();
157 //static void rdp_texrectflip();
158 static void rdp_loadsync();
159 static void rdp_pipesync();
160 static void rdp_tilesync();
161 static void rdp_fullsync();
162 static void rdp_setkeygb();
163 static void rdp_setkeyr();
164 static void rdp_setconvert();
165 static void rdp_setscissor();
166 static void rdp_setprimdepth();
167 static void rdp_setothermode();
168 static void rdp_loadtlut();
169 static void rdp_settilesize();
170 static void rdp_loadblock();
171 static void rdp_loadtile();
172 static void rdp_settile();
173 static void rdp_fillrect();
174 static void rdp_setfillcolor();
175 static void rdp_setfogcolor();
176 static void rdp_setblendcolor();
177 static void rdp_setprimcolor();
178 static void rdp_setenvcolor();
179 static void rdp_setcombine();
180 static void rdp_settextureimage();
181 static void rdp_setdepthimage();
182 static void rdp_setcolorimage();
183 static void rdp_trifill();
184 static void rdp_trishade();
185 static void rdp_tritxtr();
186 static void rdp_trishadetxtr();
187 static void rdp_trifillz();
188 static void rdp_trishadez();
189 static void rdp_tritxtrz();
190 static void rdp_trishadetxtrz();
192 static void rsp_reserved0();
193 static void rsp_reserved1();
194 static void rsp_reserved2();
195 static void rsp_reserved3();
197 static void ys_memrect();
199 BYTE microcode[4096];
200 DWORD uc_crc;
201 void microcheck ();
203 // ** UCODE FUNCTIONS **
204 #include "Ucode00.h"
205 #include "ucode01.h"
206 #include "ucode02.h"
207 #include "ucode03.h"
208 #include "ucode04.h"
209 #include "ucode05.h"
210 #include "ucode06.h"
211 #include "ucode07.h"
212 #include "ucode08.h"
213 #include "ucode.h"
215 static BOOL reset = 0;
216 static int old_ucode = -1;
218 // rdp_reset - resets the RDP_E
219 void rdp_reset ()
221 reset = 1;
223 rdp.model_i = 0;
225 rdp.n_cached[0] = 0;
226 rdp.n_cached[1] = 0;
227 rdp.cur_cache[0] = NULL;
228 rdp.cur_cache[1] = NULL;
230 rdp.tmem_ptr[0] = offset_textures;
231 rdp.tmem_ptr[1] = offset_textures;
232 if (grTextureBufferExt)
233 rdp.tmem_ptr[1] = TEXMEM_2MB_EDGE * 2;
235 rdp.c_a0 = 0;
236 rdp.c_b0 = 0;
237 rdp.c_c0 = 0;
238 rdp.c_d0 = 0;
239 rdp.c_Aa0 = 0;
240 rdp.c_Ab0 = 0;
241 rdp.c_Ac0 = 0;
242 rdp.c_Ad0 = 0;
244 rdp.c_a1 = 0;
245 rdp.c_b1 = 0;
246 rdp.c_c1 = 0;
247 rdp.c_d1 = 0;
248 rdp.c_Aa1 = 0;
249 rdp.c_Ab1 = 0;
250 rdp.c_Ac1 = 0;
251 rdp.c_Ad1 = 0;
253 // Clear the palette CRC
254 int i;
255 for (i=0; i<16; i++)
256 rdp.pal_8_crc[i] = 0;
258 // Clear the palettes
259 for (i=0; i<256; i++)
260 rdp.pal_8[i] = 0;
262 rdp.tlut_mode = 0;
264 // Clear all segments ** VERY IMPORTANT FOR ZELDA **
265 for (i=0; i<16; i++)
266 rdp.segment[i] = 0;
268 for (i=0; i<512; i++)
269 rdp.addr[i] = 0;
271 // set all vertex numbers
272 for (i=0; i<MAX_VTX; i++)
273 rdp.vtx[i].number = i;
275 rdp.scissor_o.ul_x = 0;
276 rdp.scissor_o.ul_y = 0;
277 rdp.scissor_o.lr_x = 320;
278 rdp.scissor_o.lr_y = 240;
279 rdp.num_lights = 0;
280 rdp.lookat[0][0] = rdp.lookat[1][1] = 1.0f;
281 rdp.lookat[0][1] = rdp.lookat[0][2] = rdp.lookat[1][0] = rdp.lookat[1][2] = 0.0f;
282 rdp.texrecting = 0;
283 rdp.rm = 0;
284 rdp.render_mode_changed = 0;
285 rdp.othermode_h = 0;
286 rdp.othermode_l = 0;
288 rdp.tex_ctr = 0;
290 rdp.tex = 0;
292 rdp.cimg = 0;
293 rdp.ocimg = 0;
294 rdp.zimg = 0;
295 rdp.ci_width = 0;
296 rdp.cycle_mode = 2;
298 rdp.allow_combine = 1;
300 rdp.fog_coord_enabled = FALSE;
301 rdp.skip_drawing = FALSE;
303 memset(rdp.frame_buffers, 0, sizeof(rdp.frame_buffers));
304 rdp.main_ci_index = 0;
305 rdp.maincimg[0].addr = rdp.maincimg[1].addr = rdp.last_drawn_ci_addr = 0x7FFFFFFF;
306 rdp.read_previous_ci = FALSE;
307 rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
308 rdp.yuv_im_begin = 0x00FFFFFF;
309 rdp.yuv_image = FALSE;
310 rdp.cur_tex_buf = 0;
311 rdp.acc_tex_buf = 0;
312 rdp.cur_image = 0;
313 rdp.hires_tex = 0;
315 hotkey_info.fb_always = 0;
316 hotkey_info.fb_motionblur = (settings.buff_clear == 0)?0:60;
317 hotkey_info.filtering = hotkey_info.fb_motionblur;
318 hotkey_info.corona = hotkey_info.fb_motionblur;
319 #ifdef _WIN32
320 GetAsyncKeyState (VK_BACK);
321 GetAsyncKeyState(0x42);
322 GetAsyncKeyState(0x56);
323 GetAsyncKeyState(0x43);
324 #endif // _WIN32
325 for (i = 0; i < num_tmu; i++)
326 rdp.texbufs[i].count = 0;
327 rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
328 rdp.view_scale[0] = 160.0f * rdp.scale_x;
329 rdp.view_scale[1] = -120.0f * rdp.scale_y;
330 rdp.view_trans[0] = 160.0f * rdp.scale_x;
331 rdp.view_trans[1] = 120.0f * rdp.scale_y;
332 rdp.view_scale[2] = 32.0f * 511.0f;
333 rdp.view_trans[2] = 32.0f * 511.0f;
336 # define PCEndian
337 # ifdef PCEndian
338 # define ByteEndian(address) (address^3)
339 # define WordEndian(address) (address^2)
340 # endif
341 # define _Read8Endian(array, address) (*((BYTE *)(array+ByteEndian(address))))
342 __inline static DWORD searchrdram(const char *ct)
344 DWORD pos, pos2;
345 const char *t;
346 t = ct;
347 for (pos=0; pos<0x400000; pos++) {
348 for (pos2=pos, t=ct; *ct != 0; t++, pos2++) {
349 if (_Read8Endian(gfx.RDRAM, pos2) != *t)
350 break;
351 else
352 if (*(t + 1) == 0)
353 return pos;
356 return 0;
359 void microcheck ()
361 DWORD i;
362 uc_crc = 0;
364 // Check first 3k of ucode, because the last 1k sometimes contains trash
365 for (i=0; i<3072>>2; i++)
367 uc_crc += ((DWORD*)microcode)[i];
370 FRDP_E ("crc: %08lx\n", uc_crc);
372 #ifdef LOG_UCODE
373 std::ofstream ucf;
374 ucf.open ("ucode.txt", ios::out | ios::binary);
375 char d;
376 for (i=0; i<0x400000; i++)
378 d = ((char*)gfx.RDRAM)[i^3];
379 ucf.write (&d, 1);
381 ucf.close ();
382 #endif
384 char str[9];
385 sprintf (str, "%08lx", (unsigned long)uc_crc);
387 INI_Open ();
388 INI_FindSection ("UCODE");
389 FRDP("ucode = %s\n", str);
390 int uc = INI_ReadInt (str, -2, 0);
392 if (uc == -2 && ucode_error_report)
394 INI_FindSection ("SETTINGS");
395 settings.ucode = INI_ReadInt ("ucode", 0);
396 INI_Close ();
398 ReleaseGfx ();
399 sprintf (out_buf, "Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc);
400 #ifdef _WIN32
401 MessageBox (gfx.hWnd, out_buf, "Error", MB_OK|MB_ICONEXCLAMATION);
402 #else // _WIN32
403 messagebox("Error", MB_OK|MB_ICONEXCLAMATION, out_buf);
404 #endif // _WIN32
406 ucode_error_report = FALSE; // don't report any more ucode errors from this game
408 else if (uc == -1 && ucode_error_report)
410 INI_FindSection ("SETTINGS");
411 settings.ucode = INI_ReadInt ("ucode", 0);
412 INI_Close ();
414 ReleaseGfx ();
415 sprintf (out_buf, "Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc);
416 #ifdef _WIN32
417 MessageBox (gfx.hWnd, out_buf, "Error", MB_OK|MB_ICONEXCLAMATION);
418 #else // _WIN32
419 messagebox("Error", MB_OK|MB_ICONEXCLAMATION, out_buf);
420 #endif // _WIN32
422 ucode_error_report = FALSE; // don't report any more ucode errors from this game
424 else
426 old_ucode = settings.ucode;
427 settings.ucode = uc;
428 FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode, uc);
429 //INI_FindSection ("SETTINGS");
430 //INI_WriteInt ("ucode", uc);
431 INI_Close ();
435 #ifdef _WIN32
436 RECT prev_rect;
437 #endif // _WIN32
439 void drawNoFullscreenMessage()
441 LOG ("drawNoFullscreenMessage ()\n");
442 #ifdef _WIN32
443 SIZE str_size;
444 RECT win_rect;
445 HWND active_wnd = GetForegroundWindow ();
447 GetClientRect (gfx.hWnd, &win_rect);
448 if (win_rect.bottom != prev_rect.bottom ||
449 win_rect.right != prev_rect.right ||
450 rdp.window_changed)
452 rdp.window_changed = FALSE;
454 prev_rect.bottom = win_rect.bottom;
455 prev_rect.right = win_rect.right;
457 HDC hdc = GetDC(gfx.hWnd);
458 SetBkMode (hdc, TRANSPARENT);
459 SetTextColor (hdc, RGB(255,255,255));
461 FillRect (hdc, &win_rect, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
463 win_rect.bottom >>= 1;
464 win_rect.right >>= 1;
466 sprintf (out_buf, "Glide64");
467 GetTextExtentPoint32 (hdc, out_buf, strlen(out_buf), &str_size);
468 TextOut (hdc, win_rect.right - (str_size.cx>>1),
469 win_rect.bottom - str_size.cy - 32, out_buf, strlen(out_buf));
471 sprintf (out_buf, "Gfx cannot be drawn in windowed mode");
472 GetTextExtentPoint32 (hdc, out_buf, strlen(out_buf), &str_size);
473 TextOut (hdc, win_rect.right - (str_size.cx>>1),
474 win_rect.bottom - str_size.cy - 2, out_buf, strlen(out_buf));
476 sprintf (out_buf, "Press Alt+Enter to switch to fullscreen");
477 GetTextExtentPoint32 (hdc, out_buf, strlen(out_buf), &str_size);
478 TextOut (hdc, win_rect.right - (str_size.cx>>1),
479 win_rect.bottom + 2, out_buf, strlen(out_buf));
481 #endif // _WIN32
484 static WORD yuv_to_rgb(BYTE y, BYTE u, BYTE v)
486 float r = y + (1.370705f * (v-128));
487 float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128));
488 float b = y + (1.732446f * (u-128));
489 r *= 0.125f;
490 g *= 0.125f;
491 b *= 0.125f;
492 //clipping the result
493 if (r > 32) r = 32;
494 if (g > 32) g = 32;
495 if (b > 32) b = 32;
496 if (r < 0) r = 0;
497 if (g < 0) g = 0;
498 if (b < 0) b = 0;
500 WORD c = (WORD)(((WORD)(r) << 11) |
501 ((WORD)(g) << 6) |
502 ((WORD)(b) << 1) | 1);
503 return c;
506 static void DrawYUVImageToFrameBuffer()
508 WORD width = (WORD)(rdp.yuv_lr_x - rdp.yuv_ul_x);
509 WORD height = (WORD)(rdp.yuv_lr_y - rdp.yuv_ul_y);
510 DWORD * mb = (DWORD*)(gfx.RDRAM+rdp.yuv_im_begin); //pointer to the first macro block
511 WORD * cimg = (WORD*)(gfx.RDRAM+rdp.cimg);
512 //yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg
513 for (WORD y = 0; y < height; y+=16)
515 for (WORD x = 0; x < width; x+=16)
517 WORD *dst = cimg + x + y * rdp.ci_width;
518 for (WORD h = 0; h < 16; h++)
520 for (WORD w = 0; w < 8; w++)
522 DWORD t = *(mb++); //each DWORD contains 2 pixels
523 if ((x < rdp.ci_width) && (y < rdp.ci_height)) //clipping. texture image may be larger than color image
525 BYTE y0 = (BYTE)t&0xFF;
526 BYTE v = (BYTE)(t>>8)&0xFF;
527 BYTE y1 = (BYTE)(t>>16)&0xFF;
528 BYTE u = (BYTE)(t>>24)&0xFF;
529 *(dst++) = yuv_to_rgb(y0, u, v);
530 *(dst++) = yuv_to_rgb(y1, u, v);
533 dst += rdp.ci_width - 16;
535 mb += 64; //macro block is 768 bytes long, last 256 bytes are useless
540 static DWORD d_ul_x, d_ul_y, d_lr_x, d_lr_y;
542 typedef struct {
543 int ul_x, ul_y, lr_x, lr_y;
544 } FB_PART;
546 static void DrawPart(int scr_ul_x, int scr_ul_y, int prt_ul_x, int prt_ul_y, int width, int height, float scale_x, float scale_y)
548 WORD * dst = new WORD[width*height];
549 DWORD shift = ((d_ul_y+prt_ul_y) * rdp.ci_width + d_ul_x + prt_ul_x) << 1;
550 WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
551 WORD c;
552 for (int y=0; y < height; y++)
554 for (int x=0; x < width; x++)
556 c = src[(int(x*scale_x)+int(y*scale_y)*rdp.ci_width)^1];
557 dst[x+y*width] = c?((c >> 1) | 0x8000):0;
561 grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
562 scr_ul_x,
563 scr_ul_y,
564 GR_LFB_SRC_FMT_1555,
565 width,
566 height,
567 FXTRUE,
568 width<<1,
569 dst);
570 delete[] dst;
573 static void DrawFrameBufferToScreen()
575 FRDP("DrawFrameBufferToScreen. cimg: %08lx, ul_x: %d, uly: %d, lr_x: %d, lr_y: %d\n", rdp.cimg, d_ul_x, d_ul_y, d_lr_x, d_lr_y);
576 if (!fullscreen)
577 return;
578 grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
579 GR_COMBINE_FACTOR_ONE,
580 GR_COMBINE_LOCAL_NONE,
581 GR_COMBINE_OTHER_TEXTURE,
582 FXFALSE);
583 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
584 GR_COMBINE_FACTOR_ONE,
585 GR_COMBINE_LOCAL_NONE,
586 GR_COMBINE_OTHER_TEXTURE,
587 FXFALSE);
588 grConstantColorValue (0xFFFFFFFF);
589 grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
590 GR_BLEND_ONE_MINUS_SRC_ALPHA,
591 GR_BLEND_ONE,
592 GR_BLEND_ZERO);
593 rdp.update |= UPDATE_COMBINE;
595 float scale_x_dst = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
596 float scale_y_dst = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
597 float scale_x_src = (float)rdp.vi_width / (float)settings.scr_res_x;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
598 float scale_y_src = (float)rdp.vi_height / (float)settings.scr_res_y;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
599 int src_width = d_lr_x - d_ul_x + 1;
600 int src_height = d_lr_y - d_ul_y + 1;
601 int dst_width, dst_height, ul_x, ul_y;
603 if (!settings.fb_optimize_write || ((src_width < 33) && (src_height < 33)))
605 dst_width = int(src_width*scale_x_dst);
606 dst_height = int(src_height*scale_y_dst);
607 ul_x = int(d_ul_x*scale_x_dst);
608 ul_y = int(d_ul_y*scale_y_dst);
609 DrawPart(ul_x, ul_y, 0, 0, dst_width, dst_height, scale_x_src, scale_y_src);
610 memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
611 return;
614 FB_PART parts[8];
615 int p;
616 for (p = 0; p < 8; p++)
618 parts[p].lr_x = parts[p].lr_y = 0;
619 parts[p].ul_x = parts[p].ul_y = 0xFFFF;
622 int num_of_parts = 0;
623 int cur_part = 0;
624 int most_left = d_ul_x;
625 int most_right = d_lr_x;
626 DWORD shift = (d_ul_y * rdp.ci_width + d_ul_x) << 1;
627 WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
628 for (int h = 0; h < src_height; h++)
630 cur_part = 0;
631 int w = 0;
632 while (w < src_width)
634 while (w < src_width)
636 if (src[(w+h*rdp.ci_width)^1] == 0)
637 w++;
638 else
639 break;
641 if (w == src_width)
642 break;
643 if (num_of_parts == 0) //first part
645 parts[0].ul_x = w;
646 most_left = w;
647 parts[0].ul_y = h;
648 cur_part = 0;
650 else if (w < most_left - 2) //new part
652 parts[num_of_parts].ul_x = w;
653 most_left = w;
654 parts[num_of_parts].ul_y = h;
655 cur_part = num_of_parts;
656 num_of_parts++;
658 else if (w > most_right + 2) //new part
660 parts[num_of_parts].ul_x = w;
661 most_right = w;
662 parts[num_of_parts].ul_y = h;
663 cur_part = num_of_parts;
664 num_of_parts++;
666 else
668 for (p = 0; p < num_of_parts; p++)
670 if ((w > parts[p].ul_x - 2) && (w < parts[p].lr_x+2))
672 if (w < parts[p].ul_x) parts[p].ul_x = w;
673 break;
676 cur_part = p;
678 while (w < src_width)
680 if (src[(w+h*rdp.ci_width)^1] != 0)
681 w++;
682 else
683 break;
685 if (num_of_parts == 0) //first part
687 parts[0].lr_x = w;
688 most_right = w;
689 num_of_parts++;
691 else
693 if (parts[cur_part].lr_x < w) parts[cur_part].lr_x = w;
694 if (most_right < w) most_right = w;
695 parts[cur_part].lr_y = h;
700 for (p = 0; p < num_of_parts; p++)
702 FRDP("part#%d ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d\n", p, parts[p].ul_x, parts[p].ul_y, parts[p].lr_x, parts[p].lr_y);
705 for (p = 0; p < num_of_parts; p++)
707 dst_width = int((parts[p].lr_x-parts[p].ul_x + 1)*scale_x_dst);
708 dst_height = int((parts[p].lr_y-parts[p].ul_y + 1)*scale_y_dst);
709 ul_x = int((d_ul_x+parts[p].ul_x)*scale_x_dst);
710 ul_y = int((d_ul_y+parts[p].ul_y)*scale_y_dst);
711 DrawPart(ul_x, ul_y, parts[p].ul_x, parts[p].ul_y, dst_width, dst_height, scale_x_src, scale_y_src);
713 memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
716 #define RGBA16TO32(color) \
717 ((color&1)?0xFF:0) | \
718 ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \
719 ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \
720 ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8)
722 static void CopyFrameBuffer (GrBuffer_t buffer = GR_BUFFER_BACKBUFFER)
724 if (!fullscreen)
725 return;
726 FRDP ("CopyFrameBuffer: %08lx... ", rdp.cimg);
728 // don't bother to write the stuff in asm... the slow part is the read from video card,
729 // not the copy.
731 int width = rdp.ci_width;//*gfx.VI_WIDTH_REG;
732 int height;
733 if (settings.fb_smart && !settings.PPL)
735 int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0;
736 height = rdp.frame_buffers[ind].height;
738 else
740 height = rdp.ci_lower_bound;
741 if (settings.PPL)
742 height -= rdp.ci_upper_bound;
744 FRDP ("width: %d, height: %d... ", width, height);
746 if (rdp.scale_x < 1.1f)
748 WORD * ptr_src = new WORD[width*height];
749 if (grLfbReadRegion(buffer,
751 0,//rdp.ci_upper_bound,
752 width,
753 height,
754 width<<1,
755 ptr_src))
757 WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
758 DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
759 WORD c;
761 for (int y=0; y<height; y++)
763 for (int x=0; x<width; x++)
765 c = ptr_src[x + y * width];
766 if (settings.fb_read_alpha)
768 if (c > 0)
769 c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
771 else
773 c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
775 if (rdp.ci_size == 2)
776 ptr_dst[(x + y * width)^1] = c;
777 else
778 ptr_dst32[x + y * width] = RGBA16TO32(c);
783 else //8bit I or CI
785 BYTE *ptr_dst = (BYTE*)(gfx.RDRAM+rdp.cimg);
786 WORD c;
788 for (int y=0; y<height; y++)
790 for (int x=0; x<width; x++)
792 c = ptr_src[x + y * width];
793 BYTE b = (BYTE)((float)(c&0x1F)/31.0f*85.0f);
794 BYTE g = (BYTE)((float)((c>>5)&0x3F)/63.0f*85.0f);
795 BYTE r = (BYTE)((float)((c>>11)&0x1F)/31.0f*85.0f);
796 c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
797 // FRDP("src: %08lx, dst: %d\n",c,(BYTE)(r+g+b));
798 ptr_dst[(x + y * width)^1] = (BYTE)(r+g+b);
799 // ptr_dst[(x + y * width)^1] = (BYTE)((c>>8)&0xFF);
802 } */
803 RDP ("ReadRegion. Framebuffer copy complete.\n");
805 else
807 RDP ("Framebuffer copy failed.\n");
809 delete[] ptr_src;
811 else
813 if (rdp.motionblur && settings.fb_hires)
815 return;
817 else
819 float scale_x = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
820 float scale_y = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
822 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);
823 GrLfbInfo_t info;
824 info.size = sizeof(GrLfbInfo_t);
827 // VP 888 disconnected for now
828 if (1||rdp.ci_size <= 2) {
829 if (grLfbLock (GR_LFB_READ_ONLY,
830 buffer,
831 GR_LFBWRITEMODE_565,
832 GR_ORIGIN_UPPER_LEFT,
833 FXFALSE,
834 &info))
836 WORD *ptr_src = (WORD*)info.lfbPtr;
837 WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
838 DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
839 WORD c;
840 DWORD stride = info.strideInBytes>>1;
842 BOOL read_alpha = settings.fb_read_alpha;
843 if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux)
844 read_alpha = FALSE;
845 for (int y=0; y<height; y++)
847 for (int x=0; x<width; x++)
849 c = ptr_src[int(x*scale_x) + int(y * scale_y) * stride];
850 c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
851 if (read_alpha && c == 1)
852 c = 0;
853 if (rdp.ci_size <= 2)
854 ptr_dst[(x + y * width)^1] = c;
855 else
856 ptr_dst32[x + y * width] = RGBA16TO32(c);
860 // Unlock the backbuffer
861 grLfbUnlock (GR_LFB_READ_ONLY, buffer);
862 RDP ("LfbLock. Framebuffer copy complete.\n");
864 else
866 RDP ("Framebuffer copy failed.\n");
868 } else {
869 if (grLfbLock (GR_LFB_READ_ONLY,
870 buffer,
871 GR_LFBWRITEMODE_888,
872 GR_ORIGIN_UPPER_LEFT,
873 FXFALSE,
874 &info))
876 DWORD *ptr_src = (DWORD*)info.lfbPtr;
877 //FIXME: Why unused?
878 //WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
879 DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
880 DWORD c;
881 DWORD stride = info.strideInBytes>>1;
883 BOOL read_alpha = settings.fb_read_alpha;
884 if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux)
885 read_alpha = FALSE;
886 for (int y=0; y<height; y++)
888 for (int x=0; x<width; x++)
890 c = ptr_src[int(x*scale_x) + int(y * scale_y) * stride];
891 // c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
892 // if (read_alpha && c == 1)
893 // c = 0;
894 ptr_dst32[x + y * width] = c;
898 // Unlock the backbuffer
899 grLfbUnlock (GR_LFB_READ_ONLY, buffer);
900 RDP ("LfbLock. Framebuffer copy complete.\n");
902 else
904 RDP ("Framebuffer copy failed.\n");
911 /******************************************************************
912 Function: ProcessDList
913 Purpose: This function is called when there is a Dlist to be
914 processed. (High level GFX list)
915 input: none
916 output: none
917 *******************************************************************/
918 void DetectFrameBufferUsage ();
919 DWORD fbreads_front = 0;
920 DWORD fbreads_back = 0;
921 BOOL cpu_fb_read_called = FALSE;
922 BOOL cpu_fb_write_called = FALSE;
923 BOOL cpu_fb_write = FALSE;
924 BOOL cpu_fb_ignore = FALSE;
925 BOOL CI_SET = TRUE;
927 EXPORT void CALL ProcessDList(void)
929 no_dlist = FALSE;
930 update_screen_count = 0;
931 ChangeSize ();
933 #ifdef ALTTAB_FIX
934 if (!hhkLowLevelKybd)
936 hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
937 LowLevelKeyboardProc, hInstance, 0);
939 #endif
941 LOG ("ProcessDList ()\n");
943 if (!fullscreen)
945 drawNoFullscreenMessage();
946 // Set an interrupt to allow the game to continue
947 *gfx.MI_INTR_REG |= 0x20;
948 gfx.CheckInterrupts();
951 if (reset)
953 reset = 0;
955 memset (microcode, 0, 4096);
956 if (settings.autodetect_ucode)
958 // Thanks to ZeZu for ucode autodetection!!!
960 DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
961 memcpy (microcode, gfx.RDRAM+startUcode, 4096);
962 microcheck ();
966 else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
968 DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
969 memcpy (microcode, gfx.RDRAM+startUcode, 4096);
970 microcheck ();
973 if (exception) return;
975 // Switch to fullscreen?
976 if (to_fullscreen)
978 to_fullscreen = FALSE;
980 if (!InitGfx (FALSE))
982 LOG ("FAILED!!!\n");
983 return;
985 fullscreen = TRUE;
986 #ifdef _WIN32
987 if (gfx.hStatusBar)
988 ShowWindow( gfx.hStatusBar, SW_HIDE );
989 ShowCursor( FALSE );
990 #endif // _WIN32
993 if (!fullscreen && !settings.run_in_window) return;
995 // Clear out the RDP log
996 #ifdef RDP_LOGGING
997 if (settings.logging && settings.log_clear)
999 CLOSE_RDP_LOG ();
1000 OPEN_RDP_LOG ();
1002 #endif
1004 #ifdef UNIMP_LOG
1005 if (settings.log_unk && settings.unk_clear)
1007 std::ofstream unimp;
1008 unimp.open("unimp.txt");
1009 unimp.close();
1011 #endif
1013 //* Set states *//
1014 if (settings.swapmode > 0)
1015 SwapOK = TRUE;
1016 rdp.updatescreen = 1;
1018 rdp.tri_n = 0; // 0 triangles so far this frame
1019 rdp.debug_n = 0;
1021 rdp.model_i = 0; // 0 matrices so far in stack
1022 //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin!
1023 rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
1024 if (rdp.model_stack_size == 0)
1025 rdp.model_stack_size = 32;
1026 rdp.fb_drawn = rdp.fb_drawn_front = FALSE;
1027 rdp.update = 0x7FFFFFFF; // All but clear cache
1028 rdp.geom_mode = 0;
1029 rdp.acmp = 0;
1030 rdp.maincimg[1] = rdp.maincimg[0];
1031 rdp.skip_drawing = FALSE;
1032 rdp.s2dex_tex_loaded = FALSE;
1033 fbreads_front = fbreads_back = 0;
1034 rdp.fog_multiplier = rdp.fog_offset = 0;
1035 rdp.zsrc = 0;
1037 if (cpu_fb_write == TRUE)
1038 DrawFrameBufferToScreen();
1039 cpu_fb_write = FALSE;
1040 cpu_fb_read_called = FALSE;
1041 cpu_fb_write_called = FALSE;
1042 cpu_fb_ignore = FALSE;
1043 d_ul_x = 0xffff;
1044 d_ul_y = 0xffff;
1045 d_lr_x = 0;
1046 d_lr_y = 0;
1048 //analize possible frame buffer usage
1049 if (settings.fb_smart)
1050 DetectFrameBufferUsage();
1051 if (!settings.lego || rdp.num_of_ci > 1)
1052 rdp.last_bg = 0;
1053 //* End of set states *//
1056 // Get the start of the display list and the length of it
1057 DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
1058 DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
1059 FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length);
1060 FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
1062 if (settings.tonic && dlist_length < 16)
1064 rdp_fullsync();
1065 FRDP_E("DLIST is too short!\n");
1066 return;
1069 // Start executing at the start of the display list
1070 rdp.pc_i = 0;
1071 rdp.pc[rdp.pc_i] = dlist_start;
1072 rdp.dl_count = -1;
1073 rdp.halt = 0;
1074 DWORD a;
1076 // catches exceptions so that it doesn't freeze
1077 #ifdef CATCH_EXCEPTIONS
1078 try {
1079 #endif
1081 // MAIN PROCESSING LOOP
1082 do {
1084 // Get the address of the next command
1085 a = rdp.pc[rdp.pc_i] & BMASK;
1087 // Load the next command and its input
1088 rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
1089 rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
1090 // cmd2 and cmd3 are filled only when needed, by the function that needs them
1092 // Output the address before the command
1093 #ifdef LOG_COMMANDS
1094 FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1);
1095 #else
1096 FRDP ("%08lx: ", a);
1097 #endif
1099 // Go to the next instruction
1100 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
1102 #ifdef PERFORMANCE
1103 QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
1104 #endif
1105 // Process this instruction
1106 gfx_instruction[settings.ucode][rdp.cmd0>>24] ();
1108 // check DL counter
1109 if (rdp.dl_count != -1)
1111 rdp.dl_count --;
1112 if (rdp.dl_count == 0)
1114 rdp.dl_count = -1;
1116 RDP ("End of DL\n");
1117 rdp.pc_i --;
1121 #ifdef PERFORMANCE
1122 QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
1123 __int64 t = perf_next-perf_cur;
1124 sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
1125 rdp_log << out_buf;
1126 #endif
1128 } while (!rdp.halt);
1129 #ifdef CATCH_EXCEPTIONS
1130 } catch (...) {
1132 if (fullscreen) ReleaseGfx ();
1133 # ifdef _WIN32
1134 if (MessageBox (gfx.hWnd, "The GFX plugin caused an exception and has been disabled.\nWould you like to turn it back on and attempt to continue?", "Glide64 Exception", MB_YESNO|MB_ICONEXCLAMATION) == IDNO)
1135 exception = TRUE;
1136 # else // _WIN32
1137 if (messagebox("Glide64 Exception", MB_YESNO|MB_ICONEXCLAMATION, "The GFX plugin caused an exception and has been disabled.\nWould you like to turn it back on and attempt to continue?") == 2)
1138 exception = TRUE;
1139 # endif // _WIN32
1141 #endif
1143 if (settings.fb_smart)
1145 rdp.scale_x = rdp.scale_x_bak;
1146 rdp.scale_y = rdp.scale_y_bak;
1148 if (settings.fb_read_always)
1150 CopyFrameBuffer ();
1152 if (rdp.yuv_image)
1154 DrawYUVImageToFrameBuffer();
1155 rdp.yuv_image = FALSE;
1156 // FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
1157 // rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
1158 rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
1159 rdp.yuv_im_begin = 0x00FFFFFF;
1161 if (rdp.cur_image)
1162 CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
1164 if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
1166 newSwapBuffers ();
1167 CI_SET = FALSE;
1169 RDP("ProcessDList end\n");
1172 // undef - undefined instruction, always ignore
1173 static void undef()
1175 FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0);
1176 FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0);
1177 #ifdef _FINAL_RELEASE_
1178 *gfx.MI_INTR_REG |= 0x20;
1179 gfx.CheckInterrupts();
1180 rdp.halt = 1;
1181 #endif
1184 // spnoop - no operation, always ignore
1185 static void spnoop()
1187 RDP("spnoop\n");
1190 // noop - no operation, always ignore
1191 static void rdp_noop()
1193 RDP("noop\n");
1196 static void ys_memrect ()
1198 DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
1200 DWORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
1201 DWORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
1202 DWORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
1203 DWORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
1205 rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
1207 if (lr_y > rdp.scissor_o.lr_y) lr_y = rdp.scissor_o.lr_y;
1209 FRDP ("memrect (%d, %d, %d, %d), ci_width: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.ci_width);
1211 DWORD y, width = lr_x - ul_x;
1212 DWORD texaddr = rdp.addr[rdp.tiles[tile].t_mem];
1213 DWORD tex_width = rdp.tiles[tile].line << 3;
1215 for (y = ul_y; y < lr_y; y++) {
1216 BYTE *src = gfx.RDRAM + texaddr + (y - ul_y) * tex_width;
1217 BYTE *dst = gfx.RDRAM + rdp.cimg + ul_x + y * rdp.ci_width;
1218 memcpy (dst, src, width);
1222 static void pm_palette_mod ()
1224 BYTE envr = (BYTE)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f);
1225 BYTE envg = (BYTE)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f);
1226 BYTE envb = (BYTE)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f);
1227 WORD env16 = (WORD)((envr<<11)|(envg<<6)|(envb<<1)|1);
1228 BYTE prmr = (BYTE)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f);
1229 BYTE prmg = (BYTE)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f);
1230 BYTE prmb = (BYTE)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f);
1231 WORD prim16 = (WORD)((prmr<<11)|(prmg<<6)|(prmb<<1)|1);
1232 WORD * dst = (WORD*)(gfx.RDRAM+rdp.cimg);
1233 for (int i = 0; i < 16; i++)
1235 dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16;
1237 RDP("Texrect palette modification\n");
1240 static void rdp_texrect()
1242 DWORD a = rdp.pc[rdp.pc_i];
1243 rdp.cmd2 = ((DWORD*)gfx.RDRAM)[(a>>2)+1];
1244 rdp.cmd3 = ((DWORD*)gfx.RDRAM)[(a>>2)+3];
1246 if (settings.ASB) //modified Rice's hack for All-Star Baseball games
1248 DWORD dwHalf1 = (((DWORD*)gfx.RDRAM)[(a>>2)+0]) >> 24;
1249 if ((dwHalf1 != 0xF1) && (dwHalf1 != 0xb3))
1251 rdp.pc[rdp.pc_i] += 16;
1253 else
1255 rdp.pc[rdp.pc_i] += 8;
1256 rdp.cmd3 = rdp.cmd2;
1257 rdp.cmd2 = 0;
1260 else if (settings.yoshi && settings.ucode == 6)
1262 ys_memrect();
1263 return;
1265 else
1267 rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
1270 if (rdp.skip_drawing || (!settings.fb_smart && (rdp.cimg == rdp.zimg)))
1272 if (settings.PM && rdp.ci_status == ci_useless)
1274 pm_palette_mod ();
1276 else
1278 RDP("Texrect skipped\n");
1280 return;
1283 if ((settings.ucode == 8) && rdp.cur_image && rdp.cur_image->format)
1285 //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);
1286 RDP("Shadow texrect is skipped.\n");
1287 rdp.tri_n += 2;
1288 return;
1291 WORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
1292 WORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
1293 WORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
1294 WORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
1295 if (ul_x >= lr_x) return;
1296 if (rdp.cycle_mode > 1 || settings.increase_texrect_edge)
1298 lr_x++;
1299 lr_y++;
1301 if (ul_y == lr_y)
1303 lr_y ++;
1306 //*
1307 if (rdp.hires_tex && settings.fb_optimize_texrect)
1309 if (!rdp.hires_tex->drawn)
1311 DRAWIMAGE d;
1312 d.imageX = 0;
1313 d.imageW = (WORD)rdp.hires_tex->width;
1314 d.frameX = ul_x;
1315 d.frameW = (WORD)(rdp.hires_tex->width);//(WORD)(ul_x + rdp.hires_tex->width);//lr_x;
1317 d.imageY = 0;
1318 d.imageH = (WORD)rdp.hires_tex->height;
1319 d.frameY = ul_y;
1320 d.frameH = (WORD)(rdp.hires_tex->height);//(ul_y + rdp.hires_tex->height);
1321 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.hires_tex->width, rdp.hires_tex->height);
1322 d.scaleX = 1.0f;
1323 d.scaleY = 1.0f;
1324 DrawHiresImage(&d, rdp.hires_tex->width == rdp.ci_width);
1325 rdp.hires_tex->drawn = TRUE;
1327 return;
1329 //*/
1330 // framebuffer workaround for Zelda: MM LOT
1331 if ((rdp.othermode_l & 0xFFFF0000) == 0x0f5a0000)
1332 return;
1334 /*Gonetz*/
1335 //hack for Zelda MM. it removes black texrects which cover all geometry in "Link meets Zelda" cut scene
1336 if (settings.zelda && rdp.timg.addr >= rdp.cimg && rdp.timg.addr < rdp.ci_end)
1338 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);
1339 rdp.tri_n += 2;
1340 return;
1342 //*
1343 //hack for Banjo2. it removes black texrects under Banjo
1344 if (!settings.fb_hires && ((rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF)) == 0xFFFFFFFF && (rdp.othermode_l & 0xFFFF0000) == 0x00500000)
1346 rdp.tri_n += 2;
1347 return;
1349 //*/
1351 //remove motion blur in night vision
1352 if ((settings.ucode == 7) && (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)))
1354 if (settings.fb_smart)
1355 if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self || !settings.fb_motionblur)
1357 // 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);
1358 RDP("Wrong Texrect.\n");
1359 rdp.tri_n += 2;
1360 return;
1363 //*/
1365 int i;
1367 DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
1369 // update MUST be at the beginning, b/c of update_scissor
1370 if (rdp.cycle_mode == 2)
1372 rdp.tex = 1;
1373 rdp.allow_combine = 0;
1375 cmb.tmu1_func = cmb.tmu0_func = GR_COMBINE_FUNCTION_LOCAL;
1376 cmb.tmu1_fac = cmb.tmu0_fac = GR_COMBINE_FACTOR_NONE;
1377 cmb.tmu1_a_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;
1378 cmb.tmu1_a_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
1379 cmb.tmu1_invert = cmb.tmu0_invert = FXFALSE;
1380 cmb.tmu1_a_invert = cmb.tmu0_a_invert = FXFALSE;
1383 rdp.texrecting = 1;
1385 DWORD prev_tile = rdp.cur_tile;
1386 rdp.cur_tile = tile;
1387 rdp.update |= UPDATE_COMBINE;
1388 update ();
1390 rdp.texrecting = 0;
1391 rdp.allow_combine = 1;
1393 if (!rdp.cur_cache[0])
1395 rdp.cur_tile = prev_tile;
1396 rdp.tri_n += 2;
1397 return;
1399 // ****
1400 // ** Texrect offset by Gugaman **
1401 float off_x = (float)((short)((rdp.cmd2 & 0xFFFF0000) >> 16)) / 32.0f;
1402 if ((int(off_x) == 512) && (rdp.timg.width < 512)) off_x = 0.0f;
1403 float off_y = (float)((short)(rdp.cmd2 & 0x0000FFFF)) / 32.0f;
1404 float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f;
1405 float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f;
1407 if (rdp.cycle_mode == 2) dsdx /= 4.0f;
1409 float s_ul_x = ul_x * rdp.scale_x + rdp.offset_x;
1410 float s_lr_x = lr_x * rdp.scale_x + rdp.offset_x;
1411 float s_ul_y = ul_y * rdp.scale_y + rdp.offset_y;
1412 float s_lr_y = lr_y * rdp.scale_y + rdp.offset_y;
1414 FRDP("texrect (%d, %d, %d, %d), tile: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, tile, rdp.tri_n, rdp.tri_n+1);
1415 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);
1416 FRDP("\toff_x: %f, off_y: %f, dsdx: %f, dtdy: %f\n", off_x, off_y, dsdx, dtdy);
1418 float off_size_x;
1419 float off_size_y;
1421 if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1423 off_size_x = (float)((lr_y - ul_y - 1) * dsdx);
1424 off_size_y = (float)((lr_x - ul_x - 1) * dtdy);
1426 else
1428 off_size_x = (float)((lr_x - ul_x - 1) * dsdx);
1429 off_size_y = (float)((lr_y - ul_y - 1) * dtdy);
1432 float lr_u0, lr_v0, ul_u0, ul_v0, lr_u1, lr_v1, ul_u1, ul_v1;
1434 if (rdp.cur_cache[0] && (rdp.tex & 1))
1436 float sx=1, sy=1;
1437 if (rdp.tiles[rdp.cur_tile].shift_s)
1439 if (rdp.tiles[rdp.cur_tile].shift_s > 10)
1440 sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s));
1441 else
1442 sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_s);
1444 if (rdp.tiles[rdp.cur_tile].shift_t)
1446 if (rdp.tiles[rdp.cur_tile].shift_t > 10)
1447 sy = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t));
1448 else
1449 sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_t);
1451 if (rdp.hires_tex && rdp.hires_tex->tile == 0)
1453 off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
1454 off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
1455 FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y);
1456 ul_u0 = off_x * sx;
1457 ul_v0 = off_y * sy;
1459 lr_u0 = ul_u0 + off_size_x * sx;
1460 lr_v0 = ul_v0 + off_size_y * sy;
1462 ul_u0 *= rdp.hires_tex->u_scale;
1463 ul_v0 *= rdp.hires_tex->v_scale;
1464 lr_u0 *= rdp.hires_tex->u_scale;
1465 lr_v0 *= rdp.hires_tex->v_scale;
1466 FRDP("hires_tex ul_u0: %f, ul_v0: %f, lr_u0: %f, lr_v0: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
1468 else
1470 ul_u0 = off_x * sx;
1471 ul_v0 = off_y * sy;
1473 ul_u0 -= rdp.tiles[rdp.cur_tile].f_ul_s;
1474 ul_v0 -= rdp.tiles[rdp.cur_tile].f_ul_t;
1476 lr_u0 = ul_u0 + off_size_x * sx;
1477 lr_v0 = ul_v0 + off_size_y * sy;
1479 ul_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * ul_u0;
1480 lr_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * lr_u0;
1481 ul_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * ul_v0;
1482 lr_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * lr_v0;
1485 else
1487 ul_u0 = ul_v0 = lr_u0 = lr_v0 = 0;
1489 if (rdp.cur_cache[1] && (rdp.tex & 2))
1491 float sx=1, sy=1;
1493 if (rdp.tiles[rdp.cur_tile+1].shift_s)
1495 if (rdp.tiles[rdp.cur_tile+1].shift_s > 10)
1496 sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s));
1497 else
1498 sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_s);
1500 if (rdp.tiles[rdp.cur_tile+1].shift_t)
1502 if (rdp.tiles[rdp.cur_tile+1].shift_t > 10)
1503 sy = 1;//(float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t));
1504 else
1505 sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_t);
1508 if (rdp.hires_tex && rdp.hires_tex->tile == 1)
1510 off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
1511 off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
1512 FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y);
1513 ul_u1 = off_x * sx;
1514 ul_v1 = off_y * sy;
1516 lr_u1 = ul_u1 + off_size_x * sx;
1517 lr_v1 = ul_v1 + off_size_y * sy;
1519 ul_u1 *= rdp.hires_tex->u_scale;
1520 ul_v1 *= rdp.hires_tex->v_scale;
1521 lr_u1 *= rdp.hires_tex->u_scale;
1522 lr_v1 *= rdp.hires_tex->v_scale;
1523 FRDP("hires_tex ul_u1: %f, ul_v1: %f, lr_u1: %f, lr_v1: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
1526 else
1528 ul_u1 = off_x * sx;
1529 ul_v1 = off_y * sy;
1531 ul_u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s;
1532 ul_v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t;
1534 lr_u1 = ul_u1 + off_size_x * sx;
1535 lr_v1 = ul_v1 + off_size_y * sy;
1537 ul_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * ul_u1;
1538 lr_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * lr_u1;
1539 ul_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * ul_v1;
1540 lr_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * lr_v1;
1543 else
1545 ul_u1 = ul_v1 = lr_u1 = lr_v1 = 0;
1547 rdp.cur_tile = prev_tile;
1549 // ****
1551 FRDP (" scissor: (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y);
1553 CCLIP2 (s_ul_x, s_lr_x, ul_u0, lr_u0, ul_u1, lr_u1, (float)rdp.scissor.ul_x, (float)rdp.scissor.lr_x);
1554 CCLIP2 (s_ul_y, s_lr_y, ul_v0, lr_v0, ul_v1, lr_v1, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y);
1555 // CCLIP2 (s_lr_y, s_ul_y, lr_v0, ul_v0, lr_v1, ul_v1, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y);
1557 FRDP (" draw at: (%f, %f) -> (%f, %f)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
1559 // DO NOT SET CLAMP MODE HERE
1561 float Z = 1.0f;
1562 if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030)) // othermode check makes sure it
1563 // USES the z-buffer. Otherwise it returns bad (unset) values for lot and telescope
1564 //in zelda:mm.
1566 FRDP ("prim_depth = %d\n", rdp.prim_depth);
1567 Z = rdp.prim_depth;
1568 if (settings.increase_primdepth)
1569 Z += 8.0f;
1570 Z = ScaleZ(Z);
1572 grDepthBufferFunction (GR_CMP_LEQUAL);
1573 rdp.update |= UPDATE_ZBUF_ENABLED;
1575 else
1577 RDP ("no prim_depth used, using 1.0\n");
1580 VERTEX vstd[4] = {
1581 { s_ul_x, s_ul_y, Z, 1.0f, ul_u0, ul_v0, ul_u1, ul_v1, { 0, 0, 0, 0}, 255 },
1582 { s_lr_x, s_ul_y, Z, 1.0f, lr_u0, ul_v0, lr_u1, ul_v1, { 0, 0, 0, 0}, 255 },
1583 { s_ul_x, s_lr_y, Z, 1.0f, ul_u0, lr_v0, ul_u1, lr_v1, { 0, 0, 0, 0}, 255 },
1584 { s_lr_x, s_lr_y, Z, 1.0f, lr_u0, lr_v0, lr_u1, lr_v1, { 0, 0, 0, 0}, 255 } };
1586 if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1588 vstd[1].u0 = ul_u0;
1589 vstd[1].v0 = lr_v0;
1590 vstd[1].u1 = ul_u1;
1591 vstd[1].v1 = lr_v1;
1593 vstd[2].u0 = lr_u0;
1594 vstd[2].v0 = ul_v0;
1595 vstd[2].u1 = lr_u1;
1596 vstd[2].v1 = ul_v1;
1599 VERTEX *vptr = vstd;
1600 int n_vertices = 4;
1602 VERTEX *vnew = 0;
1603 // for (int j =0; j < 4; j++)
1604 // 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);
1607 if (!rdp.hires_tex && rdp.cur_cache[0]->splits != 1)
1609 // ** LARGE TEXTURE HANDLING **
1610 // *VERY* simple algebra for texrects
1611 float min_u, min_x, max_u, max_x;
1612 if (vstd[0].u0 < vstd[1].u0)
1614 min_u = vstd[0].u0;
1615 min_x = vstd[0].x;
1616 max_u = vstd[1].u0;
1617 max_x = vstd[1].x;
1619 else
1621 min_u = vstd[1].u0;
1622 min_x = vstd[1].x;
1623 max_u = vstd[0].u0;
1624 max_x = vstd[0].x;
1627 int start_u_256, end_u_256;
1629 if (settings.ucode == 7)
1631 start_u_256 = 0;
1632 end_u_256 = (lr_x - ul_x - 1)>>8;
1634 else
1636 start_u_256 = (int)min_u >> 8;
1637 end_u_256 = (int)max_u >> 8;
1639 //FRDP(" min_u: %f, max_u: %f start: %d, end: %d\n", min_u, max_u, start_u_256, end_u_256);
1641 int splitheight = rdp.cur_cache[0]->splitheight;
1643 int num_verts_line = 2 + ((end_u_256-start_u_256)<<1);
1644 vnew = new VERTEX [num_verts_line << 1];
1646 n_vertices = num_verts_line << 1;
1647 vptr = vnew;
1649 vnew[0] = vstd[0];
1650 vnew[0].u0 -= 256.0f * start_u_256;
1651 vnew[0].v0 += splitheight * start_u_256;
1652 vnew[0].u1 -= 256.0f * start_u_256;
1653 vnew[0].v1 += splitheight * start_u_256;
1654 vnew[1] = vstd[2];
1655 vnew[1].u0 -= 256.0f * start_u_256;
1656 vnew[1].v0 += splitheight * start_u_256;
1657 vnew[1].u1 -= 256.0f * start_u_256;
1658 vnew[1].v1 += splitheight * start_u_256;
1659 vnew[n_vertices-2] = vstd[1];
1660 vnew[n_vertices-2].u0 -= 256.0f * end_u_256;
1661 vnew[n_vertices-2].v0 += splitheight * end_u_256;
1662 vnew[n_vertices-2].u1 -= 256.0f * end_u_256;
1663 vnew[n_vertices-2].v1 += splitheight * end_u_256;
1664 vnew[n_vertices-1] = vstd[3];
1665 vnew[n_vertices-1].u0 -= 256.0f * end_u_256;
1666 vnew[n_vertices-1].v0 += splitheight * end_u_256;
1667 vnew[n_vertices-1].u1 -= 256.0f * end_u_256;
1668 vnew[n_vertices-1].v1 += splitheight * end_u_256;
1670 // find the equation of the line of u,x
1671 float m = (max_x - min_x) / (max_u - min_u); // m = delta x / delta u
1672 float b = min_x - m * min_u; // b = y - m * x
1674 for (i=start_u_256; i<end_u_256; i++)
1676 // Find where x = current 256 multiple
1677 float x = m * ((i<<8)+256) + b;
1679 int vn = 2 + ((i-start_u_256)<<2);
1680 vnew[vn] = vnew[0];
1681 vnew[vn].x = x;
1682 vnew[vn].u0 = 255.5f;
1683 vnew[vn].v0 += (float)splitheight * i;
1684 vnew[vn].u1 = 255.5f;
1685 vnew[vn].v1 += (float)splitheight * i;
1687 vn ++;
1688 vnew[vn] = vnew[1];
1689 vnew[vn].x = x;
1690 vnew[vn].u0 = 255.5f;
1691 vnew[vn].v0 += (float)splitheight * i;
1692 vnew[vn].u1 = 255.5f;
1693 vnew[vn].v1 += (float)splitheight * i;
1695 vn ++;
1696 vnew[vn] = vnew[vn-2];
1697 vnew[vn].u0 = 0.5f;
1698 vnew[vn].v0 += (float)splitheight;
1699 vnew[vn].u1 = 0.5f;
1700 vnew[vn].v1 += (float)splitheight;
1702 vn ++;
1703 vnew[vn] = vnew[vn-2];
1704 vnew[vn].u0 = 0.5f;
1705 vnew[vn].v0 += (float)splitheight;
1706 vnew[vn].u1 = 0.5f;
1707 vnew[vn].v1 += (float)splitheight;
1711 AllowShadeMods (vptr, n_vertices);
1712 for (i=0; i<n_vertices; i++)
1714 VERTEX *z = &vptr[i];
1716 z->u0 *= z->q;
1717 z->v0 *= z->q;
1718 z->u1 *= z->q;
1719 z->v1 *= z->q;
1721 apply_shade_mods (z);
1724 if (fullscreen)
1726 grFogMode (GR_FOG_DISABLE);
1728 grClipWindow (0, 0, settings.res_x, settings.res_y);
1730 grCullMode (GR_CULL_DISABLE);
1732 if (rdp.cycle_mode == 2)
1734 grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
1735 GR_COMBINE_FACTOR_ONE,
1736 GR_COMBINE_LOCAL_NONE,
1737 GR_COMBINE_OTHER_TEXTURE,
1738 FXFALSE);
1739 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
1740 GR_COMBINE_FACTOR_ONE,
1741 GR_COMBINE_LOCAL_NONE,
1742 GR_COMBINE_OTHER_TEXTURE,
1743 FXFALSE);
1744 grAlphaBlendFunction (GR_BLEND_ONE,
1745 GR_BLEND_ZERO,
1746 GR_BLEND_ZERO,
1747 GR_BLEND_ZERO);
1748 if (rdp.othermode_l & 1)
1750 grAlphaTestFunction (GR_CMP_GEQUAL);
1751 grAlphaTestReferenceValue (0x80);
1753 else
1754 grAlphaTestFunction (GR_CMP_ALWAYS);
1756 rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
1759 ConvertCoordsConvert (vptr, n_vertices);
1761 if (settings.wireframe)
1763 SetWireframeCol ();
1764 grDrawLine (&vstd[0], &vstd[2]);
1765 grDrawLine (&vstd[2], &vstd[1]);
1766 grDrawLine (&vstd[1], &vstd[0]);
1767 grDrawLine (&vstd[2], &vstd[3]);
1768 grDrawLine (&vstd[3], &vstd[1]);
1770 else
1772 grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, n_vertices, vptr, sizeof(VERTEX));
1775 if (debug.capture)
1777 VERTEX vl[3];
1778 vl[0] = vstd[0];
1779 vl[1] = vstd[2];
1780 vl[2] = vstd[1];
1781 add_tri (vl, 3, TRI_TEXRECT);
1782 rdp.tri_n ++;
1783 vl[0] = vstd[2];
1784 vl[1] = vstd[3];
1785 vl[2] = vstd[1];
1786 add_tri (vl, 3, TRI_TEXRECT);
1787 rdp.tri_n ++;
1789 else
1790 rdp.tri_n += 2;
1792 if (settings.fog && (rdp.flags & FOG_ENABLED))
1794 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
1796 rdp.update |= UPDATE_CULL_MODE | UPDATE_VIEWPORT;
1798 else
1800 rdp.tri_n += 2;
1803 delete[] vnew;
1806 static void rdp_loadsync()
1808 RDP("loadsync - ignored\n");
1811 static void rdp_pipesync()
1813 RDP("pipesync - ignored\n");
1816 static void rdp_tilesync()
1818 RDP("tilesync - ignored\n");
1821 static void rdp_fullsync()
1823 // Set an interrupt to allow the game to continue
1824 *gfx.MI_INTR_REG |= 0x20;
1825 gfx.CheckInterrupts();
1826 RDP("fullsync\n");
1829 static void rdp_setkeygb()
1831 RDP_E("setkeygb - IGNORED\n");
1832 RDP("setkeygb - IGNORED\n");
1835 static void rdp_setkeyr()
1837 RDP_E("setkeyr - IGNORED\n");
1838 RDP("setkeyr - IGNORED\n");
1841 static void rdp_setconvert()
1844 rdp.YUV_C0 = 1.1647f ;
1845 rdp.YUV_C1 = 0.79931f ;
1846 rdp.YUV_C2 = -0.1964f ;
1847 rdp.YUV_C3 = -0.40651f;
1848 rdp.YUV_C4 = 1.014f ;
1850 rdp.K5 = (BYTE)(rdp.cmd1&0x1FF);
1851 RDP_E("setconvert - IGNORED\n");
1852 RDP("setconvert - IGNORED\n");
1856 // setscissor - sets the screen clipping rectangle
1859 static void rdp_setscissor()
1861 // clipper resolution is 320x240, scale based on computer resolution
1862 rdp.scissor_o.ul_x = /*min(*/(DWORD)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/;
1863 rdp.scissor_o.ul_y = /*min(*/(DWORD)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/;
1864 rdp.scissor_o.lr_x = /*min(*/(DWORD)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/;
1865 rdp.scissor_o.lr_y = /*min(*/(DWORD)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/;
1867 rdp.ci_upper_bound = rdp.scissor_o.ul_y;
1868 rdp.ci_lower_bound = rdp.scissor_o.lr_y;
1870 FRDP("setscissor: (%d,%d) -> (%d,%d)\n", rdp.scissor_o.ul_x, rdp.scissor_o.ul_y,
1871 rdp.scissor_o.lr_x, rdp.scissor_o.lr_y);
1873 rdp.update |= UPDATE_SCISSOR;
1876 static void rdp_setprimdepth()
1878 rdp.prim_depth = (WORD)((rdp.cmd1 >> 16) & 0x7FFF);
1880 FRDP("setprimdepth: %d\n", rdp.prim_depth);
1883 static void rdp_setothermode()
1885 #define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \
1886 rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \
1887 rdp.cmd1 = data; \
1888 gfx_instruction[settings.ucode][cmd] (); \
1890 #define SETOTHERMODE(cmd,sft,len,data) { \
1891 rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \
1892 rdp.cmd1 = data; \
1893 gfx_instruction[settings.ucode][cmd] (); \
1896 RDP("rdp_setothermode\n");
1898 if ((settings.ucode == 2) || (settings.ucode == 8))
1900 int cmd0 = rdp.cmd0;
1901 F3DEX2_SETOTHERMODE(0xE2, 0, 32, rdp.cmd1); // SETOTHERMODE_L
1902 F3DEX2_SETOTHERMODE(0xE3, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H
1904 else
1906 int cmd0 = rdp.cmd0;
1907 SETOTHERMODE(0xB9, 0, 32, rdp.cmd1); // SETOTHERMODE_L
1908 SETOTHERMODE(0xBA, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H
1912 void load_palette (DWORD addr, WORD start, WORD count)
1914 RDP ("Loading palette... ");
1915 WORD *dpal = rdp.pal_8 + start;
1916 WORD end = start+count;
1917 // WORD *spal = (WORD*)(gfx.RDRAM + (addr & BMASK));
1919 for (WORD i=start; i<end; i++)
1921 *(dpal++) = *(WORD *)(gfx.RDRAM + (addr^2));
1922 addr += 2;
1924 #ifdef TLUT_LOGGING
1925 FRDP ("%d: %08lx\n", i, *(WORD *)(gfx.RDRAM + (addr^2)));
1926 #endif
1928 start >>= 4;
1929 end = start + (count >> 4);
1930 for (WORD p = start; p < end; p++)
1932 rdp.pal_8_crc[p] = CRC_Calculate( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 );
1934 rdp.pal_256_crc = CRC_Calculate( 0xFFFFFFFF, rdp.pal_8_crc, 64 );
1935 RDP ("Done.\n");
1938 static void rdp_loadtlut()
1940 DWORD tile = (rdp.cmd1 >> 24) & 0x07;
1941 WORD start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes
1942 // WORD start = ((WORD)(rdp.cmd1 >> 2) & 0x3FF) + 1;
1943 WORD count = ((WORD)(rdp.cmd1 >> 14) & 0x3FF) + 1; // number to copy
1945 if (rdp.timg.addr + (count<<1) > BMASK)
1946 count = (WORD)((BMASK - rdp.timg.addr) >> 1);
1948 if (start+count > 256) count = 256-start;
1950 FRDP("loadtlut: tile: %d, start: %d, count: %d, from: %08lx\n", tile, start, count,
1951 rdp.timg.addr);
1953 load_palette (rdp.timg.addr, start, count);
1955 rdp.timg.addr += count << 1;
1958 BOOL tile_set = 0;
1959 static void rdp_settilesize()
1961 DWORD tile = (rdp.cmd1 >> 24) & 0x07;
1962 rdp.last_tile_size = tile;
1964 rdp.tiles[tile].f_ul_s = (float)((rdp.cmd0 >> 12) & 0xFFF) / 4.0f;
1965 rdp.tiles[tile].f_ul_t = (float)(rdp.cmd0 & 0xFFF) / 4.0f;
1967 int ul_s = (((WORD)(rdp.cmd0 >> 14)) & 0x03ff);
1968 int ul_t = (((WORD)(rdp.cmd0 >> 2 )) & 0x03ff);
1969 int lr_s = (((WORD)(rdp.cmd1 >> 14)) & 0x03ff);
1970 int lr_t = (((WORD)(rdp.cmd1 >> 2 )) & 0x03ff);
1972 if (lr_s == 0 && ul_s == 0) //pokemon puzzle league set such tile size
1973 wrong_tile = tile;
1974 else if (wrong_tile == (int)tile)
1975 wrong_tile = -1;
1977 if (settings.use_sts1_only)
1979 // ** USE FIRST SETTILESIZE ONLY **
1980 // This option helps certain textures while using the 'Alternate texture size method',
1981 // but may break others. (should help more than break)
1983 if (tile_set)
1985 // coords in 10.2 format
1986 rdp.tiles[tile].ul_s = ul_s;
1987 rdp.tiles[tile].ul_t = ul_t;
1988 rdp.tiles[tile].lr_s = lr_s;
1989 rdp.tiles[tile].lr_t = lr_t;
1990 tile_set = 0;
1993 else
1995 // coords in 10.2 format
1996 rdp.tiles[tile].ul_s = ul_s;
1997 rdp.tiles[tile].ul_t = ul_t;
1998 rdp.tiles[tile].lr_s = lr_s;
1999 rdp.tiles[tile].lr_t = lr_t;
2002 // handle wrapping
2003 if (rdp.tiles[tile].lr_s < rdp.tiles[tile].ul_s) rdp.tiles[tile].lr_s += 0x400;
2004 if (rdp.tiles[tile].lr_t < rdp.tiles[tile].ul_t) rdp.tiles[tile].lr_t += 0x400;
2006 rdp.update |= UPDATE_TEXTURE;
2008 rdp.first = 1;
2010 if (tile == 0 && rdp.hires_tex)
2011 //if ((rdp.tiles[tile].size != 2) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
2012 if (((rdp.tiles[tile].format == 0) && (rdp.tiles[tile].size != 2)) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
2013 rdp.hires_tex = 0;
2014 if (rdp.hires_tex)
2016 if (rdp.tiles[tile].format == 0 && rdp.hires_tex->format == 0)
2018 if (tile == 1 && (DWORD)rdp.hires_tex->tmu != tile)
2019 SwapTextureBuffer();
2020 rdp.hires_tex->tile = tile;
2021 rdp.hires_tex->info.format = GR_TEXFMT_RGB_565;
2022 FRDP ("hires_tex: tile: %d\n", tile);
2024 else if (tile == 0)
2026 rdp.hires_tex->info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
2029 FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n",
2030 tile, ul_s, ul_t, lr_s, lr_t);
2033 static void CopyswapBlock(int *pDst, unsigned int cnt, unsigned int SrcOffs)
2035 // copy and byteswap a block of 8-byte dwords
2036 int rem = SrcOffs & 3;
2037 if (rem == 0)
2039 int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + SrcOffs);
2040 for (unsigned int x = 0; x < cnt; x++)
2042 int s1 = *pSrc++;
2043 int s2 = *pSrc++;
2044 BYTESWAP2(s1, s2)
2045 *pDst++ = s1;
2046 *pDst++ = s2;
2049 else
2051 // set source pointer to 4-byte aligned RDRAM location before the start
2052 int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + (SrcOffs & 0xfffffffc));
2053 // do the first partial 32-bit word
2054 int s0 = *pSrc++;
2055 BYTESWAP1(s0)
2056 for (int x = 0; x < rem; x++)
2057 s0 >>= 8;
2058 for (int x = 4; x > rem; x--)
2060 *((char *) pDst) = s0 & 0xff;
2061 pDst = (int *) ((char *) pDst + 1);
2062 s0 >>= 8;
2064 // do one full 32-bit word
2065 s0 = *pSrc++;
2066 BYTESWAP1(s0)
2067 *pDst++ = s0;
2068 // do 'cnt-1' 64-bit dwords
2069 for (unsigned int x = 0; x < cnt-1; x++)
2071 int s1 = *pSrc++;
2072 int s2 = *pSrc++;
2073 BYTESWAP2(s1, s2)
2074 *pDst++ = s1;
2075 *pDst++ = s2;
2077 // do last partial 32-bit word
2078 s0 = *pSrc++;
2079 BYTESWAP1(s0)
2080 for (; rem > 0; rem--)
2082 *((char *) pDst) = s0 & 0xff;
2083 pDst = (int *) ((char *) pDst + 1);
2084 s0 >>= 8;
2089 static void WordswapBlock(int *pDst, unsigned int cnt, unsigned int TileSize)
2091 // Since it's not loading 32-bit textures as the N64 would, 32-bit textures need to
2092 // be swapped by 64-bits, not 32.
2093 if (TileSize == 3)
2095 // swapblock64 dst, cnt
2096 for (unsigned int x = 0; x < cnt / 2; x++, pDst += 4)
2098 long long s1 = ((long long *) pDst)[0];
2099 long long s2 = ((long long *) pDst)[1];
2100 ((long long *) pDst)[0] = s2;
2101 ((long long *) pDst)[1] = s1;
2104 else
2106 // swapblock32 dst, cnt
2107 for (unsigned int x = 0; x < cnt; x++, pDst += 2)
2109 int s1 = pDst[0];
2110 int s2 = pDst[1];
2111 pDst[0] = s2;
2112 pDst[1] = s1;
2117 static void rdp_loadblock()
2119 if (rdp.skip_drawing)
2121 RDP("loadblock skipped\n");
2122 return;
2124 DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2125 DWORD dxt = (DWORD)(rdp.cmd1 & 0x0FFF);
2127 rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2129 // ** DXT is used for swapping every other line
2130 /* double fdxt = (double)0x8000000F/(double)((DWORD)(2047/(dxt-1))); // F for error
2131 DWORD _dxt = (DWORD)fdxt;*/
2133 // 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit)
2134 DWORD _dxt = dxt << 20;
2136 DWORD addr = segoffset(rdp.timg.addr) & BMASK;
2138 // lr_s specifies number of 64-bit words to copy
2139 // 10.2 format
2140 WORD ul_s = (WORD)(rdp.cmd0 >> 14) & 0x3FF;
2141 WORD ul_t = (WORD)(rdp.cmd0 >> 2) & 0x3FF;
2142 WORD lr_s = (WORD)(rdp.cmd1 >> 14) & 0x3FF;
2144 rdp.tiles[tile].ul_s = ul_s;
2145 rdp.tiles[tile].ul_t = ul_t;
2146 rdp.tiles[tile].lr_s = lr_s;
2148 rdp.timg.set_by = 0; // load block
2150 // do a quick boundary check before copying to eliminate the possibility for exception
2151 if (ul_s >= 512) {
2152 lr_s = 1; // 1 so that it doesn't die on memcpy
2153 ul_s = 511;
2155 if (ul_s+lr_s > 512)
2156 lr_s = 512-ul_s;
2158 if (addr+(lr_s<<3) > BMASK+1)
2159 lr_s = (WORD)((BMASK-addr)>>3);
2161 DWORD offs = rdp.timg.addr;
2162 DWORD cnt = lr_s+1;
2163 if (rdp.tiles[tile].size == 3)
2164 cnt <<= 1;
2165 //FIXME: unused? DWORD start_line = 0;
2167 // if (lr_s > 0)
2168 rdp.timg.addr += cnt << 3;
2170 int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
2172 // Load the block from RDRAM and byteswap it as it loads
2173 CopyswapBlock(pDst, cnt, offs);
2175 // now do 32-bit or 64-bit word swapping on every other row of data
2176 int dxt_accum = 0;
2177 while (cnt > 0)
2179 // skip over unswapped blocks
2182 pDst += 2;
2183 if (--cnt == 0)
2184 break;
2185 dxt_accum += _dxt;
2186 } while (!(dxt_accum & 0x80000000));
2187 // count number of blocks to swap
2188 if (cnt == 0) break;
2189 int swapcnt = 0;
2192 swapcnt++;
2193 if (--cnt == 0)
2194 break;
2195 dxt_accum += _dxt;
2196 } while (dxt_accum & 0x80000000);
2197 // do 32-bit or 64-bit swap operation on this block
2198 WordswapBlock(pDst, swapcnt, rdp.tiles[tile].size);
2199 pDst += swapcnt * 2;
2202 rdp.update |= UPDATE_TEXTURE;
2204 FRDP ("loadblock: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, dxt: %08lx -> %08lx\n",
2205 tile, ul_s, ul_t, lr_s,
2206 dxt, _dxt);
2209 static void rdp_loadtile()
2211 if (rdp.skip_drawing)
2212 return;
2213 rdp.timg.set_by = 1; // load tile
2215 DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2216 if (rdp.tiles[tile].format == 1)
2218 rdp.yuv_image = TRUE;
2219 if (rdp.timg.addr < rdp.yuv_im_begin) rdp.yuv_im_begin = rdp.timg.addr;
2220 return;
2223 rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2225 WORD ul_s = (WORD)((rdp.cmd0 >> 14) & 0x03FF);
2226 WORD ul_t = (WORD)((rdp.cmd0 >> 2 ) & 0x03FF);
2227 WORD lr_s = (WORD)((rdp.cmd1 >> 14) & 0x03FF);
2228 WORD lr_t = (WORD)((rdp.cmd1 >> 2 ) & 0x03FF);
2230 if (lr_s < ul_s || lr_t < ul_t) return;
2232 if (wrong_tile >= 0) //there was a tile with zero length
2234 rdp.tiles[wrong_tile].lr_s = lr_s;
2236 if (rdp.tiles[tile].size > rdp.tiles[wrong_tile].size)
2237 rdp.tiles[wrong_tile].lr_s <<= (rdp.tiles[tile].size - rdp.tiles[wrong_tile].size);
2238 else if (rdp.tiles[tile].size < rdp.tiles[wrong_tile].size)
2239 rdp.tiles[wrong_tile].lr_s >>= (rdp.tiles[wrong_tile].size - rdp.tiles[tile].size);
2240 rdp.tiles[wrong_tile].lr_t = lr_t;
2241 // wrong_tile = -1;
2244 if (rdp.hires_tex)// && (rdp.tiles[tile].format == 0))
2246 FRDP("loadtile: hires_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t);
2247 rdp.hires_tex->tile_uls = ul_s;
2248 rdp.hires_tex->tile_ult = ul_t;
2251 if (settings.tonic && tile == 7)
2253 rdp.tiles[0].ul_s = ul_s;
2254 rdp.tiles[0].ul_t = ul_t;
2255 rdp.tiles[0].lr_s = lr_s;
2256 rdp.tiles[0].lr_t = lr_t;
2259 DWORD height = lr_t - ul_t + 1; // get height
2260 DWORD width = lr_s - ul_s + 1;
2262 DWORD wid_64 = rdp.tiles[tile].line;
2264 // CHEAT: it's very unlikely that it loads more than 1 32-bit texture in one command,
2265 // so i don't bother to write in two different places at once. Just load once with
2266 // twice as much data.
2267 if (rdp.tiles[tile].size == 3)
2268 wid_64 <<= 1;
2270 int line_n = rdp.timg.width;
2271 if (rdp.tiles[tile].size == 0)
2272 line_n >>= 1;
2273 else
2274 line_n <<= (rdp.tiles[tile].size-1);
2276 int offs = ul_t * line_n;
2277 offs += ul_s << rdp.tiles[tile].size >> 1;
2278 offs += rdp.timg.addr;
2279 if ((unsigned int) offs >= BMASK)
2280 return;
2282 // check if points to bad location
2283 DWORD size = width * height;
2284 if (rdp.tiles[tile].size == 0)
2285 size >>= 1;
2286 else
2287 size <<= (rdp.tiles[tile].size-1);
2289 if (offs + line_n*height > BMASK)
2290 height = (BMASK - offs) / line_n;
2292 int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
2293 int * pEnd = (int *) ((uintptr_t)rdp.tmem+4096 - (wid_64<<3));
2295 for (unsigned int y = 0; y < height; y++)
2297 if (pDst > pEnd) break;
2298 CopyswapBlock(pDst, wid_64, offs);
2299 if (y & 1)
2301 WordswapBlock(pDst, wid_64, rdp.tiles[tile].size);
2303 pDst += wid_64 * 2;
2304 offs += line_n;
2307 FRDP("loadtile: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile,
2308 ul_s, ul_t, lr_s, lr_t);
2311 static void rdp_settile()
2313 tile_set = 1; // used to check if we only load the first settilesize
2315 rdp.first = 0;
2317 //rdp.cur_tile_n = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2318 //rdp.cur_tile = &rdp.tiles[rdp.cur_tile_n];
2320 rdp.last_tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2321 TILE *tile = &rdp.tiles[rdp.last_tile];
2323 tile->format = (BYTE)((rdp.cmd0 >> 21) & 0x07);
2324 tile->size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
2325 tile->line = (WORD)((rdp.cmd0 >> 9) & 0x01FF);
2326 tile->t_mem = (WORD)(rdp.cmd0 & 0x1FF);
2327 tile->palette = (BYTE)((rdp.cmd1 >> 20) & 0x0F);
2328 tile->clamp_t = (BYTE)((rdp.cmd1 >> 19) & 0x01);
2329 tile->mirror_t = (BYTE)((rdp.cmd1 >> 18) & 0x01);
2330 tile->mask_t = (BYTE)((rdp.cmd1 >> 14) & 0x0F);
2331 tile->shift_t = (BYTE)((rdp.cmd1 >> 10) & 0x0F);
2332 tile->clamp_s = (BYTE)((rdp.cmd1 >> 9) & 0x01);
2333 tile->mirror_s = (BYTE)((rdp.cmd1 >> 8) & 0x01);
2334 tile->mask_s = (BYTE)((rdp.cmd1 >> 4) & 0x0F);
2335 tile->shift_s = (BYTE)(rdp.cmd1 & 0x0F);
2337 rdp.update |= UPDATE_TEXTURE;
2339 FRDP ("settile: tile: %d, format: %s, size: %s, line: %d, "
2340 "t_mem: %08lx, palette: %d, clamp_t/mirror_t: %s, mask_t: %d, "
2341 "shift_t: %d, clamp_s/mirror_s: %s, mask_s: %d, shift_s: %d\n",
2342 rdp.last_tile, str_format[tile->format], str_size[tile->size], tile->line,
2343 tile->t_mem, tile->palette, str_cm[(tile->clamp_t<<1)|tile->mirror_t], tile->mask_t,
2344 tile->shift_t, str_cm[(tile->clamp_s<<1)|tile->mirror_s], tile->mask_s, tile->shift_s);
2348 // fillrect - fills a rectangle
2351 static void rdp_fillrect()
2353 DWORD ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14);
2354 DWORD ul_y = (rdp.cmd1 & 0x00000FFF) >> 2;
2355 DWORD lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1;
2356 DWORD lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1;
2357 if ((rdp.cimg == rdp.zimg) || (settings.fb_smart && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg))
2359 RDP ("Fillrect - cleared the depth buffer\n");
2360 if (fullscreen)
2363 grDepthMask (FXTRUE);
2364 grColorMask (FXFALSE, FXFALSE);
2365 grBufferClear (0, 0, 0xFFFF);
2366 grColorMask (FXTRUE, FXTRUE);
2367 rdp.update |= UPDATE_ZBUF_ENABLED;
2368 if (settings.fb_depth_clear)
2370 ul_x = min(max(ul_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2371 lr_x = min(max(lr_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2372 ul_y = min(max(ul_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2373 lr_y = min(max(lr_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2374 //FIXME:unused? DWORD zi_height = lr_y - ul_y - 1;
2375 // rdp.zi_nb_pixels = rdp.zi_width * zi_height;
2376 rdp.zi_lry = lr_y - 1;
2377 rdp.zi_lrx = lr_x - 1;
2378 // FRDP ("zi_width: %d, zi_height: %d\n", rdp.zi_width, zi_height);
2379 DWORD fillrect_width_in_dwords = (lr_x-ul_x) >> 1;
2380 DWORD zi_width_in_dwords = rdp.zi_width >> 1;
2381 ul_x >>= 1;
2382 DWORD * dst = (DWORD*)(gfx.RDRAM+rdp.cimg);
2383 dst += ul_y * zi_width_in_dwords;
2384 for (DWORD y = ul_y; y < lr_y; y++)
2386 for (DWORD x = ul_x; x < fillrect_width_in_dwords; x++)
2388 dst[x] = rdp.fill_color;
2390 dst += zi_width_in_dwords;
2394 return;
2397 if (rdp.skip_drawing)
2399 RDP("Fillrect skipped\n");
2400 return;
2403 // Update scissor
2404 update_scissor ();
2406 if ((ul_x > lr_x) || (ul_y > lr_y)) return;
2407 if (settings.bomberman64 && (lr_x == rdp.ci_width) && (rdp.cimg == rdp.ocimg)) //bomberman64 hack
2408 return;
2410 if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x))
2412 DWORD color = rdp.fill_color;
2413 color = ((color&1)?0xFF:0) |
2414 ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2415 ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2416 ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2417 grDepthMask (FXFALSE);
2418 grBufferClear (color, 0, 0xFFFF);
2419 grDepthMask (FXTRUE);
2420 rdp.update |= UPDATE_ZBUF_ENABLED;
2421 return;
2424 if (settings.decrease_fillrect_edge && rdp.cycle_mode == 0)
2426 lr_x--; lr_y--;
2428 FRDP("fillrect (%d,%d) -> (%d,%d), cycle mode: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, rdp.cycle_mode,
2429 rdp.tri_n, rdp.tri_n+1);
2431 FRDP("scissor (%d,%d) -> (%d,%d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x,
2432 rdp.scissor.lr_y);
2434 // KILL the floating point error with 0.01f
2435 DWORD s_ul_x = (DWORD)min(max(ul_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
2436 DWORD s_lr_x = (DWORD)min(max(lr_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
2437 DWORD s_ul_y = (DWORD)min(max(ul_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y);
2438 DWORD s_lr_y = (DWORD)min(max(lr_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y);
2440 if (s_lr_x < 0.0f) s_lr_x = 0;
2441 if (s_lr_y < 0.0f) s_lr_y = 0;
2442 if (s_ul_x > (float)settings.res_x) s_ul_x = settings.res_x;
2443 if (s_ul_y > (float)settings.res_y) s_ul_y = settings.res_y;
2445 FRDP (" - %d, %d, %d, %d\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
2447 if (fullscreen)
2449 grFogMode (GR_FOG_DISABLE);
2451 grClipWindow (0, 0, settings.res_x, settings.res_y);
2453 float Z = 1.0f;
2454 if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030))
2456 Z = ScaleZ(rdp.prim_depth);
2457 grDepthBufferFunction (GR_CMP_LEQUAL);
2458 // grDepthMask (FXTRUE);
2459 FRDP ("prim_depth = %d\n", rdp.prim_depth);
2461 else
2463 grDepthBufferFunction (GR_CMP_ALWAYS);
2464 grDepthMask (FXFALSE);
2465 RDP ("no prim_depth used, using 1.0\n");
2467 // Draw the rectangle
2468 VERTEX v[4] = {
2469 { (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 },
2470 { (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 },
2471 { (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 },
2472 { (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 } };
2474 if (rdp.cycle_mode == 3)
2476 DWORD color = (settings.fillcolor_fix) ? rdp.fill_color : (rdp.fill_color >> 16);
2478 if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux)
2480 //background of auxilary frame buffers must have zero alpha.
2481 //make it black, set 0 alpha to plack pixels on frame buffer read
2482 color = 0;
2484 else
2486 color = ((color&1)?0xFF:0) |
2487 ((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2488 ((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2489 ((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2491 grConstantColorValue (color);
2493 grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
2494 GR_COMBINE_FACTOR_NONE,
2495 GR_COMBINE_LOCAL_CONSTANT,
2496 GR_COMBINE_OTHER_NONE,
2497 FXFALSE);
2499 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
2500 GR_COMBINE_FACTOR_NONE,
2501 GR_COMBINE_LOCAL_CONSTANT,
2502 GR_COMBINE_OTHER_NONE,
2503 FXFALSE);
2505 grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO);
2507 rdp.update |= UPDATE_COMBINE;
2509 else
2511 Combine ();
2512 TexCache (); // (to update combiner)
2513 DWORD cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF);
2514 DWORD cmb_mode_a = (rdp.cycle1 & 0x0FFF0000) | ((rdp.cycle2 >> 16) & 0x00000FFF);
2515 if (cmb_mode_c == 0x9fff9fff || cmb_mode_a == 0x09ff09ff) //shade
2517 AllowShadeMods (v, 4);
2518 for (int k = 0; k < 4; k++)
2519 apply_shade_mods (&v[k]);
2523 grAlphaTestFunction (GR_CMP_ALWAYS);
2524 if (grStippleModeExt)
2525 grStippleModeExt(GR_STIPPLE_DISABLE);
2527 grCullMode(GR_CULL_DISABLE);
2529 if (settings.wireframe)
2531 SetWireframeCol ();
2532 grDrawLine (&v[0], &v[2]);
2533 grDrawLine (&v[2], &v[1]);
2534 grDrawLine (&v[1], &v[0]);
2535 grDrawLine (&v[2], &v[3]);
2536 grDrawLine (&v[3], &v[1]);
2537 //grDrawLine (&v[1], &v[2]);
2539 else
2541 grDrawTriangle (&v[0], &v[2], &v[1]);
2542 grDrawTriangle (&v[2], &v[3], &v[1]);
2545 if (debug.capture)
2547 VERTEX v1[3];
2548 v1[0] = v[0];
2549 v1[1] = v[2];
2550 v1[2] = v[1];
2551 add_tri (v1, 3, TRI_FILLRECT);
2552 rdp.tri_n ++;
2553 v1[0] = v[2];
2554 v1[1] = v[3];
2555 add_tri (v1, 3, TRI_FILLRECT);
2556 rdp.tri_n ++;
2558 else
2559 rdp.tri_n += 2;
2561 if (settings.fog && (rdp.flags & FOG_ENABLED))
2563 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
2566 rdp.update |= UPDATE_CULL_MODE | UPDATE_ALPHA_COMPARE | UPDATE_ZBUF_ENABLED;
2568 else
2570 rdp.tri_n += 2;
2575 // setfillcolor - sets the filling color
2578 static void rdp_setfillcolor()
2580 rdp.fill_color = rdp.cmd1;
2581 rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
2583 FRDP("setfillcolor: %08lx\n", rdp.cmd1);
2586 static void rdp_setfogcolor()
2588 rdp.fog_color = rdp.cmd1;
2589 rdp.update |= UPDATE_COMBINE | UPDATE_FOG_ENABLED;
2591 FRDP("setfogcolor - %08lx\n", rdp.cmd1);
2594 static void rdp_setblendcolor()
2596 rdp.blend_color = rdp.cmd1;
2597 rdp.update |= UPDATE_COMBINE;
2599 FRDP("setblendcolor: %08lx\n", rdp.cmd1);
2602 static void rdp_setprimcolor()
2604 rdp.prim_color = rdp.cmd1;
2605 rdp.prim_lodmin = (rdp.cmd0 >> 8) & 0xFF;
2606 rdp.prim_lodfrac = max(rdp.cmd0 & 0xFF, rdp.prim_lodmin);
2607 rdp.update |= UPDATE_COMBINE;
2609 FRDP("setprimcolor: %08lx, lodmin: %d, lodfrac: %d\n", rdp.cmd1, rdp.prim_lodmin,
2610 rdp.prim_lodfrac);
2613 static void rdp_setenvcolor()
2615 rdp.env_color = rdp.cmd1;
2616 rdp.update |= UPDATE_COMBINE;
2618 FRDP("setenvcolor: %08lx\n", rdp.cmd1);
2621 static void rdp_setcombine()
2623 rdp.c_a0 = (BYTE)((rdp.cmd0 >> 20) & 0xF);
2624 rdp.c_b0 = (BYTE)((rdp.cmd1 >> 28) & 0xF);
2625 rdp.c_c0 = (BYTE)((rdp.cmd0 >> 15) & 0x1F);
2626 rdp.c_d0 = (BYTE)((rdp.cmd1 >> 15) & 0x7);
2627 rdp.c_Aa0 = (BYTE)((rdp.cmd0 >> 12) & 0x7);
2628 rdp.c_Ab0 = (BYTE)((rdp.cmd1 >> 12) & 0x7);
2629 rdp.c_Ac0 = (BYTE)((rdp.cmd0 >> 9) & 0x7);
2630 rdp.c_Ad0 = (BYTE)((rdp.cmd1 >> 9) & 0x7);
2632 rdp.c_a1 = (BYTE)((rdp.cmd0 >> 5) & 0xF);
2633 rdp.c_b1 = (BYTE)((rdp.cmd1 >> 24) & 0xF);
2634 rdp.c_c1 = (BYTE)((rdp.cmd0 >> 0) & 0x1F);
2635 rdp.c_d1 = (BYTE)((rdp.cmd1 >> 6) & 0x7);
2636 rdp.c_Aa1 = (BYTE)((rdp.cmd1 >> 21) & 0x7);
2637 rdp.c_Ab1 = (BYTE)((rdp.cmd1 >> 3) & 0x7);
2638 rdp.c_Ac1 = (BYTE)((rdp.cmd1 >> 18) & 0x7);
2639 rdp.c_Ad1 = (BYTE)((rdp.cmd1 >> 0) & 0x7);
2641 rdp.cycle1 = (rdp.c_a0<<0) | (rdp.c_b0<<4) | (rdp.c_c0<<8) | (rdp.c_d0<<13)|
2642 (rdp.c_Aa0<<16)| (rdp.c_Ab0<<19)| (rdp.c_Ac0<<22)| (rdp.c_Ad0<<25);
2643 rdp.cycle2 = (rdp.c_a1<<0) | (rdp.c_b1<<4) | (rdp.c_c1<<8) | (rdp.c_d1<<13)|
2644 (rdp.c_Aa1<<16)| (rdp.c_Ab1<<19)| (rdp.c_Ac1<<22)| (rdp.c_Ad1<<25);
2646 rdp.update |= UPDATE_COMBINE;
2648 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",
2649 Mode0[rdp.c_a0], Mode1[rdp.c_b0], Mode2[rdp.c_c0], Mode3[rdp.c_d0],
2650 Alpha0[rdp.c_Aa0], Alpha1[rdp.c_Ab0], Alpha2[rdp.c_Ac0], Alpha3[rdp.c_Ad0],
2651 Mode0[rdp.c_a1], Mode1[rdp.c_b1], Mode2[rdp.c_c1], Mode3[rdp.c_d1],
2652 Alpha0[rdp.c_Aa1], Alpha1[rdp.c_Ab1], Alpha2[rdp.c_Ac1], Alpha3[rdp.c_Ad1]);
2656 // settextureimage - sets the source for an image copy
2659 static void rdp_settextureimage()
2661 static const char *format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
2662 static const char *size[] = { "4bit", "8bit", "16bit", "32bit" };
2664 rdp.timg.format = (BYTE)((rdp.cmd0 >> 21) & 0x07);
2665 rdp.timg.size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
2666 rdp.timg.width = (WORD)(1 + (rdp.cmd0 & 0x00000FFF));
2667 rdp.timg.addr = segoffset(rdp.cmd1);
2668 rdp.s2dex_tex_loaded = TRUE;
2669 rdp.update |= UPDATE_TEXTURE;
2671 if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self && (rdp.timg.addr >= rdp.cimg) && (rdp.timg.addr < rdp.ci_end))
2673 if (!rdp.fb_drawn)
2675 if (!rdp.cur_image)
2676 CopyFrameBuffer();
2677 else if (rdp.frame_buffers[rdp.ci_count].status != ci_copy)
2678 CloseTextureBuffer(TRUE);
2679 rdp.fb_drawn = TRUE;
2683 if (settings.fb_hires) //search this texture among drawn texture buffers
2685 if (settings.zelda)
2687 if (rdp.timg.size == 2)
2688 FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
2690 else
2691 FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
2694 FRDP("settextureimage: format: %s, size: %s, width: %d, addr: %08lx\n",
2695 format[rdp.timg.format], size[rdp.timg.size],
2696 rdp.timg.width, rdp.timg.addr);
2699 static void rdp_setdepthimage()
2701 rdp.zimg = segoffset(rdp.cmd1) & BMASK;
2702 rdp.zi_width = rdp.ci_width;
2703 FRDP("setdepthimage - %08lx\n", rdp.zimg);
2707 BOOL SwapOK = TRUE;
2708 static void RestoreScale()
2710 FRDP("Return to original scale: x = %f, y = %f\n", rdp.scale_x_bak, rdp.scale_y_bak);
2711 rdp.scale_x = rdp.scale_x_bak;
2712 rdp.scale_y = rdp.scale_y_bak;
2713 // update_scissor();
2714 rdp.view_scale[0] *= rdp.scale_x;
2715 rdp.view_scale[1] *= rdp.scale_y;
2716 rdp.view_trans[0] *= rdp.scale_x;
2717 rdp.view_trans[1] *= rdp.scale_y;
2718 rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR;
2720 if (fullscreen)
2722 grDepthMask (FXFALSE);
2723 grBufferClear (0, 0, 0xFFFF);
2724 grDepthMask (FXTRUE);
2726 //*/
2729 static DWORD swapped_addr = 0;
2731 static void rdp_setcolorimage()
2733 render_depth_mode = 0;
2734 if (settings.fb_smart && (rdp.num_of_ci < NUMTEXBUF))
2736 COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count];
2737 COLOR_IMAGE & prev_fb = rdp.frame_buffers[rdp.ci_count-1];
2738 COLOR_IMAGE & next_fb = rdp.frame_buffers[rdp.ci_count+1];
2739 switch (cur_fb.status)
2741 case ci_main:
2744 if (rdp.ci_count == 0)
2746 if ((rdp.ci_status == ci_aux)) //for PPL
2748 float sx = rdp.scale_x;
2749 float sy = rdp.scale_y;
2750 rdp.scale_x = 1.0f;
2751 rdp.scale_y = 1.0f;
2752 CopyFrameBuffer ();
2753 rdp.scale_x = sx;
2754 rdp.scale_y = sy;
2756 if (!settings.fb_hires)
2758 if ((rdp.num_of_ci > 1) &&
2759 (next_fb.status == ci_aux) &&
2760 (next_fb.width >= cur_fb.width))
2762 rdp.scale_x = 1.0f;
2763 rdp.scale_y = 1.0f;
2766 else if (rdp.copy_ci_index && settings.PM) //tidal wave
2767 OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2769 else if (!rdp.motionblur && settings.fb_hires && !SwapOK && (rdp.ci_count <= rdp.copy_ci_index))
2771 if (next_fb.status == ci_aux_copy)
2772 OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2773 else
2774 OpenTextureBuffer(rdp.frame_buffers[rdp.copy_ci_index]);
2776 else if (settings.fb_hires && rdp.read_whole_frame && prev_fb.status == ci_aux)
2778 OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2780 //else if (rdp.ci_status == ci_aux && !rdp.copy_ci_index)
2781 // CloseTextureBuffer();
2783 rdp.skip_drawing = FALSE;
2785 break;
2786 case ci_copy:
2788 if (!rdp.motionblur || settings.fb_motionblur)
2790 if (cur_fb.width == rdp.ci_width)
2792 if (CopyTextureBuffer(prev_fb, cur_fb))
2793 // if (CloseTextureBuffer(TRUE))
2795 else
2797 if (!rdp.fb_drawn || prev_fb.status == ci_copy_self)
2799 CopyFrameBuffer ();
2800 rdp.fb_drawn = TRUE;
2802 memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2805 else
2807 CloseTextureBuffer(TRUE);
2810 else
2812 memset(gfx.RDRAM+cur_fb.addr, 0, cur_fb.width*cur_fb.height*rdp.ci_size);
2814 rdp.skip_drawing = TRUE;
2816 break;
2817 case ci_aux_copy:
2819 rdp.skip_drawing = FALSE;
2820 if (CloseTextureBuffer(prev_fb.status != ci_aux_copy))
2822 else if (!rdp.fb_drawn)
2824 CopyFrameBuffer ();
2825 rdp.fb_drawn = TRUE;
2827 if (settings.fb_hires)
2828 OpenTextureBuffer(cur_fb);
2830 break;
2831 case ci_old_copy:
2833 if (!rdp.motionblur || settings.fb_motionblur)
2835 if (cur_fb.width == rdp.ci_width)
2837 memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.maincimg[1].addr, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2839 //rdp.skip_drawing = TRUE;
2841 else
2843 memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<<rdp.ci_size>>1);
2846 break;
2848 else if (rdp.frame_buffers[rdp.ci_count].status == ci_main_i)
2850 // CopyFrameBuffer ();
2851 rdp.scale_x = rdp.scale_x_bak;
2852 rdp.scale_y = rdp.scale_y_bak;
2853 rdp.skip_drawing = FALSE;
2856 case ci_aux:
2858 if (!settings.fb_hires && cur_fb.format != 0)
2859 rdp.skip_drawing = TRUE;
2860 else
2862 rdp.skip_drawing = FALSE;
2863 if (settings.fb_hires && OpenTextureBuffer(cur_fb))
2865 else
2867 if (cur_fb.format != 0)
2868 rdp.skip_drawing = TRUE;
2869 if (rdp.ci_count == 0)
2871 // if (rdp.num_of_ci > 1)
2872 // {
2873 rdp.scale_x = 1.0f;
2874 rdp.scale_y = 1.0f;
2875 // }
2877 else if (!settings.fb_hires && (prev_fb.status == ci_main) &&
2878 (prev_fb.width == cur_fb.width)) // for Pokemon Stadium
2879 CopyFrameBuffer ();
2882 cur_fb.status = ci_aux;
2884 break;
2885 case ci_zimg:
2886 // ZIGGY
2887 // Zelda LoT effect save/restore depth buffer
2888 if (cur_fb.addr == rdp.zimg) {
2889 render_depth_mode = 1;
2890 } else {
2891 render_depth_mode = 2;
2893 rdp.skip_drawing = TRUE;
2894 break;
2895 case ci_useless:
2896 //case ci_zcopy:
2897 rdp.skip_drawing = TRUE;
2898 break;
2899 case ci_copy_self:
2900 if (settings.fb_hires && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2))
2901 OpenTextureBuffer(cur_fb);
2902 rdp.skip_drawing = FALSE;
2904 if (settings.fb_hires)
2906 if (SwapOK)
2908 rdp.cimg = rdp.frame_buffers[rdp.ci_count].addr;
2909 rdp.maincimg[0].addr = rdp.cimg;
2910 newSwapBuffers();
2911 SwapOK = FALSE;
2912 OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count]);
2916 break;
2917 default:
2918 rdp.skip_drawing = FALSE;
2921 if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium
2923 if (!settings.fb_hires && prev_fb.format == 0)
2924 CopyFrameBuffer ();
2926 if (!settings.fb_hires && cur_fb.status == ci_copy)
2928 if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux))
2930 RestoreScale();
2933 if (!settings.fb_hires && cur_fb.status == ci_aux)
2935 if (cur_fb.format == 0)
2937 if (settings.PPL && (rdp.scale_x < 1.1f)) //need to put current image back to frame buffer
2939 int width = cur_fb.width;
2940 int height = cur_fb.height;
2941 WORD *ptr_dst = new WORD[width*height];
2942 WORD *ptr_src = (WORD*)(gfx.RDRAM+cur_fb.addr);
2943 WORD c;
2945 for (int y=0; y<height; y++)
2947 for (int x=0; x<width; x++)
2949 c = ((ptr_src[(x + y * width)^1]) >> 1) | 0x8000;
2950 ptr_dst[x + y * width] = c;
2953 grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
2956 GR_LFB_SRC_FMT_555,
2957 width,
2958 height,
2959 FXFALSE,
2960 width<<1,
2961 ptr_dst);
2962 delete[] ptr_dst;
2965 else //just clear buffer
2968 grColorMask(FXTRUE, FXTRUE);
2969 grBufferClear (0, 0, 0xFFFF);
2975 if ((cur_fb.status == ci_main) && (rdp.ci_count > 0))
2977 BOOL to_org_res = TRUE;
2978 for (int i = rdp.ci_count + 1; i < rdp.num_of_ci; i++)
2980 if ((rdp.frame_buffers[i].status != ci_main) && (rdp.frame_buffers[i].status != ci_zimg) && (rdp.frame_buffers[i].status != ci_zcopy))
2982 to_org_res = FALSE;
2983 break;
2986 if (to_org_res)
2988 RDP("return to original scale\n");
2989 rdp.scale_x = rdp.scale_x_bak;
2990 rdp.scale_y = rdp.scale_y_bak;
2991 if (settings.fb_hires && !rdp.read_whole_frame)
2992 CloseTextureBuffer();
2994 if (settings.fb_hires && !rdp.read_whole_frame && (prev_fb.status >= ci_aux) && (rdp.ci_count > rdp.copy_ci_index))
2995 CloseTextureBuffer();
2998 rdp.ci_status = cur_fb.status;
2999 rdp.ci_count++;
3002 rdp.ocimg = rdp.cimg;
3003 rdp.cimg = segoffset(rdp.cmd1) & BMASK;
3004 rdp.ci_width = (rdp.cmd0 & 0xFFF) + 1;
3005 if (settings.fb_smart)
3006 rdp.ci_height = rdp.frame_buffers[rdp.ci_count-1].height;
3007 else if (rdp.ci_width == 32)
3008 rdp.ci_height = 32;
3009 else
3010 rdp.ci_height = rdp.scissor_o.lr_y;
3011 if (rdp.zimg == rdp.cimg)
3013 rdp.zi_width = rdp.ci_width;
3014 // int zi_height = min((int)rdp.zi_width*3/4, (int)rdp.vi_height);
3015 // rdp.zi_words = rdp.zi_width * zi_height;
3017 DWORD format = (rdp.cmd0 >> 21) & 0x7;
3018 rdp.ci_size = (rdp.cmd0 >> 19) & 0x3;
3019 rdp.ci_end = rdp.cimg + ((rdp.ci_width*rdp.ci_height)<<(rdp.ci_size-1));
3020 FRDP("setcolorimage - %08lx, width: %d, height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size);
3021 FRDP("cimg: %08lx, ocimg: %08lx, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK);
3023 if (format != 0 && !rdp.cur_image) //can't draw into non RGBA buffer
3025 if (settings.fb_hires && rdp.ci_width <= 64)
3026 OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]);
3027 else if (format > 2)
3028 rdp.skip_drawing = TRUE;
3029 return;
3031 else
3033 if (!settings.fb_smart)
3034 rdp.skip_drawing = FALSE;
3037 CI_SET = TRUE;
3038 if (settings.swapmode > 0)
3040 if (rdp.zimg == rdp.cimg)
3041 rdp.updatescreen = 1;
3043 BOOL viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE;
3044 if ((rdp.zimg != rdp.cimg) && (rdp.ocimg != rdp.cimg) && SwapOK && viSwapOK && !rdp.cur_image)
3046 if (settings.fb_smart)
3047 rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3048 else
3049 rdp.maincimg[0].addr = rdp.cimg;
3050 rdp.last_drawn_ci_addr = (settings.swapmode == 2) ? swapped_addr : rdp.maincimg[0].addr;
3051 swapped_addr = rdp.cimg;
3052 newSwapBuffers();
3053 rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
3054 SwapOK = FALSE;
3055 if (settings.fb_hires)
3057 if (rdp.copy_ci_index && (rdp.frame_buffers[rdp.ci_count-1].status != ci_zimg))
3059 int idx = (rdp.frame_buffers[rdp.ci_count].status == ci_aux_copy) ? rdp.main_ci_index : rdp.copy_ci_index;
3060 FRDP("attempt open tex buffer. status: %s, addr: %08lx\n", CIStatus[rdp.frame_buffers[idx].status], rdp.frame_buffers[idx].addr);
3061 OpenTextureBuffer(rdp.frame_buffers[idx]);
3062 if (rdp.frame_buffers[rdp.copy_ci_index].status == ci_main) //tidal wave
3063 rdp.copy_ci_index = 0;
3065 else if (rdp.read_whole_frame && !rdp.cur_image)
3067 OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3074 static void rdp_trifill()
3076 RDP_E("trifill - IGNORED\n");
3077 RDP("trifill - IGNORED\n");
3080 static void rdp_trishade()
3082 RDP_E("trishade - IGNORED\n");
3083 RDP("trishade - IGNORED\n");
3086 static void rdp_tritxtr()
3088 RDP_E("tritxtr - IGNORED\n");
3089 RDP("tritxtr - IGNORED\n");
3092 static void rdp_trishadetxtr()
3094 RDP_E("trishadetxtr - IGNORED\n");
3095 RDP("trishadetxtr - IGNORED\n");
3098 static void rdp_trifillz()
3100 RDP_E("trifillz - IGNORED\n");
3101 RDP("trifillz - IGNORED\n");
3104 static void rdp_trishadez()
3106 RDP_E("trishadez - IGNORED\n");
3107 RDP("trishadez - IGNORED\n");
3110 static void rdp_tritxtrz()
3112 RDP_E("tritxtrz - IGNORED\n");
3113 RDP("tritxtrz - IGNORED\n");
3116 static void rdp_trishadetxtrz()
3118 RDP_E("trishadetxtrz - IGNORED\n");
3119 RDP("trishadetxtrz - IGNORED\n");
3122 static void rsp_reserved0()
3124 RDP_E("reserved0 - IGNORED\n");
3125 RDP("reserved0 - IGNORED\n");
3128 static void rsp_reserved1()
3130 RDP("reserved1 - ignored\n");
3133 static void rsp_reserved2()
3135 RDP("reserved2\n");
3138 static void rsp_reserved3()
3140 RDP("reserved3 - ignored\n");
3143 void SetWireframeCol ()
3145 if (!fullscreen) return;
3147 switch (settings.wfmode)
3149 //case 0: // normal colors, don't do anything
3150 case 1: // vertex colors
3151 grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3152 GR_COMBINE_FACTOR_NONE,
3153 GR_COMBINE_LOCAL_ITERATED,
3154 GR_COMBINE_OTHER_NONE,
3155 FXFALSE);
3156 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3157 GR_COMBINE_FACTOR_NONE,
3158 GR_COMBINE_LOCAL_ITERATED,
3159 GR_COMBINE_OTHER_NONE,
3160 FXFALSE);
3161 grAlphaBlendFunction (GR_BLEND_ONE,
3162 GR_BLEND_ZERO,
3163 GR_BLEND_ZERO,
3164 GR_BLEND_ZERO);
3165 grTexCombine (GR_TMU0,
3166 GR_COMBINE_FUNCTION_ZERO,
3167 GR_COMBINE_FACTOR_NONE,
3168 GR_COMBINE_FUNCTION_ZERO,
3169 GR_COMBINE_FACTOR_NONE,
3170 FXFALSE, FXFALSE);
3171 grTexCombine (GR_TMU1,
3172 GR_COMBINE_FUNCTION_ZERO,
3173 GR_COMBINE_FACTOR_NONE,
3174 GR_COMBINE_FUNCTION_ZERO,
3175 GR_COMBINE_FACTOR_NONE,
3176 FXFALSE, FXFALSE);
3177 break;
3178 case 2: // red only
3179 grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3180 GR_COMBINE_FACTOR_NONE,
3181 GR_COMBINE_LOCAL_CONSTANT,
3182 GR_COMBINE_OTHER_NONE,
3183 FXFALSE);
3184 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3185 GR_COMBINE_FACTOR_NONE,
3186 GR_COMBINE_LOCAL_CONSTANT,
3187 GR_COMBINE_OTHER_NONE,
3188 FXFALSE);
3189 grConstantColorValue (0xFF0000FF);
3190 grAlphaBlendFunction (GR_BLEND_ONE,
3191 GR_BLEND_ZERO,
3192 GR_BLEND_ZERO,
3193 GR_BLEND_ZERO);
3194 grTexCombine (GR_TMU0,
3195 GR_COMBINE_FUNCTION_ZERO,
3196 GR_COMBINE_FACTOR_NONE,
3197 GR_COMBINE_FUNCTION_ZERO,
3198 GR_COMBINE_FACTOR_NONE,
3199 FXFALSE, FXFALSE);
3200 grTexCombine (GR_TMU1,
3201 GR_COMBINE_FUNCTION_ZERO,
3202 GR_COMBINE_FACTOR_NONE,
3203 GR_COMBINE_FUNCTION_ZERO,
3204 GR_COMBINE_FACTOR_NONE,
3205 FXFALSE, FXFALSE);
3206 break;
3209 grAlphaTestFunction (GR_CMP_ALWAYS);
3210 grCullMode (GR_CULL_DISABLE);
3212 //grDepthBufferFunction (GR_CMP_ALWAYS);
3213 //grDepthMask (FXFALSE);
3215 rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE;
3218 /******************************************************************
3219 Function: FrameBufferRead
3220 Purpose: This function is called to notify the dll that the
3221 frame buffer memory is beening read at the given address.
3222 DLL should copy content from its render buffer to the frame buffer
3223 in N64 RDRAM
3224 DLL is responsible to maintain its own frame buffer memory addr list
3225 DLL should copy 4KB block content back to RDRAM frame buffer.
3226 Emulator should not call this function again if other memory
3227 is read within the same 4KB range
3228 input: addr rdram address
3229 val val
3230 size 1 = BYTE, 2 = WORD, 4 = DWORD
3231 output: none
3232 *******************************************************************/
3233 EXPORT void CALL FBRead(DWORD addr)
3235 printf("FBRead\n");
3236 LOG ("FBRead ()\n");
3238 if (cpu_fb_ignore)
3239 return;
3240 if (cpu_fb_write_called)
3242 cpu_fb_ignore = TRUE;
3243 cpu_fb_write = FALSE;
3244 return;
3246 cpu_fb_read_called = TRUE;
3247 DWORD a = segoffset(addr);
3248 FRDP("FBRead. addr: %08lx\n", a);
3249 if (!rdp.fb_drawn && (a >= rdp.cimg) && (a < rdp.ci_end))
3251 fbreads_back++;
3252 //if (fbreads_back > 2) //&& (rdp.ci_width <= 320))
3254 CopyFrameBuffer ();
3255 rdp.fb_drawn = TRUE;
3258 if (!rdp.fb_drawn_front && (a >= rdp.maincimg[1].addr) && (a < rdp.maincimg[1].addr + rdp.ci_width*rdp.ci_height*2))
3260 fbreads_front++;
3261 //if (fbreads_front > 2)//&& (rdp.ci_width <= 320))
3263 DWORD cimg = rdp.cimg;
3264 rdp.cimg = rdp.maincimg[1].addr;
3265 if (settings.fb_smart)
3267 rdp.ci_width = rdp.maincimg[1].width;
3268 rdp.ci_count = 0;
3269 DWORD h = rdp.frame_buffers[0].height;
3270 rdp.frame_buffers[0].height = rdp.maincimg[1].height;
3271 CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3272 rdp.frame_buffers[0].height = h;
3274 else
3276 CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3278 rdp.cimg = cimg;
3279 rdp.fb_drawn_front = TRUE;
3284 /******************************************************************
3285 Function: FrameBufferWriteList
3286 Purpose: This function is called to notify the dll that the
3287 frame buffer has been modified by CPU at the given address.
3288 input: FrameBufferModifyEntry *plist
3289 size = size of the plist, max = 1024
3290 output: none
3291 *******************************************************************/
3292 EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size)
3294 LOG ("FBWList ()\n");
3295 FRDP("FBWList. size: %d\n", size);
3296 printf("FBWList. size: %d\n", size);
3300 /******************************************************************
3301 Function: FrameBufferWrite
3302 Purpose: This function is called to notify the dll that the
3303 frame buffer has been modified by CPU at the given address.
3304 input: addr rdram address
3305 val val
3306 size 1 = BYTE, 2 = WORD, 4 = DWORD
3307 output: none
3308 *******************************************************************/
3309 EXPORT void CALL FBWrite(DWORD addr, DWORD size)
3311 LOG ("FBWrite ()\n");
3312 if (cpu_fb_ignore)
3313 return;
3314 if (cpu_fb_read_called)
3316 cpu_fb_ignore = TRUE;
3317 cpu_fb_write = FALSE;
3318 return;
3320 cpu_fb_write_called = TRUE;
3321 DWORD a = segoffset(addr);
3322 FRDP("FBWrite. addr: %08lx\n", a);
3323 // ZIGGY : added a test on ci_width, otherwise we crash on zero division below
3324 if (!rdp.ci_width || a < rdp.cimg || a > rdp.ci_end)
3325 return;
3326 cpu_fb_write = TRUE;
3327 DWORD shift_l = (a-rdp.cimg) >> 1;
3328 DWORD shift_r = shift_l+2;
3330 d_ul_x = min(d_ul_x, shift_l%rdp.ci_width);
3331 d_ul_y = min(d_ul_y, shift_l/rdp.ci_width);
3332 d_lr_x = max(d_lr_x, shift_r%rdp.ci_width);
3333 d_lr_y = max(d_lr_y, shift_r/rdp.ci_width);
3337 /************************************************************************
3338 Function: FBGetFrameBufferInfo
3339 Purpose: This function is called by the emulator core to retrieve frame
3340 buffer information from the video plugin in order to be able
3341 to notify the video plugin about CPU frame buffer read/write
3342 operations
3344 size:
3345 = 1 byte
3346 = 2 word (16 bit) <-- this is N64 default depth buffer format
3347 = 4 dword (32 bit)
3349 when frame buffer information is not available yet, set all values
3350 in the FrameBufferInfo structure to 0
3352 input: FrameBufferInfo pinfo[6]
3353 pinfo is pointed to a FrameBufferInfo structure which to be
3354 filled in by this function
3355 output: Values are return in the FrameBufferInfo structure
3356 Plugin can return up to 6 frame buffer info
3357 ************************************************************************/
3358 ///*
3359 typedef struct
3361 DWORD addr;
3362 DWORD size;
3363 DWORD width;
3364 DWORD height;
3365 } FrameBufferInfo;
3366 EXPORT void CALL FBGetFrameBufferInfo(void *p)
3368 LOG ("FBGetFrameBufferInfo ()\n");
3369 FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
3370 memset(pinfo,0,sizeof(FrameBufferInfo)*6);
3371 if (!settings.fb_get_info)
3372 return;
3373 RDP("FBGetFrameBufferInfo ()\n");
3375 if (settings.fb_smart)
3377 pinfo[0].addr = rdp.maincimg[1].addr;
3378 pinfo[0].size = rdp.maincimg[1].size;
3379 pinfo[0].width = rdp.maincimg[1].width;
3380 pinfo[0].height = rdp.maincimg[1].height;
3381 int info_index = 1;
3382 for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++)
3384 COLOR_IMAGE & cur_fb = rdp.frame_buffers[i];
3385 if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self ||
3386 cur_fb.status == ci_old_copy)
3388 pinfo[info_index].addr = cur_fb.addr;
3389 pinfo[info_index].size = cur_fb.size;
3390 pinfo[info_index].width = cur_fb.width;
3391 pinfo[info_index].height = cur_fb.height;
3392 info_index++;
3396 else
3398 pinfo[0].addr = rdp.maincimg[0].addr;
3399 pinfo[0].size = rdp.ci_size;
3400 pinfo[0].width = rdp.ci_width;
3401 pinfo[0].height = rdp.ci_width*3/4;
3402 pinfo[1].addr = rdp.maincimg[1].addr;
3403 pinfo[1].size = rdp.ci_size;
3404 pinfo[1].width = rdp.ci_width;
3405 pinfo[1].height = rdp.ci_width*3/4;
3407 //*/
3409 //*/
3410 #include "UcodeFB.h"
3412 void DetectFrameBufferUsage ()
3414 RDP("DetectFrameBufferUsage\n");
3416 DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
3417 #ifdef _WIN32
3418 DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
3419 #endif // _WIN32
3420 DWORD a;
3422 BOOL tidal = FALSE;
3423 if (settings.PM && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self))
3424 tidal = TRUE;
3425 DWORD ci = rdp.cimg, zi = rdp.zimg; // ci_width = rdp.ci_width;
3426 rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0;
3427 rdp.main_ci_index = rdp.copy_ci_index = 0;
3428 rdp.zimg_end = 0;
3429 rdp.tmpzimg = 0;
3430 rdp.motionblur = FALSE;
3431 rdp.main_ci_last_tex_addr = 0;
3432 BOOL previous_ci_was_read = rdp.read_previous_ci;
3433 rdp.read_previous_ci = FALSE;
3434 rdp.read_whole_frame = FALSE;
3435 rdp.swap_ci_index = rdp.black_ci_index = -1;
3436 SwapOK = TRUE;
3438 // Start executing at the start of the display list
3439 rdp.pc_i = 0;
3440 rdp.pc[rdp.pc_i] = dlist_start;
3441 rdp.dl_count = -1;
3442 rdp.halt = 0;
3443 rdp.scale_x_bak = rdp.scale_x;
3444 rdp.scale_y_bak = rdp.scale_y;
3446 // MAIN PROCESSING LOOP
3447 do {
3449 // Get the address of the next command
3450 a = rdp.pc[rdp.pc_i] & BMASK;
3452 // Load the next command and its input
3453 rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
3454 rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
3456 // Output the address before the command
3458 // Go to the next instruction
3459 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
3461 if ((intptr_t)(gfx_instruction_lite[settings.ucode][rdp.cmd0>>24]))
3462 gfx_instruction_lite[settings.ucode][rdp.cmd0>>24] ();
3464 // check DL counter
3465 if (rdp.dl_count != -1)
3467 rdp.dl_count --;
3468 if (rdp.dl_count == 0)
3470 rdp.dl_count = -1;
3472 RDP ("End of DL\n");
3473 rdp.pc_i --;
3477 } while (!rdp.halt);
3478 SwapOK = TRUE;
3479 if (rdp.ci_count > NUMTEXBUF) //overflow
3481 rdp.cimg = ci;
3482 rdp.zimg = zi;
3483 rdp.num_of_ci = rdp.ci_count;
3484 rdp.scale_x = rdp.scale_x_bak;
3485 rdp.scale_y = rdp.scale_y_bak;
3486 return;
3489 if (rdp.black_ci_index > 0 && rdp.black_ci_index < rdp.copy_ci_index)
3490 rdp.frame_buffers[rdp.black_ci_index].status = ci_main;
3492 if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown)
3494 if (rdp.ci_count > 1)
3495 rdp.frame_buffers[rdp.ci_count-1].status = ci_aux;
3496 else
3497 rdp.frame_buffers[rdp.ci_count-1].status = ci_main;
3500 if ((rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) &&
3501 (rdp.frame_buffers[rdp.main_ci_index].width < 320) &&
3502 (rdp.frame_buffers[rdp.ci_count-1].width > rdp.frame_buffers[rdp.main_ci_index].width))
3504 for (int i = 0; i < rdp.ci_count; i++)
3506 if (rdp.frame_buffers[i].status == ci_main)
3507 rdp.frame_buffers[i].status = ci_aux;
3508 else if (rdp.frame_buffers[i].addr == rdp.frame_buffers[rdp.ci_count-1].addr)
3509 rdp.frame_buffers[i].status = ci_main;
3510 // FRDP("rdp.frame_buffers[%d].status = %d\n", i, rdp.frame_buffers[i].status);
3512 rdp.main_ci_index = rdp.ci_count-1;
3515 BOOL all_zimg = TRUE;
3516 int i;
3517 for (i = 0; i < rdp.ci_count; i++)
3519 if (rdp.frame_buffers[i].status != ci_zimg)
3521 all_zimg = FALSE;
3522 break;
3525 if (all_zimg)
3527 for (i = 0; i < rdp.ci_count; i++)
3528 rdp.frame_buffers[i].status = ci_main;
3531 RDP("detect fb final results: \n");
3532 for (i = 0; i < rdp.ci_count; i++)
3534 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);
3537 rdp.cimg = ci;
3538 rdp.zimg = zi;
3539 rdp.num_of_ci = rdp.ci_count;
3540 if (rdp.read_previous_ci && previous_ci_was_read)
3541 if (!settings.fb_hires || !rdp.copy_ci_index)
3542 rdp.motionblur = TRUE;
3543 if (rdp.motionblur || settings.fb_hires || (rdp.frame_buffers[rdp.copy_ci_index].status == ci_aux_copy))
3545 rdp.scale_x = rdp.scale_x_bak;
3546 rdp.scale_y = rdp.scale_y_bak;
3549 if ((rdp.read_previous_ci || previous_ci_was_read) && !rdp.copy_ci_index)
3550 rdp.read_whole_frame = TRUE;
3551 if (rdp.read_whole_frame)
3553 if (settings.fb_hires && !settings.fb_ignore_previous)
3555 if (rdp.swap_ci_index < 0)
3557 rdp.texbufs[0].clear_allowed = rdp.texbufs[0].clear_allowed = TRUE;
3558 OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3561 else
3563 if (rdp.motionblur)
3565 if (settings.fb_motionblur)
3566 CopyFrameBuffer();
3567 else
3568 memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
3570 else //if (ci_width == rdp.frame_buffers[rdp.main_ci_index].width)
3572 if (rdp.maincimg[0].height > 65) //for 1080
3574 rdp.cimg = rdp.maincimg[0].addr;
3575 rdp.ci_width = rdp.maincimg[0].width;
3576 rdp.ci_count = 0;
3577 DWORD h = rdp.frame_buffers[0].height;
3578 rdp.frame_buffers[0].height = rdp.maincimg[0].height;
3579 CopyFrameBuffer();
3580 rdp.frame_buffers[0].height = h;
3582 else //conker
3584 CopyFrameBuffer();
3590 if (settings.fb_hires)
3592 for (i = 0; i < num_tmu; i++)
3594 rdp.texbufs[i].clear_allowed = TRUE;
3595 for (int j = 0; j < 256; j++)
3597 rdp.texbufs[i].images[j].drawn = FALSE;
3598 rdp.texbufs[i].images[j].clear = TRUE;
3601 if (tidal)
3603 //RDP("Tidal wave!\n");
3604 rdp.copy_ci_index = rdp.main_ci_index;
3607 rdp.ci_count = 0;
3608 if (settings.fb_ignore_previous)
3609 rdp.read_whole_frame = FALSE;
3610 else
3611 rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3612 // rdp.scale_x = rdp.scale_x_bak;
3613 // rdp.scale_y = rdp.scale_y_bak;
3614 RDP("DetectFrameBufferUsage End\n");
3621 /******************************************************************
3622 Function: ProcessRDPList
3623 Purpose: This function is called when there is a Dlist to be
3624 processed. (Low level GFX list)
3625 input: none
3626 output: none
3627 *******************************************************************/
3628 EXPORT void CALL ProcessRDPList(void)
3630 if (settings.KI)
3632 *gfx.MI_INTR_REG |= 0x20;
3633 gfx.CheckInterrupts();
3635 LOG ("ProcessRDPList ()\n");
3641 no_dlist = FALSE;
3642 update_screen_count = 0;
3643 ChangeSize ();
3645 #ifdef ALTTAB_FIX
3646 if (!hhkLowLevelKybd)
3648 hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
3649 LowLevelKeyboardProc, hInstance, 0);
3651 #endif
3653 LOG ("ProcessDList ()\n");
3655 if (!fullscreen)
3657 drawNoFullscreenMessage();
3658 // Set an interrupt to allow the game to continue
3659 *gfx.MI_INTR_REG |= 0x20;
3660 gfx.CheckInterrupts();
3663 if (reset)
3665 reset = 0;
3667 memset (microcode, 0, 4096);
3668 if (settings.autodetect_ucode)
3670 // Thanks to ZeZu for ucode autodetection!!!
3672 DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
3673 memcpy (microcode, gfx.RDRAM+startUcode, 4096);
3674 microcheck ();
3678 else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
3680 DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
3681 memcpy (microcode, gfx.RDRAM+startUcode, 4096);
3682 microcheck ();
3685 if (exception) return;
3687 // Switch to fullscreen?
3688 if (to_fullscreen)
3690 to_fullscreen = FALSE;
3692 if (!InitGfx (FALSE))
3694 LOG ("FAILED!!!\n");
3695 return;
3697 fullscreen = TRUE;
3698 #ifdef _WIN32
3699 if (gfx.hStatusBar)
3700 ShowWindow( gfx.hStatusBar, SW_HIDE );
3701 ShowCursor( FALSE );
3702 #endif // _WIN32
3705 if (!fullscreen && !settings.run_in_window) return;
3707 // Clear out the RDP log
3708 #ifdef RDP_LOGGING
3709 if (settings.logging && settings.log_clear)
3711 CLOSE_RDP_LOG ();
3712 OPEN_RDP_LOG ();
3714 #endif
3716 #ifdef UNIMP_LOG
3717 if (settings.log_unk && settings.unk_clear)
3719 std::ofstream unimp;
3720 unimp.open("unimp.txt");
3721 unimp.close();
3723 #endif
3725 //* Set states *//
3726 if (settings.swapmode > 0)
3727 SwapOK = TRUE;
3728 rdp.updatescreen = 1;
3730 rdp.tri_n = 0; // 0 triangles so far this frame
3731 rdp.debug_n = 0;
3733 rdp.model_i = 0; // 0 matrices so far in stack
3734 //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin!
3735 rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
3736 if (rdp.model_stack_size == 0)
3737 rdp.model_stack_size = 32;
3738 rdp.fb_drawn = rdp.fb_drawn_front = FALSE;
3739 rdp.update = 0x7FFFFFFF; // All but clear cache
3740 rdp.geom_mode = 0;
3741 rdp.acmp = 0;
3742 rdp.maincimg[1] = rdp.maincimg[0];
3743 rdp.skip_drawing = FALSE;
3744 rdp.s2dex_tex_loaded = FALSE;
3745 fbreads_front = fbreads_back = 0;
3746 rdp.fog_multiplier = rdp.fog_offset = 0;
3747 rdp.zsrc = 0;
3749 if (cpu_fb_write == TRUE)
3750 DrawFrameBufferToScreen();
3751 cpu_fb_write = FALSE;
3752 cpu_fb_read_called = FALSE;
3753 cpu_fb_write_called = FALSE;
3754 cpu_fb_ignore = FALSE;
3755 d_ul_x = 0xffff;
3756 d_ul_y = 0xffff;
3757 d_lr_x = 0;
3758 d_lr_y = 0;
3760 //analize possible frame buffer usage
3761 if (settings.fb_smart)
3762 DetectFrameBufferUsage();
3763 if (!settings.lego || rdp.num_of_ci > 1)
3764 rdp.last_bg = 0;
3765 //* End of set states *//
3768 // Get the start of the display list and the length of it
3769 // DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
3770 // DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
3771 DWORD dlist_start = *gfx.DPC_CURRENT_REG;
3772 DWORD dlist_length = *gfx.DPC_END_REG - *gfx.DPC_CURRENT_REG;
3773 FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length);
3774 FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
3776 if (settings.tonic && dlist_length < 16)
3778 rdp_fullsync();
3779 FRDP_E("DLIST is too short!\n");
3780 return;
3783 // Start executing at the start of the display list
3784 rdp.pc_i = 0;
3785 rdp.pc[rdp.pc_i] = dlist_start;
3786 rdp.dl_count = -1;
3787 rdp.halt = 0;
3788 DWORD a;
3790 // catches exceptions so that it doesn't freeze
3791 #ifdef CATCH_EXCEPTIONS
3792 try {
3793 #endif
3795 // MAIN PROCESSING LOOP
3796 do {
3798 // Get the address of the next command
3799 a = rdp.pc[rdp.pc_i] & BMASK;
3801 // Load the next command and its input
3802 rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
3803 rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
3804 // cmd2 and cmd3 are filled only when needed, by the function that needs them
3806 // Output the address before the command
3807 #ifdef LOG_COMMANDS
3808 FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1);
3809 #else
3810 FRDP ("%08lx: ", a);
3811 #endif
3813 // Go to the next instruction
3814 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
3816 #ifdef PERFORMANCE
3817 QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
3818 #endif
3819 // Process this instruction
3820 gfx_instruction[settings.ucode][((rdp.cmd0>>24)&0x3f) + 0x100-0x40] ();
3822 // check DL counter
3823 if (rdp.dl_count != -1)
3825 rdp.dl_count --;
3826 if (rdp.dl_count == 0)
3828 rdp.dl_count = -1;
3830 RDP ("End of DL\n");
3831 rdp.pc_i --;
3835 #ifdef PERFORMANCE
3836 QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
3837 __int64 t = perf_next-perf_cur;
3838 sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
3839 rdp_log << out_buf;
3840 #endif
3842 } while (0);
3843 #ifdef CATCH_EXCEPTIONS
3844 } catch (...) {
3846 if (fullscreen) ReleaseGfx ();
3847 # ifdef _WIN32
3848 if (MessageBox (gfx.hWnd, "The GFX plugin caused an exception and has been disabled.\nWould you like to turn it back on and attempt to continue?", "Glide64 Exception", MB_YESNO|MB_ICONEXCLAMATION) == IDNO)
3849 exception = TRUE;
3850 # else // _WIN32
3851 if (messagebox("Glide64 Exception", MB_YESNO|MB_ICONEXCLAMATION, "The GFX plugin caused an exception and has been disabled.\nWould you like to turn it back on and attempt to continue?") == 2)
3852 exception = TRUE;
3853 # endif // _WIN32
3855 #endif
3857 if (settings.fb_smart)
3859 rdp.scale_x = rdp.scale_x_bak;
3860 rdp.scale_y = rdp.scale_y_bak;
3862 if (settings.fb_read_always)
3864 CopyFrameBuffer ();
3866 if (rdp.yuv_image)
3868 DrawYUVImageToFrameBuffer();
3869 rdp.yuv_image = FALSE;
3870 // FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
3871 // rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
3872 rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
3873 rdp.yuv_im_begin = 0x00FFFFFF;
3875 if (rdp.cur_image)
3876 CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
3878 if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
3880 newSwapBuffers ();
3881 CI_SET = FALSE;
3883 RDP("ProcessDList end\n");
3890 printf("ProcessRPDList %x %x %x\n",
3891 *gfx.DPC_START_REG,
3892 *gfx.DPC_END_REG,
3893 *gfx.DPC_CURRENT_REG);
3894 //*gfx.DPC_STATUS_REG = 0xffffffff; // &= ~0x0002;
3896 *gfx.DPC_START_REG = *gfx.DPC_END_REG;
3897 *gfx.DPC_CURRENT_REG = *gfx.DPC_END_REG;
3905 // Local Variables: ***
3906 // tab-width:4 ***
3907 // c-file-offset:4 ***
3908 // End: ***