Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / ucode06.h
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
42 static 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
116 void uc6_sprite2d ();
117
118 typedef 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
137 typedef 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
153 void DrawHiresDepthImage (const DRAWIMAGE & d)
154 {
155 Check_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
250 void DrawDepthImage (const DRAWIMAGE & d)
251 {
252 Check_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
293 void DrawImage (DRAWIMAGE & d)
294 {
295 Check_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
614 void DrawHiresImage(DRAWIMAGE & d, int screensize = FALSE)
615 {
616 Check_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
718 struct 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
725 static 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
765 static 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
800 static void uc6_bg_1cyc ()
801 {
802   uc6_bg(true);
803 }
804
805 static void uc6_bg_copy ()
806 {
807   uc6_bg(false);
808 }
809
810 static void draw_split_triangle(VERTEX **vtx)
811 {
812 Check_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
960 static void uc6_draw_polygons (VERTEX v[4])
961 {
962 Check_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
1010 static 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
1040 static 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
1065 static void uc6_obj_rectangle ()
1066 {
1067 Check_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
1136 static void uc6_obj_sprite ()
1137 {
1138 Check_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
1199 static 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
1230 static void uc6_select_dl ()
1231 {
1232   LRDP("uc6:select_dl\n");
1233   RDP_E ("uc6:select_dl\n");
1234 }
1235
1236 static void uc6_obj_rendermode ()
1237 {
1238   LRDP("uc6:obj_rendermode\n");
1239   RDP_E ("uc6:obj_rendermode\n");
1240 }
1241
1242 static 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
1264 static void uc6_DrawYUVImageToFrameBuffer(wxUint16 ul_x, wxUint16 ul_y, wxUint16 lr_x, wxUint16 lr_y)
1265 {
1266 Check_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
1303 static void uc6_obj_rectangle_r ()
1304 {
1305 Check_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
1376 static void uc6_obj_loadtxtr ()
1377 {
1378 Check_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
1443 static 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
1453 static 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
1463 static 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
1473 static 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
1486 void uc6_sprite2d ()
1487 {
1488 Check_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 }