Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-video-glide64/src/rdp.cpp
2 views
1
/*
2
* Glide64 - Glide video plugin for Nintendo 64 emulators.
3
* Copyright (c) 2002 Dave2001
4
* Copyright (c) 2008 Günther <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public
17
* Licence along with this program; if not, write to the Free
18
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
* Boston, MA 02110-1301, USA
20
*/
21
22
//****************************************************************
23
//
24
// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
25
// Project started on December 29th, 2001
26
//
27
// To modify Glide64:
28
// * 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.
29
// * 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
//
31
// Official Glide64 development channel: #Glide64 on EFnet
32
//
33
// Original author: Dave2001 ([email protected])
34
// Other authors: Gonetz, Gugaman
35
//
36
//****************************************************************
37
38
#define M64P_PLUGIN_PROTOTYPES 1
39
#include "m64p_types.h"
40
#include "m64p_plugin.h"
41
#include "m64p_config.h"
42
#include "m64p_vidext.h"
43
#include "3dmath.h"
44
#include "Util.h"
45
#include "Debugger.h"
46
#include "Combine.h"
47
#include "Util.h"
48
#include "Ini.h"
49
#include "Config.h"
50
#include "Tmem.h"
51
#include "TexCache.h"
52
#include "TexCache.h"
53
#include "TexBuffer.h"
54
#include "CRC.h"
55
#include "rdp.h"
56
57
#ifndef _WIN32
58
#include <sys/time.h>
59
#endif // _WIN32
60
61
char out_buf[2048];
62
63
DWORD frame_count; // frame counter
64
65
BOOL ucode_error_report = TRUE;
66
int wrong_tile = -1;
67
68
int drawFlag = 1; // draw flag for rendering callback
69
70
#if defined(__GNUC__)
71
#define bswap32(x) __builtin_bswap32(x)
72
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
73
#include <stdlib.h>
74
#define bswap32(x) _byteswap_ulong(x)
75
#else
76
static inline uint32_t bswap32(uint32_t val)
77
{
78
return (((val & 0xff000000) >> 24) |
79
((val & 0x00ff0000) >> 8) |
80
((val & 0x0000ff00) << 8) |
81
((val & 0x000000ff) << 24));
82
}
83
#endif
84
85
// global strings
86
const char *ACmp[4] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" };
87
88
const char *Mode0[16] = { "COMBINED", "TEXEL0",
89
"TEXEL1", "PRIMITIVE",
90
"SHADE", "ENVIORNMENT",
91
"1", "NOISE",
92
"0", "0",
93
"0", "0",
94
"0", "0",
95
"0", "0" };
96
const char *Mode1[16] = { "COMBINED", "TEXEL0",
97
"TEXEL1", "PRIMITIVE",
98
"SHADE", "ENVIORNMENT",
99
"CENTER", "K4",
100
"0", "0",
101
"0", "0",
102
"0", "0",
103
"0", "0" };
104
const char *Mode2[32] = { "COMBINED", "TEXEL0",
105
"TEXEL1", "PRIMITIVE",
106
"SHADE", "ENVIORNMENT",
107
"SCALE", "COMBINED_ALPHA",
108
"T0_ALPHA", "T1_ALPHA",
109
"PRIM_ALPHA", "SHADE_ALPHA",
110
"ENV_ALPHA", "LOD_FRACTION",
111
"PRIM_LODFRAC", "K5",
112
"0", "0",
113
"0", "0",
114
"0", "0",
115
"0", "0",
116
"0", "0",
117
"0", "0",
118
"0", "0",
119
"0", "0" };
120
const char *Mode3[8] = { "COMBINED", "TEXEL0",
121
"TEXEL1", "PRIMITIVE",
122
"SHADE", "ENVIORNMENT",
123
"1", "0" };
124
125
const char *Alpha0[8] = { "COMBINED", "TEXEL0",
126
"TEXEL1", "PRIMITIVE",
127
"SHADE", "ENVIORNMENT",
128
"1", "0" };
129
const char *Alpha2[8] = { "LOD_FRACTION", "TEXEL0",
130
"TEXEL1", "PRIMITIVE",
131
"SHADE", "ENVIORNMENT",
132
"PRIM_LODFRAC", "0" };
133
134
//FIXME:unused?
135
//const char *FBLa[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG" };
136
//const char *FBLb[] = { "G_BL_A_IN", "G_BL_A_FOG", "G_BL_A_SHADE", "G_BL_0" };
137
//const char *FBLc[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG"};
138
//const char *FBLd[] = { "G_BL_1MA", "G_BL_A_MEM", "G_BL_1", "G_BL_0" };
139
140
const char *str_zs[2] = { "G_ZS_PIXEL", "G_ZS_PRIM" };
141
142
const char *str_yn[2] = { "NO", "YES" };
143
const char *str_offon[2] = { "OFF", "ON" };
144
145
const char *str_cull[4] = { "DISABLE", "FRONT", "BACK", "BOTH" };
146
147
// I=intensity probably
148
const char *str_format[8] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
149
const char *str_size[4] = { "4bit", "8bit", "16bit", "32bit" };
150
const char *str_cm[4] = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" };
151
152
//const char *str_lod[] = { "1", "2", "4", "8", "16", "32", "64", "128", "256" };
153
//const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" };
154
155
const char *str_filter[3] = { "Point Sampled", "Average (box)", "Bilinear" };
156
157
const char *str_tlut[4] = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" };
158
159
const char *CIStatus[10] = { "ci_main", "ci_zimg", "ci_unknown", "ci_useless",
160
"ci_old_copy", "ci_copy", "ci_copy_self",
161
"ci_zcopy", "ci_aux", "ci_aux_copy" };
162
163
typedef struct
164
{
165
int ucode;
166
int crc;
167
} UcodeData;
168
169
static UcodeData UcodeList[] =
170
{
171
{0, 0x006bd77f},
172
{2, 0x03044b84},
173
{2, 0x030f4b84},
174
{1, 0x05165579},
175
{1, 0x05777c62},
176
{1, 0x057e7c62},
177
{1, 0x07200895},
178
{2, 0x0bf36d36},
179
{-1, 0x0d7bbffb},
180
{5, 0x0d7cbffb},
181
{2, 0x0ff79527},
182
{-1, 0x0ff795bf},
183
{1, 0x1118b3e0},
184
{2, 0x168e9cd5},
185
{2, 0x1a1e18a0},
186
{2, 0x1a1e1920},
187
{2, 0x1a62dbaf},
188
{2, 0x1a62dc2f},
189
{1, 0x1de712ff},
190
{6, 0x1ea9e30f},
191
{2, 0x21f91834},
192
{2, 0x21f91874},
193
{2, 0x22099872},
194
{1, 0x24cd885b},
195
{1, 0x26a7879a},
196
{6, 0x299d5072},
197
{2, 0x2b291027},
198
{6, 0x2b5a89c2},
199
{1, 0x2c7975d6},
200
{2, 0x2f71d1d5},
201
{2, 0x2f7dd1d5},
202
{1, 0x327b933d},
203
{1, 0x339872a6},
204
{2, 0x377359b6},
205
{0, 0x3a1c2b34},
206
{0, 0x3a1cbac3},
207
{0, 0x3f7247fb},
208
{1, 0x3ff1a4ca},
209
{0, 0x4165e1fd},
210
{1, 0x4340ac9b},
211
{1, 0x440cfad6},
212
{7, 0x47d46e86},
213
{2, 0x485abff2},
214
{1, 0x4fe6df78},
215
{0, 0x5182f610},
216
{1, 0x5257cd2a},
217
{1, 0x5414030c},
218
{1, 0x5414030d},
219
{1, 0x559ff7d4},
220
{4, 0x5b5d36e3},
221
{3, 0x5b5d3763},
222
{0, 0x5d1d6f53},
223
{2, 0x5d3099f1},
224
{1, 0x5df1408c},
225
{1, 0x5ef4e34a},
226
{1, 0x6075e9eb},
227
{1, 0x60c1dcc4},
228
{2, 0x6124a508},
229
{2, 0x630a61fb},
230
{5, 0x63be08b1},
231
{5, 0x63be08b3},
232
{1, 0x64ed27e5},
233
{2, 0x65201989},
234
{2, 0x65201a09},
235
{1, 0x66c0b10a},
236
{2, 0x679e1205},
237
{6, 0x6bb745c9},
238
{2, 0x6d8f8f8a},
239
{0, 0x6e4d50af},
240
{1, 0x6eaa1da8},
241
{1, 0x72a4f34e},
242
{1, 0x73999a23},
243
{6, 0x74af0a74},
244
{2, 0x753be4a5},
245
{6, 0x794c3e28},
246
{1, 0x7df75834},
247
{1, 0x7f2d0a2e},
248
{1, 0x82f48073},
249
{1, 0x841ce10f},
250
{-1, 0x844b55b5},
251
{1, 0x863e1ca7},
252
{-1, 0x86b1593e},
253
{1, 0x8805ffea},
254
{1, 0x8d5735b2},
255
{1, 0x8d5735b3},
256
{-1, 0x8ec3e124},
257
{2, 0x93d11f7b},
258
{2, 0x93d11ffb},
259
{2, 0x93d1ff7b},
260
{2, 0x9551177b},
261
{2, 0x955117fb},
262
{2, 0x95cd0062},
263
{1, 0x97d1b58a},
264
{2, 0xa2d0f88e},
265
{1, 0xa346a5cc},
266
{2, 0xaa86cb1d},
267
{2, 0xaae4a5b9},
268
{2, 0xad0a6292},
269
{2, 0xad0a6312},
270
{0, 0xae08d5b9},
271
{1, 0xb1821ed3},
272
{1, 0xb4577b9c},
273
{0, 0xb54e7f93},
274
{2, 0xb62f900f},
275
{2, 0xba65ea1e},
276
{8, 0xba86cb1d},
277
{0, 0xbc03e969},
278
{2, 0xbc45382e},
279
{1, 0xbe78677c},
280
{1, 0xbed8b069},
281
{1, 0xc3704e41},
282
{1, 0xc46dbc3d},
283
{1, 0xc99a4c6c},
284
{2, 0xc901ce73},
285
{2, 0xc901cef3},
286
{2, 0xcb8c9b6c},
287
{1, 0xcee7920f},
288
{2, 0xcfa35a45},
289
{1, 0xd1663234},
290
{6, 0xd20dedbf},
291
{1, 0xd2a9f59c},
292
{1, 0xd41db5f7},
293
{0, 0xd5604971},
294
{1, 0xd57049a5},
295
{-1, 0xd5c4dc96},
296
{0, 0xd5d68b1f},
297
{1, 0xd802ec04},
298
{2, 0xda13ab96},
299
{2, 0xde7d67d4},
300
{2, 0xe1290fa2},
301
{0, 0xe41ec47e},
302
{2, 0xe65cb4ad},
303
{1, 0xe89c2b92},
304
{1, 0xe9231df2},
305
{1, 0xec040469},
306
{1, 0xee47381b},
307
{1, 0xef54ee35},
308
{-1, 0xf9893f70},
309
{1, 0xfb816260},
310
{-1, 0xff372492}
311
};
312
313
// ZIGGY
314
// depth save/restore variables
315
// 0 : normal mode
316
// 1 : writing in normal depth buffer
317
// 2 : writing in alternate depth buffer
318
static int render_depth_mode;
319
320
// ** RDP graphics functions **
321
static void undef();
322
static void spnoop();
323
324
static void rdp_noop();
325
static void rdp_texrect();
326
//static void rdp_texrectflip();
327
static void rdp_loadsync();
328
static void rdp_pipesync();
329
static void rdp_tilesync();
330
static void rdp_fullsync();
331
static void rdp_setkeygb();
332
static void rdp_setkeyr();
333
static void rdp_setconvert();
334
static void rdp_setscissor();
335
static void rdp_setprimdepth();
336
static void rdp_setothermode();
337
static void rdp_loadtlut();
338
static void rdp_settilesize();
339
static void rdp_loadblock();
340
static void rdp_loadtile();
341
static void rdp_settile();
342
static void rdp_fillrect();
343
static void rdp_setfillcolor();
344
static void rdp_setfogcolor();
345
static void rdp_setblendcolor();
346
static void rdp_setprimcolor();
347
static void rdp_setenvcolor();
348
static void rdp_setcombine();
349
static void rdp_settextureimage();
350
static void rdp_setdepthimage();
351
static void rdp_setcolorimage();
352
static void rdp_trifill();
353
static void rdp_trishade();
354
static void rdp_tritxtr();
355
static void rdp_trishadetxtr();
356
static void rdp_trifillz();
357
static void rdp_trishadez();
358
static void rdp_tritxtrz();
359
static void rdp_trishadetxtrz();
360
361
static void rsp_reserved0();
362
static void rsp_reserved1();
363
static void rsp_reserved2();
364
static void rsp_reserved3();
365
366
static void ys_memrect();
367
368
BYTE microcode[4096];
369
DWORD uc_crc;
370
void microcheck ();
371
372
// ** UCODE FUNCTIONS **
373
#include "Ucode00.h"
374
#include "ucode01.h"
375
#include "ucode02.h"
376
#include "ucode03.h"
377
#include "ucode04.h"
378
#include "ucode05.h"
379
#include "ucode06.h"
380
#include "ucode07.h"
381
#include "ucode08.h"
382
#include "ucode.h"
383
384
static BOOL reset = 0;
385
static int old_ucode = -1;
386
387
// rdp_reset - resets the RDP_E
388
void rdp_reset ()
389
{
390
reset = 1;
391
392
rdp.model_i = 0;
393
394
rdp.n_cached[0] = 0;
395
rdp.n_cached[1] = 0;
396
rdp.cur_cache[0] = NULL;
397
rdp.cur_cache[1] = NULL;
398
/*
399
rdp.tmem_ptr[0] = offset_textures;
400
rdp.tmem_ptr[1] = offset_textures;
401
if (grTextureBufferExt)
402
rdp.tmem_ptr[1] = TEXMEM_2MB_EDGE * 2;
403
*/
404
rdp.c_a0 = 0;
405
rdp.c_b0 = 0;
406
rdp.c_c0 = 0;
407
rdp.c_d0 = 0;
408
rdp.c_Aa0 = 0;
409
rdp.c_Ab0 = 0;
410
rdp.c_Ac0 = 0;
411
rdp.c_Ad0 = 0;
412
413
rdp.c_a1 = 0;
414
rdp.c_b1 = 0;
415
rdp.c_c1 = 0;
416
rdp.c_d1 = 0;
417
rdp.c_Aa1 = 0;
418
rdp.c_Ab1 = 0;
419
rdp.c_Ac1 = 0;
420
rdp.c_Ad1 = 0;
421
422
// Clear the palette CRC
423
int i;
424
for (i=0; i<16; i++)
425
rdp.pal_8_crc[i] = 0;
426
427
// Clear the palettes
428
for (i=0; i<256; i++)
429
rdp.pal_8[i] = 0;
430
431
rdp.tlut_mode = 0;
432
433
// Clear all segments ** VERY IMPORTANT FOR ZELDA **
434
for (i=0; i<16; i++)
435
rdp.segment[i] = 0;
436
437
for (i=0; i<512; i++)
438
rdp.addr[i] = 0;
439
440
// set all vertex numbers
441
for (i=0; i<MAX_VTX; i++)
442
rdp.vtx[i].number = i;
443
444
rdp.scissor_o.ul_x = 0;
445
rdp.scissor_o.ul_y = 0;
446
rdp.scissor_o.lr_x = 320;
447
rdp.scissor_o.lr_y = 240;
448
rdp.num_lights = 0;
449
rdp.lookat[0][0] = rdp.lookat[1][1] = 1.0f;
450
rdp.lookat[0][1] = rdp.lookat[0][2] = rdp.lookat[1][0] = rdp.lookat[1][2] = 0.0f;
451
rdp.texrecting = 0;
452
rdp.rm = 0;
453
rdp.render_mode_changed = 0;
454
rdp.othermode_h = 0;
455
rdp.othermode_l = 0;
456
457
rdp.tex_ctr = 0;
458
459
rdp.tex = 0;
460
461
rdp.cimg = 0;
462
rdp.ocimg = 0;
463
rdp.zimg = 0;
464
rdp.ci_width = 0;
465
rdp.cycle_mode = 2;
466
467
rdp.allow_combine = 1;
468
469
rdp.fog_coord_enabled = FALSE;
470
rdp.skip_drawing = FALSE;
471
472
memset(rdp.frame_buffers, 0, sizeof(rdp.frame_buffers));
473
rdp.main_ci_index = 0;
474
rdp.maincimg[0].addr = rdp.maincimg[1].addr = rdp.last_drawn_ci_addr = 0x7FFFFFFF;
475
rdp.read_previous_ci = FALSE;
476
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
477
rdp.yuv_im_begin = 0x00FFFFFF;
478
rdp.yuv_image = FALSE;
479
rdp.cur_tex_buf = 0;
480
rdp.acc_tex_buf = 0;
481
rdp.cur_image = 0;
482
rdp.hires_tex = 0;
483
484
hotkey_info.fb_always = 0;
485
hotkey_info.fb_motionblur = (settings.buff_clear == 0)?0:60;
486
hotkey_info.filtering = hotkey_info.fb_motionblur;
487
hotkey_info.corona = hotkey_info.fb_motionblur;
488
#ifdef _WIN32
489
GetAsyncKeyState (VK_BACK);
490
GetAsyncKeyState(0x42);
491
GetAsyncKeyState(0x56);
492
GetAsyncKeyState(0x43);
493
#endif // _WIN32
494
for (i = 0; i < num_tmu; i++)
495
rdp.texbufs[i].count = 0;
496
rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
497
rdp.view_scale[0] = 160.0f * rdp.scale_x;
498
rdp.view_scale[1] = -120.0f * rdp.scale_y;
499
rdp.view_trans[0] = 160.0f * rdp.scale_x;
500
rdp.view_trans[1] = 120.0f * rdp.scale_y;
501
rdp.view_scale[2] = 32.0f * 511.0f;
502
rdp.view_trans[2] = 32.0f * 511.0f;
503
}
504
505
# define PCEndian
506
# ifdef PCEndian
507
# define ByteEndian(address) (address^3)
508
# define WordEndian(address) (address^2)
509
# endif
510
# define _Read8Endian(array, address) (*((BYTE *)(array+ByteEndian(address))))
511
__inline static DWORD searchrdram(const char *ct)
512
{
513
DWORD pos, pos2;
514
const char *t;
515
t = ct;
516
for (pos=0; pos<0x400000; pos++) {
517
for (pos2=pos, t=ct; *ct != 0; t++, pos2++) {
518
if (_Read8Endian(gfx.RDRAM, pos2) != *t)
519
break;
520
else
521
if (*(t + 1) == 0)
522
return pos;
523
}
524
}
525
return 0;
526
}
527
528
int LookupUcode (int crc)
529
{
530
for (int i = 0; i < sizeof(UcodeList)/sizeof(UcodeData); i++)
531
{
532
if (crc == UcodeList[i].crc)
533
{
534
return UcodeList[i].ucode;
535
}
536
}
537
538
return -2;
539
}
540
541
void microcheck ()
542
{
543
DWORD i;
544
uc_crc = 0;
545
546
// Check first 3k of ucode, because the last 1k sometimes contains trash
547
for (i=0; i<3072>>2; i++)
548
{
549
uc_crc += ((DWORD*)microcode)[i];
550
}
551
552
FRDP_E ("crc: %08lx\n", uc_crc);
553
554
#ifdef LOG_UCODE
555
std::ofstream ucf;
556
ucf.open ("ucode.txt", ios::out | ios::binary);
557
char d;
558
for (i=0; i<0x400000; i++)
559
{
560
d = ((char*)gfx.RDRAM)[i^3];
561
ucf.write (&d, 1);
562
}
563
ucf.close ();
564
#endif
565
566
char str[9];
567
sprintf (str, "%08lx", (unsigned long)uc_crc);
568
569
FRDP("ucode = %s\n", str);
570
int uc = LookupUcode(uc_crc);
571
WriteLog(M64MSG_INFO, "ucode = %d\n", uc);
572
if (uc == -2 && ucode_error_report)
573
{
574
Config_Open();
575
settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE);
576
577
ReleaseGfx ();
578
WriteLog(M64MSG_ERROR, "Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc);
579
580
ucode_error_report = FALSE; // don't report any more ucode errors from this game
581
}
582
else if (uc == -1 && ucode_error_report)
583
{
584
Config_Open();
585
settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE);
586
587
ReleaseGfx ();
588
WriteLog(M64MSG_ERROR, "Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc);
589
590
ucode_error_report = FALSE; // don't report any more ucode errors from this game
591
}
592
else
593
{
594
old_ucode = settings.ucode;
595
settings.ucode = uc;
596
FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode, uc);
597
}
598
}
599
600
void drawNoFullscreenMessage()
601
{
602
LOG ("drawNoFullscreenMessage ()\n");
603
}
604
605
static WORD yuv_to_rgb(BYTE y, BYTE u, BYTE v)
606
{
607
float r = y + (1.370705f * (v-128));
608
float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128));
609
float b = y + (1.732446f * (u-128));
610
r *= 0.125f;
611
g *= 0.125f;
612
b *= 0.125f;
613
//clipping the result
614
if (r > 32) r = 32;
615
if (g > 32) g = 32;
616
if (b > 32) b = 32;
617
if (r < 0) r = 0;
618
if (g < 0) g = 0;
619
if (b < 0) b = 0;
620
621
WORD c = (WORD)(((WORD)(r) << 11) |
622
((WORD)(g) << 6) |
623
((WORD)(b) << 1) | 1);
624
return c;
625
}
626
627
static void DrawYUVImageToFrameBuffer()
628
{
629
WORD width = (WORD)(rdp.yuv_lr_x - rdp.yuv_ul_x);
630
WORD height = (WORD)(rdp.yuv_lr_y - rdp.yuv_ul_y);
631
DWORD * mb = (DWORD*)(gfx.RDRAM+rdp.yuv_im_begin); //pointer to the first macro block
632
WORD * cimg = (WORD*)(gfx.RDRAM+rdp.cimg);
633
//yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg
634
for (WORD y = 0; y < height; y+=16)
635
{
636
for (WORD x = 0; x < width; x+=16)
637
{
638
WORD *dst = cimg + x + y * rdp.ci_width;
639
for (WORD h = 0; h < 16; h++)
640
{
641
for (WORD w = 0; w < 8; w++)
642
{
643
DWORD t = *(mb++); //each DWORD contains 2 pixels
644
if ((x < rdp.ci_width) && (y < rdp.ci_height)) //clipping. texture image may be larger than color image
645
{
646
BYTE y0 = (BYTE)t&0xFF;
647
BYTE v = (BYTE)(t>>8)&0xFF;
648
BYTE y1 = (BYTE)(t>>16)&0xFF;
649
BYTE u = (BYTE)(t>>24)&0xFF;
650
*(dst++) = yuv_to_rgb(y0, u, v);
651
*(dst++) = yuv_to_rgb(y1, u, v);
652
}
653
}
654
dst += rdp.ci_width - 16;
655
}
656
mb += 64; //macro block is 768 bytes long, last 256 bytes are useless
657
}
658
}
659
}
660
661
static DWORD d_ul_x, d_ul_y, d_lr_x, d_lr_y;
662
663
typedef struct {
664
int ul_x, ul_y, lr_x, lr_y;
665
} FB_PART;
666
667
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)
668
{
669
WORD * dst = new WORD[width*height];
670
DWORD shift = ((d_ul_y+prt_ul_y) * rdp.ci_width + d_ul_x + prt_ul_x) << 1;
671
WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
672
WORD c;
673
for (int y=0; y < height; y++)
674
{
675
for (int x=0; x < width; x++)
676
{
677
c = src[(int(x*scale_x)+int(y*scale_y)*rdp.ci_width)^1];
678
dst[x+y*width] = c?((c >> 1) | 0x8000):0;
679
}
680
}
681
682
grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
683
scr_ul_x,
684
scr_ul_y,
685
GR_LFB_SRC_FMT_1555,
686
width,
687
height,
688
FXTRUE,
689
width<<1,
690
dst);
691
delete[] dst;
692
}
693
694
static void DrawFrameBufferToScreen()
695
{
696
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);
697
if (!fullscreen)
698
return;
699
grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
700
GR_COMBINE_FACTOR_ONE,
701
GR_COMBINE_LOCAL_NONE,
702
GR_COMBINE_OTHER_TEXTURE,
703
FXFALSE);
704
grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
705
GR_COMBINE_FACTOR_ONE,
706
GR_COMBINE_LOCAL_NONE,
707
GR_COMBINE_OTHER_TEXTURE,
708
FXFALSE);
709
grConstantColorValue (0xFFFFFFFF);
710
grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
711
GR_BLEND_ONE_MINUS_SRC_ALPHA,
712
GR_BLEND_ONE,
713
GR_BLEND_ZERO);
714
rdp.update |= UPDATE_COMBINE;
715
716
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);
717
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);
718
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);
719
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);
720
int src_width = d_lr_x - d_ul_x + 1;
721
int src_height = d_lr_y - d_ul_y + 1;
722
int dst_width, dst_height, ul_x, ul_y;
723
724
if (!settings.fb_optimize_write || ((src_width < 33) && (src_height < 33)))
725
{
726
dst_width = int(src_width*scale_x_dst);
727
dst_height = int(src_height*scale_y_dst);
728
ul_x = int(d_ul_x*scale_x_dst);
729
ul_y = int(d_ul_y*scale_y_dst);
730
DrawPart(ul_x, ul_y, 0, 0, dst_width, dst_height, scale_x_src, scale_y_src);
731
memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
732
return;
733
}
734
735
FB_PART parts[8];
736
int p;
737
for (p = 0; p < 8; p++)
738
{
739
parts[p].lr_x = parts[p].lr_y = 0;
740
parts[p].ul_x = parts[p].ul_y = 0xFFFF;
741
}
742
743
int num_of_parts = 0;
744
int cur_part = 0;
745
int most_left = d_ul_x;
746
int most_right = d_lr_x;
747
DWORD shift = (d_ul_y * rdp.ci_width + d_ul_x) << 1;
748
WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
749
for (int h = 0; h < src_height; h++)
750
{
751
cur_part = 0;
752
int w = 0;
753
while (w < src_width)
754
{
755
while (w < src_width)
756
{
757
if (src[(w+h*rdp.ci_width)^1] == 0)
758
w++;
759
else
760
break;
761
}
762
if (w == src_width)
763
break;
764
if (num_of_parts == 0) //first part
765
{
766
parts[0].ul_x = w;
767
most_left = w;
768
parts[0].ul_y = h;
769
cur_part = 0;
770
}
771
else if (w < most_left - 2) //new part
772
{
773
parts[num_of_parts].ul_x = w;
774
most_left = w;
775
parts[num_of_parts].ul_y = h;
776
cur_part = num_of_parts;
777
num_of_parts++;
778
}
779
else if (w > most_right + 2) //new part
780
{
781
parts[num_of_parts].ul_x = w;
782
most_right = w;
783
parts[num_of_parts].ul_y = h;
784
cur_part = num_of_parts;
785
num_of_parts++;
786
}
787
else
788
{
789
for (p = 0; p < num_of_parts; p++)
790
{
791
if ((w > parts[p].ul_x - 2) && (w < parts[p].lr_x+2))
792
{
793
if (w < parts[p].ul_x) parts[p].ul_x = w;
794
break;
795
}
796
}
797
cur_part = p;
798
}
799
while (w < src_width)
800
{
801
if (src[(w+h*rdp.ci_width)^1] != 0)
802
w++;
803
else
804
break;
805
}
806
if (num_of_parts == 0) //first part
807
{
808
parts[0].lr_x = w;
809
most_right = w;
810
num_of_parts++;
811
}
812
else
813
{
814
if (parts[cur_part].lr_x < w) parts[cur_part].lr_x = w;
815
if (most_right < w) most_right = w;
816
parts[cur_part].lr_y = h;
817
}
818
}
819
}
820
/*
821
for (p = 0; p < num_of_parts; p++)
822
{
823
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);
824
}
825
*/
826
for (p = 0; p < num_of_parts; p++)
827
{
828
dst_width = int((parts[p].lr_x-parts[p].ul_x + 1)*scale_x_dst);
829
dst_height = int((parts[p].lr_y-parts[p].ul_y + 1)*scale_y_dst);
830
ul_x = int((d_ul_x+parts[p].ul_x)*scale_x_dst);
831
ul_y = int((d_ul_y+parts[p].ul_y)*scale_y_dst);
832
DrawPart(ul_x, ul_y, parts[p].ul_x, parts[p].ul_y, dst_width, dst_height, scale_x_src, scale_y_src);
833
}
834
memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
835
}
836
837
#define RGBA16TO32(color) \
838
((color&1)?0xFF:0) | \
839
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \
840
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \
841
((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8)
842
843
static void CopyFrameBuffer (GrBuffer_t buffer = GR_BUFFER_BACKBUFFER)
844
{
845
if (!fullscreen)
846
return;
847
FRDP ("CopyFrameBuffer: %08lx... ", rdp.cimg);
848
849
// don't bother to write the stuff in asm... the slow part is the read from video card,
850
// not the copy.
851
852
int width = rdp.ci_width;//*gfx.VI_WIDTH_REG;
853
int height;
854
if (settings.fb_smart && !settings.PPL)
855
{
856
int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0;
857
height = rdp.frame_buffers[ind].height;
858
}
859
else
860
{
861
height = rdp.ci_lower_bound;
862
if (settings.PPL)
863
height -= rdp.ci_upper_bound;
864
}
865
FRDP ("width: %d, height: %d... ", width, height);
866
867
if (rdp.scale_x < 1.1f)
868
{
869
WORD * ptr_src = new WORD[width*height];
870
if (grLfbReadRegion(buffer,
871
0,
872
0,//rdp.ci_upper_bound,
873
width,
874
height,
875
width<<1,
876
ptr_src))
877
{
878
WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
879
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
880
WORD c;
881
882
for (int y=0; y<height; y++)
883
{
884
for (int x=0; x<width; x++)
885
{
886
c = ptr_src[x + y * width];
887
if (settings.fb_read_alpha)
888
{
889
if (c > 0)
890
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
891
}
892
else
893
{
894
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
895
}
896
if (rdp.ci_size == 2)
897
ptr_dst[(x + y * width)^1] = c;
898
else
899
ptr_dst32[x + y * width] = RGBA16TO32(c);
900
}
901
}
902
/*
903
}
904
else //8bit I or CI
905
{
906
BYTE *ptr_dst = (BYTE*)(gfx.RDRAM+rdp.cimg);
907
WORD c;
908
909
for (int y=0; y<height; y++)
910
{
911
for (int x=0; x<width; x++)
912
{
913
c = ptr_src[x + y * width];
914
BYTE b = (BYTE)((float)(c&0x1F)/31.0f*85.0f);
915
BYTE g = (BYTE)((float)((c>>5)&0x3F)/63.0f*85.0f);
916
BYTE r = (BYTE)((float)((c>>11)&0x1F)/31.0f*85.0f);
917
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
918
// FRDP("src: %08lx, dst: %d\n",c,(BYTE)(r+g+b));
919
ptr_dst[(x + y * width)^1] = (BYTE)(r+g+b);
920
// ptr_dst[(x + y * width)^1] = (BYTE)((c>>8)&0xFF);
921
}
922
}
923
} */
924
RDP ("ReadRegion. Framebuffer copy complete.\n");
925
}
926
else
927
{
928
RDP ("Framebuffer copy failed.\n");
929
}
930
delete[] ptr_src;
931
}
932
else
933
{
934
if (rdp.motionblur && settings.fb_hires)
935
{
936
return;
937
}
938
else
939
{
940
float scale_x = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
941
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);
942
943
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);
944
GrLfbInfo_t info;
945
info.size = sizeof(GrLfbInfo_t);
946
947
948
// VP 888 disconnected for now
949
if (1||rdp.ci_size <= 2) {
950
if (grLfbLock (GR_LFB_READ_ONLY,
951
buffer,
952
GR_LFBWRITEMODE_565,
953
GR_ORIGIN_UPPER_LEFT,
954
FXFALSE,
955
&info))
956
{
957
WORD *ptr_src = (WORD*)info.lfbPtr;
958
WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
959
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
960
WORD c;
961
DWORD stride = info.strideInBytes>>1;
962
963
BOOL read_alpha = settings.fb_read_alpha;
964
if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux)
965
read_alpha = FALSE;
966
for (int y=0; y<height; y++)
967
{
968
for (int x=0; x<width; x++)
969
{
970
c = ptr_src[int(x*scale_x) + int(y * scale_y) * stride];
971
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
972
if (read_alpha && c == 1)
973
c = 0;
974
if (rdp.ci_size <= 2)
975
ptr_dst[(x + y * width)^1] = c;
976
else
977
ptr_dst32[x + y * width] = RGBA16TO32(c);
978
}
979
}
980
981
// Unlock the backbuffer
982
grLfbUnlock (GR_LFB_READ_ONLY, buffer);
983
RDP ("LfbLock. Framebuffer copy complete.\n");
984
}
985
else
986
{
987
RDP ("Framebuffer copy failed.\n");
988
}
989
990
} else {
991
992
if (grLfbLock (GR_LFB_READ_ONLY,
993
buffer,
994
GR_LFBWRITEMODE_888,
995
GR_ORIGIN_UPPER_LEFT,
996
FXFALSE,
997
&info))
998
{
999
DWORD *ptr_src = (DWORD*)info.lfbPtr;
1000
//FIXME: Why unused?
1001
//WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
1002
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
1003
DWORD c;
1004
DWORD stride = info.strideInBytes>>1;
1005
1006
for (int y=0; y<height; y++)
1007
{
1008
for (int x=0; x<width; x++)
1009
{
1010
c = ptr_src[int(x*scale_x) + int(y * scale_y) * stride];
1011
ptr_dst32[x + y * width] = c;
1012
}
1013
}
1014
1015
// Unlock the backbuffer
1016
grLfbUnlock (GR_LFB_READ_ONLY, buffer);
1017
RDP ("LfbLock. Framebuffer copy complete.\n");
1018
}
1019
else
1020
{
1021
RDP ("Framebuffer copy failed.\n");
1022
}
1023
}
1024
}
1025
}
1026
}
1027
1028
/******************************************************************
1029
Function: ProcessDList
1030
Purpose: This function is called when there is a Dlist to be
1031
processed. (High level GFX list)
1032
input: none
1033
output: none
1034
*******************************************************************/
1035
void DetectFrameBufferUsage ();
1036
DWORD fbreads_front = 0;
1037
DWORD fbreads_back = 0;
1038
BOOL cpu_fb_read_called = FALSE;
1039
BOOL cpu_fb_write_called = FALSE;
1040
BOOL cpu_fb_write = FALSE;
1041
BOOL cpu_fb_ignore = FALSE;
1042
BOOL CI_SET = TRUE;
1043
1044
#ifdef __cplusplus
1045
extern "C" {
1046
#endif
1047
1048
EXPORT void CALL ProcessDList(void)
1049
{
1050
no_dlist = FALSE;
1051
update_screen_count = 0;
1052
ChangeSize ();
1053
1054
#ifdef ALTTAB_FIX
1055
if (!hhkLowLevelKybd)
1056
{
1057
hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
1058
LowLevelKeyboardProc, hInstance, 0);
1059
}
1060
#endif
1061
1062
LOG ("ProcessDList ()\n");
1063
1064
if (!fullscreen)
1065
{
1066
drawNoFullscreenMessage();
1067
// Set an interrupt to allow the game to continue
1068
*gfx.MI_INTR_REG |= 0x20;
1069
gfx.CheckInterrupts();
1070
}
1071
1072
if (reset)
1073
{
1074
reset = 0;
1075
1076
memset (microcode, 0, 4096);
1077
if (settings.autodetect_ucode)
1078
{
1079
// Thanks to ZeZu for ucode autodetection!!!
1080
1081
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
1082
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
1083
microcheck ();
1084
1085
}
1086
}
1087
else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
1088
{
1089
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
1090
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
1091
microcheck ();
1092
}
1093
1094
if (exception) return;
1095
1096
// Switch to fullscreen?
1097
if (to_fullscreen)
1098
{
1099
to_fullscreen = FALSE;
1100
1101
if (!InitGfx (FALSE))
1102
{
1103
LOG ("FAILED!!!\n");
1104
return;
1105
}
1106
fullscreen = TRUE;
1107
}
1108
1109
// Clear out the RDP log
1110
#ifdef RDP_LOGGING
1111
if (settings.logging && settings.log_clear)
1112
{
1113
CLOSE_RDP_LOG ();
1114
OPEN_RDP_LOG ();
1115
}
1116
#endif
1117
1118
#ifdef UNIMP_LOG
1119
if (settings.log_unk && settings.unk_clear)
1120
{
1121
std::ofstream unimp;
1122
unimp.open("unimp.txt");
1123
unimp.close();
1124
}
1125
#endif
1126
1127
//* Set states *//
1128
if (settings.swapmode > 0)
1129
SwapOK = TRUE;
1130
rdp.updatescreen = 1;
1131
1132
rdp.tri_n = 0; // 0 triangles so far this frame
1133
rdp.debug_n = 0;
1134
1135
rdp.model_i = 0; // 0 matrices so far in stack
1136
//stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin!
1137
rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
1138
if (rdp.model_stack_size == 0)
1139
rdp.model_stack_size = 32;
1140
rdp.fb_drawn = rdp.fb_drawn_front = FALSE;
1141
rdp.update = 0x7FFFFFFF; // All but clear cache
1142
rdp.geom_mode = 0;
1143
rdp.acmp = 0;
1144
rdp.maincimg[1] = rdp.maincimg[0];
1145
rdp.skip_drawing = FALSE;
1146
rdp.s2dex_tex_loaded = FALSE;
1147
fbreads_front = fbreads_back = 0;
1148
rdp.fog_multiplier = rdp.fog_offset = 0;
1149
rdp.zsrc = 0;
1150
1151
if (cpu_fb_write == TRUE)
1152
DrawFrameBufferToScreen();
1153
cpu_fb_write = FALSE;
1154
cpu_fb_read_called = FALSE;
1155
cpu_fb_write_called = FALSE;
1156
cpu_fb_ignore = FALSE;
1157
d_ul_x = 0xffff;
1158
d_ul_y = 0xffff;
1159
d_lr_x = 0;
1160
d_lr_y = 0;
1161
1162
//analize possible frame buffer usage
1163
if (settings.fb_smart)
1164
DetectFrameBufferUsage();
1165
if (!settings.lego || rdp.num_of_ci > 1)
1166
rdp.last_bg = 0;
1167
//* End of set states *//
1168
1169
1170
// Get the start of the display list and the length of it
1171
DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
1172
DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
1173
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);
1174
FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
1175
1176
if (settings.tonic && dlist_length < 16)
1177
{
1178
rdp_fullsync();
1179
FRDP_E("DLIST is too short!\n");
1180
return;
1181
}
1182
1183
// Start executing at the start of the display list
1184
rdp.pc_i = 0;
1185
rdp.pc[rdp.pc_i] = dlist_start;
1186
rdp.dl_count = -1;
1187
rdp.halt = 0;
1188
DWORD a;
1189
1190
// catches exceptions so that it doesn't freeze
1191
#ifdef CATCH_EXCEPTIONS
1192
try {
1193
#endif
1194
1195
// MAIN PROCESSING LOOP
1196
do {
1197
1198
// Get the address of the next command
1199
a = rdp.pc[rdp.pc_i] & BMASK;
1200
1201
// Load the next command and its input
1202
rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
1203
rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
1204
// cmd2 and cmd3 are filled only when needed, by the function that needs them
1205
1206
// Output the address before the command
1207
#ifdef LOG_COMMANDS
1208
FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1);
1209
#else
1210
FRDP ("%08lx: ", a);
1211
#endif
1212
1213
// Go to the next instruction
1214
rdp.pc[rdp.pc_i] = (a+8) & BMASK;
1215
1216
#ifdef PERFORMANCE
1217
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
1218
#endif
1219
// Process this instruction
1220
gfx_instruction[settings.ucode][rdp.cmd0>>24] ();
1221
1222
// check DL counter
1223
if (rdp.dl_count != -1)
1224
{
1225
rdp.dl_count --;
1226
if (rdp.dl_count == 0)
1227
{
1228
rdp.dl_count = -1;
1229
1230
RDP ("End of DL\n");
1231
rdp.pc_i --;
1232
}
1233
}
1234
1235
#ifdef PERFORMANCE
1236
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
1237
__int64 t = perf_next-perf_cur;
1238
sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
1239
rdp_log << out_buf;
1240
#endif
1241
1242
} while (!rdp.halt);
1243
#ifdef CATCH_EXCEPTIONS
1244
} catch (...) {
1245
1246
if (fullscreen) ReleaseGfx ();
1247
WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled.");
1248
exception = TRUE;
1249
}
1250
#endif
1251
1252
if (settings.fb_smart)
1253
{
1254
rdp.scale_x = rdp.scale_x_bak;
1255
rdp.scale_y = rdp.scale_y_bak;
1256
}
1257
if (settings.fb_read_always)
1258
{
1259
CopyFrameBuffer ();
1260
}
1261
if (rdp.yuv_image)
1262
{
1263
DrawYUVImageToFrameBuffer();
1264
rdp.yuv_image = FALSE;
1265
// FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
1266
// rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
1267
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
1268
rdp.yuv_im_begin = 0x00FFFFFF;
1269
}
1270
if (rdp.cur_image)
1271
CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
1272
1273
if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
1274
{
1275
newSwapBuffers ();
1276
CI_SET = FALSE;
1277
}
1278
RDP("ProcessDList end\n");
1279
}
1280
1281
#ifdef __cplusplus
1282
}
1283
#endif
1284
1285
// undef - undefined instruction, always ignore
1286
static void undef()
1287
{
1288
FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0);
1289
FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0);
1290
#ifdef _FINAL_RELEASE_
1291
*gfx.MI_INTR_REG |= 0x20;
1292
gfx.CheckInterrupts();
1293
rdp.halt = 1;
1294
#endif
1295
}
1296
1297
// spnoop - no operation, always ignore
1298
static void spnoop()
1299
{
1300
RDP("spnoop\n");
1301
}
1302
1303
// noop - no operation, always ignore
1304
static void rdp_noop()
1305
{
1306
RDP("noop\n");
1307
}
1308
1309
static void ys_memrect ()
1310
{
1311
DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
1312
1313
DWORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
1314
DWORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
1315
DWORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
1316
DWORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
1317
1318
rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
1319
1320
if (lr_y > rdp.scissor_o.lr_y) lr_y = rdp.scissor_o.lr_y;
1321
1322
FRDP ("memrect (%d, %d, %d, %d), ci_width: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.ci_width);
1323
1324
DWORD y, width = lr_x - ul_x;
1325
DWORD texaddr = rdp.addr[rdp.tiles[tile].t_mem];
1326
DWORD tex_width = rdp.tiles[tile].line << 3;
1327
1328
for (y = ul_y; y < lr_y; y++) {
1329
BYTE *src = gfx.RDRAM + texaddr + (y - ul_y) * tex_width;
1330
BYTE *dst = gfx.RDRAM + rdp.cimg + ul_x + y * rdp.ci_width;
1331
memcpy (dst, src, width);
1332
}
1333
}
1334
1335
static void pm_palette_mod ()
1336
{
1337
BYTE envr = (BYTE)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f);
1338
BYTE envg = (BYTE)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f);
1339
BYTE envb = (BYTE)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f);
1340
WORD env16 = (WORD)((envr<<11)|(envg<<6)|(envb<<1)|1);
1341
BYTE prmr = (BYTE)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f);
1342
BYTE prmg = (BYTE)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f);
1343
BYTE prmb = (BYTE)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f);
1344
WORD prim16 = (WORD)((prmr<<11)|(prmg<<6)|(prmb<<1)|1);
1345
WORD * dst = (WORD*)(gfx.RDRAM+rdp.cimg);
1346
for (int i = 0; i < 16; i++)
1347
{
1348
dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16;
1349
}
1350
RDP("Texrect palette modification\n");
1351
}
1352
1353
static void rdp_texrect()
1354
{
1355
DWORD a = rdp.pc[rdp.pc_i];
1356
rdp.cmd2 = ((DWORD*)gfx.RDRAM)[(a>>2)+1];
1357
rdp.cmd3 = ((DWORD*)gfx.RDRAM)[(a>>2)+3];
1358
1359
if (settings.ASB) //modified Rice's hack for All-Star Baseball games
1360
{
1361
DWORD dwHalf1 = (((DWORD*)gfx.RDRAM)[(a>>2)+0]) >> 24;
1362
if ((dwHalf1 != 0xF1) && (dwHalf1 != 0xb3))
1363
{
1364
rdp.pc[rdp.pc_i] += 16;
1365
}
1366
else
1367
{
1368
rdp.pc[rdp.pc_i] += 8;
1369
rdp.cmd3 = rdp.cmd2;
1370
rdp.cmd2 = 0;
1371
}
1372
}
1373
else if (settings.yoshi && settings.ucode == 6)
1374
{
1375
ys_memrect();
1376
return;
1377
}
1378
else
1379
{
1380
rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
1381
}
1382
1383
if (rdp.skip_drawing || (!settings.fb_smart && (rdp.cimg == rdp.zimg)))
1384
{
1385
if (settings.PM && rdp.ci_status == ci_useless)
1386
{
1387
pm_palette_mod ();
1388
}
1389
else
1390
{
1391
RDP("Texrect skipped\n");
1392
}
1393
return;
1394
}
1395
1396
if ((settings.ucode == 8) && rdp.cur_image && rdp.cur_image->format)
1397
{
1398
//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);
1399
RDP("Shadow texrect is skipped.\n");
1400
rdp.tri_n += 2;
1401
return;
1402
}
1403
1404
WORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
1405
WORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
1406
WORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
1407
WORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
1408
if (ul_x >= lr_x) return;
1409
if (rdp.cycle_mode > 1 || settings.increase_texrect_edge)
1410
{
1411
lr_x++;
1412
lr_y++;
1413
}
1414
if (ul_y == lr_y)
1415
{
1416
lr_y ++;
1417
}
1418
1419
//*
1420
if (rdp.hires_tex && settings.fb_optimize_texrect)
1421
{
1422
if (!rdp.hires_tex->drawn)
1423
{
1424
DRAWIMAGE d;
1425
d.imageX = 0;
1426
d.imageW = (WORD)rdp.hires_tex->width;
1427
d.frameX = ul_x;
1428
d.frameW = (WORD)(rdp.hires_tex->width);//(WORD)(ul_x + rdp.hires_tex->width);//lr_x;
1429
1430
d.imageY = 0;
1431
d.imageH = (WORD)rdp.hires_tex->height;
1432
d.frameY = ul_y;
1433
d.frameH = (WORD)(rdp.hires_tex->height);//(ul_y + rdp.hires_tex->height);
1434
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);
1435
d.scaleX = 1.0f;
1436
d.scaleY = 1.0f;
1437
DrawHiresImage(&d, rdp.hires_tex->width == rdp.ci_width);
1438
rdp.hires_tex->drawn = TRUE;
1439
}
1440
return;
1441
}
1442
//*/
1443
// framebuffer workaround for Zelda: MM LOT
1444
if ((rdp.othermode_l & 0xFFFF0000) == 0x0f5a0000)
1445
return;
1446
1447
/*Gonetz*/
1448
//hack for Zelda MM. it removes black texrects which cover all geometry in "Link meets Zelda" cut scene
1449
if (settings.zelda && rdp.timg.addr >= rdp.cimg && rdp.timg.addr < rdp.ci_end)
1450
{
1451
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);
1452
rdp.tri_n += 2;
1453
return;
1454
}
1455
//*
1456
//hack for Banjo2. it removes black texrects under Banjo
1457
if (!settings.fb_hires && ((rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF)) == 0xFFFFFFFF && (rdp.othermode_l & 0xFFFF0000) == 0x00500000)
1458
{
1459
rdp.tri_n += 2;
1460
return;
1461
}
1462
//*/
1463
//*
1464
//remove motion blur in night vision
1465
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)))
1466
{
1467
if (settings.fb_smart)
1468
if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self || !settings.fb_motionblur)
1469
{
1470
// 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);
1471
RDP("Wrong Texrect.\n");
1472
rdp.tri_n += 2;
1473
return;
1474
}
1475
}
1476
//*/
1477
1478
int i;
1479
1480
DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
1481
1482
// update MUST be at the beginning, b/c of update_scissor
1483
if (rdp.cycle_mode == 2)
1484
{
1485
rdp.tex = 1;
1486
rdp.allow_combine = 0;
1487
1488
cmb.tmu1_func = cmb.tmu0_func = GR_COMBINE_FUNCTION_LOCAL;
1489
cmb.tmu1_fac = cmb.tmu0_fac = GR_COMBINE_FACTOR_NONE;
1490
cmb.tmu1_a_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;
1491
cmb.tmu1_a_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
1492
cmb.tmu1_invert = cmb.tmu0_invert = FXFALSE;
1493
cmb.tmu1_a_invert = cmb.tmu0_a_invert = FXFALSE;
1494
}
1495
1496
rdp.texrecting = 1;
1497
1498
DWORD prev_tile = rdp.cur_tile;
1499
rdp.cur_tile = tile;
1500
rdp.update |= UPDATE_COMBINE;
1501
update ();
1502
1503
rdp.texrecting = 0;
1504
rdp.allow_combine = 1;
1505
1506
if (!rdp.cur_cache[0])
1507
{
1508
rdp.cur_tile = prev_tile;
1509
rdp.tri_n += 2;
1510
return;
1511
}
1512
// ****
1513
// ** Texrect offset by Gugaman **
1514
float off_x = (float)((short)((rdp.cmd2 & 0xFFFF0000) >> 16)) / 32.0f;
1515
if ((int(off_x) == 512) && (rdp.timg.width < 512)) off_x = 0.0f;
1516
float off_y = (float)((short)(rdp.cmd2 & 0x0000FFFF)) / 32.0f;
1517
float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f;
1518
float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f;
1519
1520
if (rdp.cycle_mode == 2) dsdx /= 4.0f;
1521
1522
float s_ul_x = ul_x * rdp.scale_x + rdp.offset_x;
1523
float s_lr_x = lr_x * rdp.scale_x + rdp.offset_x;
1524
float s_ul_y = ul_y * rdp.scale_y + rdp.offset_y;
1525
float s_lr_y = lr_y * rdp.scale_y + rdp.offset_y;
1526
1527
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);
1528
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);
1529
FRDP("\toff_x: %f, off_y: %f, dsdx: %f, dtdy: %f\n", off_x, off_y, dsdx, dtdy);
1530
1531
float off_size_x;
1532
float off_size_y;
1533
1534
if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1535
{
1536
off_size_x = (float)((lr_y - ul_y - 1) * dsdx);
1537
off_size_y = (float)((lr_x - ul_x - 1) * dtdy);
1538
}
1539
else
1540
{
1541
off_size_x = (float)((lr_x - ul_x - 1) * dsdx);
1542
off_size_y = (float)((lr_y - ul_y - 1) * dtdy);
1543
}
1544
1545
float lr_u0, lr_v0, ul_u0, ul_v0, lr_u1, lr_v1, ul_u1, ul_v1;
1546
1547
if (rdp.cur_cache[0] && (rdp.tex & 1))
1548
{
1549
float sx=1, sy=1;
1550
if (rdp.tiles[rdp.cur_tile].shift_s)
1551
{
1552
if (rdp.tiles[rdp.cur_tile].shift_s > 10)
1553
sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s));
1554
else
1555
sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_s);
1556
}
1557
if (rdp.tiles[rdp.cur_tile].shift_t)
1558
{
1559
if (rdp.tiles[rdp.cur_tile].shift_t > 10)
1560
sy = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t));
1561
else
1562
sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_t);
1563
}
1564
if (rdp.hires_tex && rdp.hires_tex->tile == 0)
1565
{
1566
off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
1567
off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
1568
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);
1569
ul_u0 = off_x * sx;
1570
ul_v0 = off_y * sy;
1571
1572
lr_u0 = ul_u0 + off_size_x * sx;
1573
lr_v0 = ul_v0 + off_size_y * sy;
1574
1575
ul_u0 *= rdp.hires_tex->u_scale;
1576
ul_v0 *= rdp.hires_tex->v_scale;
1577
lr_u0 *= rdp.hires_tex->u_scale;
1578
lr_v0 *= rdp.hires_tex->v_scale;
1579
FRDP("hires_tex ul_u0: %f, ul_v0: %f, lr_u0: %f, lr_v0: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
1580
}
1581
else
1582
{
1583
ul_u0 = off_x * sx;
1584
ul_v0 = off_y * sy;
1585
1586
ul_u0 -= rdp.tiles[rdp.cur_tile].f_ul_s;
1587
ul_v0 -= rdp.tiles[rdp.cur_tile].f_ul_t;
1588
1589
lr_u0 = ul_u0 + off_size_x * sx;
1590
lr_v0 = ul_v0 + off_size_y * sy;
1591
1592
ul_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * ul_u0;
1593
lr_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * lr_u0;
1594
ul_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * ul_v0;
1595
lr_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * lr_v0;
1596
}
1597
}
1598
else
1599
{
1600
ul_u0 = ul_v0 = lr_u0 = lr_v0 = 0;
1601
}
1602
if (rdp.cur_cache[1] && (rdp.tex & 2))
1603
{
1604
float sx=1, sy=1;
1605
1606
if (rdp.tiles[rdp.cur_tile+1].shift_s)
1607
{
1608
if (rdp.tiles[rdp.cur_tile+1].shift_s > 10)
1609
sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s));
1610
else
1611
sx = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_s);
1612
}
1613
if (rdp.tiles[rdp.cur_tile+1].shift_t)
1614
{
1615
if (rdp.tiles[rdp.cur_tile+1].shift_t > 10)
1616
sy = 1;//(float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t));
1617
else
1618
sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_t);
1619
}
1620
1621
if (rdp.hires_tex && rdp.hires_tex->tile == 1)
1622
{
1623
off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
1624
off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
1625
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);
1626
ul_u1 = off_x * sx;
1627
ul_v1 = off_y * sy;
1628
1629
lr_u1 = ul_u1 + off_size_x * sx;
1630
lr_v1 = ul_v1 + off_size_y * sy;
1631
1632
ul_u1 *= rdp.hires_tex->u_scale;
1633
ul_v1 *= rdp.hires_tex->v_scale;
1634
lr_u1 *= rdp.hires_tex->u_scale;
1635
lr_v1 *= rdp.hires_tex->v_scale;
1636
FRDP("hires_tex ul_u1: %f, ul_v1: %f, lr_u1: %f, lr_v1: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
1637
1638
}
1639
else
1640
{
1641
ul_u1 = off_x * sx;
1642
ul_v1 = off_y * sy;
1643
1644
ul_u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s;
1645
ul_v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t;
1646
1647
lr_u1 = ul_u1 + off_size_x * sx;
1648
lr_v1 = ul_v1 + off_size_y * sy;
1649
1650
ul_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * ul_u1;
1651
lr_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * lr_u1;
1652
ul_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * ul_v1;
1653
lr_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * lr_v1;
1654
}
1655
}
1656
else
1657
{
1658
ul_u1 = ul_v1 = lr_u1 = lr_v1 = 0;
1659
}
1660
rdp.cur_tile = prev_tile;
1661
1662
// ****
1663
1664
FRDP (" scissor: (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y);
1665
1666
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);
1667
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);
1668
// 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);
1669
1670
FRDP (" draw at: (%f, %f) -> (%f, %f)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
1671
1672
// DO NOT SET CLAMP MODE HERE
1673
1674
float Z = 1.0f;
1675
if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030)) // othermode check makes sure it
1676
// USES the z-buffer. Otherwise it returns bad (unset) values for lot and telescope
1677
//in zelda:mm.
1678
{
1679
FRDP ("prim_depth = %d\n", rdp.prim_depth);
1680
Z = rdp.prim_depth;
1681
if (settings.increase_primdepth)
1682
Z += 8.0f;
1683
Z = ScaleZ(Z);
1684
1685
grDepthBufferFunction (GR_CMP_LEQUAL);
1686
rdp.update |= UPDATE_ZBUF_ENABLED;
1687
}
1688
else
1689
{
1690
RDP ("no prim_depth used, using 1.0\n");
1691
}
1692
1693
VERTEX vstd[4] = {
1694
{ s_ul_x, s_ul_y, Z, 1.0f, ul_u0, ul_v0, ul_u1, ul_v1, { 0, 0, 0, 0}, 255 },
1695
{ s_lr_x, s_ul_y, Z, 1.0f, lr_u0, ul_v0, lr_u1, ul_v1, { 0, 0, 0, 0}, 255 },
1696
{ s_ul_x, s_lr_y, Z, 1.0f, ul_u0, lr_v0, ul_u1, lr_v1, { 0, 0, 0, 0}, 255 },
1697
{ s_lr_x, s_lr_y, Z, 1.0f, lr_u0, lr_v0, lr_u1, lr_v1, { 0, 0, 0, 0}, 255 } };
1698
1699
if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
1700
{
1701
vstd[1].u0 = ul_u0;
1702
vstd[1].v0 = lr_v0;
1703
vstd[1].u1 = ul_u1;
1704
vstd[1].v1 = lr_v1;
1705
1706
vstd[2].u0 = lr_u0;
1707
vstd[2].v0 = ul_v0;
1708
vstd[2].u1 = lr_u1;
1709
vstd[2].v1 = ul_v1;
1710
}
1711
1712
VERTEX *vptr = vstd;
1713
int n_vertices = 4;
1714
1715
VERTEX *vnew = 0;
1716
// for (int j =0; j < 4; j++)
1717
// 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);
1718
1719
1720
if (!rdp.hires_tex && rdp.cur_cache[0]->splits != 1)
1721
{
1722
// ** LARGE TEXTURE HANDLING **
1723
// *VERY* simple algebra for texrects
1724
float min_u, min_x, max_u, max_x;
1725
if (vstd[0].u0 < vstd[1].u0)
1726
{
1727
min_u = vstd[0].u0;
1728
min_x = vstd[0].x;
1729
max_u = vstd[1].u0;
1730
max_x = vstd[1].x;
1731
}
1732
else
1733
{
1734
min_u = vstd[1].u0;
1735
min_x = vstd[1].x;
1736
max_u = vstd[0].u0;
1737
max_x = vstd[0].x;
1738
}
1739
1740
int start_u_256, end_u_256;
1741
1742
if (settings.ucode == 7)
1743
{
1744
start_u_256 = 0;
1745
end_u_256 = (lr_x - ul_x - 1)>>8;
1746
}
1747
else
1748
{
1749
start_u_256 = (int)min_u >> 8;
1750
end_u_256 = (int)max_u >> 8;
1751
}
1752
//FRDP(" min_u: %f, max_u: %f start: %d, end: %d\n", min_u, max_u, start_u_256, end_u_256);
1753
1754
int splitheight = rdp.cur_cache[0]->splitheight;
1755
1756
int num_verts_line = 2 + ((end_u_256-start_u_256)<<1);
1757
vnew = new VERTEX [num_verts_line << 1];
1758
1759
n_vertices = num_verts_line << 1;
1760
vptr = vnew;
1761
1762
vnew[0] = vstd[0];
1763
vnew[0].u0 -= 256.0f * start_u_256;
1764
vnew[0].v0 += splitheight * start_u_256;
1765
vnew[0].u1 -= 256.0f * start_u_256;
1766
vnew[0].v1 += splitheight * start_u_256;
1767
vnew[1] = vstd[2];
1768
vnew[1].u0 -= 256.0f * start_u_256;
1769
vnew[1].v0 += splitheight * start_u_256;
1770
vnew[1].u1 -= 256.0f * start_u_256;
1771
vnew[1].v1 += splitheight * start_u_256;
1772
vnew[n_vertices-2] = vstd[1];
1773
vnew[n_vertices-2].u0 -= 256.0f * end_u_256;
1774
vnew[n_vertices-2].v0 += splitheight * end_u_256;
1775
vnew[n_vertices-2].u1 -= 256.0f * end_u_256;
1776
vnew[n_vertices-2].v1 += splitheight * end_u_256;
1777
vnew[n_vertices-1] = vstd[3];
1778
vnew[n_vertices-1].u0 -= 256.0f * end_u_256;
1779
vnew[n_vertices-1].v0 += splitheight * end_u_256;
1780
vnew[n_vertices-1].u1 -= 256.0f * end_u_256;
1781
vnew[n_vertices-1].v1 += splitheight * end_u_256;
1782
1783
// find the equation of the line of u,x
1784
float m = (max_x - min_x) / (max_u - min_u); // m = delta x / delta u
1785
float b = min_x - m * min_u; // b = y - m * x
1786
1787
for (i=start_u_256; i<end_u_256; i++)
1788
{
1789
// Find where x = current 256 multiple
1790
float x = m * ((i<<8)+256) + b;
1791
1792
int vn = 2 + ((i-start_u_256)<<2);
1793
vnew[vn] = vnew[0];
1794
vnew[vn].x = x;
1795
vnew[vn].u0 = 255.5f;
1796
vnew[vn].v0 += (float)splitheight * i;
1797
vnew[vn].u1 = 255.5f;
1798
vnew[vn].v1 += (float)splitheight * i;
1799
1800
vn ++;
1801
vnew[vn] = vnew[1];
1802
vnew[vn].x = x;
1803
vnew[vn].u0 = 255.5f;
1804
vnew[vn].v0 += (float)splitheight * i;
1805
vnew[vn].u1 = 255.5f;
1806
vnew[vn].v1 += (float)splitheight * i;
1807
1808
vn ++;
1809
vnew[vn] = vnew[vn-2];
1810
vnew[vn].u0 = 0.5f;
1811
vnew[vn].v0 += (float)splitheight;
1812
vnew[vn].u1 = 0.5f;
1813
vnew[vn].v1 += (float)splitheight;
1814
1815
vn ++;
1816
vnew[vn] = vnew[vn-2];
1817
vnew[vn].u0 = 0.5f;
1818
vnew[vn].v0 += (float)splitheight;
1819
vnew[vn].u1 = 0.5f;
1820
vnew[vn].v1 += (float)splitheight;
1821
}
1822
}
1823
1824
AllowShadeMods (vptr, n_vertices);
1825
for (i=0; i<n_vertices; i++)
1826
{
1827
VERTEX *z = &vptr[i];
1828
1829
z->u0 *= z->q;
1830
z->v0 *= z->q;
1831
z->u1 *= z->q;
1832
z->v1 *= z->q;
1833
1834
apply_shade_mods (z);
1835
}
1836
1837
if (fullscreen)
1838
{
1839
grFogMode (GR_FOG_DISABLE);
1840
1841
grClipWindow (0, 0, settings.res_x, settings.res_y);
1842
1843
grCullMode (GR_CULL_DISABLE);
1844
1845
if (rdp.cycle_mode == 2)
1846
{
1847
grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
1848
GR_COMBINE_FACTOR_ONE,
1849
GR_COMBINE_LOCAL_NONE,
1850
GR_COMBINE_OTHER_TEXTURE,
1851
FXFALSE);
1852
grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
1853
GR_COMBINE_FACTOR_ONE,
1854
GR_COMBINE_LOCAL_NONE,
1855
GR_COMBINE_OTHER_TEXTURE,
1856
FXFALSE);
1857
grAlphaBlendFunction (GR_BLEND_ONE,
1858
GR_BLEND_ZERO,
1859
GR_BLEND_ZERO,
1860
GR_BLEND_ZERO);
1861
if (rdp.othermode_l & 1)
1862
{
1863
grAlphaTestFunction (GR_CMP_GEQUAL);
1864
grAlphaTestReferenceValue (0x80);
1865
}
1866
else
1867
grAlphaTestFunction (GR_CMP_ALWAYS);
1868
1869
rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
1870
}
1871
1872
ConvertCoordsConvert (vptr, n_vertices);
1873
1874
if (settings.wireframe)
1875
{
1876
SetWireframeCol ();
1877
grDrawLine (&vstd[0], &vstd[2]);
1878
grDrawLine (&vstd[2], &vstd[1]);
1879
grDrawLine (&vstd[1], &vstd[0]);
1880
grDrawLine (&vstd[2], &vstd[3]);
1881
grDrawLine (&vstd[3], &vstd[1]);
1882
}
1883
else
1884
{
1885
grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, n_vertices, vptr, sizeof(VERTEX));
1886
}
1887
1888
if (debug.capture)
1889
{
1890
VERTEX vl[3];
1891
vl[0] = vstd[0];
1892
vl[1] = vstd[2];
1893
vl[2] = vstd[1];
1894
add_tri (vl, 3, TRI_TEXRECT);
1895
rdp.tri_n ++;
1896
vl[0] = vstd[2];
1897
vl[1] = vstd[3];
1898
vl[2] = vstd[1];
1899
add_tri (vl, 3, TRI_TEXRECT);
1900
rdp.tri_n ++;
1901
}
1902
else
1903
rdp.tri_n += 2;
1904
1905
if (settings.fog && (rdp.flags & FOG_ENABLED))
1906
{
1907
grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
1908
}
1909
rdp.update |= UPDATE_CULL_MODE | UPDATE_VIEWPORT;
1910
}
1911
else
1912
{
1913
rdp.tri_n += 2;
1914
}
1915
1916
delete[] vnew;
1917
}
1918
1919
static void rdp_loadsync()
1920
{
1921
RDP("loadsync - ignored\n");
1922
}
1923
1924
static void rdp_pipesync()
1925
{
1926
RDP("pipesync - ignored\n");
1927
}
1928
1929
static void rdp_tilesync()
1930
{
1931
RDP("tilesync - ignored\n");
1932
}
1933
1934
static void rdp_fullsync()
1935
{
1936
// Set an interrupt to allow the game to continue
1937
*gfx.MI_INTR_REG |= 0x20;
1938
gfx.CheckInterrupts();
1939
RDP("fullsync\n");
1940
}
1941
1942
static void rdp_setkeygb()
1943
{
1944
RDP_E("setkeygb - IGNORED\n");
1945
RDP("setkeygb - IGNORED\n");
1946
}
1947
1948
static void rdp_setkeyr()
1949
{
1950
RDP_E("setkeyr - IGNORED\n");
1951
RDP("setkeyr - IGNORED\n");
1952
}
1953
1954
static void rdp_setconvert()
1955
{
1956
/*
1957
rdp.YUV_C0 = 1.1647f ;
1958
rdp.YUV_C1 = 0.79931f ;
1959
rdp.YUV_C2 = -0.1964f ;
1960
rdp.YUV_C3 = -0.40651f;
1961
rdp.YUV_C4 = 1.014f ;
1962
*/
1963
rdp.K5 = (BYTE)(rdp.cmd1&0x1FF);
1964
RDP_E("setconvert - IGNORED\n");
1965
RDP("setconvert - IGNORED\n");
1966
}
1967
1968
//
1969
// setscissor - sets the screen clipping rectangle
1970
//
1971
1972
static void rdp_setscissor()
1973
{
1974
// clipper resolution is 320x240, scale based on computer resolution
1975
rdp.scissor_o.ul_x = /*min(*/(DWORD)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/;
1976
rdp.scissor_o.ul_y = /*min(*/(DWORD)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/;
1977
rdp.scissor_o.lr_x = /*min(*/(DWORD)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/;
1978
rdp.scissor_o.lr_y = /*min(*/(DWORD)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/;
1979
1980
rdp.ci_upper_bound = rdp.scissor_o.ul_y;
1981
rdp.ci_lower_bound = rdp.scissor_o.lr_y;
1982
1983
FRDP("setscissor: (%d,%d) -> (%d,%d)\n", rdp.scissor_o.ul_x, rdp.scissor_o.ul_y,
1984
rdp.scissor_o.lr_x, rdp.scissor_o.lr_y);
1985
1986
rdp.update |= UPDATE_SCISSOR;
1987
}
1988
1989
static void rdp_setprimdepth()
1990
{
1991
rdp.prim_depth = (WORD)((rdp.cmd1 >> 16) & 0x7FFF);
1992
1993
FRDP("setprimdepth: %d\n", rdp.prim_depth);
1994
}
1995
1996
static void rdp_setothermode()
1997
{
1998
#define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \
1999
rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \
2000
rdp.cmd1 = data; \
2001
gfx_instruction[settings.ucode][cmd] (); \
2002
}
2003
#define SETOTHERMODE(cmd,sft,len,data) { \
2004
rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \
2005
rdp.cmd1 = data; \
2006
gfx_instruction[settings.ucode][cmd] (); \
2007
}
2008
2009
RDP("rdp_setothermode\n");
2010
2011
if ((settings.ucode == 2) || (settings.ucode == 8))
2012
{
2013
int cmd0 = rdp.cmd0;
2014
F3DEX2_SETOTHERMODE(0xE2, 0, 32, rdp.cmd1); // SETOTHERMODE_L
2015
F3DEX2_SETOTHERMODE(0xE3, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H
2016
}
2017
else
2018
{
2019
int cmd0 = rdp.cmd0;
2020
SETOTHERMODE(0xB9, 0, 32, rdp.cmd1); // SETOTHERMODE_L
2021
SETOTHERMODE(0xBA, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H
2022
}
2023
}
2024
2025
void load_palette (DWORD addr, WORD start, WORD count)
2026
{
2027
RDP ("Loading palette... ");
2028
WORD *dpal = rdp.pal_8 + start;
2029
WORD end = start+count;
2030
// WORD *spal = (WORD*)(gfx.RDRAM + (addr & BMASK));
2031
2032
for (WORD i=start; i<end; i++)
2033
{
2034
*(dpal++) = *(WORD *)(gfx.RDRAM + (addr^2));
2035
addr += 2;
2036
2037
#ifdef TLUT_LOGGING
2038
FRDP ("%d: %08lx\n", i, *(WORD *)(gfx.RDRAM + (addr^2)));
2039
#endif
2040
}
2041
start >>= 4;
2042
end = start + (count >> 4);
2043
for (WORD p = start; p < end; p++)
2044
{
2045
rdp.pal_8_crc[p] = CRC_Calculate( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 );
2046
}
2047
rdp.pal_256_crc = CRC_Calculate( 0xFFFFFFFF, rdp.pal_8_crc, 64 );
2048
RDP ("Done.\n");
2049
}
2050
2051
static void rdp_loadtlut()
2052
{
2053
DWORD tile = (rdp.cmd1 >> 24) & 0x07;
2054
WORD start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes
2055
// WORD start = ((WORD)(rdp.cmd1 >> 2) & 0x3FF) + 1;
2056
WORD count = ((WORD)(rdp.cmd1 >> 14) & 0x3FF) + 1; // number to copy
2057
2058
if (rdp.timg.addr + (count<<1) > BMASK)
2059
count = (WORD)((BMASK - rdp.timg.addr) >> 1);
2060
2061
if (start+count > 256) count = 256-start;
2062
2063
FRDP("loadtlut: tile: %d, start: %d, count: %d, from: %08lx\n", tile, start, count,
2064
rdp.timg.addr);
2065
2066
load_palette (rdp.timg.addr, start, count);
2067
2068
rdp.timg.addr += count << 1;
2069
}
2070
2071
BOOL tile_set = 0;
2072
static void rdp_settilesize()
2073
{
2074
DWORD tile = (rdp.cmd1 >> 24) & 0x07;
2075
rdp.last_tile_size = tile;
2076
2077
rdp.tiles[tile].f_ul_s = (float)((rdp.cmd0 >> 12) & 0xFFF) / 4.0f;
2078
rdp.tiles[tile].f_ul_t = (float)(rdp.cmd0 & 0xFFF) / 4.0f;
2079
2080
int ul_s = (((WORD)(rdp.cmd0 >> 14)) & 0x03ff);
2081
int ul_t = (((WORD)(rdp.cmd0 >> 2 )) & 0x03ff);
2082
int lr_s = (((WORD)(rdp.cmd1 >> 14)) & 0x03ff);
2083
int lr_t = (((WORD)(rdp.cmd1 >> 2 )) & 0x03ff);
2084
2085
if (lr_s == 0 && ul_s == 0) //pokemon puzzle league set such tile size
2086
wrong_tile = tile;
2087
else if (wrong_tile == (int)tile)
2088
wrong_tile = -1;
2089
2090
if (settings.use_sts1_only)
2091
{
2092
// ** USE FIRST SETTILESIZE ONLY **
2093
// This option helps certain textures while using the 'Alternate texture size method',
2094
// but may break others. (should help more than break)
2095
2096
if (tile_set)
2097
{
2098
// coords in 10.2 format
2099
rdp.tiles[tile].ul_s = ul_s;
2100
rdp.tiles[tile].ul_t = ul_t;
2101
rdp.tiles[tile].lr_s = lr_s;
2102
rdp.tiles[tile].lr_t = lr_t;
2103
tile_set = 0;
2104
}
2105
}
2106
else
2107
{
2108
// coords in 10.2 format
2109
rdp.tiles[tile].ul_s = ul_s;
2110
rdp.tiles[tile].ul_t = ul_t;
2111
rdp.tiles[tile].lr_s = lr_s;
2112
rdp.tiles[tile].lr_t = lr_t;
2113
}
2114
2115
// handle wrapping
2116
if (rdp.tiles[tile].lr_s < rdp.tiles[tile].ul_s) rdp.tiles[tile].lr_s += 0x400;
2117
if (rdp.tiles[tile].lr_t < rdp.tiles[tile].ul_t) rdp.tiles[tile].lr_t += 0x400;
2118
2119
rdp.update |= UPDATE_TEXTURE;
2120
2121
rdp.first = 1;
2122
2123
if (tile == 0 && rdp.hires_tex)
2124
//if ((rdp.tiles[tile].size != 2) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
2125
if (((rdp.tiles[tile].format == 0) && (rdp.tiles[tile].size != 2)) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
2126
rdp.hires_tex = 0;
2127
if (rdp.hires_tex)
2128
{
2129
if (rdp.tiles[tile].format == 0 && rdp.hires_tex->format == 0)
2130
{
2131
if (tile == 1 && (DWORD)rdp.hires_tex->tmu != tile)
2132
SwapTextureBuffer();
2133
rdp.hires_tex->tile = tile;
2134
rdp.hires_tex->info.format = GR_TEXFMT_RGB_565;
2135
FRDP ("hires_tex: tile: %d\n", tile);
2136
}
2137
else if (tile == 0)
2138
{
2139
rdp.hires_tex->info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
2140
}
2141
}
2142
FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n",
2143
tile, ul_s, ul_t, lr_s, lr_t);
2144
}
2145
2146
static void CopyswapBlock(int *pDst, unsigned int cnt, unsigned int SrcOffs)
2147
{
2148
// copy and byteswap a block of 8-byte dwords
2149
int rem = SrcOffs & 3;
2150
if (rem == 0)
2151
{
2152
int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + SrcOffs);
2153
for (unsigned int x = 0; x < cnt; x++)
2154
{
2155
int s1 = bswap32(*pSrc++);
2156
int s2 = bswap32(*pSrc++);
2157
*pDst++ = s1;
2158
*pDst++ = s2;
2159
}
2160
}
2161
else
2162
{
2163
// set source pointer to 4-byte aligned RDRAM location before the start
2164
int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + (SrcOffs & 0xfffffffc));
2165
// do the first partial 32-bit word
2166
int s0 = bswap32(*pSrc++);
2167
for (int x = 0; x < rem; x++)
2168
s0 >>= 8;
2169
for (int x = 4; x > rem; x--)
2170
{
2171
*((char *) pDst) = s0 & 0xff;
2172
pDst = (int *) ((char *) pDst + 1);
2173
s0 >>= 8;
2174
}
2175
// do one full 32-bit word
2176
s0 = bswap32(*pSrc++);
2177
*pDst++ = s0;
2178
// do 'cnt-1' 64-bit dwords
2179
for (unsigned int x = 0; x < cnt-1; x++)
2180
{
2181
int s1 = bswap32(*pSrc++);
2182
int s2 = bswap32(*pSrc++);
2183
*pDst++ = s1;
2184
*pDst++ = s2;
2185
}
2186
// do last partial 32-bit word
2187
s0 = bswap32(*pSrc++);
2188
for (; rem > 0; rem--)
2189
{
2190
*((char *) pDst) = s0 & 0xff;
2191
pDst = (int *) ((char *) pDst + 1);
2192
s0 >>= 8;
2193
}
2194
}
2195
}
2196
2197
static void WordswapBlock(int *pDst, unsigned int cnt, unsigned int TileSize)
2198
{
2199
// Since it's not loading 32-bit textures as the N64 would, 32-bit textures need to
2200
// be swapped by 64-bits, not 32.
2201
if (TileSize == 3)
2202
{
2203
// swapblock64 dst, cnt
2204
for (unsigned int x = 0; x < cnt / 2; x++, pDst += 4)
2205
{
2206
long long s1 = ((long long *) pDst)[0];
2207
long long s2 = ((long long *) pDst)[1];
2208
((long long *) pDst)[0] = s2;
2209
((long long *) pDst)[1] = s1;
2210
}
2211
}
2212
else
2213
{
2214
// swapblock32 dst, cnt
2215
for (unsigned int x = 0; x < cnt; x++, pDst += 2)
2216
{
2217
int s1 = pDst[0];
2218
int s2 = pDst[1];
2219
pDst[0] = s2;
2220
pDst[1] = s1;
2221
}
2222
}
2223
}
2224
2225
static void rdp_loadblock()
2226
{
2227
if (rdp.skip_drawing)
2228
{
2229
RDP("loadblock skipped\n");
2230
return;
2231
}
2232
DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2233
DWORD dxt = (DWORD)(rdp.cmd1 & 0x0FFF);
2234
2235
rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2236
2237
// ** DXT is used for swapping every other line
2238
/* double fdxt = (double)0x8000000F/(double)((DWORD)(2047/(dxt-1))); // F for error
2239
DWORD _dxt = (DWORD)fdxt;*/
2240
2241
// 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit)
2242
DWORD _dxt = dxt << 20;
2243
2244
DWORD addr = segoffset(rdp.timg.addr) & BMASK;
2245
2246
// lr_s specifies number of 64-bit words to copy
2247
// 10.2 format
2248
WORD ul_s = (WORD)(rdp.cmd0 >> 14) & 0x3FF;
2249
WORD ul_t = (WORD)(rdp.cmd0 >> 2) & 0x3FF;
2250
WORD lr_s = (WORD)(rdp.cmd1 >> 14) & 0x3FF;
2251
2252
rdp.tiles[tile].ul_s = ul_s;
2253
rdp.tiles[tile].ul_t = ul_t;
2254
rdp.tiles[tile].lr_s = lr_s;
2255
2256
rdp.timg.set_by = 0; // load block
2257
2258
// do a quick boundary check before copying to eliminate the possibility for exception
2259
if (ul_s >= 512) {
2260
lr_s = 1; // 1 so that it doesn't die on memcpy
2261
ul_s = 511;
2262
}
2263
if (ul_s+lr_s > 512)
2264
lr_s = 512-ul_s;
2265
2266
if (addr+(lr_s<<3) > BMASK+1)
2267
lr_s = (WORD)((BMASK-addr)>>3);
2268
2269
DWORD offs = rdp.timg.addr;
2270
DWORD cnt = lr_s+1;
2271
if (rdp.tiles[tile].size == 3)
2272
cnt <<= 1;
2273
//FIXME: unused? DWORD start_line = 0;
2274
2275
// if (lr_s > 0)
2276
rdp.timg.addr += cnt << 3;
2277
2278
int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
2279
2280
// Load the block from RDRAM and byteswap it as it loads
2281
CopyswapBlock(pDst, cnt, offs);
2282
2283
// now do 32-bit or 64-bit word swapping on every other row of data
2284
int dxt_accum = 0;
2285
while (cnt > 0)
2286
{
2287
// skip over unswapped blocks
2288
do
2289
{
2290
pDst += 2;
2291
if (--cnt == 0)
2292
break;
2293
dxt_accum += _dxt;
2294
} while (!(dxt_accum & 0x80000000));
2295
// count number of blocks to swap
2296
if (cnt == 0) break;
2297
int swapcnt = 0;
2298
do
2299
{
2300
swapcnt++;
2301
if (--cnt == 0)
2302
break;
2303
dxt_accum += _dxt;
2304
} while (dxt_accum & 0x80000000);
2305
// do 32-bit or 64-bit swap operation on this block
2306
WordswapBlock(pDst, swapcnt, rdp.tiles[tile].size);
2307
pDst += swapcnt * 2;
2308
}
2309
2310
rdp.update |= UPDATE_TEXTURE;
2311
2312
FRDP ("loadblock: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, dxt: %08lx -> %08lx\n",
2313
tile, ul_s, ul_t, lr_s,
2314
dxt, _dxt);
2315
}
2316
2317
static void rdp_loadtile()
2318
{
2319
if (rdp.skip_drawing)
2320
return;
2321
rdp.timg.set_by = 1; // load tile
2322
2323
DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2324
if (rdp.tiles[tile].format == 1)
2325
{
2326
rdp.yuv_image = TRUE;
2327
if (rdp.timg.addr < rdp.yuv_im_begin) rdp.yuv_im_begin = rdp.timg.addr;
2328
return;
2329
}
2330
2331
rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
2332
2333
WORD ul_s = (WORD)((rdp.cmd0 >> 14) & 0x03FF);
2334
WORD ul_t = (WORD)((rdp.cmd0 >> 2 ) & 0x03FF);
2335
WORD lr_s = (WORD)((rdp.cmd1 >> 14) & 0x03FF);
2336
WORD lr_t = (WORD)((rdp.cmd1 >> 2 ) & 0x03FF);
2337
2338
if (lr_s < ul_s || lr_t < ul_t) return;
2339
2340
if (wrong_tile >= 0) //there was a tile with zero length
2341
{
2342
rdp.tiles[wrong_tile].lr_s = lr_s;
2343
2344
if (rdp.tiles[tile].size > rdp.tiles[wrong_tile].size)
2345
rdp.tiles[wrong_tile].lr_s <<= (rdp.tiles[tile].size - rdp.tiles[wrong_tile].size);
2346
else if (rdp.tiles[tile].size < rdp.tiles[wrong_tile].size)
2347
rdp.tiles[wrong_tile].lr_s >>= (rdp.tiles[wrong_tile].size - rdp.tiles[tile].size);
2348
rdp.tiles[wrong_tile].lr_t = lr_t;
2349
// wrong_tile = -1;
2350
}
2351
2352
if (rdp.hires_tex)// && (rdp.tiles[tile].format == 0))
2353
{
2354
FRDP("loadtile: hires_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t);
2355
rdp.hires_tex->tile_uls = ul_s;
2356
rdp.hires_tex->tile_ult = ul_t;
2357
}
2358
2359
if (settings.tonic && tile == 7)
2360
{
2361
rdp.tiles[0].ul_s = ul_s;
2362
rdp.tiles[0].ul_t = ul_t;
2363
rdp.tiles[0].lr_s = lr_s;
2364
rdp.tiles[0].lr_t = lr_t;
2365
}
2366
2367
DWORD height = lr_t - ul_t + 1; // get height
2368
DWORD width = lr_s - ul_s + 1;
2369
2370
DWORD wid_64 = rdp.tiles[tile].line;
2371
2372
// CHEAT: it's very unlikely that it loads more than 1 32-bit texture in one command,
2373
// so i don't bother to write in two different places at once. Just load once with
2374
// twice as much data.
2375
if (rdp.tiles[tile].size == 3)
2376
wid_64 <<= 1;
2377
2378
int line_n = rdp.timg.width;
2379
if (rdp.tiles[tile].size == 0)
2380
line_n >>= 1;
2381
else
2382
line_n <<= (rdp.tiles[tile].size-1);
2383
2384
int offs = ul_t * line_n;
2385
offs += ul_s << rdp.tiles[tile].size >> 1;
2386
offs += rdp.timg.addr;
2387
if ((unsigned int) offs >= BMASK)
2388
return;
2389
2390
// check if points to bad location
2391
DWORD size = width * height;
2392
if (rdp.tiles[tile].size == 0)
2393
size >>= 1;
2394
else
2395
size <<= (rdp.tiles[tile].size-1);
2396
2397
if (offs + line_n*height > BMASK)
2398
height = (BMASK - offs) / line_n;
2399
2400
int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
2401
int * pEnd = (int *) ((uintptr_t)rdp.tmem+4096 - (wid_64<<3));
2402
2403
for (unsigned int y = 0; y < height; y++)
2404
{
2405
if (pDst > pEnd) break;
2406
CopyswapBlock(pDst, wid_64, offs);
2407
if (y & 1)
2408
{
2409
WordswapBlock(pDst, wid_64, rdp.tiles[tile].size);
2410
}
2411
pDst += wid_64 * 2;
2412
offs += line_n;
2413
}
2414
2415
FRDP("loadtile: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile,
2416
ul_s, ul_t, lr_s, lr_t);
2417
}
2418
2419
static void rdp_settile()
2420
{
2421
tile_set = 1; // used to check if we only load the first settilesize
2422
2423
rdp.first = 0;
2424
2425
//rdp.cur_tile_n = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2426
//rdp.cur_tile = &rdp.tiles[rdp.cur_tile_n];
2427
2428
rdp.last_tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
2429
TILE *tile = &rdp.tiles[rdp.last_tile];
2430
2431
tile->format = (BYTE)((rdp.cmd0 >> 21) & 0x07);
2432
tile->size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
2433
tile->line = (WORD)((rdp.cmd0 >> 9) & 0x01FF);
2434
tile->t_mem = (WORD)(rdp.cmd0 & 0x1FF);
2435
tile->palette = (BYTE)((rdp.cmd1 >> 20) & 0x0F);
2436
tile->clamp_t = (BYTE)((rdp.cmd1 >> 19) & 0x01);
2437
tile->mirror_t = (BYTE)((rdp.cmd1 >> 18) & 0x01);
2438
tile->mask_t = (BYTE)((rdp.cmd1 >> 14) & 0x0F);
2439
tile->shift_t = (BYTE)((rdp.cmd1 >> 10) & 0x0F);
2440
tile->clamp_s = (BYTE)((rdp.cmd1 >> 9) & 0x01);
2441
tile->mirror_s = (BYTE)((rdp.cmd1 >> 8) & 0x01);
2442
tile->mask_s = (BYTE)((rdp.cmd1 >> 4) & 0x0F);
2443
tile->shift_s = (BYTE)(rdp.cmd1 & 0x0F);
2444
2445
rdp.update |= UPDATE_TEXTURE;
2446
2447
FRDP ("settile: tile: %d, format: %s, size: %s, line: %d, "
2448
"t_mem: %08lx, palette: %d, clamp_t/mirror_t: %s, mask_t: %d, "
2449
"shift_t: %d, clamp_s/mirror_s: %s, mask_s: %d, shift_s: %d\n",
2450
rdp.last_tile, str_format[tile->format], str_size[tile->size], tile->line,
2451
tile->t_mem, tile->palette, str_cm[(tile->clamp_t<<1)|tile->mirror_t], tile->mask_t,
2452
tile->shift_t, str_cm[(tile->clamp_s<<1)|tile->mirror_s], tile->mask_s, tile->shift_s);
2453
}
2454
2455
//
2456
// fillrect - fills a rectangle
2457
//
2458
2459
static void rdp_fillrect()
2460
{
2461
DWORD ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14);
2462
DWORD ul_y = (rdp.cmd1 & 0x00000FFF) >> 2;
2463
DWORD lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1;
2464
DWORD lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1;
2465
if ((rdp.cimg == rdp.zimg) || (settings.fb_smart && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg))
2466
{
2467
RDP ("Fillrect - cleared the depth buffer\n");
2468
if (fullscreen)
2469
{
2470
2471
grDepthMask (FXTRUE);
2472
grColorMask (FXFALSE, FXFALSE);
2473
grBufferClear (0, 0, 0xFFFF);
2474
grColorMask (FXTRUE, FXTRUE);
2475
rdp.update |= UPDATE_ZBUF_ENABLED;
2476
if (settings.fb_depth_clear)
2477
{
2478
ul_x = min(max(ul_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2479
lr_x = min(max(lr_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x);
2480
ul_y = min(max(ul_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2481
lr_y = min(max(lr_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y);
2482
//FIXME:unused? DWORD zi_height = lr_y - ul_y - 1;
2483
// rdp.zi_nb_pixels = rdp.zi_width * zi_height;
2484
rdp.zi_lry = lr_y - 1;
2485
rdp.zi_lrx = lr_x - 1;
2486
// FRDP ("zi_width: %d, zi_height: %d\n", rdp.zi_width, zi_height);
2487
DWORD fillrect_width_in_dwords = (lr_x-ul_x) >> 1;
2488
DWORD zi_width_in_dwords = rdp.zi_width >> 1;
2489
ul_x >>= 1;
2490
DWORD * dst = (DWORD*)(gfx.RDRAM+rdp.cimg);
2491
dst += ul_y * zi_width_in_dwords;
2492
for (DWORD y = ul_y; y < lr_y; y++)
2493
{
2494
for (DWORD x = ul_x; x < fillrect_width_in_dwords; x++)
2495
{
2496
dst[x] = rdp.fill_color;
2497
}
2498
dst += zi_width_in_dwords;
2499
}
2500
}
2501
}
2502
return;
2503
}
2504
2505
if (rdp.skip_drawing)
2506
{
2507
RDP("Fillrect skipped\n");
2508
return;
2509
}
2510
2511
// Update scissor
2512
update_scissor ();
2513
2514
if ((ul_x > lr_x) || (ul_y > lr_y)) return;
2515
if (settings.bomberman64 && (lr_x == rdp.ci_width) && (rdp.cimg == rdp.ocimg)) //bomberman64 hack
2516
return;
2517
2518
if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x))
2519
{
2520
DWORD color = rdp.fill_color;
2521
color = ((color&1)?0xFF:0) |
2522
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2523
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2524
((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2525
grDepthMask (FXFALSE);
2526
grBufferClear (color, 0, 0xFFFF);
2527
grDepthMask (FXTRUE);
2528
rdp.update |= UPDATE_ZBUF_ENABLED;
2529
return;
2530
}
2531
2532
if (settings.decrease_fillrect_edge && rdp.cycle_mode == 0)
2533
{
2534
lr_x--; lr_y--;
2535
}
2536
FRDP("fillrect (%d,%d) -> (%d,%d), cycle mode: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, rdp.cycle_mode,
2537
rdp.tri_n, rdp.tri_n+1);
2538
2539
FRDP("scissor (%d,%d) -> (%d,%d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x,
2540
rdp.scissor.lr_y);
2541
2542
// KILL the floating point error with 0.01f
2543
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);
2544
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);
2545
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);
2546
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);
2547
2548
if (s_lr_x < 0.0f) s_lr_x = 0;
2549
if (s_lr_y < 0.0f) s_lr_y = 0;
2550
if (s_ul_x > (float)settings.res_x) s_ul_x = settings.res_x;
2551
if (s_ul_y > (float)settings.res_y) s_ul_y = settings.res_y;
2552
2553
FRDP (" - %d, %d, %d, %d\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y);
2554
2555
if (fullscreen)
2556
{
2557
grFogMode (GR_FOG_DISABLE);
2558
2559
grClipWindow (0, 0, settings.res_x, settings.res_y);
2560
2561
float Z = 1.0f;
2562
if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030))
2563
{
2564
Z = ScaleZ(rdp.prim_depth);
2565
grDepthBufferFunction (GR_CMP_LEQUAL);
2566
// grDepthMask (FXTRUE);
2567
FRDP ("prim_depth = %d\n", rdp.prim_depth);
2568
}
2569
else
2570
{
2571
grDepthBufferFunction (GR_CMP_ALWAYS);
2572
grDepthMask (FXFALSE);
2573
RDP ("no prim_depth used, using 1.0\n");
2574
}
2575
// Draw the rectangle
2576
VERTEX v[4] = {
2577
{ (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 },
2578
{ (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 },
2579
{ (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 },
2580
{ (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 } };
2581
2582
if (rdp.cycle_mode == 3)
2583
{
2584
DWORD color = (settings.fillcolor_fix) ? rdp.fill_color : (rdp.fill_color >> 16);
2585
2586
if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux)
2587
{
2588
//background of auxilary frame buffers must have zero alpha.
2589
//make it black, set 0 alpha to plack pixels on frame buffer read
2590
color = 0;
2591
}
2592
else
2593
{
2594
color = ((color&1)?0xFF:0) |
2595
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
2596
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
2597
((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
2598
}
2599
grConstantColorValue (color);
2600
2601
grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
2602
GR_COMBINE_FACTOR_NONE,
2603
GR_COMBINE_LOCAL_CONSTANT,
2604
GR_COMBINE_OTHER_NONE,
2605
FXFALSE);
2606
2607
grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
2608
GR_COMBINE_FACTOR_NONE,
2609
GR_COMBINE_LOCAL_CONSTANT,
2610
GR_COMBINE_OTHER_NONE,
2611
FXFALSE);
2612
2613
grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO);
2614
2615
rdp.update |= UPDATE_COMBINE;
2616
}
2617
else
2618
{
2619
Combine ();
2620
TexCache (); // (to update combiner)
2621
DWORD cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF);
2622
DWORD cmb_mode_a = (rdp.cycle1 & 0x0FFF0000) | ((rdp.cycle2 >> 16) & 0x00000FFF);
2623
if (cmb_mode_c == 0x9fff9fff || cmb_mode_a == 0x09ff09ff) //shade
2624
{
2625
AllowShadeMods (v, 4);
2626
for (int k = 0; k < 4; k++)
2627
apply_shade_mods (&v[k]);
2628
}
2629
}
2630
2631
grAlphaTestFunction (GR_CMP_ALWAYS);
2632
if (grStippleModeExt)
2633
grStippleModeExt(GR_STIPPLE_DISABLE);
2634
2635
grCullMode(GR_CULL_DISABLE);
2636
2637
if (settings.wireframe)
2638
{
2639
SetWireframeCol ();
2640
grDrawLine (&v[0], &v[2]);
2641
grDrawLine (&v[2], &v[1]);
2642
grDrawLine (&v[1], &v[0]);
2643
grDrawLine (&v[2], &v[3]);
2644
grDrawLine (&v[3], &v[1]);
2645
//grDrawLine (&v[1], &v[2]);
2646
}
2647
else
2648
{
2649
grDrawTriangle (&v[0], &v[2], &v[1]);
2650
grDrawTriangle (&v[2], &v[3], &v[1]);
2651
}
2652
2653
if (debug.capture)
2654
{
2655
VERTEX v1[3];
2656
v1[0] = v[0];
2657
v1[1] = v[2];
2658
v1[2] = v[1];
2659
add_tri (v1, 3, TRI_FILLRECT);
2660
rdp.tri_n ++;
2661
v1[0] = v[2];
2662
v1[1] = v[3];
2663
add_tri (v1, 3, TRI_FILLRECT);
2664
rdp.tri_n ++;
2665
}
2666
else
2667
rdp.tri_n += 2;
2668
2669
if (settings.fog && (rdp.flags & FOG_ENABLED))
2670
{
2671
grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
2672
}
2673
2674
rdp.update |= UPDATE_CULL_MODE | UPDATE_ALPHA_COMPARE | UPDATE_ZBUF_ENABLED;
2675
}
2676
else
2677
{
2678
rdp.tri_n += 2;
2679
}
2680
}
2681
2682
//
2683
// setfillcolor - sets the filling color
2684
//
2685
2686
static void rdp_setfillcolor()
2687
{
2688
rdp.fill_color = rdp.cmd1;
2689
rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
2690
2691
FRDP("setfillcolor: %08lx\n", rdp.cmd1);
2692
}
2693
2694
static void rdp_setfogcolor()
2695
{
2696
rdp.fog_color = rdp.cmd1;
2697
rdp.update |= UPDATE_COMBINE | UPDATE_FOG_ENABLED;
2698
2699
FRDP("setfogcolor - %08lx\n", rdp.cmd1);
2700
}
2701
2702
static void rdp_setblendcolor()
2703
{
2704
rdp.blend_color = rdp.cmd1;
2705
rdp.update |= UPDATE_COMBINE;
2706
2707
FRDP("setblendcolor: %08lx\n", rdp.cmd1);
2708
}
2709
2710
static void rdp_setprimcolor()
2711
{
2712
rdp.prim_color = rdp.cmd1;
2713
rdp.prim_lodmin = (rdp.cmd0 >> 8) & 0xFF;
2714
rdp.prim_lodfrac = max(rdp.cmd0 & 0xFF, rdp.prim_lodmin);
2715
rdp.update |= UPDATE_COMBINE;
2716
2717
FRDP("setprimcolor: %08lx, lodmin: %d, lodfrac: %d\n", rdp.cmd1, rdp.prim_lodmin,
2718
rdp.prim_lodfrac);
2719
}
2720
2721
static void rdp_setenvcolor()
2722
{
2723
rdp.env_color = rdp.cmd1;
2724
rdp.update |= UPDATE_COMBINE;
2725
2726
FRDP("setenvcolor: %08lx\n", rdp.cmd1);
2727
}
2728
2729
static void rdp_setcombine()
2730
{
2731
rdp.c_a0 = (BYTE)((rdp.cmd0 >> 20) & 0xF);
2732
rdp.c_b0 = (BYTE)((rdp.cmd1 >> 28) & 0xF);
2733
rdp.c_c0 = (BYTE)((rdp.cmd0 >> 15) & 0x1F);
2734
rdp.c_d0 = (BYTE)((rdp.cmd1 >> 15) & 0x7);
2735
rdp.c_Aa0 = (BYTE)((rdp.cmd0 >> 12) & 0x7);
2736
rdp.c_Ab0 = (BYTE)((rdp.cmd1 >> 12) & 0x7);
2737
rdp.c_Ac0 = (BYTE)((rdp.cmd0 >> 9) & 0x7);
2738
rdp.c_Ad0 = (BYTE)((rdp.cmd1 >> 9) & 0x7);
2739
2740
rdp.c_a1 = (BYTE)((rdp.cmd0 >> 5) & 0xF);
2741
rdp.c_b1 = (BYTE)((rdp.cmd1 >> 24) & 0xF);
2742
rdp.c_c1 = (BYTE)((rdp.cmd0 >> 0) & 0x1F);
2743
rdp.c_d1 = (BYTE)((rdp.cmd1 >> 6) & 0x7);
2744
rdp.c_Aa1 = (BYTE)((rdp.cmd1 >> 21) & 0x7);
2745
rdp.c_Ab1 = (BYTE)((rdp.cmd1 >> 3) & 0x7);
2746
rdp.c_Ac1 = (BYTE)((rdp.cmd1 >> 18) & 0x7);
2747
rdp.c_Ad1 = (BYTE)((rdp.cmd1 >> 0) & 0x7);
2748
2749
rdp.cycle1 = (rdp.c_a0<<0) | (rdp.c_b0<<4) | (rdp.c_c0<<8) | (rdp.c_d0<<13)|
2750
(rdp.c_Aa0<<16)| (rdp.c_Ab0<<19)| (rdp.c_Ac0<<22)| (rdp.c_Ad0<<25);
2751
rdp.cycle2 = (rdp.c_a1<<0) | (rdp.c_b1<<4) | (rdp.c_c1<<8) | (rdp.c_d1<<13)|
2752
(rdp.c_Aa1<<16)| (rdp.c_Ab1<<19)| (rdp.c_Ac1<<22)| (rdp.c_Ad1<<25);
2753
2754
rdp.update |= UPDATE_COMBINE;
2755
2756
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",
2757
Mode0[rdp.c_a0], Mode1[rdp.c_b0], Mode2[rdp.c_c0], Mode3[rdp.c_d0],
2758
Alpha0[rdp.c_Aa0], Alpha1[rdp.c_Ab0], Alpha2[rdp.c_Ac0], Alpha3[rdp.c_Ad0],
2759
Mode0[rdp.c_a1], Mode1[rdp.c_b1], Mode2[rdp.c_c1], Mode3[rdp.c_d1],
2760
Alpha0[rdp.c_Aa1], Alpha1[rdp.c_Ab1], Alpha2[rdp.c_Ac1], Alpha3[rdp.c_Ad1]);
2761
}
2762
2763
//
2764
// settextureimage - sets the source for an image copy
2765
//
2766
2767
static void rdp_settextureimage()
2768
{
2769
static const char *format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
2770
static const char *size[] = { "4bit", "8bit", "16bit", "32bit" };
2771
2772
rdp.timg.format = (BYTE)((rdp.cmd0 >> 21) & 0x07);
2773
rdp.timg.size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
2774
rdp.timg.width = (WORD)(1 + (rdp.cmd0 & 0x00000FFF));
2775
rdp.timg.addr = segoffset(rdp.cmd1);
2776
rdp.s2dex_tex_loaded = TRUE;
2777
rdp.update |= UPDATE_TEXTURE;
2778
2779
if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self && (rdp.timg.addr >= rdp.cimg) && (rdp.timg.addr < rdp.ci_end))
2780
{
2781
if (!rdp.fb_drawn)
2782
{
2783
if (!rdp.cur_image)
2784
CopyFrameBuffer();
2785
else if (rdp.frame_buffers[rdp.ci_count].status != ci_copy)
2786
CloseTextureBuffer(TRUE);
2787
rdp.fb_drawn = TRUE;
2788
}
2789
}
2790
2791
if (settings.fb_hires) //search this texture among drawn texture buffers
2792
{
2793
if (settings.zelda)
2794
{
2795
if (rdp.timg.size == 2)
2796
FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
2797
}
2798
else
2799
FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
2800
}
2801
2802
FRDP("settextureimage: format: %s, size: %s, width: %d, addr: %08lx\n",
2803
format[rdp.timg.format], size[rdp.timg.size],
2804
rdp.timg.width, rdp.timg.addr);
2805
}
2806
2807
static void rdp_setdepthimage()
2808
{
2809
rdp.zimg = segoffset(rdp.cmd1) & BMASK;
2810
rdp.zi_width = rdp.ci_width;
2811
FRDP("setdepthimage - %08lx\n", rdp.zimg);
2812
}
2813
2814
2815
BOOL SwapOK = TRUE;
2816
static void RestoreScale()
2817
{
2818
FRDP("Return to original scale: x = %f, y = %f\n", rdp.scale_x_bak, rdp.scale_y_bak);
2819
rdp.scale_x = rdp.scale_x_bak;
2820
rdp.scale_y = rdp.scale_y_bak;
2821
// update_scissor();
2822
rdp.view_scale[0] *= rdp.scale_x;
2823
rdp.view_scale[1] *= rdp.scale_y;
2824
rdp.view_trans[0] *= rdp.scale_x;
2825
rdp.view_trans[1] *= rdp.scale_y;
2826
rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR;
2827
//*
2828
if (fullscreen)
2829
{
2830
grDepthMask (FXFALSE);
2831
grBufferClear (0, 0, 0xFFFF);
2832
grDepthMask (FXTRUE);
2833
}
2834
//*/
2835
}
2836
2837
static DWORD swapped_addr = 0;
2838
2839
static void rdp_setcolorimage()
2840
{
2841
render_depth_mode = 0;
2842
if (settings.fb_smart && (rdp.num_of_ci < NUMTEXBUF))
2843
{
2844
COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count];
2845
COLOR_IMAGE & prev_fb = rdp.frame_buffers[rdp.ci_count-1];
2846
COLOR_IMAGE & next_fb = rdp.frame_buffers[rdp.ci_count+1];
2847
switch (cur_fb.status)
2848
{
2849
case ci_main:
2850
{
2851
2852
if (rdp.ci_count == 0)
2853
{
2854
if (rdp.ci_status == ci_aux) //for PPL
2855
{
2856
float sx = rdp.scale_x;
2857
float sy = rdp.scale_y;
2858
rdp.scale_x = 1.0f;
2859
rdp.scale_y = 1.0f;
2860
CopyFrameBuffer ();
2861
rdp.scale_x = sx;
2862
rdp.scale_y = sy;
2863
}
2864
if (!settings.fb_hires)
2865
{
2866
if ((rdp.num_of_ci > 1) &&
2867
(next_fb.status == ci_aux) &&
2868
(next_fb.width >= cur_fb.width))
2869
{
2870
rdp.scale_x = 1.0f;
2871
rdp.scale_y = 1.0f;
2872
}
2873
}
2874
else if (rdp.copy_ci_index && settings.PM) //tidal wave
2875
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2876
}
2877
else if (!rdp.motionblur && settings.fb_hires && !SwapOK && (rdp.ci_count <= rdp.copy_ci_index))
2878
{
2879
if (next_fb.status == ci_aux_copy)
2880
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2881
else
2882
OpenTextureBuffer(rdp.frame_buffers[rdp.copy_ci_index]);
2883
}
2884
else if (settings.fb_hires && rdp.read_whole_frame && prev_fb.status == ci_aux)
2885
{
2886
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
2887
}
2888
//else if (rdp.ci_status == ci_aux && !rdp.copy_ci_index)
2889
// CloseTextureBuffer();
2890
2891
rdp.skip_drawing = FALSE;
2892
}
2893
break;
2894
case ci_copy:
2895
{
2896
if (!rdp.motionblur || settings.fb_motionblur)
2897
{
2898
if (cur_fb.width == rdp.ci_width)
2899
{
2900
if (CopyTextureBuffer(prev_fb, cur_fb))
2901
// if (CloseTextureBuffer(TRUE))
2902
;
2903
else
2904
{
2905
if (!rdp.fb_drawn || prev_fb.status == ci_copy_self)
2906
{
2907
CopyFrameBuffer ();
2908
rdp.fb_drawn = TRUE;
2909
}
2910
memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2911
}
2912
}
2913
else
2914
{
2915
CloseTextureBuffer(TRUE);
2916
}
2917
}
2918
else
2919
{
2920
memset(gfx.RDRAM+cur_fb.addr, 0, cur_fb.width*cur_fb.height*rdp.ci_size);
2921
}
2922
rdp.skip_drawing = TRUE;
2923
}
2924
break;
2925
case ci_aux_copy:
2926
{
2927
rdp.skip_drawing = FALSE;
2928
if (CloseTextureBuffer(prev_fb.status != ci_aux_copy))
2929
;
2930
else if (!rdp.fb_drawn)
2931
{
2932
CopyFrameBuffer ();
2933
rdp.fb_drawn = TRUE;
2934
}
2935
if (settings.fb_hires)
2936
OpenTextureBuffer(cur_fb);
2937
}
2938
break;
2939
case ci_old_copy:
2940
{
2941
if (!rdp.motionblur || settings.fb_motionblur)
2942
{
2943
if (cur_fb.width == rdp.ci_width)
2944
{
2945
memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.maincimg[1].addr, (cur_fb.width*cur_fb.height)<<cur_fb.size>>1);
2946
}
2947
//rdp.skip_drawing = TRUE;
2948
}
2949
else
2950
{
2951
memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<<rdp.ci_size>>1);
2952
}
2953
}
2954
break;
2955
/*
2956
else if (rdp.frame_buffers[rdp.ci_count].status == ci_main_i)
2957
{
2958
// CopyFrameBuffer ();
2959
rdp.scale_x = rdp.scale_x_bak;
2960
rdp.scale_y = rdp.scale_y_bak;
2961
rdp.skip_drawing = FALSE;
2962
}
2963
*/
2964
case ci_aux:
2965
{
2966
if (!settings.fb_hires && cur_fb.format != 0)
2967
rdp.skip_drawing = TRUE;
2968
else
2969
{
2970
rdp.skip_drawing = FALSE;
2971
if (settings.fb_hires && OpenTextureBuffer(cur_fb))
2972
;
2973
else
2974
{
2975
if (cur_fb.format != 0)
2976
rdp.skip_drawing = TRUE;
2977
if (rdp.ci_count == 0)
2978
{
2979
// if (rdp.num_of_ci > 1)
2980
// {
2981
rdp.scale_x = 1.0f;
2982
rdp.scale_y = 1.0f;
2983
// }
2984
}
2985
else if (!settings.fb_hires && (prev_fb.status == ci_main) &&
2986
(prev_fb.width == cur_fb.width)) // for Pokemon Stadium
2987
CopyFrameBuffer ();
2988
}
2989
}
2990
cur_fb.status = ci_aux;
2991
}
2992
break;
2993
case ci_zimg:
2994
// ZIGGY
2995
// Zelda LoT effect save/restore depth buffer
2996
if (cur_fb.addr == rdp.zimg) {
2997
render_depth_mode = 1;
2998
} else {
2999
render_depth_mode = 2;
3000
}
3001
rdp.skip_drawing = TRUE;
3002
break;
3003
case ci_useless:
3004
//case ci_zcopy:
3005
rdp.skip_drawing = TRUE;
3006
break;
3007
case ci_copy_self:
3008
if (settings.fb_hires && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2))
3009
OpenTextureBuffer(cur_fb);
3010
rdp.skip_drawing = FALSE;
3011
/*
3012
if (settings.fb_hires)
3013
{
3014
if (SwapOK)
3015
{
3016
rdp.cimg = rdp.frame_buffers[rdp.ci_count].addr;
3017
rdp.maincimg[0].addr = rdp.cimg;
3018
newSwapBuffers();
3019
SwapOK = FALSE;
3020
OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count]);
3021
}
3022
}
3023
*/
3024
break;
3025
default:
3026
rdp.skip_drawing = FALSE;
3027
}
3028
3029
if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium
3030
{
3031
if (!settings.fb_hires && prev_fb.format == 0)
3032
CopyFrameBuffer ();
3033
}
3034
if (!settings.fb_hires && cur_fb.status == ci_copy)
3035
{
3036
if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux))
3037
{
3038
RestoreScale();
3039
}
3040
}
3041
if (!settings.fb_hires && cur_fb.status == ci_aux)
3042
{
3043
if (cur_fb.format == 0)
3044
{
3045
if (settings.PPL && (rdp.scale_x < 1.1f)) //need to put current image back to frame buffer
3046
{
3047
int width = cur_fb.width;
3048
int height = cur_fb.height;
3049
WORD *ptr_dst = new WORD[width*height];
3050
WORD *ptr_src = (WORD*)(gfx.RDRAM+cur_fb.addr);
3051
WORD c;
3052
3053
for (int y=0; y<height; y++)
3054
{
3055
for (int x=0; x<width; x++)
3056
{
3057
c = ((ptr_src[(x + y * width)^1]) >> 1) | 0x8000;
3058
ptr_dst[x + y * width] = c;
3059
}
3060
}
3061
grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
3062
0,
3063
0,
3064
GR_LFB_SRC_FMT_555,
3065
width,
3066
height,
3067
FXFALSE,
3068
width<<1,
3069
ptr_dst);
3070
delete[] ptr_dst;
3071
}
3072
/*
3073
else //just clear buffer
3074
{
3075
3076
grColorMask(FXTRUE, FXTRUE);
3077
grBufferClear (0, 0, 0xFFFF);
3078
}
3079
*/
3080
}
3081
}
3082
3083
if ((cur_fb.status == ci_main) && (rdp.ci_count > 0))
3084
{
3085
BOOL to_org_res = TRUE;
3086
for (int i = rdp.ci_count + 1; i < rdp.num_of_ci; i++)
3087
{
3088
if ((rdp.frame_buffers[i].status != ci_main) && (rdp.frame_buffers[i].status != ci_zimg) && (rdp.frame_buffers[i].status != ci_zcopy))
3089
{
3090
to_org_res = FALSE;
3091
break;
3092
}
3093
}
3094
if (to_org_res)
3095
{
3096
RDP("return to original scale\n");
3097
rdp.scale_x = rdp.scale_x_bak;
3098
rdp.scale_y = rdp.scale_y_bak;
3099
if (settings.fb_hires && !rdp.read_whole_frame)
3100
CloseTextureBuffer();
3101
}
3102
if (settings.fb_hires && !rdp.read_whole_frame && (prev_fb.status >= ci_aux) && (rdp.ci_count > rdp.copy_ci_index))
3103
CloseTextureBuffer();
3104
3105
}
3106
rdp.ci_status = cur_fb.status;
3107
rdp.ci_count++;
3108
}
3109
3110
rdp.ocimg = rdp.cimg;
3111
rdp.cimg = segoffset(rdp.cmd1) & BMASK;
3112
rdp.ci_width = (rdp.cmd0 & 0xFFF) + 1;
3113
if (settings.fb_smart)
3114
rdp.ci_height = rdp.frame_buffers[rdp.ci_count-1].height;
3115
else if (rdp.ci_width == 32)
3116
rdp.ci_height = 32;
3117
else
3118
rdp.ci_height = rdp.scissor_o.lr_y;
3119
if (rdp.zimg == rdp.cimg)
3120
{
3121
rdp.zi_width = rdp.ci_width;
3122
// int zi_height = min((int)rdp.zi_width*3/4, (int)rdp.vi_height);
3123
// rdp.zi_words = rdp.zi_width * zi_height;
3124
}
3125
DWORD format = (rdp.cmd0 >> 21) & 0x7;
3126
rdp.ci_size = (rdp.cmd0 >> 19) & 0x3;
3127
rdp.ci_end = rdp.cimg + ((rdp.ci_width*rdp.ci_height)<<(rdp.ci_size-1));
3128
FRDP("setcolorimage - %08lx, width: %d, height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size);
3129
FRDP("cimg: %08lx, ocimg: %08lx, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK);
3130
3131
if (format != 0 && !rdp.cur_image) //can't draw into non RGBA buffer
3132
{
3133
if (settings.fb_hires && rdp.ci_width <= 64)
3134
OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]);
3135
else if (format > 2)
3136
rdp.skip_drawing = TRUE;
3137
return;
3138
}
3139
else
3140
{
3141
if (!settings.fb_smart)
3142
rdp.skip_drawing = FALSE;
3143
}
3144
3145
CI_SET = TRUE;
3146
if (settings.swapmode > 0)
3147
{
3148
if (rdp.zimg == rdp.cimg)
3149
rdp.updatescreen = 1;
3150
3151
BOOL viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE;
3152
if ((rdp.zimg != rdp.cimg) && (rdp.ocimg != rdp.cimg) && SwapOK && viSwapOK && !rdp.cur_image)
3153
{
3154
if (settings.fb_smart)
3155
rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3156
else
3157
rdp.maincimg[0].addr = rdp.cimg;
3158
rdp.last_drawn_ci_addr = (settings.swapmode == 2) ? swapped_addr : rdp.maincimg[0].addr;
3159
swapped_addr = rdp.cimg;
3160
newSwapBuffers();
3161
rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
3162
SwapOK = FALSE;
3163
if (settings.fb_hires)
3164
{
3165
if (rdp.copy_ci_index && (rdp.frame_buffers[rdp.ci_count-1].status != ci_zimg))
3166
{
3167
int idx = (rdp.frame_buffers[rdp.ci_count].status == ci_aux_copy) ? rdp.main_ci_index : rdp.copy_ci_index;
3168
FRDP("attempt open tex buffer. status: %s, addr: %08lx\n", CIStatus[rdp.frame_buffers[idx].status], rdp.frame_buffers[idx].addr);
3169
OpenTextureBuffer(rdp.frame_buffers[idx]);
3170
if (rdp.frame_buffers[rdp.copy_ci_index].status == ci_main) //tidal wave
3171
rdp.copy_ci_index = 0;
3172
}
3173
else if (rdp.read_whole_frame && !rdp.cur_image)
3174
{
3175
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3176
}
3177
}
3178
}
3179
}
3180
}
3181
3182
static void rdp_trifill()
3183
{
3184
RDP_E("trifill - IGNORED\n");
3185
RDP("trifill - IGNORED\n");
3186
}
3187
3188
static void rdp_trishade()
3189
{
3190
RDP_E("trishade - IGNORED\n");
3191
RDP("trishade - IGNORED\n");
3192
}
3193
3194
static void rdp_tritxtr()
3195
{
3196
RDP_E("tritxtr - IGNORED\n");
3197
RDP("tritxtr - IGNORED\n");
3198
}
3199
3200
static void rdp_trishadetxtr()
3201
{
3202
RDP_E("trishadetxtr - IGNORED\n");
3203
RDP("trishadetxtr - IGNORED\n");
3204
}
3205
3206
static void rdp_trifillz()
3207
{
3208
RDP_E("trifillz - IGNORED\n");
3209
RDP("trifillz - IGNORED\n");
3210
}
3211
3212
static void rdp_trishadez()
3213
{
3214
RDP_E("trishadez - IGNORED\n");
3215
RDP("trishadez - IGNORED\n");
3216
}
3217
3218
static void rdp_tritxtrz()
3219
{
3220
RDP_E("tritxtrz - IGNORED\n");
3221
RDP("tritxtrz - IGNORED\n");
3222
}
3223
3224
static void rdp_trishadetxtrz()
3225
{
3226
RDP_E("trishadetxtrz - IGNORED\n");
3227
RDP("trishadetxtrz - IGNORED\n");
3228
}
3229
3230
static void rsp_reserved0()
3231
{
3232
RDP_E("reserved0 - IGNORED\n");
3233
RDP("reserved0 - IGNORED\n");
3234
}
3235
3236
static void rsp_reserved1()
3237
{
3238
RDP("reserved1 - ignored\n");
3239
}
3240
3241
static void rsp_reserved2()
3242
{
3243
RDP("reserved2\n");
3244
}
3245
3246
static void rsp_reserved3()
3247
{
3248
RDP("reserved3 - ignored\n");
3249
}
3250
3251
void SetWireframeCol ()
3252
{
3253
if (!fullscreen) return;
3254
3255
switch (settings.wfmode)
3256
{
3257
//case 0: // normal colors, don't do anything
3258
case 1: // vertex colors
3259
grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3260
GR_COMBINE_FACTOR_NONE,
3261
GR_COMBINE_LOCAL_ITERATED,
3262
GR_COMBINE_OTHER_NONE,
3263
FXFALSE);
3264
grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3265
GR_COMBINE_FACTOR_NONE,
3266
GR_COMBINE_LOCAL_ITERATED,
3267
GR_COMBINE_OTHER_NONE,
3268
FXFALSE);
3269
grAlphaBlendFunction (GR_BLEND_ONE,
3270
GR_BLEND_ZERO,
3271
GR_BLEND_ZERO,
3272
GR_BLEND_ZERO);
3273
grTexCombine (GR_TMU0,
3274
GR_COMBINE_FUNCTION_ZERO,
3275
GR_COMBINE_FACTOR_NONE,
3276
GR_COMBINE_FUNCTION_ZERO,
3277
GR_COMBINE_FACTOR_NONE,
3278
FXFALSE, FXFALSE);
3279
grTexCombine (GR_TMU1,
3280
GR_COMBINE_FUNCTION_ZERO,
3281
GR_COMBINE_FACTOR_NONE,
3282
GR_COMBINE_FUNCTION_ZERO,
3283
GR_COMBINE_FACTOR_NONE,
3284
FXFALSE, FXFALSE);
3285
break;
3286
case 2: // red only
3287
grColorCombine (GR_COMBINE_FUNCTION_LOCAL,
3288
GR_COMBINE_FACTOR_NONE,
3289
GR_COMBINE_LOCAL_CONSTANT,
3290
GR_COMBINE_OTHER_NONE,
3291
FXFALSE);
3292
grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL,
3293
GR_COMBINE_FACTOR_NONE,
3294
GR_COMBINE_LOCAL_CONSTANT,
3295
GR_COMBINE_OTHER_NONE,
3296
FXFALSE);
3297
grConstantColorValue (0xFF0000FF);
3298
grAlphaBlendFunction (GR_BLEND_ONE,
3299
GR_BLEND_ZERO,
3300
GR_BLEND_ZERO,
3301
GR_BLEND_ZERO);
3302
grTexCombine (GR_TMU0,
3303
GR_COMBINE_FUNCTION_ZERO,
3304
GR_COMBINE_FACTOR_NONE,
3305
GR_COMBINE_FUNCTION_ZERO,
3306
GR_COMBINE_FACTOR_NONE,
3307
FXFALSE, FXFALSE);
3308
grTexCombine (GR_TMU1,
3309
GR_COMBINE_FUNCTION_ZERO,
3310
GR_COMBINE_FACTOR_NONE,
3311
GR_COMBINE_FUNCTION_ZERO,
3312
GR_COMBINE_FACTOR_NONE,
3313
FXFALSE, FXFALSE);
3314
break;
3315
}
3316
3317
grAlphaTestFunction (GR_CMP_ALWAYS);
3318
grCullMode (GR_CULL_DISABLE);
3319
3320
//grDepthBufferFunction (GR_CMP_ALWAYS);
3321
//grDepthMask (FXFALSE);
3322
3323
rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE;
3324
}
3325
3326
#ifdef __cplusplus
3327
extern "C" {
3328
#endif
3329
3330
/******************************************************************
3331
Function: FrameBufferRead
3332
Purpose: This function is called to notify the dll that the
3333
frame buffer memory is beening read at the given address.
3334
DLL should copy content from its render buffer to the frame buffer
3335
in N64 RDRAM
3336
DLL is responsible to maintain its own frame buffer memory addr list
3337
DLL should copy 4KB block content back to RDRAM frame buffer.
3338
Emulator should not call this function again if other memory
3339
is read within the same 4KB range
3340
input: addr rdram address
3341
val val
3342
size 1 = BYTE, 2 = WORD, 4 = DWORD
3343
output: none
3344
*******************************************************************/
3345
EXPORT void CALL FBRead(unsigned int addr)
3346
{
3347
LOG ("FBRead ()\n");
3348
3349
if (cpu_fb_ignore)
3350
return;
3351
if (cpu_fb_write_called)
3352
{
3353
cpu_fb_ignore = TRUE;
3354
cpu_fb_write = FALSE;
3355
return;
3356
}
3357
cpu_fb_read_called = TRUE;
3358
DWORD a = segoffset(addr);
3359
FRDP("FBRead. addr: %08lx\n", a);
3360
if (!rdp.fb_drawn && (a >= rdp.cimg) && (a < rdp.ci_end))
3361
{
3362
fbreads_back++;
3363
//if (fbreads_back > 2) //&& (rdp.ci_width <= 320))
3364
{
3365
CopyFrameBuffer ();
3366
rdp.fb_drawn = TRUE;
3367
}
3368
}
3369
if (!rdp.fb_drawn_front && (a >= rdp.maincimg[1].addr) && (a < rdp.maincimg[1].addr + rdp.ci_width*rdp.ci_height*2))
3370
{
3371
fbreads_front++;
3372
//if (fbreads_front > 2)//&& (rdp.ci_width <= 320))
3373
{
3374
DWORD cimg = rdp.cimg;
3375
rdp.cimg = rdp.maincimg[1].addr;
3376
if (settings.fb_smart)
3377
{
3378
rdp.ci_width = rdp.maincimg[1].width;
3379
rdp.ci_count = 0;
3380
DWORD h = rdp.frame_buffers[0].height;
3381
rdp.frame_buffers[0].height = rdp.maincimg[1].height;
3382
CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3383
rdp.frame_buffers[0].height = h;
3384
}
3385
else
3386
{
3387
CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
3388
}
3389
rdp.cimg = cimg;
3390
rdp.fb_drawn_front = TRUE;
3391
}
3392
}
3393
}
3394
3395
#if 0
3396
//TODO: remove
3397
/******************************************************************
3398
Function: FrameBufferWriteList
3399
Purpose: This function is called to notify the dll that the
3400
frame buffer has been modified by CPU at the given address.
3401
input: FrameBufferModifyEntry *plist
3402
size = size of the plist, max = 1024
3403
output: none
3404
*******************************************************************/
3405
EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size)
3406
{
3407
LOG ("FBWList ()\n");
3408
FRDP("FBWList. size: %d\n", size);
3409
printf("FBWList. size: %d\n", size);
3410
}
3411
#endif
3412
3413
/******************************************************************
3414
Function: FrameBufferWrite
3415
Purpose: This function is called to notify the dll that the
3416
frame buffer has been modified by CPU at the given address.
3417
input: addr rdram address
3418
val val
3419
size 1 = BYTE, 2 = WORD, 4 = DWORD
3420
output: none
3421
*******************************************************************/
3422
EXPORT void CALL FBWrite(unsigned int addr, unsigned int size)
3423
{
3424
LOG ("FBWrite ()\n");
3425
if (cpu_fb_ignore)
3426
return;
3427
if (cpu_fb_read_called)
3428
{
3429
cpu_fb_ignore = TRUE;
3430
cpu_fb_write = FALSE;
3431
return;
3432
}
3433
cpu_fb_write_called = TRUE;
3434
DWORD a = segoffset(addr);
3435
FRDP("FBWrite. addr: %08lx\n", a);
3436
// ZIGGY : added a test on ci_width, otherwise we crash on zero division below
3437
if (!rdp.ci_width || a < rdp.cimg || a > rdp.ci_end)
3438
return;
3439
cpu_fb_write = TRUE;
3440
DWORD shift_l = (a-rdp.cimg) >> 1;
3441
DWORD shift_r = shift_l+2;
3442
3443
d_ul_x = min(d_ul_x, shift_l%rdp.ci_width);
3444
d_ul_y = min(d_ul_y, shift_l/rdp.ci_width);
3445
d_lr_x = max(d_lr_x, shift_r%rdp.ci_width);
3446
d_lr_y = max(d_lr_y, shift_r/rdp.ci_width);
3447
}
3448
3449
3450
/************************************************************************
3451
Function: FBGetFrameBufferInfo
3452
Purpose: This function is called by the emulator core to retrieve frame
3453
buffer information from the video plugin in order to be able
3454
to notify the video plugin about CPU frame buffer read/write
3455
operations
3456
3457
size:
3458
= 1 byte
3459
= 2 word (16 bit) <-- this is N64 default depth buffer format
3460
= 4 dword (32 bit)
3461
3462
when frame buffer information is not available yet, set all values
3463
in the FrameBufferInfo structure to 0
3464
3465
input: FrameBufferInfo pinfo[6]
3466
pinfo is pointed to a FrameBufferInfo structure which to be
3467
filled in by this function
3468
output: Values are return in the FrameBufferInfo structure
3469
Plugin can return up to 6 frame buffer info
3470
************************************************************************/
3471
///*
3472
#if 0
3473
//TODO: remove
3474
typedef struct
3475
{
3476
DWORD addr;
3477
DWORD size;
3478
DWORD width;
3479
DWORD height;
3480
} FrameBufferInfo;
3481
#endif
3482
3483
EXPORT void CALL FBGetFrameBufferInfo(void *p)
3484
{
3485
LOG ("FBGetFrameBufferInfo ()\n");
3486
FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
3487
memset(pinfo,0,sizeof(FrameBufferInfo)*6);
3488
if (!settings.fb_get_info)
3489
return;
3490
RDP("FBGetFrameBufferInfo ()\n");
3491
//*
3492
if (settings.fb_smart)
3493
{
3494
pinfo[0].addr = rdp.maincimg[1].addr;
3495
pinfo[0].size = rdp.maincimg[1].size;
3496
pinfo[0].width = rdp.maincimg[1].width;
3497
pinfo[0].height = rdp.maincimg[1].height;
3498
int info_index = 1;
3499
for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++)
3500
{
3501
COLOR_IMAGE & cur_fb = rdp.frame_buffers[i];
3502
if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self ||
3503
cur_fb.status == ci_old_copy)
3504
{
3505
pinfo[info_index].addr = cur_fb.addr;
3506
pinfo[info_index].size = cur_fb.size;
3507
pinfo[info_index].width = cur_fb.width;
3508
pinfo[info_index].height = cur_fb.height;
3509
info_index++;
3510
}
3511
}
3512
}
3513
else
3514
{
3515
pinfo[0].addr = rdp.maincimg[0].addr;
3516
pinfo[0].size = rdp.ci_size;
3517
pinfo[0].width = rdp.ci_width;
3518
pinfo[0].height = rdp.ci_width*3/4;
3519
pinfo[1].addr = rdp.maincimg[1].addr;
3520
pinfo[1].size = rdp.ci_size;
3521
pinfo[1].width = rdp.ci_width;
3522
pinfo[1].height = rdp.ci_width*3/4;
3523
}
3524
//*/
3525
}
3526
#ifdef __cplusplus
3527
}
3528
#endif
3529
3530
//*/
3531
#include "UcodeFB.h"
3532
3533
void DetectFrameBufferUsage ()
3534
{
3535
RDP("DetectFrameBufferUsage\n");
3536
3537
DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
3538
#ifdef _WIN32
3539
DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
3540
#endif // _WIN32
3541
DWORD a;
3542
3543
BOOL tidal = FALSE;
3544
if (settings.PM && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self))
3545
tidal = TRUE;
3546
DWORD ci = rdp.cimg, zi = rdp.zimg; // ci_width = rdp.ci_width;
3547
rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0;
3548
rdp.main_ci_index = rdp.copy_ci_index = 0;
3549
rdp.zimg_end = 0;
3550
rdp.tmpzimg = 0;
3551
rdp.motionblur = FALSE;
3552
rdp.main_ci_last_tex_addr = 0;
3553
BOOL previous_ci_was_read = rdp.read_previous_ci;
3554
rdp.read_previous_ci = FALSE;
3555
rdp.read_whole_frame = FALSE;
3556
rdp.swap_ci_index = rdp.black_ci_index = -1;
3557
SwapOK = TRUE;
3558
3559
// Start executing at the start of the display list
3560
rdp.pc_i = 0;
3561
rdp.pc[rdp.pc_i] = dlist_start;
3562
rdp.dl_count = -1;
3563
rdp.halt = 0;
3564
rdp.scale_x_bak = rdp.scale_x;
3565
rdp.scale_y_bak = rdp.scale_y;
3566
3567
// MAIN PROCESSING LOOP
3568
do {
3569
3570
// Get the address of the next command
3571
a = rdp.pc[rdp.pc_i] & BMASK;
3572
3573
// Load the next command and its input
3574
rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
3575
rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
3576
3577
// Output the address before the command
3578
3579
// Go to the next instruction
3580
rdp.pc[rdp.pc_i] = (a+8) & BMASK;
3581
3582
if ((intptr_t)(gfx_instruction_lite[settings.ucode][rdp.cmd0>>24]))
3583
gfx_instruction_lite[settings.ucode][rdp.cmd0>>24] ();
3584
3585
// check DL counter
3586
if (rdp.dl_count != -1)
3587
{
3588
rdp.dl_count --;
3589
if (rdp.dl_count == 0)
3590
{
3591
rdp.dl_count = -1;
3592
3593
RDP ("End of DL\n");
3594
rdp.pc_i --;
3595
}
3596
}
3597
3598
} while (!rdp.halt);
3599
SwapOK = TRUE;
3600
if (rdp.ci_count > NUMTEXBUF) //overflow
3601
{
3602
rdp.cimg = ci;
3603
rdp.zimg = zi;
3604
rdp.num_of_ci = rdp.ci_count;
3605
rdp.scale_x = rdp.scale_x_bak;
3606
rdp.scale_y = rdp.scale_y_bak;
3607
return;
3608
}
3609
3610
if (rdp.black_ci_index > 0 && rdp.black_ci_index < rdp.copy_ci_index)
3611
rdp.frame_buffers[rdp.black_ci_index].status = ci_main;
3612
3613
if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown)
3614
{
3615
if (rdp.ci_count > 1)
3616
rdp.frame_buffers[rdp.ci_count-1].status = ci_aux;
3617
else
3618
rdp.frame_buffers[rdp.ci_count-1].status = ci_main;
3619
}
3620
3621
if ((rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) &&
3622
(rdp.frame_buffers[rdp.main_ci_index].width < 320) &&
3623
(rdp.frame_buffers[rdp.ci_count-1].width > rdp.frame_buffers[rdp.main_ci_index].width))
3624
{
3625
for (int i = 0; i < rdp.ci_count; i++)
3626
{
3627
if (rdp.frame_buffers[i].status == ci_main)
3628
rdp.frame_buffers[i].status = ci_aux;
3629
else if (rdp.frame_buffers[i].addr == rdp.frame_buffers[rdp.ci_count-1].addr)
3630
rdp.frame_buffers[i].status = ci_main;
3631
// FRDP("rdp.frame_buffers[%d].status = %d\n", i, rdp.frame_buffers[i].status);
3632
}
3633
rdp.main_ci_index = rdp.ci_count-1;
3634
}
3635
3636
BOOL all_zimg = TRUE;
3637
int i;
3638
for (i = 0; i < rdp.ci_count; i++)
3639
{
3640
if (rdp.frame_buffers[i].status != ci_zimg)
3641
{
3642
all_zimg = FALSE;
3643
break;
3644
}
3645
}
3646
if (all_zimg)
3647
{
3648
for (i = 0; i < rdp.ci_count; i++)
3649
rdp.frame_buffers[i].status = ci_main;
3650
}
3651
3652
RDP("detect fb final results: \n");
3653
for (i = 0; i < rdp.ci_count; i++)
3654
{
3655
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);
3656
}
3657
3658
rdp.cimg = ci;
3659
rdp.zimg = zi;
3660
rdp.num_of_ci = rdp.ci_count;
3661
if (rdp.read_previous_ci && previous_ci_was_read)
3662
if (!settings.fb_hires || !rdp.copy_ci_index)
3663
rdp.motionblur = TRUE;
3664
if (rdp.motionblur || settings.fb_hires || (rdp.frame_buffers[rdp.copy_ci_index].status == ci_aux_copy))
3665
{
3666
rdp.scale_x = rdp.scale_x_bak;
3667
rdp.scale_y = rdp.scale_y_bak;
3668
}
3669
3670
if ((rdp.read_previous_ci || previous_ci_was_read) && !rdp.copy_ci_index)
3671
rdp.read_whole_frame = TRUE;
3672
if (rdp.read_whole_frame)
3673
{
3674
if (settings.fb_hires && !settings.fb_ignore_previous)
3675
{
3676
if (rdp.swap_ci_index < 0)
3677
{
3678
rdp.texbufs[0].clear_allowed = TRUE;
3679
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
3680
}
3681
}
3682
else
3683
{
3684
if (rdp.motionblur)
3685
{
3686
if (settings.fb_motionblur)
3687
CopyFrameBuffer();
3688
else
3689
memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
3690
}
3691
else //if (ci_width == rdp.frame_buffers[rdp.main_ci_index].width)
3692
{
3693
if (rdp.maincimg[0].height > 65) //for 1080
3694
{
3695
rdp.cimg = rdp.maincimg[0].addr;
3696
rdp.ci_width = rdp.maincimg[0].width;
3697
rdp.ci_count = 0;
3698
DWORD h = rdp.frame_buffers[0].height;
3699
rdp.frame_buffers[0].height = rdp.maincimg[0].height;
3700
CopyFrameBuffer();
3701
rdp.frame_buffers[0].height = h;
3702
}
3703
else //conker
3704
{
3705
CopyFrameBuffer();
3706
}
3707
}
3708
}
3709
}
3710
3711
if (settings.fb_hires)
3712
{
3713
for (i = 0; i < num_tmu; i++)
3714
{
3715
rdp.texbufs[i].clear_allowed = TRUE;
3716
for (int j = 0; j < 256; j++)
3717
{
3718
rdp.texbufs[i].images[j].drawn = FALSE;
3719
rdp.texbufs[i].images[j].clear = TRUE;
3720
}
3721
}
3722
if (tidal)
3723
{
3724
//RDP("Tidal wave!\n");
3725
rdp.copy_ci_index = rdp.main_ci_index;
3726
}
3727
}
3728
rdp.ci_count = 0;
3729
if (settings.fb_ignore_previous)
3730
rdp.read_whole_frame = FALSE;
3731
else
3732
rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
3733
// rdp.scale_x = rdp.scale_x_bak;
3734
// rdp.scale_y = rdp.scale_y_bak;
3735
RDP("DetectFrameBufferUsage End\n");
3736
}
3737
3738
3739
3740
3741
#ifdef __cplusplus
3742
extern "C" {
3743
#endif
3744
3745
/******************************************************************
3746
Function: ProcessRDPList
3747
Purpose: This function is called when there is a Dlist to be
3748
processed. (Low level GFX list)
3749
input: none
3750
output: none
3751
*******************************************************************/
3752
EXPORT void CALL ProcessRDPList(void)
3753
{
3754
if (settings.KI)
3755
{
3756
*gfx.MI_INTR_REG |= 0x20;
3757
gfx.CheckInterrupts();
3758
}
3759
LOG ("ProcessRDPList ()\n");
3760
3761
no_dlist = FALSE;
3762
update_screen_count = 0;
3763
ChangeSize ();
3764
3765
#ifdef ALTTAB_FIX
3766
if (!hhkLowLevelKybd)
3767
{
3768
hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
3769
LowLevelKeyboardProc, hInstance, 0);
3770
}
3771
#endif
3772
3773
LOG ("ProcessDList ()\n");
3774
3775
if (!fullscreen)
3776
{
3777
drawNoFullscreenMessage();
3778
// Set an interrupt to allow the game to continue
3779
*gfx.MI_INTR_REG |= 0x20;
3780
gfx.CheckInterrupts();
3781
}
3782
3783
if (reset)
3784
{
3785
reset = 0;
3786
3787
memset (microcode, 0, 4096);
3788
if (settings.autodetect_ucode)
3789
{
3790
// Thanks to ZeZu for ucode autodetection!!!
3791
3792
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
3793
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
3794
microcheck ();
3795
3796
}
3797
}
3798
else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
3799
{
3800
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
3801
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
3802
microcheck ();
3803
}
3804
3805
if (exception) return;
3806
3807
// Switch to fullscreen?
3808
if (to_fullscreen)
3809
{
3810
to_fullscreen = FALSE;
3811
3812
if (!InitGfx (FALSE))
3813
{
3814
LOG ("FAILED!!!\n");
3815
return;
3816
}
3817
fullscreen = TRUE;
3818
}
3819
3820
// Clear out the RDP log
3821
#ifdef RDP_LOGGING
3822
if (settings.logging && settings.log_clear)
3823
{
3824
CLOSE_RDP_LOG ();
3825
OPEN_RDP_LOG ();
3826
}
3827
#endif
3828
3829
#ifdef UNIMP_LOG
3830
if (settings.log_unk && settings.unk_clear)
3831
{
3832
std::ofstream unimp;
3833
unimp.open("unimp.txt");
3834
unimp.close();
3835
}
3836
#endif
3837
3838
//* Set states *//
3839
if (settings.swapmode > 0)
3840
SwapOK = TRUE;
3841
rdp.updatescreen = 1;
3842
3843
rdp.tri_n = 0; // 0 triangles so far this frame
3844
rdp.debug_n = 0;
3845
3846
rdp.model_i = 0; // 0 matrices so far in stack
3847
//stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin!
3848
rdp.model_stack_size = min(32, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
3849
if (rdp.model_stack_size == 0)
3850
rdp.model_stack_size = 32;
3851
rdp.fb_drawn = rdp.fb_drawn_front = FALSE;
3852
rdp.update = 0x7FFFFFFF; // All but clear cache
3853
rdp.geom_mode = 0;
3854
rdp.acmp = 0;
3855
rdp.maincimg[1] = rdp.maincimg[0];
3856
rdp.skip_drawing = FALSE;
3857
rdp.s2dex_tex_loaded = FALSE;
3858
fbreads_front = fbreads_back = 0;
3859
rdp.fog_multiplier = rdp.fog_offset = 0;
3860
rdp.zsrc = 0;
3861
3862
if (cpu_fb_write == TRUE)
3863
DrawFrameBufferToScreen();
3864
cpu_fb_write = FALSE;
3865
cpu_fb_read_called = FALSE;
3866
cpu_fb_write_called = FALSE;
3867
cpu_fb_ignore = FALSE;
3868
d_ul_x = 0xffff;
3869
d_ul_y = 0xffff;
3870
d_lr_x = 0;
3871
d_lr_y = 0;
3872
3873
//analize possible frame buffer usage
3874
if (settings.fb_smart)
3875
DetectFrameBufferUsage();
3876
if (!settings.lego || rdp.num_of_ci > 1)
3877
rdp.last_bg = 0;
3878
//* End of set states *//
3879
3880
3881
// Get the start of the display list and the length of it
3882
// DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
3883
// DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
3884
DWORD dlist_start = *gfx.DPC_CURRENT_REG;
3885
DWORD dlist_length = *gfx.DPC_END_REG - *gfx.DPC_CURRENT_REG;
3886
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);
3887
FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
3888
3889
if (settings.tonic && dlist_length < 16)
3890
{
3891
rdp_fullsync();
3892
FRDP_E("DLIST is too short!\n");
3893
return;
3894
}
3895
3896
// Start executing at the start of the display list
3897
rdp.pc_i = 0;
3898
rdp.pc[rdp.pc_i] = dlist_start;
3899
rdp.dl_count = -1;
3900
rdp.halt = 0;
3901
DWORD a;
3902
3903
// catches exceptions so that it doesn't freeze
3904
#ifdef CATCH_EXCEPTIONS
3905
try {
3906
#endif
3907
3908
// MAIN PROCESSING LOOP
3909
do {
3910
3911
// Get the address of the next command
3912
a = rdp.pc[rdp.pc_i] & BMASK;
3913
3914
// Load the next command and its input
3915
rdp.cmd0 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
3916
rdp.cmd1 = ((DWORD*)gfx.RDRAM)[(a>>2)+1]; // /
3917
// cmd2 and cmd3 are filled only when needed, by the function that needs them
3918
3919
// Output the address before the command
3920
#ifdef LOG_COMMANDS
3921
FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1);
3922
#else
3923
FRDP ("%08lx: ", a);
3924
#endif
3925
3926
// Go to the next instruction
3927
rdp.pc[rdp.pc_i] = (a+8) & BMASK;
3928
3929
#ifdef PERFORMANCE
3930
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
3931
#endif
3932
// Process this instruction
3933
gfx_instruction[settings.ucode][((rdp.cmd0>>24)&0x3f) + 0x100-0x40] ();
3934
3935
// check DL counter
3936
if (rdp.dl_count != -1)
3937
{
3938
rdp.dl_count --;
3939
if (rdp.dl_count == 0)
3940
{
3941
rdp.dl_count = -1;
3942
3943
RDP ("End of DL\n");
3944
rdp.pc_i --;
3945
}
3946
}
3947
3948
#ifdef PERFORMANCE
3949
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
3950
__int64 t = perf_next-perf_cur;
3951
sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
3952
rdp_log << out_buf;
3953
#endif
3954
3955
} while (0);
3956
#ifdef CATCH_EXCEPTIONS
3957
} catch (...) {
3958
3959
if (fullscreen) ReleaseGfx ();
3960
WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled.");
3961
exception = TRUE;
3962
}
3963
#endif
3964
3965
if (settings.fb_smart)
3966
{
3967
rdp.scale_x = rdp.scale_x_bak;
3968
rdp.scale_y = rdp.scale_y_bak;
3969
}
3970
if (settings.fb_read_always)
3971
{
3972
CopyFrameBuffer ();
3973
}
3974
if (rdp.yuv_image)
3975
{
3976
DrawYUVImageToFrameBuffer();
3977
rdp.yuv_image = FALSE;
3978
// FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
3979
// rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
3980
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
3981
rdp.yuv_im_begin = 0x00FFFFFF;
3982
}
3983
if (rdp.cur_image)
3984
CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
3985
3986
if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
3987
{
3988
newSwapBuffers ();
3989
CI_SET = FALSE;
3990
}
3991
RDP("ProcessDList end\n");
3992
3993
3994
3995
3996
3997
3998
WriteLog(M64MSG_VERBOSE, "ProcessRPDList %x %x %x\n",
3999
*gfx.DPC_START_REG,
4000
*gfx.DPC_END_REG,
4001
*gfx.DPC_CURRENT_REG);
4002
//*gfx.DPC_STATUS_REG = 0xffffffff; // &= ~0x0002;
4003
4004
*gfx.DPC_START_REG = *gfx.DPC_END_REG;
4005
*gfx.DPC_CURRENT_REG = *gfx.DPC_END_REG;
4006
}
4007
4008
#ifdef __cplusplus
4009
}
4010
#endif
4011
4012
4013
4014
4015
4016
// Local Variables: ***
4017
// tab-width:4 ***
4018
// c-file-offset:4 ***
4019
// End: ***
4020
4021
4022