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
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
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 //****************************************************************
47 #include "TexBuffer.h"
51 #include "messagebox.h"
57 DWORD frame_count
; // frame counter
59 BOOL ucode_error_report
= TRUE
;
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) : :);
66 const char *ACmp
[4] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" };
68 const char *Mode0
[16] = { "COMBINED", "TEXEL0",
69 "TEXEL1", "PRIMITIVE",
70 "SHADE", "ENVIORNMENT",
76 const char *Mode1
[16] = { "COMBINED", "TEXEL0",
77 "TEXEL1", "PRIMITIVE",
78 "SHADE", "ENVIORNMENT",
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",
100 const char *Mode3
[8] = { "COMBINED", "TEXEL0",
101 "TEXEL1", "PRIMITIVE",
102 "SHADE", "ENVIORNMENT",
105 const char *Alpha0
[8] = { "COMBINED", "TEXEL0",
106 "TEXEL1", "PRIMITIVE",
107 "SHADE", "ENVIORNMENT",
109 const char *Alpha2
[8] = { "LOD_FRACTION", "TEXEL0",
110 "TEXEL1", "PRIMITIVE",
111 "SHADE", "ENVIORNMENT",
112 "PRIM_LODFRAC", "0" };
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" };
145 // depth save/restore variables
147 // 1 : writing in normal depth buffer
148 // 2 : writing in alternate depth buffer
149 static int render_depth_mode
;
151 // ** RDP graphics functions **
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];
203 // ** UCODE FUNCTIONS **
215 static BOOL reset
= 0;
216 static int old_ucode
= -1;
218 // rdp_reset - resets the RDP_E
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;
253 // Clear the palette CRC
256 rdp
.pal_8_crc
[i
] = 0;
258 // Clear the palettes
259 for (i
=0; i
<256; i
++)
264 // Clear all segments ** VERY IMPORTANT FOR ZELDA **
268 for (i
=0; i
<512; i
++)
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;
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
;
284 rdp
.render_mode_changed
= 0;
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
;
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
;
320 GetAsyncKeyState (VK_BACK
);
321 GetAsyncKeyState(0x42);
322 GetAsyncKeyState(0x56);
323 GetAsyncKeyState(0x43);
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
;
338 # define ByteEndian(address) (address^3)
339 # define WordEndian(address) (address^2)
341 # define _Read8Endian(array, address) (*((BYTE *)(array+ByteEndian(address))))
342 __inline
static DWORD
searchrdram(const char *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
)
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
);
374 ucf
.open ("ucode.txt", ios::out
| ios::binary
);
376 for (i
=0; i
<0x400000; i
++)
378 d
= ((char*)gfx
.RDRAM
)[i
^3];
385 sprintf (str
, "%08lx", (unsigned long)uc_crc
);
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);
399 sprintf (out_buf
, "Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc
);
401 MessageBox (gfx
.hWnd
, out_buf
, "Error", MB_OK
|MB_ICONEXCLAMATION
);
403 messagebox("Error", MB_OK
|MB_ICONEXCLAMATION
, out_buf
);
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);
415 sprintf (out_buf
, "Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc
);
417 MessageBox (gfx
.hWnd
, out_buf
, "Error", MB_OK
|MB_ICONEXCLAMATION
);
419 messagebox("Error", MB_OK
|MB_ICONEXCLAMATION
, out_buf
);
422 ucode_error_report
= FALSE
; // don't report any more ucode errors from this game
426 old_ucode
= settings
.ucode
;
428 FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode
, uc
);
429 //INI_FindSection ("SETTINGS");
430 //INI_WriteInt ("ucode", uc);
439 void drawNoFullscreenMessage()
441 LOG ("drawNoFullscreenMessage ()\n");
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
||
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
));
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));
492 //clipping the result
500 WORD c
= (WORD
)(((WORD
)(r
) << 11) |
502 ((WORD
)(b
) << 1) | 1);
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
;
543 int ul_x
, ul_y
, lr_x
, lr_y
;
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
);
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
,
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
);
578 grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER
,
579 GR_COMBINE_FACTOR_ONE
,
580 GR_COMBINE_LOCAL_NONE
,
581 GR_COMBINE_OTHER_TEXTURE
,
583 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER
,
584 GR_COMBINE_FACTOR_ONE
,
585 GR_COMBINE_LOCAL_NONE
,
586 GR_COMBINE_OTHER_TEXTURE
,
588 grConstantColorValue (0xFFFFFFFF);
589 grAlphaBlendFunction( GR_BLEND_SRC_ALPHA
,
590 GR_BLEND_ONE_MINUS_SRC_ALPHA
,
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
);
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;
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
++)
632 while (w
< src_width
)
634 while (w
< src_width
)
636 if (src
[(w
+h
*rdp
.ci_width
)^1] == 0)
643 if (num_of_parts
== 0) //first part
650 else if (w
< most_left
- 2) //new part
652 parts
[num_of_parts
].ul_x
= w
;
654 parts
[num_of_parts
].ul_y
= h
;
655 cur_part
= num_of_parts
;
658 else if (w
> most_right
+ 2) //new part
660 parts
[num_of_parts
].ul_x
= w
;
662 parts
[num_of_parts
].ul_y
= h
;
663 cur_part
= num_of_parts
;
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
;
678 while (w
< src_width
)
680 if (src
[(w
+h
*rdp
.ci_width
)^1] != 0)
685 if (num_of_parts
== 0) //first part
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
)
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,
731 int width
= rdp
.ci_width
;//*gfx.VI_WIDTH_REG;
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
;
740 height
= rdp
.ci_lower_bound
;
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,
757 WORD
*ptr_dst
= (WORD
*)(gfx
.RDRAM
+rdp
.cimg
);
758 DWORD
*ptr_dst32
= (DWORD
*)(gfx
.RDRAM
+rdp
.cimg
);
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
)
769 c
= (c
&0xFFC0) | ((c
&0x001F) << 1) | 1;
773 c
= (c
&0xFFC0) | ((c
&0x001F) << 1) | 1;
775 if (rdp
.ci_size
== 2)
776 ptr_dst
[(x
+ y
* width
)^1] = c
;
778 ptr_dst32
[x
+ y
* width
] = RGBA16TO32(c
);
785 BYTE *ptr_dst = (BYTE*)(gfx.RDRAM+rdp.cimg);
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);
803 RDP ("ReadRegion. Framebuffer copy complete.\n");
807 RDP ("Framebuffer copy failed.\n");
813 if (rdp
.motionblur
&& settings
.fb_hires
)
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
);
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
,
832 GR_ORIGIN_UPPER_LEFT
,
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
);
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
)
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)
853 if (rdp
.ci_size
<= 2)
854 ptr_dst
[(x
+ y
* width
)^1] = c
;
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");
866 RDP ("Framebuffer copy failed.\n");
869 if (grLfbLock (GR_LFB_READ_ONLY
,
872 GR_ORIGIN_UPPER_LEFT
,
876 DWORD
*ptr_src
= (DWORD
*)info
.lfbPtr
;
878 //WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
879 DWORD
*ptr_dst32
= (DWORD
*)(gfx
.RDRAM
+rdp
.cimg
);
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
)
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)
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");
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)
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
;
927 EXPORT
void CALL
ProcessDList(void)
930 update_screen_count
= 0;
934 if (!hhkLowLevelKybd
)
936 hhkLowLevelKybd
= SetWindowsHookEx(WH_KEYBOARD_LL
,
937 LowLevelKeyboardProc
, hInstance
, 0);
941 LOG ("ProcessDList ()\n");
945 drawNoFullscreenMessage();
946 // Set an interrupt to allow the game to continue
947 *gfx
.MI_INTR_REG
|= 0x20;
948 gfx
.CheckInterrupts();
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);
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);
973 if (exception
) return;
975 // Switch to fullscreen?
978 to_fullscreen
= FALSE
;
980 if (!InitGfx (FALSE
))
988 ShowWindow( gfx
.hStatusBar
, SW_HIDE
);
993 if (!fullscreen
&& !settings
.run_in_window
) return;
995 // Clear out the RDP log
997 if (settings
.logging
&& settings
.log_clear
)
1005 if (settings
.log_unk
&& settings
.unk_clear
)
1007 std::ofstream unimp
;
1008 unimp
.open("unimp.txt");
1014 if (settings
.swapmode
> 0)
1016 rdp
.updatescreen
= 1;
1018 rdp
.tri_n
= 0; // 0 triangles so far this frame
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
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;
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
;
1048 //analize possible frame buffer usage
1049 if (settings
.fb_smart
)
1050 DetectFrameBufferUsage();
1051 if (!settings
.lego
|| rdp
.num_of_ci
> 1)
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)
1065 FRDP_E("DLIST is too short!\n");
1069 // Start executing at the start of the display list
1071 rdp
.pc
[rdp
.pc_i
] = dlist_start
;
1076 // catches exceptions so that it doesn't freeze
1077 #ifdef CATCH_EXCEPTIONS
1081 // MAIN PROCESSING LOOP
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
1094 FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a
, rdp
.cmd0
, rdp
.cmd1
);
1096 FRDP ("%08lx: ", a
);
1099 // Go to the next instruction
1100 rdp
.pc
[rdp
.pc_i
] = (a
+8) & BMASK
;
1103 QueryPerformanceCounter ((LARGE_INTEGER
*)&perf_cur
);
1105 // Process this instruction
1106 gfx_instruction
[settings
.ucode
][rdp
.cmd0
>>24] ();
1109 if (rdp
.dl_count
!= -1)
1112 if (rdp
.dl_count
== 0)
1116 RDP ("End of DL\n");
1122 QueryPerformanceCounter ((LARGE_INTEGER
*)&perf_next
);
1123 __int64 t
= perf_next
-perf_cur
;
1124 sprintf (out_buf
, "perf %08lx: %016I64d\n", a
-8, t
);
1128 } while (!rdp
.halt
);
1129 #ifdef CATCH_EXCEPTIONS
1132 if (fullscreen
) ReleaseGfx ();
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
)
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)
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
)
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;
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
)
1169 RDP("ProcessDList end\n");
1172 // undef - undefined instruction, always ignore
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();
1184 // spnoop - no operation, always ignore
1185 static void spnoop()
1190 // noop - no operation, always ignore
1191 static void rdp_noop()
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;
1255 rdp
.pc
[rdp
.pc_i
] += 8;
1256 rdp
.cmd3
= rdp
.cmd2
;
1260 else if (settings
.yoshi
&& settings
.ucode
== 6)
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
)
1278 RDP("Texrect skipped\n");
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");
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
)
1307 if (rdp
.hires_tex
&& settings
.fb_optimize_texrect
)
1309 if (!rdp
.hires_tex
->drawn
)
1313 d
.imageW
= (WORD
)rdp
.hires_tex
->width
;
1315 d
.frameW
= (WORD
)(rdp
.hires_tex
->width
);//(WORD)(ul_x + rdp.hires_tex->width);//lr_x;
1318 d
.imageH
= (WORD
)rdp
.hires_tex
->height
;
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
);
1324 DrawHiresImage(&d
, rdp
.hires_tex
->width
== rdp
.ci_width
);
1325 rdp
.hires_tex
->drawn
= TRUE
;
1330 // framebuffer workaround for Zelda: MM LOT
1331 if ((rdp
.othermode_l
& 0xFFFF0000) == 0x0f5a0000)
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);
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)
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");
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)
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
;
1385 DWORD prev_tile
= rdp
.cur_tile
;
1386 rdp
.cur_tile
= tile
;
1387 rdp
.update
|= UPDATE_COMBINE
;
1391 rdp
.allow_combine
= 1;
1393 if (!rdp
.cur_cache
[0])
1395 rdp
.cur_tile
= prev_tile
;
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
);
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
);
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))
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
));
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
));
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
);
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
);
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
;
1487 ul_u0
= ul_v0
= lr_u0
= lr_v0
= 0;
1489 if (rdp
.cur_cache
[1] && (rdp
.tex
& 2))
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
));
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));
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
);
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
);
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
;
1545 ul_u1
= ul_v1
= lr_u1
= lr_v1
= 0;
1547 rdp
.cur_tile
= prev_tile
;
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
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
1566 FRDP ("prim_depth = %d\n", rdp
.prim_depth
);
1568 if (settings
.increase_primdepth
)
1572 grDepthBufferFunction (GR_CMP_LEQUAL
);
1573 rdp
.update
|= UPDATE_ZBUF_ENABLED
;
1577 RDP ("no prim_depth used, using 1.0\n");
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
1599 VERTEX
*vptr
= vstd
;
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
)
1627 int start_u_256
, end_u_256
;
1629 if (settings
.ucode
== 7)
1632 end_u_256
= (lr_x
- ul_x
- 1)>>8;
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;
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
;
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);
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
;
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
;
1696 vnew
[vn
] = vnew
[vn
-2];
1698 vnew
[vn
].v0
+= (float)splitheight
;
1700 vnew
[vn
].v1
+= (float)splitheight
;
1703 vnew
[vn
] = vnew
[vn
-2];
1705 vnew
[vn
].v0
+= (float)splitheight
;
1707 vnew
[vn
].v1
+= (float)splitheight
;
1711 AllowShadeMods (vptr
, n_vertices
);
1712 for (i
=0; i
<n_vertices
; i
++)
1714 VERTEX
*z
= &vptr
[i
];
1721 apply_shade_mods (z
);
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
,
1739 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER
,
1740 GR_COMBINE_FACTOR_ONE
,
1741 GR_COMBINE_LOCAL_NONE
,
1742 GR_COMBINE_OTHER_TEXTURE
,
1744 grAlphaBlendFunction (GR_BLEND_ONE
,
1748 if (rdp
.othermode_l
& 1)
1750 grAlphaTestFunction (GR_CMP_GEQUAL
);
1751 grAlphaTestReferenceValue (0x80);
1754 grAlphaTestFunction (GR_CMP_ALWAYS
);
1756 rdp
.update
|= UPDATE_ALPHA_COMPARE
| UPDATE_COMBINE
;
1759 ConvertCoordsConvert (vptr
, n_vertices
);
1761 if (settings
.wireframe
)
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]);
1772 grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP
, n_vertices
, vptr
, sizeof(VERTEX
));
1781 add_tri (vl
, 3, TRI_TEXRECT
);
1786 add_tri (vl
, 3, TRI_TEXRECT
);
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
;
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();
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)); \
1888 gfx_instruction[settings.ucode][cmd] (); \
1890 #define SETOTHERMODE(cmd,sft,len,data) { \
1891 rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \
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
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));
1925 FRDP ("%d: %08lx\n", i
, *(WORD
*)(gfx
.RDRAM
+ (addr
^2)));
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 );
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
,
1953 load_palette (rdp
.timg
.addr
, start
, count
);
1955 rdp
.timg
.addr
+= count
<< 1;
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
1974 else if (wrong_tile
== (int)tile
)
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)
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
;
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
;
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
;
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))))
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
);
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;
2039 int *pSrc
= (int *) ((uintptr_t) gfx
.RDRAM
+ SrcOffs
);
2040 for (unsigned int x
= 0; x
< cnt
; x
++)
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
2056 for (int x
= 0; x
< rem
; x
++)
2058 for (int x
= 4; x
> rem
; x
--)
2060 *((char *) pDst
) = s0
& 0xff;
2061 pDst
= (int *) ((char *) pDst
+ 1);
2064 // do one full 32-bit word
2068 // do 'cnt-1' 64-bit dwords
2069 for (unsigned int x
= 0; x
< cnt
-1; x
++)
2077 // do last partial 32-bit word
2080 for (; rem
> 0; rem
--)
2082 *((char *) pDst
) = s0
& 0xff;
2083 pDst
= (int *) ((char *) pDst
+ 1);
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.
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
;
2106 // swapblock32 dst, cnt
2107 for (unsigned int x
= 0; x
< cnt
; x
++, pDst
+= 2)
2117 static void rdp_loadblock()
2119 if (rdp
.skip_drawing
)
2121 RDP("loadblock skipped\n");
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
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
2152 lr_s
= 1; // 1 so that it doesn't die on memcpy
2155 if (ul_s
+lr_s
> 512)
2158 if (addr
+(lr_s
<<3) > BMASK
+1)
2159 lr_s
= (WORD
)((BMASK
-addr
)>>3);
2161 DWORD offs
= rdp
.timg
.addr
;
2163 if (rdp
.tiles
[tile
].size
== 3)
2165 //FIXME: unused? DWORD start_line = 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
2179 // skip over unswapped blocks
2186 } while (!(dxt_accum
& 0x80000000));
2187 // count number of blocks to swap
2188 if (cnt
== 0) break;
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
,
2209 static void rdp_loadtile()
2211 if (rdp
.skip_drawing
)
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
;
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
;
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)
2270 int line_n
= rdp
.timg
.width
;
2271 if (rdp
.tiles
[tile
].size
== 0)
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
)
2282 // check if points to bad location
2283 DWORD size
= width
* height
;
2284 if (rdp
.tiles
[tile
].size
== 0)
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
);
2301 WordswapBlock(pDst
, wid_64
, rdp
.tiles
[tile
].size
);
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
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");
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;
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
;
2397 if (rdp
.skip_drawing
)
2399 RDP("Fillrect skipped\n");
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
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
;
2424 if (settings
.decrease_fillrect_edge
&& rdp
.cycle_mode
== 0)
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
,
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
);
2449 grFogMode (GR_FOG_DISABLE
);
2451 grClipWindow (0, 0, settings
.res_x
, settings
.res_y
);
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
);
2463 grDepthBufferFunction (GR_CMP_ALWAYS
);
2464 grDepthMask (FXFALSE
);
2465 RDP ("no prim_depth used, using 1.0\n");
2467 // Draw the rectangle
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
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
,
2499 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL
,
2500 GR_COMBINE_FACTOR_NONE
,
2501 GR_COMBINE_LOCAL_CONSTANT
,
2502 GR_COMBINE_OTHER_NONE
,
2505 grAlphaBlendFunction (GR_BLEND_ONE
, GR_BLEND_ZERO
, GR_BLEND_ONE
, GR_BLEND_ZERO
);
2507 rdp
.update
|= UPDATE_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
)
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]);
2541 grDrawTriangle (&v
[0], &v
[2], &v
[1]);
2542 grDrawTriangle (&v
[2], &v
[3], &v
[1]);
2551 add_tri (v1
, 3, TRI_FILLRECT
);
2555 add_tri (v1
, 3, TRI_FILLRECT
);
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
;
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
,
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
))
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
2687 if (rdp
.timg
.size
== 2)
2688 FindTextureBuffer(rdp
.timg
.addr
, rdp
.timg
.width
);
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
);
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
;
2722 grDepthMask (FXFALSE
);
2723 grBufferClear (0, 0, 0xFFFF);
2724 grDepthMask (FXTRUE
);
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
)
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
;
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
))
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
]);
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
;
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))
2797 if (!rdp
.fb_drawn
|| prev_fb
.status
== ci_copy_self
)
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);
2807 CloseTextureBuffer(TRUE
);
2812 memset(gfx
.RDRAM
+cur_fb
.addr
, 0, cur_fb
.width
*cur_fb
.height
*rdp
.ci_size
);
2814 rdp
.skip_drawing
= TRUE
;
2819 rdp
.skip_drawing
= FALSE
;
2820 if (CloseTextureBuffer(prev_fb
.status
!= ci_aux_copy
))
2822 else if (!rdp
.fb_drawn
)
2825 rdp
.fb_drawn
= TRUE
;
2827 if (settings
.fb_hires
)
2828 OpenTextureBuffer(cur_fb
);
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;
2843 memset(gfx
.RDRAM
+cur_fb
.addr
, 0, (cur_fb
.width
*cur_fb
.height
)<<rdp
.ci_size
>>1);
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;
2858 if (!settings
.fb_hires
&& cur_fb
.format
!= 0)
2859 rdp
.skip_drawing
= TRUE
;
2862 rdp
.skip_drawing
= FALSE
;
2863 if (settings
.fb_hires
&& OpenTextureBuffer(cur_fb
))
2867 if (cur_fb
.format
!= 0)
2868 rdp
.skip_drawing
= TRUE
;
2869 if (rdp
.ci_count
== 0)
2871 // if (rdp.num_of_ci > 1)
2877 else if (!settings
.fb_hires
&& (prev_fb
.status
== ci_main
) &&
2878 (prev_fb
.width
== cur_fb
.width
)) // for Pokemon Stadium
2882 cur_fb
.status
= ci_aux
;
2887 // Zelda LoT effect save/restore depth buffer
2888 if (cur_fb
.addr
== rdp
.zimg
) {
2889 render_depth_mode
= 1;
2891 render_depth_mode
= 2;
2893 rdp
.skip_drawing
= TRUE
;
2897 rdp
.skip_drawing
= TRUE
;
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)
2908 rdp.cimg = rdp.frame_buffers[rdp.ci_count].addr;
2909 rdp.maincimg[0].addr = rdp.cimg;
2912 OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count]);
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)
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
))
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
);
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
,
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
))
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
;
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)
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
;
3033 if (!settings
.fb_smart
)
3034 rdp
.skip_drawing
= FALSE
;
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
];
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
;
3053 rdp
.vi_org_reg
= *gfx
.VI_ORIGIN_REG
;
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()
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
,
3156 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL
,
3157 GR_COMBINE_FACTOR_NONE
,
3158 GR_COMBINE_LOCAL_ITERATED
,
3159 GR_COMBINE_OTHER_NONE
,
3161 grAlphaBlendFunction (GR_BLEND_ONE
,
3165 grTexCombine (GR_TMU0
,
3166 GR_COMBINE_FUNCTION_ZERO
,
3167 GR_COMBINE_FACTOR_NONE
,
3168 GR_COMBINE_FUNCTION_ZERO
,
3169 GR_COMBINE_FACTOR_NONE
,
3171 grTexCombine (GR_TMU1
,
3172 GR_COMBINE_FUNCTION_ZERO
,
3173 GR_COMBINE_FACTOR_NONE
,
3174 GR_COMBINE_FUNCTION_ZERO
,
3175 GR_COMBINE_FACTOR_NONE
,
3179 grColorCombine (GR_COMBINE_FUNCTION_LOCAL
,
3180 GR_COMBINE_FACTOR_NONE
,
3181 GR_COMBINE_LOCAL_CONSTANT
,
3182 GR_COMBINE_OTHER_NONE
,
3184 grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL
,
3185 GR_COMBINE_FACTOR_NONE
,
3186 GR_COMBINE_LOCAL_CONSTANT
,
3187 GR_COMBINE_OTHER_NONE
,
3189 grConstantColorValue (0xFF0000FF);
3190 grAlphaBlendFunction (GR_BLEND_ONE
,
3194 grTexCombine (GR_TMU0
,
3195 GR_COMBINE_FUNCTION_ZERO
,
3196 GR_COMBINE_FACTOR_NONE
,
3197 GR_COMBINE_FUNCTION_ZERO
,
3198 GR_COMBINE_FACTOR_NONE
,
3200 grTexCombine (GR_TMU1
,
3201 GR_COMBINE_FUNCTION_ZERO
,
3202 GR_COMBINE_FACTOR_NONE
,
3203 GR_COMBINE_FUNCTION_ZERO
,
3204 GR_COMBINE_FACTOR_NONE
,
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
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
3230 size 1 = BYTE, 2 = WORD, 4 = DWORD
3232 *******************************************************************/
3233 EXPORT
void CALL
FBRead(DWORD addr
)
3236 LOG ("FBRead ()\n");
3240 if (cpu_fb_write_called
)
3242 cpu_fb_ignore
= TRUE
;
3243 cpu_fb_write
= FALSE
;
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
))
3252 //if (fbreads_back > 2) //&& (rdp.ci_width <= 320))
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))
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
;
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
;
3276 CopyFrameBuffer(GR_BUFFER_FRONTBUFFER
);
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
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
3306 size 1 = BYTE, 2 = WORD, 4 = DWORD
3308 *******************************************************************/
3309 EXPORT
void CALL
FBWrite(DWORD addr
, DWORD size
)
3311 LOG ("FBWrite ()\n");
3314 if (cpu_fb_read_called
)
3316 cpu_fb_ignore
= TRUE
;
3317 cpu_fb_write
= FALSE
;
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
)
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
3346 = 2 word (16 bit) <-- this is N64 default depth buffer format
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 ************************************************************************/
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
)
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
;
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
;
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;
3410 #include "UcodeFB.h"
3412 void DetectFrameBufferUsage ()
3414 RDP("DetectFrameBufferUsage\n");
3416 DWORD dlist_start
= *(DWORD
*)(gfx
.DMEM
+0xFF0);
3418 DWORD dlist_length
= *(DWORD
*)(gfx
.DMEM
+0xFF4);
3423 if (settings
.PM
&& (rdp
.copy_ci_index
|| rdp
.frame_buffers
[rdp
.copy_ci_index
].status
== ci_copy_self
))
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;
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;
3438 // Start executing at the start of the display list
3440 rdp
.pc
[rdp
.pc_i
] = dlist_start
;
3443 rdp
.scale_x_bak
= rdp
.scale_x
;
3444 rdp
.scale_y_bak
= rdp
.scale_y
;
3446 // MAIN PROCESSING LOOP
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] ();
3465 if (rdp
.dl_count
!= -1)
3468 if (rdp
.dl_count
== 0)
3472 RDP ("End of DL\n");
3477 } while (!rdp
.halt
);
3479 if (rdp
.ci_count
> NUMTEXBUF
) //overflow
3483 rdp
.num_of_ci
= rdp
.ci_count
;
3484 rdp
.scale_x
= rdp
.scale_x_bak
;
3485 rdp
.scale_y
= rdp
.scale_y_bak
;
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
;
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
;
3517 for (i
= 0; i
< rdp
.ci_count
; i
++)
3519 if (rdp
.frame_buffers
[i
].status
!= ci_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
);
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
]);
3565 if (settings
.fb_motionblur
)
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
;
3577 DWORD h
= rdp
.frame_buffers
[0].height
;
3578 rdp
.frame_buffers
[0].height
= rdp
.maincimg
[0].height
;
3580 rdp
.frame_buffers
[0].height
= h
;
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
;
3603 //RDP("Tidal wave!\n");
3604 rdp
.copy_ci_index
= rdp
.main_ci_index
;
3608 if (settings
.fb_ignore_previous
)
3609 rdp
.read_whole_frame
= FALSE
;
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)
3627 *******************************************************************/
3628 EXPORT
void CALL
ProcessRDPList(void)
3632 *gfx
.MI_INTR_REG
|= 0x20;
3633 gfx
.CheckInterrupts();
3635 LOG ("ProcessRDPList ()\n");
3642 update_screen_count
= 0;
3646 if (!hhkLowLevelKybd
)
3648 hhkLowLevelKybd
= SetWindowsHookEx(WH_KEYBOARD_LL
,
3649 LowLevelKeyboardProc
, hInstance
, 0);
3653 LOG ("ProcessDList ()\n");
3657 drawNoFullscreenMessage();
3658 // Set an interrupt to allow the game to continue
3659 *gfx
.MI_INTR_REG
|= 0x20;
3660 gfx
.CheckInterrupts();
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);
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);
3685 if (exception
) return;
3687 // Switch to fullscreen?
3690 to_fullscreen
= FALSE
;
3692 if (!InitGfx (FALSE
))
3694 LOG ("FAILED!!!\n");
3700 ShowWindow( gfx
.hStatusBar
, SW_HIDE
);
3701 ShowCursor( FALSE
);
3705 if (!fullscreen
&& !settings
.run_in_window
) return;
3707 // Clear out the RDP log
3709 if (settings
.logging
&& settings
.log_clear
)
3717 if (settings
.log_unk
&& settings
.unk_clear
)
3719 std::ofstream unimp
;
3720 unimp
.open("unimp.txt");
3726 if (settings
.swapmode
> 0)
3728 rdp
.updatescreen
= 1;
3730 rdp
.tri_n
= 0; // 0 triangles so far this frame
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
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;
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
;
3760 //analize possible frame buffer usage
3761 if (settings
.fb_smart
)
3762 DetectFrameBufferUsage();
3763 if (!settings
.lego
|| rdp
.num_of_ci
> 1)
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)
3779 FRDP_E("DLIST is too short!\n");
3783 // Start executing at the start of the display list
3785 rdp
.pc
[rdp
.pc_i
] = dlist_start
;
3790 // catches exceptions so that it doesn't freeze
3791 #ifdef CATCH_EXCEPTIONS
3795 // MAIN PROCESSING LOOP
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
3808 FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a
, rdp
.cmd0
, rdp
.cmd1
);
3810 FRDP ("%08lx: ", a
);
3813 // Go to the next instruction
3814 rdp
.pc
[rdp
.pc_i
] = (a
+8) & BMASK
;
3817 QueryPerformanceCounter ((LARGE_INTEGER
*)&perf_cur
);
3819 // Process this instruction
3820 gfx_instruction
[settings
.ucode
][((rdp
.cmd0
>>24)&0x3f) + 0x100-0x40] ();
3823 if (rdp
.dl_count
!= -1)
3826 if (rdp
.dl_count
== 0)
3830 RDP ("End of DL\n");
3836 QueryPerformanceCounter ((LARGE_INTEGER
*)&perf_next
);
3837 __int64 t
= perf_next
-perf_cur
;
3838 sprintf (out_buf
, "perf %08lx: %016I64d\n", a
-8, t
);
3843 #ifdef CATCH_EXCEPTIONS
3846 if (fullscreen
) ReleaseGfx ();
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
)
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)
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
)
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;
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
)
3883 RDP("ProcessDList end\n");
3890 printf("ProcessRPDList %x %x %x\n",
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: ***
3907 // c-file-offset:4 ***