Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / ucode06.h
CommitLineData
98e75f2d 1/*
2* Glide64 - Glide video plugin for Nintendo 64 emulators.
3* Copyright (c) 2002 Dave2001
4* Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski
5*
6* This program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, write to the Free Software
18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21//****************************************************************
22//
23// Glide64 - Glide Plugin for Nintendo 64 emulators
24// Project started on December 29th, 2001
25//
26// Authors:
27// Dave2001, original author, founded the project in 2001, left it in 2002
28// Gugaman, joined the project in 2002, left it in 2002
29// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30// Hiroshi 'KoolSmoky' Morii, joined the project in 2007
31//
32//****************************************************************
33//
34// To modify Glide64:
35// * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
36// * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
37//
38//****************************************************************
39
40// STANDARD DRAWIMAGE - draws a 2d image based on the following structure
41
42static float set_sprite_combine_mode ()
43{
44 if (rdp.cycle_mode == 2)
45 {
46 rdp.tex = 1;
47 rdp.allow_combine = 0;
48 // Now actually combine !
49 GrCombineFunction_t color_source = GR_COMBINE_FUNCTION_LOCAL;
50 if (rdp.tbuff_tex && rdp.tbuff_tex->info.format == GR_TEXFMT_ALPHA_INTENSITY_88)
51 color_source = GR_COMBINE_FUNCTION_LOCAL_ALPHA;
52 cmb.tmu1_func = cmb.tmu0_func = color_source;
53 cmb.tmu1_fac = cmb.tmu0_fac = GR_COMBINE_FACTOR_NONE;
54 cmb.tmu1_a_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;
55 cmb.tmu1_a_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
56 cmb.tmu1_invert = cmb.tmu0_invert = FXFALSE;
57 cmb.tmu1_a_invert = cmb.tmu0_a_invert = FXFALSE;
58 }
59
60 rdp.update |= UPDATE_COMBINE;
61 update ();
62
63 rdp.allow_combine = 1;
64
65 // set z buffer mode
66 float Z = 0.0f;
67 if ((rdp.othermode_l & 0x00000030) && rdp.cycle_mode < 2)
68 {
69 if (rdp.zsrc == 1)
70 {
71 Z = rdp.prim_depth;
72 }
73 FRDP ("prim_depth = %d, prim_dz = %d\n", rdp.prim_depth, rdp.prim_dz);
74 Z = ScaleZ(Z);
75
76 if (rdp.othermode_l & 0x00000400)
77 grDepthBiasLevel(rdp.prim_dz);
78 }
79 else
80 {
81 LRDP("z compare not used, using 0\n");
82 }
83
84 grCullMode (GR_CULL_DISABLE);
85 grFogMode (GR_FOG_DISABLE);
86 rdp.update |= UPDATE_CULL_MODE | UPDATE_FOG_ENABLED;
87
88 if (rdp.cycle_mode == 2)
89 {
90 grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
91 GR_COMBINE_FACTOR_ONE,
92 GR_COMBINE_LOCAL_NONE,
93 GR_COMBINE_OTHER_TEXTURE,
94 FXFALSE);
95 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
96 GR_COMBINE_FACTOR_ONE,
97 GR_COMBINE_LOCAL_NONE,
98 GR_COMBINE_OTHER_TEXTURE,
99 FXFALSE);
100 grAlphaBlendFunction (GR_BLEND_ONE,
101 GR_BLEND_ZERO,
102 GR_BLEND_ZERO,
103 GR_BLEND_ZERO);
104 if (rdp.othermode_l & 1)
105 {
106 grAlphaTestFunction (GR_CMP_GEQUAL);
107 grAlphaTestReferenceValue (0x80);
108 }
109 else
110 grAlphaTestFunction (GR_CMP_ALWAYS);
111 rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
112 }
113 return Z;
114}
115
116void uc6_sprite2d ();
117
118typedef struct DRAWIMAGE_t {
119 float frameX;
120 float frameY;
121 wxUint16 frameW;
122 wxUint16 frameH;
123 wxUint16 imageX;
124 wxUint16 imageY;
125 wxUint16 imageW;
126 wxUint16 imageH;
127 wxUint32 imagePtr;
128 wxUint8 imageFmt;
129 wxUint8 imageSiz;
130 wxUint16 imagePal;
131 wxUint8 flipX;
132 wxUint8 flipY;
133 float scaleX;
134 float scaleY;
135} DRAWIMAGE;
136
137typedef struct DRAWOBJECT_t {
138 float objX;
139 float objY;
140 float scaleW;
141 float scaleH;
142 short imageW;
143 short imageH;
144
145 wxUint16 imageStride;
146 wxUint16 imageAdrs;
147 wxUint8 imageFmt;
148 wxUint8 imageSiz;
149 wxUint8 imagePal;
150 wxUint8 imageFlags;
151} DRAWOBJECT;
152
153void DrawHiresDepthImage (const DRAWIMAGE & d)
154{
155Check_FrameSkip;
156
157 wxUint16 * src = (wxUint16*)(gfx.RDRAM+d.imagePtr);
158 wxUint16 image[512*512];
159 wxUint16 * dst = image;
160 for (int h = 0; h < d.imageH; h++)
161 {
162 for (int w = 0; w < d.imageW; w++)
163 {
164 *(dst++) = src[(w+h*d.imageW)^1];
165 }
166 dst += (512 - d.imageW);
167 }
168 GrTexInfo t_info;
169 t_info.format = GR_TEXFMT_RGB_565;
170 t_info.data = image;
171 t_info.smallLodLog2 = GR_LOD_LOG2_512;
172 t_info.largeLodLog2 = GR_LOD_LOG2_512;
173 t_info.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
174
175 grTexDownloadMipMap (rdp.texbufs[1].tmu,
176 rdp.texbufs[1].begin,
177 GR_MIPMAPLEVELMASK_BOTH,
178 &t_info);
179 grTexSource (rdp.texbufs[1].tmu,
180 rdp.texbufs[1].begin,
181 GR_MIPMAPLEVELMASK_BOTH,
182 &t_info);
183 grTexCombine( GR_TMU1,
184 GR_COMBINE_FUNCTION_LOCAL,
185 GR_COMBINE_FACTOR_NONE,
186 GR_COMBINE_FUNCTION_LOCAL,
187 GR_COMBINE_FACTOR_NONE,
188 FXFALSE,
189 FXFALSE );
190 grTexCombine( GR_TMU0,
191 GR_COMBINE_FUNCTION_SCALE_OTHER,
192 GR_COMBINE_FACTOR_ONE,
193 GR_COMBINE_FUNCTION_SCALE_OTHER,
194 GR_COMBINE_FACTOR_ONE,
195 FXFALSE,
196 FXFALSE );
197 grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
198 GR_COMBINE_FACTOR_ONE,
199 GR_COMBINE_LOCAL_NONE,
200 GR_COMBINE_OTHER_TEXTURE,
201 FXFALSE);
202 grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
203 GR_COMBINE_FACTOR_ONE,
204 GR_COMBINE_LOCAL_NONE,
205 GR_COMBINE_OTHER_TEXTURE,
206 FXFALSE);
207 grAlphaBlendFunction (GR_BLEND_ONE,
208 GR_BLEND_ZERO,
209 GR_BLEND_ONE,
210 GR_BLEND_ZERO);
211 grDepthBufferFunction (GR_CMP_ALWAYS);
212 grDepthMask (FXFALSE);
213
214 GrLOD_t LOD = GR_LOD_LOG2_1024;
215 if (settings.scr_res_x > 1024)
216 LOD = GR_LOD_LOG2_2048;
217
218 float lr_x = (float)d.imageW * rdp.scale_x;
219 float lr_y = (float)d.imageH * rdp.scale_y;
220 float lr_u = (float)d.imageW * 0.5f;// - 0.5f;
221 float lr_v = (float)d.imageH * 0.5f;// - 0.5f;
222 VERTEX v[4] = {
223 { 0, 0, 1.0f, 1.0f, 0, 0, 0, 0 },
224 { lr_x, 0, 1.0f, 1.0f, lr_u, 0, lr_u, 0 },
225 { 0, lr_y, 1.0f, 1.0f, 0, lr_v, 0, lr_v },
226 { lr_x, lr_y, 1.0f, 1.0f, lr_u, lr_v, lr_u, lr_v }
227 };
228 AddOffset(v, 4);
229 for (int i=0; i<4; i++)
230 {
231 v[i].uc(0) = v[i].uc(1) = v[i].u0;
232 v[i].vc(0) = v[i].vc(1) = v[i].v0;
233 }
234 grTextureBufferExt( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, LOD, LOD,
235 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
236 grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT );
237 grAuxBufferExt( GR_BUFFER_AUXBUFFER );
238 grSstOrigin(GR_ORIGIN_UPPER_LEFT);
239 grBufferClear (0, 0, 0xFFFF);
240 grDrawTriangle (&v[0], &v[2], &v[1]);
241 grDrawTriangle (&v[2], &v[3], &v[1]);
242 grRenderBuffer( GR_BUFFER_BACKBUFFER );
243 grTextureAuxBufferExt( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, LOD, LOD,
244 GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH );
245 grAuxBufferExt( GR_BUFFER_TEXTUREAUXBUFFER_EXT );
246 grDepthMask (FXTRUE);
247}
248
249
250void DrawDepthImage (const DRAWIMAGE & d)
251{
252Check_FrameSkip;
253
254 if (!fullscreen || !fb_depth_render_enabled)
255 return;
256 if (d.imageH > d.imageW)
257 return;
258 LRDP("Depth image write\n");
259 if (fb_hwfbe_enabled)
260 {
261 DrawHiresDepthImage(d);
262 return;
263 }
264 float scale_x_dst = rdp.scale_x;
265 float scale_y_dst = rdp.scale_y;
266 float scale_x_src = 1.0f/rdp.scale_x;
267 float scale_y_src = 1.0f/rdp.scale_y;
268 int src_width = d.imageW;
269 int src_height = d.imageH;
270 int dst_width = min(int(src_width*scale_x_dst), (int)settings.scr_res_x);
271 int dst_height = min(int(src_height*scale_y_dst), (int)settings.scr_res_y);
272 wxUint16 * src = (wxUint16*)(gfx.RDRAM+d.imagePtr);
273 wxUint16 * dst = new wxUint16[dst_width*dst_height];
274 for (int y=0; y < dst_height; y++)
275 {
276 for (int x=0; x < dst_width; x++)
277 {
278 dst[x+y*dst_width] = src[(int(x*scale_x_src)+int(y*scale_y_src)*src_width)^1];
279 }
280 }
281 grLfbWriteRegion(GR_BUFFER_AUXBUFFER,
282 0,
283 0,
284 GR_LFB_SRC_FMT_ZA16,
285 dst_width,
286 dst_height,
287 FXFALSE,
288 dst_width<<1,
289 dst);
290 delete[] dst;
291}
292
293void DrawImage (DRAWIMAGE & d)
294{
295Check_FrameSkip;
296
297 if (d.imageW == 0 || d.imageH == 0 || d.frameH == 0) return;
298
299 int x_size, y_size, x_shift, y_shift, line;
300 // choose optimum size for the format/size
301 switch (d.imageSiz)
302 {
303 case 0:
304 if (rdp.tlut_mode < 2)
305 {
306 y_size = 64;
307 y_shift = 6;
308 }
309 else
310 {
311 y_size = 32;
312 y_shift = 5;
313 }
314 x_size = 128;
315 x_shift = 7;
316 line = 8;
317 break;
318 case 1:
319 if (rdp.tlut_mode < 2)
320 {
321 y_size = 64;
322 y_shift = 6;
323 }
324 else
325 {
326 y_size = 32;
327 y_shift = 5;
328 }
329 x_size = 64;
330 x_shift = 6;
331 line = 8;
332 break;
333 case 2:
334 x_size = 64;
335 y_size = 32;
336 x_shift = 6;
337 y_shift = 5;
338 line = 16;
339 break;
340 case 3:
341 x_size = 32;
342 y_size = 16;
343 x_shift = 4;
344 y_shift = 3;
345 line = 16;
346 break;
347 default:
348 FRDP("DrawImage. unknown image size: %d\n", d.imageSiz);
349 return;
350 }
351
352 if (rdp.ci_width == 512 && !no_dlist) //RE2
353 {
354 wxUint16 width = (wxUint16)(*gfx.VI_WIDTH_REG & 0xFFF);
355 d.frameH = d.imageH = (d.frameW*d.frameH)/width;
356 d.frameW = d.imageW = width;
357 if (rdp.zimg == rdp.cimg)
358 {
359 DrawDepthImage(d);
360 rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE |
361 UPDATE_ALPHA_COMPARE | UPDATE_VIEWPORT;
362 return;
363 }
364 }
365
366 if ((settings.hacks&hack_PPL) > 0)
367 {
368 if (d.imageY > d.imageH)
369 d.imageY = (d.imageY%d.imageH);
370 }
371 else if ((settings.hacks&hack_Starcraft) > 0)
372 {
373 if (d.imageH%2 == 1)
374 d.imageH -= 1;
375 }
376 else
377 {
378 if ( (d.frameX > 0) && (d.frameW == rdp.ci_width) )
379 d.frameW -= (wxUint16)(2.0f*d.frameX);
380 if ( (d.frameY > 0) && (d.frameH == rdp.ci_height) )
381 d.frameH -= (wxUint16)(2.0f*d.frameY);
382 }
383
384 int ul_u = (int)d.imageX;
385 int ul_v = (int)d.imageY;
386 int lr_u = (int)d.imageX + (int)(d.frameW * d.scaleX);
387 int lr_v = (int)d.imageY + (int)(d.frameH * d.scaleY);
388
389 float ul_x, ul_y, lr_x, lr_y;
390 if (d.flipX)
391 {
392 ul_x = d.frameX + d.frameW;
393 lr_x = d.frameX;
394 }
395 else
396 {
397 ul_x = d.frameX;
398 lr_x = d.frameX + d.frameW;
399 }
400 if (d.flipY)
401 {
402 ul_y = d.frameY + d.frameH;
403 lr_y = d.frameY;
404 }
405 else
406 {
407 ul_y = d.frameY;
408 lr_y = d.frameY + d.frameH;
409 }
410
411 int min_wrap_u = ul_u / d.imageW;
412 //int max_wrap_u = lr_u / d.wrapW;
413 int min_wrap_v = ul_v / d.imageH;
414 //int max_wrap_v = lr_v / d.wrapH;
415 int min_256_u = ul_u >> x_shift;
416 //int max_256_u = (lr_u-1) >> x_shift;
417 int min_256_v = ul_v >> y_shift;
418 //int max_256_v = (lr_v-1) >> y_shift;
419
420
421 // SetTextureImage ()
422 rdp.timg.format = d.imageFmt; // RGBA
423 rdp.timg.size = d.imageSiz; // 16-bit
424 rdp.timg.addr = d.imagePtr;
425 rdp.timg.width = (d.imageW%2)?d.imageW-1:d.imageW;
426 rdp.timg.set_by = 0;
427
428 // SetTile ()
429 TILE *tile = &rdp.tiles[0];
430 tile->format = d.imageFmt; // RGBA
431 tile->size = d.imageSiz; // 16-bit
432 tile->line = line;
433 tile->t_mem = 0;
434 tile->palette = (wxUint8)d.imagePal;
435 tile->clamp_t = 1;
436 tile->mirror_t = 0;
437 tile->mask_t = 0;
438 tile->shift_t = 0;
439 tile->clamp_s = 1;
440 tile->mirror_s = 0;
441 tile->mask_s = 0;
442 tile->shift_s = 0;
443
444 rdp.tiles[0].ul_s = 0;
445 rdp.tiles[0].ul_t = 0;
446 rdp.tiles[0].lr_s = x_size-1;
447 rdp.tiles[0].lr_t = y_size-1;
448
449 const float Z = set_sprite_combine_mode ();
450 if (rdp.cycle_mode == 2)
451 rdp.allow_combine = 0;
452
453 if (fullscreen)
454 {
455 if (rdp.ci_width == 512 && !no_dlist)
456 grClipWindow (0, 0, settings.scr_res_x, settings.scr_res_y);
457 else if (d.scaleX == 1.0f && d.scaleY == 1.0f)
458 grClipWindow (rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y);
459 else
460 grClipWindow (rdp.scissor.ul_x, rdp.scissor.ul_y, min(rdp.scissor.lr_x, (wxUint32)((d.frameX+d.imageW/d.scaleX+0.5f)*rdp.scale_x)), min(rdp.scissor.lr_y, (wxUint32)((d.frameY+d.imageH/d.scaleY+0.5f)*rdp.scale_y)));
461 rdp.update |= UPDATE_SCISSOR;
462 }
463
464 // Texture ()
465 rdp.cur_tile = 0;
466
467 float nul_x, nul_y, nlr_x, nlr_y;
468 int nul_u, nul_v, nlr_u, nlr_v;
469 float ful_u, ful_v, flr_u, flr_v;
470 float ful_x, ful_y, flr_x, flr_y;
471
472 float mx = (float)(lr_x - ul_x) / (float)(lr_u - ul_u);
473 float bx = ul_x - mx * ul_u;
474
475 float my = (float)(lr_y - ul_y) / (float)(lr_v - ul_v);
476 float by = ul_y - my * ul_v;
477
478 int cur_wrap_u, cur_wrap_v, cur_u, cur_v;
479 int cb_u, cb_v; // coordinate-base
480 int tb_u, tb_v; // texture-base
481
482 nul_v = ul_v;
483 nul_y = ul_y;
484
485 // #162
486
487 cur_wrap_v = min_wrap_v + 1;
488 cur_v = min_256_v + 1;
489 cb_v = ((cur_v-1)<<y_shift);
490 while (cb_v >= d.imageH) cb_v -= d.imageH;
491 tb_v = cb_v;
492 rdp.bg_image_height = d.imageH;
493
494 while (1)
495 {
496 cur_wrap_u = min_wrap_u + 1;
497 cur_u = min_256_u + 1;
498
499 // calculate intersection with this point
500 nlr_v = min (min (cur_wrap_v*d.imageH, (cur_v<<y_shift)), lr_v);
501 nlr_y = my * nlr_v + by;
502
503 nul_u = ul_u;
504 nul_x = ul_x;
505 cb_u = ((cur_u-1)<<x_shift);
506 while (cb_u >= d.imageW) cb_u -= d.imageW;
507 tb_u = cb_u;
508
509 while (1)
510 {
511 // calculate intersection with this point
512 nlr_u = min (min (cur_wrap_u*d.imageW, (cur_u<<x_shift)), lr_u);
513 nlr_x = mx * nlr_u + bx;
514
515 // ** Load the texture, constant portions have been set above
516 // SetTileSize ()
517 rdp.tiles[0].ul_s = tb_u;
518 rdp.tiles[0].ul_t = tb_v;
519 rdp.tiles[0].lr_s = tb_u+x_size-1;
520 rdp.tiles[0].lr_t = tb_v+y_size-1;
521
522 // LoadTile ()
523 rdp.cmd0 = ((int)rdp.tiles[0].ul_s << 14) | ((int)rdp.tiles[0].ul_t << 2);
524 rdp.cmd1 = ((int)rdp.tiles[0].lr_s << 14) | ((int)rdp.tiles[0].lr_t << 2);
525 rdp_loadtile ();
526
527 TexCache ();
528 // **
529
530 ful_u = (float)nul_u - cb_u;
531 flr_u = (float)nlr_u - cb_u;
532 ful_v = (float)nul_v - cb_v;
533 flr_v = (float)nlr_v - cb_v;
534
535 ful_u *= rdp.cur_cache[0]->c_scl_x;
536 ful_v *= rdp.cur_cache[0]->c_scl_y;
537 flr_u *= rdp.cur_cache[0]->c_scl_x;
538 flr_v *= rdp.cur_cache[0]->c_scl_y;
539
540 ful_x = nul_x * rdp.scale_x + rdp.offset_x;
541 flr_x = nlr_x * rdp.scale_x + rdp.offset_x;
542 ful_y = nul_y * rdp.scale_y + rdp.offset_y;
543 flr_y = nlr_y * rdp.scale_y + rdp.offset_y;
544
545 // Make the vertices
546
547 if ((flr_x <= rdp.scissor.lr_x) || (ful_x < rdp.scissor.lr_x))
548 {
549 VERTEX v[4] = {
550 { ful_x, ful_y, Z, 1.0f, ful_u, ful_v },
551 { flr_x, ful_y, Z, 1.0f, flr_u, ful_v },
552 { ful_x, flr_y, Z, 1.0f, ful_u, flr_v },
553 { flr_x, flr_y, Z, 1.0f, flr_u, flr_v } };
554 AllowShadeMods (v, 4);
555 for (int s = 0; s < 4; s++)
556 apply_shade_mods (&(v[s]));
557 ConvertCoordsConvert (v, 4);
558
559 if (fullscreen)
560 grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, 4, v, sizeof(VERTEX));
561
562 if (_debugger.capture)
563 {
564 VERTEX vl[3];
565 vl[0] = v[0];
566 vl[1] = v[2];
567 vl[2] = v[1];
568 add_tri (vl, 3, TRI_BACKGROUND);
569 rdp.tri_n ++;
570 vl[0] = v[2];
571 vl[1] = v[3];
572 vl[2] = v[1];
573 add_tri (vl, 3, TRI_BACKGROUND);
574 rdp.tri_n ++;
575 }
576 else
577 rdp.tri_n += 2;
578 }
579 else
580 {
581 rdp.tri_n += 2;
582 LRDP("Clipped!\n");
583 }
584
585 // increment whatever caused this split
586 tb_u += x_size - (x_size-(nlr_u-cb_u));
587 cb_u = nlr_u;
588 if (nlr_u == cur_wrap_u*d.imageW) {
589 cur_wrap_u ++;
590 tb_u = 0;
591 }
592 if (nlr_u == (cur_u<<x_shift)) cur_u ++;
593 if (nlr_u == lr_u) break;
594 nul_u = nlr_u;
595 nul_x = nlr_x;
596 }
597
598 tb_v += y_size - (y_size-(nlr_v-cb_v));
599 cb_v = nlr_v;
600 if (nlr_v == cur_wrap_v*d.imageH) {
601 cur_wrap_v ++;
602 tb_v = 0;
603 }
604 if (nlr_v == (cur_v<<y_shift)) cur_v ++;
605 if (nlr_v == lr_v) break;
606 nul_v = nlr_v;
607 nul_y = nlr_y;
608 }
609
610 rdp.allow_combine = 1;
611 rdp.bg_image_height = 0xFFFF;
612}
613
614void DrawHiresImage(DRAWIMAGE & d, int screensize = FALSE)
615{
616Check_FrameSkip;
617
618 if (!fullscreen)
619 return;
620 TBUFF_COLOR_IMAGE *tbuff_tex = rdp.tbuff_tex;
621 if (rdp.motionblur)
622 rdp.tbuff_tex = &(rdp.texbufs[rdp.cur_tex_buf^1].images[0]);
623 else if (rdp.tbuff_tex == 0)
624 return;
625 FRDP("DrawHiresImage. fb format=%d\n", rdp.tbuff_tex->info.format);
626
627 setTBufTex(rdp.tbuff_tex->t_mem, rdp.tbuff_tex->width << rdp.tbuff_tex->size >> 1);
628
629 const float Z = set_sprite_combine_mode ();
630 grClipWindow (0, 0, settings.res_x, settings.res_y);
631
632 if (d.imageW%2 == 1) d.imageW -= 1;
633 if (d.imageH%2 == 1) d.imageH -= 1;
634 if (d.imageY > d.imageH) d.imageY = (d.imageY%d.imageH);
635
636 if (!(settings.hacks&hack_PPL))
637 {
638 if ( (d.frameX > 0) && (d.frameW == rdp.ci_width) )
639 d.frameW -= (wxUint16)(2.0f*d.frameX);
640 if ( (d.frameY > 0) && (d.frameH == rdp.ci_height) )
641 d.frameH -= (wxUint16)(2.0f*d.frameY);
642 }
643
644 float ul_x, ul_y, ul_u, ul_v, lr_x, lr_y, lr_u, lr_v;
645 if (screensize)
646 {
647 ul_x = 0.0f;
648 ul_y = 0.0f;
649 ul_u = 0.15f;
650 ul_v = 0.15f;
651 lr_x = rdp.tbuff_tex->scr_width;
652 lr_y = rdp.tbuff_tex->scr_height;
653 lr_u = rdp.tbuff_tex->lr_u;
654 lr_v = rdp.tbuff_tex->lr_v;
655 }
656 else
657 {
658 ul_u = d.imageX;
659 ul_v = d.imageY;
660 lr_u = d.imageX + (d.frameW * d.scaleX) ;
661 lr_v = d.imageY + (d.frameH * d.scaleY) ;
662
663 ul_x = d.frameX;
664 ul_y = d.frameY;
665
666 lr_x = d.frameX + d.frameW;
667 lr_y = d.frameY + d.frameH;
668 ul_x *= rdp.scale_x;
669 lr_x *= rdp.scale_x;
670 ul_y *= rdp.scale_y;
671 lr_y *= rdp.scale_y;
672 ul_u *= rdp.tbuff_tex->u_scale;
673 lr_u *= rdp.tbuff_tex->u_scale;
674 ul_v *= rdp.tbuff_tex->v_scale;
675 lr_v *= rdp.tbuff_tex->v_scale;
676 ul_u = max(0.15f, ul_u);
677 ul_v = max(0.15f, ul_v);
678 if (lr_x > rdp.scissor.lr_x) lr_x = (float)rdp.scissor.lr_x;
679 if (lr_y > rdp.scissor.lr_y) lr_y = (float)rdp.scissor.lr_y;
680 }
681 // Make the vertices
682 VERTEX v[4] = {
683 { ul_x, ul_y, Z, 1.0f, ul_u, ul_v, ul_u, ul_v },
684 { lr_x, ul_y, Z, 1.0f, lr_u, ul_v, lr_u, ul_v },
685 { ul_x, lr_y, Z, 1.0f, ul_u, lr_v, ul_u, lr_v },
686 { lr_x, lr_y, Z, 1.0f, lr_u, lr_v, lr_u, lr_v } };
687 ConvertCoordsConvert (v, 4);
688 AllowShadeMods (v, 4);
689 AddOffset(v, 4);
690 for (int s = 0; s < 4; s++)
691 apply_shade_mods (&(v[s]));
692 grDrawTriangle (&v[0], &v[2], &v[1]);
693 grDrawTriangle (&v[2], &v[3], &v[1]);
694 rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE | UPDATE_TEXTURE | UPDATE_ALPHA_COMPARE | UPDATE_SCISSOR;
695 if (_debugger.capture)
696 {
697 VERTEX vl[3];
698 vl[0] = v[0];
699 vl[1] = v[2];
700 vl[2] = v[1];
701 add_tri (vl, 3, TRI_BACKGROUND);
702 rdp.tri_n ++;
703 vl[0] = v[2];
704 vl[1] = v[3];
705 vl[2] = v[1];
706 add_tri (vl, 3, TRI_BACKGROUND);
707 rdp.tri_n ++;
708 }
709 else
710 rdp.tri_n += 2;
711 rdp.tbuff_tex = tbuff_tex;
712
713}
714
715//****************************************************************
716
717
718struct MAT2D {
719 float A, B, C, D;
720 float X, Y;
721 float BaseScaleX;
722 float BaseScaleY;
723} mat_2d = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f};
724
725static void uc6_read_background_data (DRAWIMAGE & d, bool bReadScale)
726{
727 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
728
729 d.imageX = (((wxUint16 *)gfx.RDRAM)[(addr+0)^1] >> 5); // 0
730 d.imageW = (((wxUint16 *)gfx.RDRAM)[(addr+1)^1] >> 2); // 1
731 d.frameX = ((short*)gfx.RDRAM)[(addr+2)^1] / 4.0f; // 2
732 d.frameW = ((wxUint16 *)gfx.RDRAM)[(addr+3)^1] >> 2; // 3
733
734 d.imageY = (((wxUint16 *)gfx.RDRAM)[(addr+4)^1] >> 5); // 4
735 d.imageH = (((wxUint16 *)gfx.RDRAM)[(addr+5)^1] >> 2); // 5
736 d.frameY = ((short*)gfx.RDRAM)[(addr+6)^1] / 4.0f; // 6
737 d.frameH = ((wxUint16 *)gfx.RDRAM)[(addr+7)^1] >> 2; // 7
738
739 d.imagePtr = segoffset(((wxUint32*)gfx.RDRAM)[(addr+8)>>1]); // 8,9
740 d.imageFmt = ((wxUint8 *)gfx.RDRAM)[(((addr+11)<<1)+0)^3]; // 11
741 d.imageSiz = ((wxUint8 *)gfx.RDRAM)[(((addr+11)<<1)+1)^3]; // |
742 d.imagePal = ((wxUint16 *)gfx.RDRAM)[(addr+12)^1]; // 12
743 wxUint16 imageFlip = ((wxUint16 *)gfx.RDRAM)[(addr+13)^1]; // 13;
744 d.flipX = (wxUint8)imageFlip&0x01;
745
746 if (bReadScale)
747 {
748 d.scaleX = ((short *)gfx.RDRAM)[(addr+14)^1] / 1024.0f; // 14
749 d.scaleY = ((short *)gfx.RDRAM)[(addr+15)^1] / 1024.0f; // 15
750 }
751 else
752 d.scaleX = d.scaleY = 1.0f;
753
754 d.flipY = 0;
755 int imageYorig= ((int *)gfx.RDRAM)[(addr+16)>>1] >> 5;
756 rdp.last_bg = d.imagePtr;
757
758 FRDP ("imagePtr: %08lx\n", d.imagePtr);
759 FRDP ("frameX: %f, frameW: %d, frameY: %f, frameH: %d\n", d.frameX, d.frameW, d.frameY, d.frameH);
760 FRDP ("imageX: %d, imageW: %d, imageY: %d, imageH: %d\n", d.imageX, d.imageW, d.imageY, d.imageH);
761 FRDP ("imageYorig: %d, scaleX: %f, scaleY: %f\n", imageYorig, d.scaleX, d.scaleY);
762 FRDP ("imageFmt: %d, imageSiz: %d, imagePal: %d, imageFlip: %d\n", d.imageFmt, d.imageSiz, d.imagePal, d.flipX);
763}
764
765static void uc6_bg (bool bg_1cyc)
766{
767 static const char *strFuncNames[] = {"uc6:bg_1cyc", "uc6:bg_copy"};
768 const char *strFuncName = bg_1cyc ? strFuncNames[0] : strFuncNames[1];
769 if (rdp.skip_drawing)
770 {
771 FRDP("%s skipped\n", strFuncName);
772 return;
773 }
774 FRDP ("%s #%d, #%d\n", strFuncName, rdp.tri_n, rdp.tri_n+1);
775
776 DRAWIMAGE d;
777 uc6_read_background_data(d, bg_1cyc);
778
779 if (fb_hwfbe_enabled && FindTextureBuffer(d.imagePtr, d.imageW))
780 {
781 DrawHiresImage(d);
782 return;
783 }
784
785 if (settings.ucode == ucode_F3DEX2 || (settings.hacks&hack_PPL))
786 {
787 if ( (d.imagePtr != rdp.cimg) && (d.imagePtr != rdp.ocimg) && d.imagePtr) //can't draw from framebuffer
788 DrawImage (d);
789 else
790 {
791 FRDP("%s skipped\n", strFuncName);
792 }
793 }
794 else
795 {
796 DrawImage (d);
797 }
798}
799
800static void uc6_bg_1cyc ()
801{
802 uc6_bg(true);
803}
804
805static void uc6_bg_copy ()
806{
807 uc6_bg(false);
808}
809
810static void draw_split_triangle(VERTEX **vtx)
811{
812Check_FrameSkip;
813
814 vtx[0]->not_zclipped = vtx[1]->not_zclipped = vtx[2]->not_zclipped = 1;
815
816 int index,i,j, min_256,max_256, cur_256,left_256,right_256;
817 float percent;
818
819 min_256 = min((int)vtx[0]->u0,(int)vtx[1]->u0); // bah, don't put two mins on one line
820 min_256 = min(min_256,(int)vtx[2]->u0) >> 8; // or it will be calculated twice
821
822 max_256 = max((int)vtx[0]->u0,(int)vtx[1]->u0); // not like it makes much difference
823 max_256 = max(max_256,(int)vtx[2]->u0) >> 8; // anyway :P
824
825 for (cur_256=min_256; cur_256<=max_256; cur_256++)
826 {
827 left_256 = cur_256 << 8;
828 right_256 = (cur_256+1) << 8;
829
830 // Set vertex buffers
831 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
832 rdp.vtxbuf2 = rdp.vtx2;
833 rdp.vtx_buffer = 0;
834 rdp.n_global = 3;
835 index = 0;
836
837 // ** Left plane **
838 for (i=0; i<3; i++)
839 {
840 j = i+1;
841 if (j == 3) j = 0;
842
843 VERTEX *v1 = vtx[i];
844 VERTEX *v2 = vtx[j];
845
846 if (v1->u0 >= left_256)
847 {
848 if (v2->u0 >= left_256) // Both are in, save the last one
849 {
850 rdp.vtxbuf[index] = *v2;
851 rdp.vtxbuf[index].u0 -= left_256;
852 rdp.vtxbuf[index++].v0 += rdp.cur_cache[0]->c_scl_y * (cur_256 * rdp.cur_cache[0]->splitheight);
853 }
854 else // First is in, second is out, save intersection
855 {
856 percent = (left_256 - v1->u0) / (v2->u0 - v1->u0);
857 rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent;
858 rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent;
859 rdp.vtxbuf[index].z = 1;
860 rdp.vtxbuf[index].q = 1;
861 rdp.vtxbuf[index].u0 = 0.5f;
862 rdp.vtxbuf[index].v0 = v1->v0 + (v2->v0 - v1->v0) * percent +
863 rdp.cur_cache[0]->c_scl_y * cur_256 * rdp.cur_cache[0]->splitheight;
864 rdp.vtxbuf[index].b = (wxUint8)(v1->b + (v2->b - v1->b) * percent);
865 rdp.vtxbuf[index].g = (wxUint8)(v1->g + (v2->g - v1->g) * percent);
866 rdp.vtxbuf[index].r = (wxUint8)(v1->r + (v2->r - v1->r) * percent);
867 rdp.vtxbuf[index++].a = (wxUint8)(v1->a + (v2->a - v1->a) * percent);
868 }
869 }
870 else
871 {
872 //if (v2->u0 < left_256) // Both are out, save nothing
873 if (v2->u0 >= left_256) // First is out, second is in, save intersection & in point
874 {
875 percent = (left_256 - v2->u0) / (v1->u0 - v2->u0);
876 rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent;
877 rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent;
878 rdp.vtxbuf[index].z = 1;
879 rdp.vtxbuf[index].q = 1;
880 rdp.vtxbuf[index].u0 = 0.5f;
881 rdp.vtxbuf[index].v0 = v2->v0 + (v1->v0 - v2->v0) * percent +
882 rdp.cur_cache[0]->c_scl_y * cur_256 * rdp.cur_cache[0]->splitheight;
883 rdp.vtxbuf[index].b = (wxUint8)(v2->b + (v1->b - v2->b) * percent);
884 rdp.vtxbuf[index].g = (wxUint8)(v2->g + (v1->g - v2->g) * percent);
885 rdp.vtxbuf[index].r = (wxUint8)(v2->r + (v1->r - v2->r) * percent);
886 rdp.vtxbuf[index++].a = (wxUint8)(v2->a + (v1->a - v2->a) * percent);
887
888 // Save the in point
889 rdp.vtxbuf[index] = *v2;
890 rdp.vtxbuf[index].u0 -= left_256;
891 rdp.vtxbuf[index++].v0 += rdp.cur_cache[0]->c_scl_y * (cur_256 * rdp.cur_cache[0]->splitheight);
892 }
893 }
894 }
895 rdp.n_global = index;
896
897 rdp.vtxbuf = rdp.vtx2; // now vtx1 holds the value, & vtx2 is the destination
898 rdp.vtxbuf2 = rdp.vtx1;
899 rdp.vtx_buffer ^= 1;
900 index = 0;
901
902 for (i=0; i<rdp.n_global; i++)
903 {
904 j = i+1;
905 if (j == rdp.n_global) j = 0;
906
907 VERTEX *v1 = &rdp.vtxbuf2[i];
908 VERTEX *v2 = &rdp.vtxbuf2[j];
909
910 // ** Right plane **
911 if (v1->u0 <= 256.0f)
912 {
913 if (v2->u0 <= 256.0f) // Both are in, save the last one
914 {
915 rdp.vtxbuf[index++] = *v2;
916 }
917 else // First is in, second is out, save intersection
918 {
919 percent = (right_256 - v1->u0) / (v2->u0 - v1->u0);
920 rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent;
921 rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent;
922 rdp.vtxbuf[index].z = 1;
923 rdp.vtxbuf[index].q = 1;
924 rdp.vtxbuf[index].u0 = 255.5f;
925 rdp.vtxbuf[index].v0 = v1->v0 + (v2->v0 - v1->v0) * percent;
926 rdp.vtxbuf[index].b = (wxUint8)(v1->b + (v2->b - v1->b) * percent);
927 rdp.vtxbuf[index].g = (wxUint8)(v1->g + (v2->g - v1->g) * percent);
928 rdp.vtxbuf[index].r = (wxUint8)(v1->r + (v2->r - v1->r) * percent);
929 rdp.vtxbuf[index++].a = (wxUint8)(v1->a + (v2->a - v1->a) * percent);
930 }
931 }
932 else
933 {
934 //if (v2->u0 > 256.0f) // Both are out, save nothing
935 if (v2->u0 <= 256.0f) // First is out, second is in, save intersection & in point
936 {
937 percent = (right_256 - v2->u0) / (v1->u0 - v2->u0);
938 rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent;
939 rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent;
940 rdp.vtxbuf[index].z = 1;
941 rdp.vtxbuf[index].q = 1;
942 rdp.vtxbuf[index].u0 = 255.5f;
943 rdp.vtxbuf[index].v0 = v2->v0 + (v1->v0 - v2->v0) * percent;
944 rdp.vtxbuf[index].b = (wxUint8)(v2->b + (v1->b - v2->b) * percent);
945 rdp.vtxbuf[index].g = (wxUint8)(v2->g + (v1->g - v2->g) * percent);
946 rdp.vtxbuf[index].r = (wxUint8)(v2->r + (v1->r - v2->r) * percent);
947 rdp.vtxbuf[index++].a = (wxUint8)(v2->a + (v1->a - v2->a) * percent);
948
949 // Save the in point
950 rdp.vtxbuf[index++] = *v2;
951 }
952 }
953 }
954 rdp.n_global = index;
955
956 do_triangle_stuff_2 ();
957 }
958}
959
960static void uc6_draw_polygons (VERTEX v[4])
961{
962Check_FrameSkip;
963
964 AllowShadeMods (v, 4);
965 for (int s = 0; s < 4; s++)
966 apply_shade_mods (&(v[s]));
967 AddOffset(v, 4);
968
969 // Set vertex buffers
970 if (rdp.cur_cache[0] && rdp.cur_cache[0]->splits > 1)
971 {
972 VERTEX *vptr[3];
973 int i;
974 for (i = 0; i < 3; i++)
975 vptr[i] = &v[i];
976 draw_split_triangle(vptr);
977
978 rdp.tri_n ++;
979 for (i = 0; i < 3; i++)
980 vptr[i] = &v[i+1];
981 draw_split_triangle(vptr);
982 rdp.tri_n ++;
983 }
984 else
985 {
986 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
987 rdp.vtxbuf2 = rdp.vtx2;
988 rdp.vtx_buffer = 0;
989 rdp.n_global = 3;
990 memcpy (rdp.vtxbuf, v, sizeof(VERTEX)*3);
991 do_triangle_stuff_2 ();
992 rdp.tri_n ++;
993
994 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
995 rdp.vtxbuf2 = rdp.vtx2;
996 rdp.vtx_buffer = 0;
997 rdp.n_global = 3;
998 memcpy (rdp.vtxbuf, v+1, sizeof(VERTEX)*3);
999 do_triangle_stuff_2 ();
1000 rdp.tri_n ++;
1001 }
1002 rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_VIEWPORT;
1003
1004 if (fullscreen && settings.fog && (rdp.flags & FOG_ENABLED))
1005 {
1006 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
1007 }
1008}
1009
1010static void uc6_read_object_data (DRAWOBJECT & d)
1011{
1012 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
1013
1014 d.objX = ((short*)gfx.RDRAM)[(addr+0)^1] / 4.0f; // 0
1015 d.scaleW = ((wxUint16 *)gfx.RDRAM)[(addr+1)^1] / 1024.0f; // 1
1016 d.imageW = ((short*)gfx.RDRAM)[(addr+2)^1] >> 5; // 2, 3 is padding
1017 d.objY = ((short*)gfx.RDRAM)[(addr+4)^1] / 4.0f; // 4
1018 d.scaleH = ((wxUint16 *)gfx.RDRAM)[(addr+5)^1] / 1024.0f; // 5
1019 d.imageH = ((short*)gfx.RDRAM)[(addr+6)^1] >> 5; // 6, 7 is padding
1020
1021 d.imageStride = ((wxUint16 *)gfx.RDRAM)[(addr+8)^1]; // 8
1022 d.imageAdrs = ((wxUint16 *)gfx.RDRAM)[(addr+9)^1]; // 9
1023 d.imageFmt = ((wxUint8 *)gfx.RDRAM)[(((addr+10)<<1)+0)^3]; // 10
1024 d.imageSiz = ((wxUint8 *)gfx.RDRAM)[(((addr+10)<<1)+1)^3]; // |
1025 d.imagePal = ((wxUint8 *)gfx.RDRAM)[(((addr+10)<<1)+2)^3]; // 11
1026 d.imageFlags = ((wxUint8 *)gfx.RDRAM)[(((addr+10)<<1)+3)^3]; // |
1027
1028 if (d.imageW < 0)
1029 d.imageW = (short)rdp.scissor_o.lr_x - (short)d.objX - d.imageW;
1030 if (d.imageH < 0)
1031 d.imageH = (short)rdp.scissor_o.lr_y - (short)d.objY - d.imageH;
1032
1033 FRDP ("#%d, #%d\n"
1034 "objX: %f, scaleW: %f, imageW: %d\n"
1035 "objY: %f, scaleH: %f, imageH: %d\n"
1036 "size: %d, format: %d\n", rdp.tri_n, rdp.tri_n+1,
1037 d.objX, d.scaleW, d.imageW, d.objY, d.scaleH, d.imageH, d.imageSiz, d.imageFmt);
1038}
1039
1040static void uc6_init_tile(const DRAWOBJECT & d)
1041{
1042 // SetTile ()
1043 TILE *tile = &rdp.tiles[0];
1044 tile->format = d.imageFmt; // RGBA
1045 tile->size = d.imageSiz; // 16-bit
1046 tile->line = d.imageStride;
1047 tile->t_mem = d.imageAdrs;
1048 tile->palette = d.imagePal;
1049 tile->clamp_t = 1;
1050 tile->mirror_t = 0;
1051 tile->mask_t = 0;
1052 tile->shift_t = 0;
1053 tile->clamp_s = 1;
1054 tile->mirror_s = 0;
1055 tile->mask_s = 0;
1056 tile->shift_s = 0;
1057
1058 // SetTileSize ()
1059 rdp.tiles[0].ul_s = 0;
1060 rdp.tiles[0].ul_t = 0;
1061 rdp.tiles[0].lr_s = (d.imageW>0)?d.imageW-1:0;
1062 rdp.tiles[0].lr_t = (d.imageH>0)?d.imageH-1:0;
1063}
1064
1065static void uc6_obj_rectangle ()
1066{
1067Check_FrameSkip;
1068
1069 LRDP ("uc6:obj_rectangle ");
1070 DRAWOBJECT d;
1071 uc6_read_object_data(d);
1072
1073 if (d.imageAdrs > 4096)
1074 {
1075 FRDP("tmem: %08lx is out of bounds! return\n", d.imageAdrs);
1076 return;
1077 }
1078 if (!rdp.s2dex_tex_loaded)
1079 {
1080 LRDP("Texture was not loaded! return\n");
1081 return;
1082 }
1083
1084 uc6_init_tile(d);
1085
1086 float Z = set_sprite_combine_mode ();
1087
1088 float ul_x = d.objX;
1089 float lr_x = d.objX + d.imageW/d.scaleW;
1090 float ul_y = d.objY;
1091 float lr_y = d.objY + d.imageH/d.scaleH;
1092 float ul_u, lr_u, ul_v, lr_v;
1093 if (rdp.cur_cache[0]->splits > 1)
1094 {
1095 lr_u = (float)(d.imageW-1);
1096 lr_v = (float)(d.imageH-1);
1097 }
1098 else
1099 {
1100 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
1101 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
1102 }
1103
1104 if (d.imageFlags&0x01) //flipS
1105 {
1106 ul_u = lr_u;
1107 lr_u = 0.5f;
1108 }
1109 else
1110 ul_u = 0.5f;
1111 if (d.imageFlags&0x10) //flipT
1112 {
1113 ul_v = lr_v;
1114 lr_v = 0.5f;
1115 }
1116 else
1117 ul_v = 0.5f;
1118
1119 // Make the vertices
1120 VERTEX v[4] = {
1121 { ul_x, ul_y, Z, 1, ul_u, ul_v },
1122 { lr_x, ul_y, Z, 1, lr_u, ul_v },
1123 { ul_x, lr_y, Z, 1, ul_u, lr_v },
1124 { lr_x, lr_y, Z, 1, lr_u, lr_v }
1125 };
1126
1127 for (int i=0; i<4; i++)
1128 {
1129 v[i].x *= rdp.scale_x;
1130 v[i].y *= rdp.scale_y;
1131 }
1132
1133 uc6_draw_polygons (v);
1134}
1135
1136static void uc6_obj_sprite ()
1137{
1138Check_FrameSkip;
1139
1140 LRDP ("uc6:obj_sprite ");
1141 DRAWOBJECT d;
1142 uc6_read_object_data(d);
1143 uc6_init_tile(d);
1144
1145 float Z = set_sprite_combine_mode ();
1146
1147 float ul_x = d.objX;
1148 float lr_x = d.objX + d.imageW/d.scaleW;
1149 float ul_y = d.objY;
1150 float lr_y = d.objY + d.imageH/d.scaleH;
1151 float ul_u, lr_u, ul_v, lr_v;
1152 if (rdp.cur_cache[0]->splits > 1)
1153 {
1154 lr_u = (float)(d.imageW-1);
1155 lr_v = (float)(d.imageH-1);
1156 }
1157 else
1158 {
1159 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
1160 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
1161 }
1162
1163 if (d.imageFlags&0x01) //flipS
1164 {
1165 ul_u = lr_u;
1166 lr_u = 0.5f;
1167 }
1168 else
1169 ul_u = 0.5f;
1170 if (d.imageFlags&0x10) //flipT
1171 {
1172 ul_v = lr_v;
1173 lr_v = 0.5f;
1174 }
1175 else
1176 ul_v = 0.5f;
1177
1178 // Make the vertices
1179 // FRDP("scale_x: %f, scale_y: %f\n", rdp.cur_cache[0]->scale_x, rdp.cur_cache[0]->scale_y);
1180
1181 VERTEX v[4] = {
1182 { ul_x, ul_y, Z, 1, ul_u, ul_v },
1183 { lr_x, ul_y, Z, 1, lr_u, ul_v },
1184 { ul_x, lr_y, Z, 1, ul_u, lr_v },
1185 { lr_x, lr_y, Z, 1, lr_u, lr_v }
1186 };
1187
1188 for (int i=0; i<4; i++)
1189 {
1190 float x = v[i].x;
1191 float y = v[i].y;
1192 v[i].x = (x * mat_2d.A + y * mat_2d.B + mat_2d.X) * rdp.scale_x;
1193 v[i].y = (x * mat_2d.C + y * mat_2d.D + mat_2d.Y) * rdp.scale_y;
1194 }
1195
1196 uc6_draw_polygons (v);
1197}
1198
1199static void uc6_obj_movemem ()
1200{
1201 LRDP("uc6:obj_movemem\n");
1202
1203 int index = rdp.cmd0 & 0xFFFF;
1204 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
1205
1206 if (index == 0) { // movemem matrix
1207 mat_2d.A = ((int*)gfx.RDRAM)[(addr+0)>>1] / 65536.0f;
1208 mat_2d.B = ((int*)gfx.RDRAM)[(addr+2)>>1] / 65536.0f;
1209 mat_2d.C = ((int*)gfx.RDRAM)[(addr+4)>>1] / 65536.0f;
1210 mat_2d.D = ((int*)gfx.RDRAM)[(addr+6)>>1] / 65536.0f;
1211 mat_2d.X = ((short*)gfx.RDRAM)[(addr+8)^1] / 4.0f;
1212 mat_2d.Y = ((short*)gfx.RDRAM)[(addr+9)^1] / 4.0f;
1213 mat_2d.BaseScaleX = ((wxUint16*)gfx.RDRAM)[(addr+10)^1] / 1024.0f;
1214 mat_2d.BaseScaleY = ((wxUint16*)gfx.RDRAM)[(addr+11)^1] / 1024.0f;
1215
1216 FRDP ("mat_2d\nA: %f, B: %f, c: %f, D: %f\nX: %f, Y: %f\nBaseScaleX: %f, BaseScaleY: %f\n",
1217 mat_2d.A, mat_2d.B, mat_2d.C, mat_2d.D, mat_2d.X, mat_2d.Y, mat_2d.BaseScaleX, mat_2d.BaseScaleY);
1218 }
1219 else if (index == 2) { // movemem submatrix
1220 mat_2d.X = ((short*)gfx.RDRAM)[(addr+0)^1] / 4.0f;
1221 mat_2d.Y = ((short*)gfx.RDRAM)[(addr+1)^1] / 4.0f;
1222 mat_2d.BaseScaleX = ((wxUint16*)gfx.RDRAM)[(addr+2)^1] / 1024.0f;
1223 mat_2d.BaseScaleY = ((wxUint16*)gfx.RDRAM)[(addr+3)^1] / 1024.0f;
1224
1225 FRDP ("submatrix\nX: %f, Y: %f\nBaseScaleX: %f, BaseScaleY: %f\n",
1226 mat_2d.X, mat_2d.Y, mat_2d.BaseScaleX, mat_2d.BaseScaleY);
1227 }
1228}
1229
1230static void uc6_select_dl ()
1231{
1232 LRDP("uc6:select_dl\n");
1233 RDP_E ("uc6:select_dl\n");
1234}
1235
1236static void uc6_obj_rendermode ()
1237{
1238 LRDP("uc6:obj_rendermode\n");
1239 RDP_E ("uc6:obj_rendermode\n");
1240}
1241
1242static wxUint16 uc6_yuv_to_rgba(wxUint8 y, wxUint8 u, wxUint8 v)
1243{
1244 float r = y + (1.370705f * (v-128));
1245 float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128));
1246 float b = y + (1.732446f * (u-128));
1247 r *= 0.125f;
1248 g *= 0.125f;
1249 b *= 0.125f;
1250 //clipping the result
1251 if (r > 32) r = 32;
1252 if (g > 32) g = 32;
1253 if (b > 32) b = 32;
1254 if (r < 0) r = 0;
1255 if (g < 0) g = 0;
1256 if (b < 0) b = 0;
1257
1258 wxUint16 c = (wxUint16)(((wxUint16)(r) << 11) |
1259 ((wxUint16)(g) << 6) |
1260 ((wxUint16)(b) << 1) | 1);
1261 return c;
1262}
1263
1264static void uc6_DrawYUVImageToFrameBuffer(wxUint16 ul_x, wxUint16 ul_y, wxUint16 lr_x, wxUint16 lr_y)
1265{
1266Check_FrameSkip;
1267
1268 FRDP ("uc6:DrawYUVImageToFrameBuffer ul_x%d, ul_y%d, lr_x%d, lr_y%d\n", ul_x, ul_y, lr_x, lr_y);
1269 wxUint32 ci_width = rdp.ci_width;
1270 wxUint32 ci_height = rdp.ci_lower_bound;
1271 if (ul_x >= ci_width)
1272 return;
1273 if (ul_y >= ci_height)
1274 return;
1275 wxUint32 width = 16, height = 16;
1276 if (lr_x > ci_width)
1277 width = ci_width - ul_x;
1278 if (lr_y > ci_height)
1279 height = ci_height - ul_y;
1280 wxUint32 * mb = (wxUint32*)(gfx.RDRAM+rdp.timg.addr); //pointer to the first macro block
1281 wxUint16 * dst = (wxUint16*)(gfx.RDRAM+rdp.cimg);
1282 dst += ul_x + ul_y * ci_width;
1283 //yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg
1284 for (wxUint16 h = 0; h < 16; h++)
1285 {
1286 for (wxUint16 w = 0; w < 16; w+=2)
1287 {
1288 wxUint32 t = *(mb++); //each wxUint32 contains 2 pixels
1289 if ((h < height) && (w < width)) //clipping. texture image may be larger than color image
1290 {
1291 wxUint8 y0 = (wxUint8)t&0xFF;
1292 wxUint8 v = (wxUint8)(t>>8)&0xFF;
1293 wxUint8 y1 = (wxUint8)(t>>16)&0xFF;
1294 wxUint8 u = (wxUint8)(t>>24)&0xFF;
1295 *(dst++) = uc6_yuv_to_rgba(y0, u, v);
1296 *(dst++) = uc6_yuv_to_rgba(y1, u, v);
1297 }
1298 }
1299 dst += rdp.ci_width - 16;
1300 }
1301}
1302
1303static void uc6_obj_rectangle_r ()
1304{
1305Check_FrameSkip;
1306
1307 LRDP ("uc6:obj_rectangle_r ");
1308 DRAWOBJECT d;
1309 uc6_read_object_data(d);
1310
1311 if (d.imageFmt == 1 && (settings.hacks&hack_Ogre64)) //Ogre Battle needs to copy YUV texture to frame buffer
1312 {
1313 float ul_x = d.objX/mat_2d.BaseScaleX + mat_2d.X;
1314 float lr_x = (d.objX + d.imageW/d.scaleW)/mat_2d.BaseScaleX + mat_2d.X;
1315 float ul_y = d.objY/mat_2d.BaseScaleY + mat_2d.Y;
1316 float lr_y = (d.objY + d.imageH/d.scaleH)/mat_2d.BaseScaleY + mat_2d.Y;
1317 uc6_DrawYUVImageToFrameBuffer((wxUint16)ul_x, (wxUint16)ul_y, (wxUint16)lr_x, (wxUint16)lr_y);
1318 rdp.tri_n += 2;
1319 return;
1320 }
1321
1322 uc6_init_tile(d);
1323
1324 float Z = set_sprite_combine_mode ();
1325
1326 float ul_x = d.objX/mat_2d.BaseScaleX;
1327 float lr_x = (d.objX + d.imageW/d.scaleW)/mat_2d.BaseScaleX;
1328 float ul_y = d.objY/mat_2d.BaseScaleY;
1329 float lr_y = (d.objY + d.imageH/d.scaleH)/mat_2d.BaseScaleY;
1330 float ul_u, lr_u, ul_v, lr_v;
1331 if (rdp.cur_cache[0]->splits > 1)
1332 {
1333 lr_u = (float)(d.imageW-1);
1334 lr_v = (float)(d.imageH-1);
1335 }
1336 else
1337 {
1338 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
1339 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
1340 }
1341
1342 if (d.imageFlags&0x01) //flipS
1343 {
1344 ul_u = lr_u;
1345 lr_u = 0.5f;
1346 }
1347 else
1348 ul_u = 0.5f;
1349 if (d.imageFlags&0x10) //flipT
1350 {
1351 ul_v = lr_v;
1352 lr_v = 0.5f;
1353 }
1354 else
1355 ul_v = 0.5f;
1356
1357 // Make the vertices
1358 VERTEX v[4] = {
1359 { ul_x, ul_y, Z, 1, ul_u, ul_v },
1360 { lr_x, ul_y, Z, 1, lr_u, ul_v },
1361 { ul_x, lr_y, Z, 1, ul_u, lr_v },
1362 { lr_x, lr_y, Z, 1, lr_u, lr_v }
1363 };
1364
1365 for (int i=0; i<4; i++)
1366 {
1367 float x = v[i].x;
1368 float y = v[i].y;
1369 v[i].x = (x + mat_2d.X) * rdp.scale_x;
1370 v[i].y = (y + mat_2d.Y) * rdp.scale_y;
1371 }
1372
1373 uc6_draw_polygons (v);
1374}
1375
1376static void uc6_obj_loadtxtr ()
1377{
1378Check_FrameSkip;
1379
1380 LRDP("uc6:obj_loadtxtr ");
1381 rdp.s2dex_tex_loaded = TRUE;
1382 rdp.update |= UPDATE_TEXTURE;
1383
1384 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
1385 wxUint32 type = ((wxUint32*)gfx.RDRAM)[(addr + 0) >> 1]; // 0, 1
1386
1387 if (type == 0x00000030) { // TLUT
1388 wxUint32 image = segoffset(((wxUint32*)gfx.RDRAM)[(addr + 2) >> 1]); // 2, 3
1389 wxUint16 phead = ((wxUint16 *)gfx.RDRAM)[(addr + 4) ^ 1] - 256; // 4
1390 wxUint16 pnum = ((wxUint16 *)gfx.RDRAM)[(addr + 5) ^ 1] + 1; // 5
1391
1392 FRDP ("palette addr: %08lx, start: %d, num: %d\n", image, phead, pnum);
1393 load_palette (image, phead, pnum);
1394 }
1395 else if (type == 0x00001033) { // TxtrBlock
1396 wxUint32 image = segoffset(((wxUint32*)gfx.RDRAM)[(addr + 2) >> 1]); // 2, 3
1397 wxUint16 tmem = ((wxUint16 *)gfx.RDRAM)[(addr + 4) ^ 1]; // 4
1398 wxUint16 tsize = ((wxUint16 *)gfx.RDRAM)[(addr + 5) ^ 1]; // 5
1399 wxUint16 tline = ((wxUint16 *)gfx.RDRAM)[(addr + 6) ^ 1]; // 6
1400
1401 FRDP ("addr: %08lx, tmem: %08lx, size: %d\n", image, tmem, tsize);
1402 rdp.timg.addr = image;
1403 rdp.timg.width = 1;
1404 rdp.timg.size = 1;
1405
1406 rdp.tiles[7].t_mem = tmem;
1407 rdp.tiles[7].size = 1;
1408 rdp.cmd0 = 0;
1409 rdp.cmd1 = 0x07000000 | (tsize << 14) | tline;
1410 rdp_loadblock ();
1411 }
1412 else if (type == 0x00fc1034)
1413 {
1414 wxUint32 image = segoffset(((wxUint32*)gfx.RDRAM)[(addr + 2) >> 1]); // 2, 3
1415 wxUint16 tmem = ((wxUint16 *)gfx.RDRAM)[(addr + 4) ^ 1]; // 4
1416 wxUint16 twidth = ((wxUint16 *)gfx.RDRAM)[(addr + 5) ^ 1]; // 5
1417 wxUint16 theight = ((wxUint16 *)gfx.RDRAM)[(addr + 6) ^ 1]; // 6
1418
1419 FRDP ("tile addr: %08lx, tmem: %08lx, twidth: %d, theight: %d\n", image, tmem, twidth, theight);
1420
1421 int line = (twidth + 1) >> 2;
1422
1423 rdp.timg.addr = image;
1424 rdp.timg.width = line << 3;
1425 rdp.timg.size = 1;
1426
1427 rdp.tiles[7].t_mem = tmem;
1428 rdp.tiles[7].line = line;
1429 rdp.tiles[7].size = 1;
1430
1431 rdp.cmd0 = 0;
1432 rdp.cmd1 = 0x07000000 | (twidth << 14) | (theight << 2);
1433
1434 rdp_loadtile ();
1435 }
1436 else
1437 {
1438 FRDP ("UNKNOWN (0x%08lx)\n", type);
1439 FRDP_E ("uc6:obj_loadtxtr UNKNOWN (0x%08lx)\n", type);
1440 }
1441}
1442
1443static void uc6_obj_ldtx_sprite ()
1444{
1445 LRDP("uc6:obj_ldtx_sprite\n");
1446
1447 wxUint32 addr = rdp.cmd1;
1448 uc6_obj_loadtxtr ();
1449 rdp.cmd1 = addr + 24;
1450 uc6_obj_sprite ();
1451}
1452
1453static void uc6_obj_ldtx_rect ()
1454{
1455 LRDP("uc6:obj_ldtx_rect\n");
1456
1457 wxUint32 addr = rdp.cmd1;
1458 uc6_obj_loadtxtr ();
1459 rdp.cmd1 = addr + 24;
1460 uc6_obj_rectangle ();
1461}
1462
1463static void uc6_ldtx_rect_r ()
1464{
1465 LRDP("uc6:ldtx_rect_r\n");
1466
1467 wxUint32 addr = rdp.cmd1;
1468 uc6_obj_loadtxtr ();
1469 rdp.cmd1 = addr + 24;
1470 uc6_obj_rectangle_r ();
1471}
1472
1473static void uc6_loaducode ()
1474{
1475 LRDP("uc6:load_ucode\n");
1476 RDP_E ("uc6:load_ucode\n");
1477
1478 // copy the microcode data
1479 wxUint32 addr = segoffset(rdp.cmd1);
1480 wxUint32 size = (rdp.cmd0 & 0xFFFF) + 1;
1481 memcpy (microcode, gfx.RDRAM+addr, size);
1482
1483 microcheck ();
1484}
1485
1486void uc6_sprite2d ()
1487{
1488Check_FrameSkip;
1489
1490 wxUint32 a = rdp.pc[rdp.pc_i] & BMASK;
1491 wxUint32 cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; //check next command
1492 if ( (cmd0>>24) != 0xBE )
1493 return;
1494
1495 FRDP ("uc6:uc6_sprite2d #%d, #%d\n", rdp.tri_n, rdp.tri_n+1);
1496 wxUint32 addr = segoffset(rdp.cmd1) >> 1;
1497 DRAWIMAGE d;
1498
1499 d.imagePtr = segoffset(((wxUint32*)gfx.RDRAM)[(addr+0)>>1]); // 0,1
1500 wxUint16 stride = (((wxUint16 *)gfx.RDRAM)[(addr+4)^1]); // 4
1501 d.imageW = (((wxUint16 *)gfx.RDRAM)[(addr+5)^1]); // 5
1502 d.imageH = (((wxUint16 *)gfx.RDRAM)[(addr+6)^1]); // 6
1503 d.imageFmt = ((wxUint8 *)gfx.RDRAM)[(((addr+7)<<1)+0)^3]; // 7
1504 d.imageSiz = ((wxUint8 *)gfx.RDRAM)[(((addr+7)<<1)+1)^3]; // |
1505 d.imagePal = 0;
1506 d.imageX = (((wxUint16 *)gfx.RDRAM)[(addr+8)^1]); // 8
1507 d.imageY = (((wxUint16 *)gfx.RDRAM)[(addr+9)^1]); // 9
1508 wxUint32 tlut = ((wxUint32*)gfx.RDRAM)[(addr + 2) >> 1]; // 2, 3
1509 //low-level implementation of sprite2d apparently calls setothermode command to set tlut mode
1510 //However, description of sprite2d microcode just says that
1511 //TlutPointer should be Null when CI images will not be used.
1512 //HLE implementation sets rdp.tlut_mode=2 if TlutPointer is not null, and rdp.tlut_mode=0 otherwise
1513 //Alas, it is not sufficient, since WCW Nitro uses non-Null TlutPointer for rgba textures.
1514 //So, additional check added.
1515 if (tlut)
1516 {
1517 load_palette (segoffset(tlut), 0, 256);
1518 if (d.imageFmt > 0)
1519 rdp.tlut_mode = 2;
1520 else
1521 rdp.tlut_mode = 0;
1522 }
1523 else
1524 {
1525 rdp.tlut_mode = 0;
1526 }
1527
1528 if (d.imageW == 0)
1529 return;// d.imageW = stride;
1530
1531 cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; //check next command
1532 while (1)
1533 {
1534 if ( (cmd0>>24) == 0xBE )
1535 {
1536 wxUint32 cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1];
1537 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
1538
1539 d.scaleX = ((cmd1>>16)&0xFFFF)/1024.0f;
1540 d.scaleY = (cmd1&0xFFFF)/1024.0f;
1541 //the code below causes wrong background height in super robot spirit, so it is disabled.
1542 //need to find, for which game this hack was made
1543 //if( (cmd1&0xFFFF) < 0x100 )
1544 // d.scaleY = d.scaleX;
1545 d.flipX = (wxUint8)((cmd0>>8)&0xFF);
1546 d.flipY = (wxUint8)(cmd0&0xFF);
1547
1548 a = rdp.pc[rdp.pc_i] & BMASK;
1549 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
1550 cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; //check next command
1551 }
1552 if ( (cmd0>>24) == 0xBD )
1553 {
1554 wxUint32 cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1];
1555
1556 d.frameX = ((short)((cmd1>>16)&0xFFFF)) / 4.0f;
1557 d.frameY = ((short)(cmd1&0xFFFF)) / 4.0f;
1558 d.frameW = (wxUint16) (d.imageW / d.scaleX);
1559 d.frameH = (wxUint16) (d.imageH / d.scaleY);
1560 if (settings.hacks&hack_WCWnitro)
1561 {
1562 int scaleY = (int)d.scaleY;
1563 d.imageH /= scaleY;
1564 d.imageY /= scaleY;
1565 stride *= scaleY;
1566 d.scaleY = 1.0f;
1567 }
1568 FRDP ("imagePtr: %08lx\n", d.imagePtr);
1569 FRDP ("frameX: %f, frameW: %d, frameY: %f, frameH: %d\n", d.frameX, d.frameW, d.frameY, d.frameH);
1570 FRDP ("imageX: %d, imageW: %d, imageY: %d, imageH: %d\n", d.imageX, d.imageW, d.imageY, d.imageH);
1571 FRDP ("imageFmt: %d, imageSiz: %d, imagePal: %d, imageStride: %d\n", d.imageFmt, d.imageSiz, d.imagePal, stride);
1572 FRDP ("scaleX: %f, scaleY: %f\n", d.scaleX, d.scaleY);
1573 }
1574 else
1575 {
1576 return;
1577 }
1578
1579 const wxUint32 texsize = (d.imageW * d.imageH) << d.imageSiz >> 1;
1580 const wxUint32 maxTexSize = rdp.tlut_mode < 2 ? 4096 : 2048;
1581
1582 if (texsize > maxTexSize)
1583 {
1584 if (d.scaleX != 1)
1585 d.scaleX *= (float)stride/(float)d.imageW;
1586 d.imageW = stride;
1587 d.imageH += d.imageY;
1588 DrawImage (d);
1589 }
1590 else
1591 {
1592 wxUint16 line = d.imageW;
1593 if (line & 7) line += 8; // round up
1594 line >>= 3;
1595 if (d.imageSiz == 0)
1596 {
1597 if (line%2)
1598 line++;
1599 line >>= 1;
1600 }
1601 else
1602 {
1603 line <<= (d.imageSiz-1);
1604 }
1605 if (line == 0)
1606 line = 1;
1607
1608 rdp.timg.addr = d.imagePtr;
1609 rdp.timg.width = stride;
1610 rdp.tiles[7].t_mem = 0;
1611 rdp.tiles[7].line = line;//(d.imageW>>3);
1612 rdp.tiles[7].size = d.imageSiz;
1613 rdp.cmd0 = (d.imageX << 14) | (d.imageY << 2);
1614 rdp.cmd1 = 0x07000000 | ((d.imageX+d.imageW-1) << 14) | ((d.imageY+d.imageH-1) << 2);
1615 rdp_loadtile ();
1616
1617 // SetTile ()
1618 TILE *tile = &rdp.tiles[0];
1619 tile->format = d.imageFmt;
1620 tile->size = d.imageSiz;
1621 tile->line = line;//(d.imageW>>3);
1622 tile->t_mem = 0;
1623 tile->palette = 0;
1624 tile->clamp_t = 1;
1625 tile->mirror_t = 0;
1626 tile->mask_t = 0;
1627 tile->shift_t = 0;
1628 tile->clamp_s = 1;
1629 tile->mirror_s = 0;
1630 tile->mask_s = 0;
1631 tile->shift_s = 0;
1632
1633 // SetTileSize ()
1634 rdp.tiles[0].ul_s = d.imageX;
1635 rdp.tiles[0].ul_t = d.imageY;
1636 rdp.tiles[0].lr_s = d.imageX+d.imageW-1;
1637 rdp.tiles[0].lr_t = d.imageY+d.imageH-1;
1638
1639 float Z = set_sprite_combine_mode ();
1640
1641 float ul_x, ul_y, lr_x, lr_y;
1642 if (d.flipX)
1643 {
1644 ul_x = d.frameX + d.frameW;
1645 lr_x = d.frameX;
1646 }
1647 else
1648 {
1649 ul_x = d.frameX;
1650 lr_x = d.frameX + d.frameW;
1651 }
1652 if (d.flipY)
1653 {
1654 ul_y = d.frameY + d.frameH;
1655 lr_y = d.frameY;
1656 }
1657 else
1658 {
1659 ul_y = d.frameY;
1660 lr_y = d.frameY + d.frameH;
1661 }
1662
1663 float lr_u, lr_v;
1664 if (rdp.cur_cache[0]->splits > 1)
1665 {
1666 lr_u = (float)(d.imageW-1);
1667 lr_v = (float)(d.imageH-1);
1668 }
1669 else
1670 {
1671 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
1672 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
1673 }
1674
1675 // Make the vertices
1676 VERTEX v[4] = {
1677 { ul_x, ul_y, Z, 1, 0.5f, 0.5f },
1678 { lr_x, ul_y, Z, 1, lr_u, 0.5f },
1679 { ul_x, lr_y, Z, 1, 0.5f, lr_v },
1680 { lr_x, lr_y, Z, 1, lr_u, lr_v } };
1681
1682 for (int i=0; i<4; i++)
1683 {
1684 v[i].x *= rdp.scale_x;
1685 v[i].y *= rdp.scale_y;
1686 }
1687
1688 // ConvertCoordsConvert (v, 4);
1689 AllowShadeMods (v, 4);
1690 for (int s = 0; s < 4; s++)
1691 apply_shade_mods (&(v[s]));
1692 AddOffset(v, 4);
1693
1694 // Set vertex buffers
1695 if (rdp.cur_cache[0]->splits > 1)
1696 {
1697 VERTEX *vptr[3];
1698 int i;
1699 for (i = 0; i < 3; i++)
1700 vptr[i] = &v[i];
1701 draw_split_triangle(vptr);
1702
1703 rdp.tri_n ++;
1704 for (i = 0; i < 3; i++)
1705 vptr[i] = &v[i+1];
1706 draw_split_triangle(vptr);
1707 rdp.tri_n ++;
1708 }
1709 else
1710 {
1711 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
1712 rdp.vtxbuf2 = rdp.vtx2;
1713 rdp.vtx_buffer = 0;
1714 rdp.n_global = 3;
1715 memcpy (rdp.vtxbuf, v, sizeof(VERTEX)*3);
1716 do_triangle_stuff_2 ();
1717 rdp.tri_n ++;
1718
1719 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
1720 rdp.vtxbuf2 = rdp.vtx2;
1721 rdp.vtx_buffer = 0;
1722 rdp.n_global = 3;
1723 memcpy (rdp.vtxbuf, v+1, sizeof(VERTEX)*3);
1724 do_triangle_stuff_2 ();
1725 rdp.tri_n ++;
1726 }
1727 rdp.update |= UPDATE_ZBUF_ENABLED | UPDATE_VIEWPORT;
1728
1729 if (fullscreen && settings.fog && (rdp.flags & FOG_ENABLED))
1730 {
1731 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
1732 }
1733
1734 }
1735 a = rdp.pc[rdp.pc_i] & BMASK;
1736 cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; //check next command
1737 if (( (cmd0>>24) == 0xBD ) || ( (cmd0>>24) == 0xBE ))
1738 rdp.pc[rdp.pc_i] = (a+8) & BMASK;
1739 else
1740 return;
1741 }
1742}