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 #include "../../Graphics/HLE/Microcode/S2DEX.h"
41 #include "../../Graphics/image_convert.h"
42
43
44 typedef struct DRAWIMAGE_t
45 {
46 float frameX;
47 float frameY;
48 uint16_t frameW;
49 uint16_t frameH;
50 uint16_t imageX;
51 uint16_t imageY;
52 uint16_t imageW;
53 uint16_t imageH;
54 uint32_t imagePtr;
55 uint8_t imageFmt;
56 uint8_t imageSiz;
57 uint16_t imagePal;
58 uint8_t flipX;
59 uint8_t flipY;
60 float scaleX;
61 float scaleY;
62 } DRAWIMAGE;
63
DrawDepthImage(const DRAWIMAGE * d)64 static void DrawDepthImage (const DRAWIMAGE *d)
65 {
66 float scale_x_src, scale_y_src, scale_x_dst, scale_y_dst;
67 uint16_t *src, *dst;
68 int32_t x, y, src_width, src_height, dst_width, dst_height;
69
70 if (!fb_depth_render_enabled || d->imageH > d->imageW)
71 return;
72
73 scale_x_dst = rdp.scale_x;
74 scale_y_dst = rdp.scale_y;
75 scale_x_src = 1.0f/rdp.scale_x;
76 scale_y_src = 1.0f/rdp.scale_y;
77 src_width = d->imageW;
78 src_height = d->imageH;
79 dst_width = MIN((int)(src_width*scale_x_dst), (int)settings.scr_res_x);
80 dst_height = MIN((int)(src_height*scale_y_dst), (int)settings.scr_res_y);
81 src = (uint16_t*)(gfx_info.RDRAM+d->imagePtr);
82 dst = (uint16_t*)malloc(dst_width * dst_height * sizeof(uint16_t));
83
84 for (y = 0; y < dst_height; y++)
85 {
86 for (x = 0; x < dst_width; x++)
87 dst[x + y * dst_width] = src[((int)(x * scale_x_src) + (int)(y*scale_y_src) * src_width)^1];
88 }
89 grLfbWriteRegion(GR_BUFFER_AUXBUFFER,
90 0,
91 0,
92 GR_LFB_SRC_FMT_ZA16,
93 dst_width,
94 dst_height,
95 FXFALSE,
96 dst_width<<1,
97 dst);
98 free(dst);
99 }
100
DrawImage(DRAWIMAGE * d)101 static void DrawImage (DRAWIMAGE *d)
102 {
103 int x_size, y_size, x_shift, y_shift, line;
104 int min_wrap_u, min_wrap_v, min_256_u, min_256_v;
105 float nul_y, nlr_x;
106 int nul_v, nlr_u;
107 int cur_wrap_v, cur_v;
108 int cb_v; // coordinate-base
109 int tb_v; // texture-base
110 float ful_u, ful_v, flr_u, flr_v;
111 float ful_x, ful_y, flr_x, flr_y, mx, bx, my, by;
112 float Z;
113 struct gDPTile *tile;
114 int ul_u, ul_v, lr_u, lr_v;
115 float ul_x, ul_y, lr_x, lr_y;
116
117 if (d->imageW == 0 || d->imageH == 0 || d->frameH == 0)
118 return;
119
120 // choose optimum size for the format/size
121 switch (d->imageSiz)
122 {
123 case 0:
124 y_size = 32;
125 y_shift = 5;
126 if (rdp.tlut_mode < G_TT_RGBA16)
127 {
128 y_size = 64;
129 y_shift = 6;
130 }
131 x_size = 128;
132 x_shift = 7;
133 line = 8;
134 break;
135 case 1:
136 y_size = 32;
137 y_shift = 5;
138 if (rdp.tlut_mode < G_TT_RGBA16)
139 {
140 y_size = 64;
141 y_shift = 6;
142 }
143 x_size = 64;
144 x_shift = 6;
145 line = 8;
146 break;
147 case 2:
148 x_size = 64;
149 y_size = 32;
150 x_shift = 6;
151 y_shift = 5;
152 line = 16;
153 break;
154 case 3:
155 x_size = 32;
156 y_size = 16;
157 x_shift = 4;
158 y_shift = 3;
159 line = 16;
160 break;
161 default:
162 FRDP("DrawImage. unknown image size: %d\n", d->imageSiz);
163 return;
164 }
165
166 if (gDP.colorImage.width == 512 && !no_dlist) //RE2
167 {
168 uint16_t width = (uint16_t)(*gfx_info.VI_WIDTH_REG & 0xFFF);
169 d->frameH = d->imageH = (d->frameW * d->frameH)/width;
170 d->frameW = d->imageW = width;
171
172 if (g_gdp.zb_address == gDP.colorImage.address)
173 {
174 DrawDepthImage(d);
175 g_gdp.flags |= UPDATE_ZBUF_ENABLED | UPDATE_COMBINE |
176 UPDATE_ALPHA_COMPARE | UPDATE_VIEWPORT;
177 return;
178 }
179 }
180
181 if ((settings.hacks&hack_PPL) > 0)
182 {
183 if (d->imageY > d->imageH)
184 d->imageY = (d->imageY % d->imageH);
185 }
186 else
187 if ((settings.hacks&hack_Starcraft) > 0)
188 {
189 if (d->imageH%2 == 1)
190 d->imageH -= 1;
191 }
192 else
193 {
194 if ( (d->frameX > 0) && (d->frameW == gDP.colorImage.width) )
195 d->frameW -= (uint16_t)(2.0f*d->frameX);
196 if ( (d->frameY > 0) && (d->frameH == gDP.colorImage.height) )
197 d->frameH -= (uint16_t)(2.0f*d->frameY);
198 }
199
200
201 ul_u = (int)d->imageX;
202 ul_v = (int)d->imageY;
203 lr_u = (int)d->imageX + (int)(d->frameW * d->scaleX);
204 lr_v = (int)d->imageY + (int)(d->frameH * d->scaleY);
205
206 ul_x = d->frameX;
207 lr_x = d->frameX + d->frameW;
208 ul_y = d->frameY;
209 lr_y = d->frameY + d->frameH;
210
211 if (d->flipX)
212 {
213 ul_x = d->frameX + d->frameW;
214 lr_x = d->frameX;
215 }
216 if (d->flipY)
217 {
218 ul_y = d->frameY + d->frameH;
219 lr_y = d->frameY;
220 }
221
222 min_wrap_u = ul_u / d->imageW;
223 min_wrap_v = ul_v / d->imageH;
224 min_256_u = ul_u >> x_shift;
225 min_256_v = ul_v >> y_shift;
226
227 glide64gDPSetTextureImage(
228 d->imageFmt, /* format - RGBA */
229 d->imageSiz, /* size - 16bit */
230 (d->imageW%2)?d->imageW-1:d->imageW, /* width */
231 d->imagePtr /* address */
232 );
233
234 rdp.timg.set_by = 0;
235
236 glide64gDPSetTile(
237 d->imageFmt, /* RGBA */
238 d->imageSiz, /* 16bit */
239 line, /* line */
240 0, /* tmem */
241 0, /* tile */
242 (uint8_t)d->imagePal, /* palette */
243 0, /* cmt */
244 0, /* mask_t */
245 0, /* shift_t */
246 0, /* cms */
247 0, /* mask_s */
248 0 /* shift_s */
249 );
250
251 glide64gDPSetTileSize(
252 0, /* tile */
253 0, /* ulx */
254 0, /* uly */
255 x_size - 1, /* lrs */
256 y_size - 1 /* lrt */
257 );
258
259 Z = set_sprite_combine_mode ();
260 if (((gDP.otherMode.h & RDP_CYCLE_TYPE) >> 20) == G_CYC_COPY)
261 rdp.allow_combine = 0;
262
263 {
264 uint32_t minx = 0;
265 uint32_t miny = 0;
266 uint32_t maxx, maxy;
267 if (gDP.colorImage.width == 512 && !no_dlist)
268 {
269 maxx = settings.scr_res_x;
270 maxy = settings.scr_res_y;
271 }
272 else if (d->scaleX == 1.0f && d->scaleY == 1.0f)
273 {
274 minx = rdp.scissor.ul_x;
275 miny = rdp.scissor.ul_y;
276 maxx = rdp.scissor.lr_x;
277 maxy = rdp.scissor.lr_y;
278 }
279 else
280 {
281 minx = rdp.scissor.ul_x;
282 miny = rdp.scissor.ul_y;
283 maxx = MIN(rdp.scissor.lr_x, (uint32_t)((d->frameX+d->imageW/d->scaleX+0.5f)*rdp.scale_x));
284 maxy = MIN(rdp.scissor.lr_y, (uint32_t)((d->frameY+d->imageH/d->scaleY+0.5f)*rdp.scale_y));
285 }
286 grClipWindow(minx, miny, maxx, maxy);
287 g_gdp.flags |= UPDATE_SCISSOR;
288 }
289
290 // Texture ()
291 rdp.cur_tile = 0;
292
293 mx = (float)(lr_x - ul_x) / (float)(lr_u - ul_u);
294 bx = ul_x - mx * ul_u;
295
296 my = (float)(lr_y - ul_y) / (float)(lr_v - ul_v);
297 by = ul_y - my * ul_v;
298
299
300 nul_v = ul_v;
301 nul_y = ul_y;
302
303 // #162
304
305 cur_wrap_v = min_wrap_v + 1;
306 cur_v = min_256_v + 1;
307 cb_v = ((cur_v-1)<<y_shift);
308 while (cb_v >= d->imageH) cb_v -= d->imageH;
309 tb_v = cb_v;
310 rdp.bg_image_height = d->imageH;
311
312 while (1)
313 {
314 int nul_u, cb_u, tb_u;
315 float nul_x, nlr_y;
316 int cur_wrap_u = min_wrap_u + 1;
317 int cur_u = min_256_u + 1;
318
319 // calculate intersection with this point
320 int nlr_v = MIN (MIN (cur_wrap_v*d->imageH, (cur_v<<y_shift)), lr_v);
321 nlr_y = my * nlr_v + by;
322
323 nul_u = ul_u;
324 nul_x = ul_x;
325 cb_u = ((cur_u-1)<<x_shift);
326 while (cb_u >= d->imageW)
327 cb_u -= d->imageW;
328 tb_u = cb_u;
329
330 while (1)
331 {
332 // calculate intersection with this point
333 nlr_u = MIN (MIN (cur_wrap_u * d->imageW, (cur_u<<x_shift)), lr_u);
334 nlr_x = mx * nlr_u + bx;
335
336 // ** Load the texture, constant portions have been set above
337 glide64gDPSetTileSize(
338 0, /* tile */
339 tb_u, /* uls */
340 tb_v, /* ult */
341 tb_u+x_size-1, /* lrs */
342 tb_v+y_size-1 /* lrt */
343 );
344
345 __RSP.w0 = ((int)g_gdp.tile[0].sh << 14) | ((int)g_gdp.tile[0].th << 2);
346 __RSP.w1 = ((int)g_gdp.tile[0].sl << 14) | ((int)g_gdp.tile[0].tl << 2);
347 glide64gDPLoadTile(
348 (uint32_t)((__RSP.w1 >> 24) & 0x07), /* tile */
349 (uint32_t)((__RSP.w0 >> 14) & 0x03FF), /* ul_s */
350 (uint32_t)((__RSP.w0 >> 2 ) & 0x03FF), /* ul_t */
351 (uint32_t)((__RSP.w1 >> 14) & 0x03FF), /* lr_s */
352 (uint32_t)((__RSP.w1 >> 2 ) & 0x03FF) /* lr_t */
353 );
354 TexCache ();
355
356 ful_u = (float)nul_u - cb_u;
357 flr_u = (float)nlr_u - cb_u;
358 ful_v = (float)nul_v - cb_v;
359 flr_v = (float)nlr_v - cb_v;
360
361 ful_u *= rdp.cur_cache[0]->c_scl_x;
362 ful_v *= rdp.cur_cache[0]->c_scl_y;
363 flr_u *= rdp.cur_cache[0]->c_scl_x;
364 flr_v *= rdp.cur_cache[0]->c_scl_y;
365
366 ful_x = nul_x * rdp.scale_x + rdp.offset_x;
367 flr_x = nlr_x * rdp.scale_x + rdp.offset_x;
368 ful_y = nul_y * rdp.scale_y + rdp.offset_y;
369 flr_y = nlr_y * rdp.scale_y + rdp.offset_y;
370
371 /* Make the vertices */
372
373 if ((flr_x <= rdp.scissor.lr_x) || (ful_x < rdp.scissor.lr_x))
374 {
375 VERTEX v[4];
376
377 v[0].x = ful_x;
378 v[0].y = ful_y;
379 v[0].z = Z;
380 v[0].q = 1.0f;
381 v[0].u[0] = ful_u;
382 v[0].v[0] = ful_v;
383
384 v[1].x = flr_x;
385 v[1].y = ful_y;
386 v[1].z = Z;
387 v[1].q = 1.0f;
388 v[1].u[0] = flr_u;
389 v[1].v[0] = ful_v;
390
391 v[2].x = ful_x;
392 v[2].y = flr_y;
393 v[2].z = Z;
394 v[2].q = 1.0f;
395 v[2].u[0] = ful_u;
396 v[2].v[0] = flr_v;
397
398 v[3].x = flr_x;
399 v[3].y = flr_y;
400 v[3].z = Z;
401 v[3].q = 1.0f;
402 v[3].u[0] = flr_u;
403 v[3].v[0] = flr_v;
404
405 apply_shading(v);
406 ConvertCoordsConvert (v, 4);
407 grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, 4, v);
408 }
409
410 // increment whatever caused this split
411 tb_u += x_size - (x_size-(nlr_u-cb_u));
412 cb_u = nlr_u;
413 if (nlr_u == cur_wrap_u * d->imageW)
414 {
415 cur_wrap_u ++;
416 tb_u = 0;
417 }
418 if (nlr_u == (cur_u<<x_shift))
419 cur_u ++;
420 if (nlr_u == lr_u)
421 break;
422 nul_u = nlr_u;
423 nul_x = nlr_x;
424 }
425
426 tb_v += y_size - (y_size-(nlr_v-cb_v));
427 cb_v = nlr_v;
428 if (nlr_v == cur_wrap_v* d->imageH)
429 {
430 cur_wrap_v ++;
431 tb_v = 0;
432 }
433 if (nlr_v == (cur_v<<y_shift))
434 cur_v ++;
435 if (nlr_v == lr_v)
436 break;
437 nul_v = nlr_v;
438 nul_y = nlr_y;
439 }
440
441 rdp.allow_combine = 1;
442 rdp.bg_image_height = 0xFFFF;
443 }
444
445 //****************************************************************
446
uc6_read_background_data(DRAWIMAGE * d,bool bReadScale)447 static void uc6_read_background_data (DRAWIMAGE *d, bool bReadScale)
448 {
449 int imageYorig;
450 uint16_t imageFlip;
451 uint32_t addr = RSP_SegmentToPhysical(__RSP.w1) >> 1;
452
453 d->imageX = (((uint16_t *)gfx_info.RDRAM)[(addr+0)^1] >> 5); // 0
454 d->imageW = (((uint16_t *)gfx_info.RDRAM)[(addr+1)^1] >> 2); // 1
455 d->frameX = ((int16_t*)gfx_info.RDRAM)[(addr+2)^1] / 4.0f; // 2
456 d->frameW = ((uint16_t *)gfx_info.RDRAM)[(addr+3)^1] >> 2; // 3
457
458 d->imageY = (((uint16_t *)gfx_info.RDRAM)[(addr+4)^1] >> 5); // 4
459 d->imageH = (((uint16_t *)gfx_info.RDRAM)[(addr+5)^1] >> 2); // 5
460 d->frameY = ((int16_t*)gfx_info.RDRAM)[(addr+6)^1] / 4.0f; // 6
461 d->frameH = ((uint16_t *)gfx_info.RDRAM)[(addr+7)^1] >> 2; // 7
462
463 d->imagePtr = RSP_SegmentToPhysical(((uint32_t*)gfx_info.RDRAM)[(addr+8)>>1]); // 8,9
464 d->imageFmt = ((uint8_t *)gfx_info.RDRAM)[(((addr+11)<<1)+0)^3]; // 11
465 d->imageSiz = ((uint8_t *)gfx_info.RDRAM)[(((addr+11)<<1)+1)^3]; // |
466 d->imagePal = ((uint16_t *)gfx_info.RDRAM)[(addr+12)^1]; // 12
467 imageFlip = ((uint16_t *)gfx_info.RDRAM)[(addr+13)^1]; // 13;
468 d->flipX = (uint8_t)imageFlip & G_BG_FLAG_FLIPS;
469
470 if (bReadScale)
471 {
472 d->scaleX = ((int16_t*)gfx_info.RDRAM)[(addr+14)^1] / 1024.0f; // 14
473 d->scaleY = ((int16_t*)gfx_info.RDRAM)[(addr+15)^1] / 1024.0f; // 15
474 }
475 else
476 d->scaleX = d->scaleY = 1.0f;
477
478 d->flipY = 0;
479 imageYorig = ((int *)gfx_info.RDRAM)[(addr+16)>>1] >> 5;
480 rdp.last_bg = d->imagePtr;
481 }
482
uc6_bg(bool first_cycle)483 static void uc6_bg(bool first_cycle)
484 {
485 DRAWIMAGE d;
486
487 if (rdp.skip_drawing)
488 return;
489
490 uc6_read_background_data(&d, first_cycle);
491
492 if (settings.ucode == ucode_F3DEX2 || (settings.hacks&hack_PPL))
493 {
494 /* can't draw from framebuffer */
495 if (d.imagePtr == gDP.colorImage.address || d.imagePtr == rdp.ocimg)
496 return;
497 if (!d.imagePtr)
498 return;
499 }
500
501 DrawImage(&d);
502 }
503
uc6_bg_1cyc(uint32_t w0,uint32_t w1)504 static void uc6_bg_1cyc(uint32_t w0, uint32_t w1)
505 {
506 uc6_bg(true);
507 }
508
uc6_bg_copy(uint32_t w0,uint32_t w1)509 static void uc6_bg_copy(uint32_t w0, uint32_t w1)
510 {
511 uc6_bg(false);
512 }
513
draw_split_triangle(VERTEX ** vtx)514 static void draw_split_triangle(VERTEX **vtx)
515 {
516 int index,i,j, min_256,max_256, cur_256;
517 float percent;
518
519 vtx[0]->not_zclipped = 1;
520 vtx[1]->not_zclipped = 1;
521 vtx[2]->not_zclipped = 1;
522
523 min_256 = MIN((int)vtx[0]->u[0],(int)vtx[1]->u[0]); // bah, don't put two mins on one line
524 min_256 = MIN(min_256,(int)vtx[2]->u[0]) >> 8; // or it will be calculated twice
525
526 max_256 = MAX((int)vtx[0]->u[0],(int)vtx[1]->u[0]); // not like it makes much difference
527 max_256 = MAX(max_256,(int)vtx[2]->u[0]) >> 8; // anyway :P
528
529 for (cur_256=min_256; cur_256<=max_256; cur_256++)
530 {
531 int left_256 = cur_256 << 8;
532 int right_256 = (cur_256+1) << 8;
533
534 // Set vertex buffers
535 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
536 rdp.vtxbuf2 = rdp.vtx2;
537 rdp.vtx_buffer = 0;
538 rdp.n_global = 3;
539 index = 0;
540
541 // ** Left plane **
542 for (i=0; i<3; i++)
543 {
544 VERTEX *v2 = NULL;
545 VERTEX *v1 = (VERTEX*)vtx[i];
546
547 j = i+1;
548 if (j == 3)
549 j = 0;
550
551 v2 = (VERTEX*)vtx[j];
552
553 if (v1->u[0] >= left_256)
554 {
555 if (v2->u[0] >= left_256) // Both are in, save the last one
556 {
557 rdp.vtxbuf[index] = *v2;
558 rdp.vtxbuf[index].u[0] -= left_256;
559 rdp.vtxbuf[index++].v[0] += rdp.cur_cache[0]->c_scl_y * (cur_256 * rdp.cur_cache[0]->splitheight);
560 }
561 else // First is in, second is out, save intersection
562 {
563 percent = (left_256 - v1->u[0]) / (v2->u[0] - v1->u[0]);
564 rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent;
565 rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent;
566 rdp.vtxbuf[index].z = 1;
567 rdp.vtxbuf[index].q = 1;
568 rdp.vtxbuf[index].u[0] = 0.5f;
569 rdp.vtxbuf[index].v[0] = v1->v[0] + (v2->v[0] - v1->v[0]) * percent +
570 rdp.cur_cache[0]->c_scl_y * cur_256 * rdp.cur_cache[0]->splitheight;
571 rdp.vtxbuf[index].b = (uint8_t)(v1->b + (v2->b - v1->b) * percent);
572 rdp.vtxbuf[index].g = (uint8_t)(v1->g + (v2->g - v1->g) * percent);
573 rdp.vtxbuf[index].r = (uint8_t)(v1->r + (v2->r - v1->r) * percent);
574 rdp.vtxbuf[index++].a = (uint8_t)(v1->a + (v2->a - v1->a) * percent);
575 }
576 }
577 else
578 {
579 if (v2->u[0] >= left_256) // First is out, second is in, save intersection & in point
580 {
581 percent = (left_256 - v2->u[0]) / (v1->u[0] - v2->u[0]);
582 rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent;
583 rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent;
584 rdp.vtxbuf[index].z = 1;
585 rdp.vtxbuf[index].q = 1;
586 rdp.vtxbuf[index].u[0] = 0.5f;
587 rdp.vtxbuf[index].v[0] = v2->v[0] + (v1->v[0] - v2->v[0]) * percent +
588 rdp.cur_cache[0]->c_scl_y * cur_256 * rdp.cur_cache[0]->splitheight;
589 rdp.vtxbuf[index].b = (uint8_t)(v2->b + (v1->b - v2->b) * percent);
590 rdp.vtxbuf[index].g = (uint8_t)(v2->g + (v1->g - v2->g) * percent);
591 rdp.vtxbuf[index].r = (uint8_t)(v2->r + (v1->r - v2->r) * percent);
592 rdp.vtxbuf[index++].a = (uint8_t)(v2->a + (v1->a - v2->a) * percent);
593
594 // Save the in point
595 rdp.vtxbuf[index] = *v2;
596 rdp.vtxbuf[index].u[0] -= left_256;
597 rdp.vtxbuf[index++].v[0] += rdp.cur_cache[0]->c_scl_y * (cur_256 * rdp.cur_cache[0]->splitheight);
598 }
599 }
600 }
601 rdp.n_global = index;
602
603 rdp.vtxbuf = rdp.vtx2; // now vtx1 holds the value, & vtx2 is the destination
604 rdp.vtxbuf2 = rdp.vtx1;
605 rdp.vtx_buffer ^= 1;
606 index = 0;
607
608 for (i=0; i<rdp.n_global; i++)
609 {
610 VERTEX *v1 = (VERTEX*)&rdp.vtxbuf2[i];
611 VERTEX *v2 = NULL;
612
613 j = i+1;
614 if (j == rdp.n_global)
615 j = 0;
616
617 v2 = (VERTEX*)&rdp.vtxbuf2[j];
618
619 // ** Right plane **
620 if (v1->u[0] <= 256.0f)
621 {
622 if (v2->u[0] <= 256.0f) // Both are in, save the last one
623 {
624 rdp.vtxbuf[index++] = *v2;
625 }
626 else // First is in, second is out, save intersection
627 {
628 percent = (right_256 - v1->u[0]) / (v2->u[0] - v1->u[0]);
629 rdp.vtxbuf[index].x = v1->x + (v2->x - v1->x) * percent;
630 rdp.vtxbuf[index].y = v1->y + (v2->y - v1->y) * percent;
631 rdp.vtxbuf[index].z = 1;
632 rdp.vtxbuf[index].q = 1;
633 rdp.vtxbuf[index].u[0] = 255.5f;
634 rdp.vtxbuf[index].v[0] = v1->v[0] + (v2->v[0] - v1->v[0]) * percent;
635 rdp.vtxbuf[index].b = (uint8_t)(v1->b + (v2->b - v1->b) * percent);
636 rdp.vtxbuf[index].g = (uint8_t)(v1->g + (v2->g - v1->g) * percent);
637 rdp.vtxbuf[index].r = (uint8_t)(v1->r + (v2->r - v1->r) * percent);
638 rdp.vtxbuf[index++].a = (uint8_t)(v1->a + (v2->a - v1->a) * percent);
639 }
640 }
641 else
642 {
643 if (v2->u[0] <= 256.0f) // First is out, second is in, save intersection & in point
644 {
645 percent = (right_256 - v2->u[0]) / (v1->u[0] - v2->u[0]);
646 rdp.vtxbuf[index].x = v2->x + (v1->x - v2->x) * percent;
647 rdp.vtxbuf[index].y = v2->y + (v1->y - v2->y) * percent;
648 rdp.vtxbuf[index].z = 1;
649 rdp.vtxbuf[index].q = 1;
650 rdp.vtxbuf[index].u[0] = 255.5f;
651 rdp.vtxbuf[index].v[0] = v2->v[0] + (v1->v[0] - v2->v[0]) * percent;
652 rdp.vtxbuf[index].b = (uint8_t)(v2->b + (v1->b - v2->b) * percent);
653 rdp.vtxbuf[index].g = (uint8_t)(v2->g + (v1->g - v2->g) * percent);
654 rdp.vtxbuf[index].r = (uint8_t)(v2->r + (v1->r - v2->r) * percent);
655 rdp.vtxbuf[index++].a = (uint8_t)(v2->a + (v1->a - v2->a) * percent);
656
657 // Save the in point
658 rdp.vtxbuf[index++] = *v2;
659 }
660 }
661 }
662 rdp.n_global = index;
663
664 do_triangle_stuff_2 (0, 1, 1);
665 }
666 }
667
uc6_draw_polygons(VERTEX v[4])668 static void uc6_draw_polygons (VERTEX v[4])
669 {
670 apply_shading(v);
671
672 {
673 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
674 rdp.vtxbuf2 = rdp.vtx2;
675 rdp.vtx_buffer = 0;
676 rdp.n_global = 3;
677 memcpy (rdp.vtxbuf, v, sizeof(VERTEX)*3);
678 do_triangle_stuff_2 (0, 1, 1);
679
680 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
681 rdp.vtxbuf2 = rdp.vtx2;
682 rdp.vtx_buffer = 0;
683 rdp.n_global = 3;
684 memcpy (rdp.vtxbuf, v+1, sizeof(VERTEX)*3);
685 do_triangle_stuff_2 (0, 1, 1);
686 }
687 g_gdp.flags |= UPDATE_ZBUF_ENABLED | UPDATE_VIEWPORT;
688
689 if (settings.fog && (rdp.flags & FOG_ENABLED))
690 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT, g_gdp.fog_color.total);
691 }
692
uc6_read_object_data(DRAWOBJECT * d)693 static void uc6_read_object_data (DRAWOBJECT *d)
694 {
695 uint32_t addr = RSP_SegmentToPhysical(__RSP.w1) >> 1;
696
697 d->objX = ((int16_t*)gfx_info.RDRAM)[(addr+0)^1] / 4.0f; // 0
698 d->scaleW = ((uint16_t *)gfx_info.RDRAM)[(addr+1)^1] / 1024.0f; // 1
699 d->imageW = ((int16_t*)gfx_info.RDRAM)[(addr+2)^1] >> 5; // 2, 3 is padding
700 d->objY = ((int16_t*)gfx_info.RDRAM)[(addr+4)^1] / 4.0f; // 4
701 d->scaleH = ((uint16_t *)gfx_info.RDRAM)[(addr+5)^1] / 1024.0f; // 5
702 d->imageH = ((int16_t*)gfx_info.RDRAM)[(addr+6)^1] >> 5; // 6, 7 is padding
703
704 d->imageStride = ((uint16_t *)gfx_info.RDRAM)[(addr+8)^1]; // 8
705 d->imageAdrs = ((uint16_t *)gfx_info.RDRAM)[(addr+9)^1]; // 9
706 d->imageFmt = ((uint8_t *)gfx_info.RDRAM)[(((addr+10)<<1)+0)^3]; // 10
707 d->imageSiz = ((uint8_t *)gfx_info.RDRAM)[(((addr+10)<<1)+1)^3]; // |
708 d->imagePal = ((uint8_t *)gfx_info.RDRAM)[(((addr+10)<<1)+2)^3]; // 11
709 d->imageFlags = ((uint8_t *)gfx_info.RDRAM)[(((addr+10)<<1)+3)^3]; // |
710
711 if (d->imageW < 0)
712 d->imageW = (int16_t)g_gdp.__clip.xl - (int16_t)d->objX - d->imageW;
713 if (d->imageH < 0)
714 d->imageH = (int16_t)g_gdp.__clip.yl - (int16_t)d->objY - d->imageH;
715 }
716
uc6_init_tile(const DRAWOBJECT * d)717 static void uc6_init_tile(const DRAWOBJECT *d)
718 {
719 glide64gDPSetTile(
720 d->imageFmt, /* fmt - RGBA */
721 d->imageSiz, /* siz - 16bit */
722 d->imageStride, /* line */
723 d->imageAdrs, /* tmem */
724 0, /* tile */
725 d->imagePal, /* palette */
726 0, /* cmt */
727 0, /* maskt */
728 0, /* shift_t */
729 0, /* cms */
730 0, /* mask_s */
731 0 /* shift_s */
732 );
733
734 glide64gDPSetTileSize(
735 0, /* tile */
736 0, /* uls */
737 0, /* ult */
738 (d->imageW>0) ? (d->imageW-1) : 0, /* lrs */
739 (d->imageH>0) ? (d->imageH-1) : 0 /* lrt */
740 );
741 }
742
uc6_obj_rectangle(uint32_t w0,uint32_t w1)743 static void uc6_obj_rectangle(uint32_t w0, uint32_t w1)
744 {
745 int i;
746 float Z, ul_x, lr_x, ul_y, lr_y, ul_u, ul_v, lr_u, lr_v;
747 VERTEX v[4];
748 DRAWOBJECT d;
749
750 uc6_read_object_data(&d);
751
752 if (d.imageAdrs > 4096)
753 {
754 FRDP("tmem: %08lx is out of bounds! return\n", d.imageAdrs);
755 return;
756 }
757 if (!rdp.s2dex_tex_loaded)
758 {
759 LRDP("Texture was not loaded! return\n");
760 return;
761 }
762
763 uc6_init_tile(&d);
764
765 Z = set_sprite_combine_mode();
766
767 ul_x = d.objX;
768 lr_x = d.objX + d.imageW / d.scaleW;
769 ul_y = d.objY;
770 lr_y = d.objY + d.imageH / d.scaleH;
771 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
772 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
773 ul_u = 0.5f;
774 ul_v = 0.5f;
775
776 if (d.imageFlags & G_BG_FLAG_FLIPS) /* flipS */
777 {
778 ul_u = lr_u;
779 lr_u = 0.5f;
780 }
781
782 if (d.imageFlags & G_BG_FLAG_FLIPT) //flipT
783 {
784 ul_v = lr_v;
785 lr_v = 0.5f;
786 }
787
788 /* Make the vertices */
789
790 v[0].x = ul_x;
791 v[0].y = ul_y;
792 v[0].z = Z;
793 v[0].q = 1.0f;
794 v[0].u[0] = ul_u;
795 v[0].v[0] = ul_v;
796
797 v[1].x = lr_x;
798 v[1].y = ul_y;
799 v[1].z = Z;
800 v[1].q = 1.0f;
801 v[1].u[0] = lr_u;
802 v[1].v[0] = ul_v;
803
804 v[2].x = ul_x;
805 v[2].y = lr_y;
806 v[2].z = Z;
807 v[2].q = 1.0f;
808 v[2].u[0] = ul_u;
809 v[2].v[0] = lr_v;
810
811 v[3].x = lr_x;
812 v[3].y = lr_y;
813 v[3].z = Z;
814 v[3].q = 1.0f;
815 v[3].u[0] = lr_u;
816 v[3].v[0] = lr_v;
817
818 for (i = 0; i < 4; i++)
819 {
820 v[i].x = (v[i].x * rdp.scale_x) + rdp.offset_x;
821 v[i].y = (v[i].y * rdp.scale_y) + rdp.offset_y;
822 }
823
824 uc6_draw_polygons (v);
825 }
826
uc6_obj_sprite(uint32_t w0,uint32_t w1)827 void uc6_obj_sprite(uint32_t w0, uint32_t w1)
828 {
829 DRAWOBJECT d;
830 VERTEX v[4];
831 int i;
832 float Z, ul_x, lr_x, ul_y, lr_y, ul_u, lr_u, ul_v, lr_v;
833
834 uc6_read_object_data(&d);
835 uc6_init_tile(&d);
836
837 Z = set_sprite_combine_mode ();
838
839 ul_x = d.objX;
840 lr_x = d.objX + d.imageW/d.scaleW;
841 ul_y = d.objY;
842 lr_y = d.objY + d.imageH/d.scaleH;
843
844 #if 0
845 if (rdp.cur_cache[0]->splits > 1)
846 {
847 lr_u = (float)(d.imageW-1);
848 lr_v = (float)(d.imageH-1);
849 }
850 else
851 #endif
852 {
853 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
854 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
855 }
856
857 if (d.imageFlags&0x01) //flipS
858 {
859 ul_u = lr_u;
860 lr_u = 0.5f;
861 }
862 else
863 ul_u = 0.5f;
864 if (d.imageFlags&0x10) //flipT
865 {
866 ul_v = lr_v;
867 lr_v = 0.5f;
868 }
869 else
870 ul_v = 0.5f;
871
872 /* Make the vertices */
873 // FRDP("scale_x: %f, scale_y: %f\n", rdp.cur_cache[0]->scale_x, rdp.cur_cache[0]->scale_y);
874
875 v[0].x = ul_x;
876 v[0].y = ul_y;
877 v[0].z = Z;
878 v[0].q = 1.0f;
879 v[0].u[0] = ul_u;
880 v[0].v[0] = ul_v;
881
882 v[1].x = lr_x;
883 v[1].y = ul_y;
884 v[1].z = Z;
885 v[1].q = 1.0f;
886 v[1].u[0] = lr_u;
887 v[1].v[0] = ul_v;
888
889 v[2].x = ul_x;
890 v[2].y = lr_y;
891 v[2].z = Z;
892 v[2].q = 1.0f;
893 v[2].u[0] = ul_u;
894 v[2].v[0] = lr_v;
895
896 v[3].x = lr_x;
897 v[3].y = lr_y;
898 v[3].z = Z;
899 v[3].q = 1.0f;
900 v[3].u[0] = lr_u;
901 v[3].v[0] = lr_v;
902
903 for (i = 0; i < 4; i++)
904 {
905 float x = v[i].x;
906 float y = v[i].y;
907 v[i].x = ((x * gSP.objMatrix.A + y * gSP.objMatrix.B + gSP.objMatrix.X) * rdp.scale_x) + rdp.offset_x;
908 v[i].y = ((x * gSP.objMatrix.C + y * gSP.objMatrix.D + gSP.objMatrix.Y) * rdp.scale_y) + rdp.offset_y;
909 }
910
911 uc6_draw_polygons (v);
912 }
913
uc6_obj_movemem(uint32_t w0,uint32_t w1)914 static void uc6_obj_movemem(uint32_t w0, uint32_t w1)
915 {
916 switch (_SHIFTR( w0, 0, 16 ))
917 {
918 case S2DEX_MV_MATRIX:
919 glide64gSPObjMatrix( w1 );
920 break;
921 case S2DEX_MV_SUBMATRIX:
922 glide64gSPObjSubMatrix( w1 );
923 break;
924 }
925 }
926
uc6_select_dl(uint32_t w0,uint32_t w1)927 static void uc6_select_dl(uint32_t w0, uint32_t w1)
928 {
929 }
930
uc6_obj_rendermode(uint32_t w0,uint32_t w1)931 static void uc6_obj_rendermode(uint32_t w0, uint32_t w1)
932 {
933 }
934
DrawYUVImageToFrameBuffer(uint16_t ul_x,uint16_t ul_y,uint16_t lr_x,uint16_t lr_y)935 static void DrawYUVImageToFrameBuffer(uint16_t ul_x, uint16_t ul_y, uint16_t lr_x, uint16_t lr_y)
936 {
937 uint16_t h, w, *dst;
938 uint32_t width, height, *mb;
939
940 uint32_t ci_width = gDP.colorImage.width;
941 uint32_t ci_height = rdp.ci_lower_bound;
942
943 if (ul_x >= ci_width)
944 return;
945 if (ul_y >= ci_height)
946 return;
947
948 width = 16;
949 height = 16;
950
951 if (lr_x > ci_width)
952 width = ci_width - ul_x;
953 if (lr_y > ci_height)
954 height = ci_height - ul_y;
955
956 mb = (uint32_t*)(gfx_info.RDRAM + g_gdp.ti_address); //pointer to the first macro block
957 dst = (uint16_t*)(gfx_info.RDRAM + gDP.colorImage.address);
958 dst += ul_x + ul_y * ci_width;
959
960 /* YUV macro block contains 16x16 texture.
961 * we need to put it in the proper place inside cimg */
962 for (h = 0; h < 16; h++)
963 {
964 for (w = 0; w < 16; w+=2)
965 {
966 uint32_t t = *(mb++); /* each uint32_t contains 2 pixels */
967 if ((h < height) && (w < width)) /* clipping. texture image may be larger than color image */
968 {
969 uint8_t y0 = (uint8_t)t&0xFF;
970 uint8_t v = (uint8_t)(t>>8)&0xFF;
971 uint8_t y1 = (uint8_t)(t>>16)&0xFF;
972 uint8_t u = (uint8_t)(t>>24)&0xFF;
973 *(dst++) = YUVtoRGBA16(y0, u, v);
974 *(dst++) = YUVtoRGBA16(y1, u, v);
975 }
976 }
977 dst += ci_width - 16;
978 }
979 }
980
uc6_obj_rectangle_r(uint32_t w0,uint32_t w1)981 static void uc6_obj_rectangle_r(uint32_t w0, uint32_t w1)
982 {
983 int i;
984 float Z, ul_x, lr_x, ul_y, lr_y, ul_u, ul_v, lr_u, lr_v;
985 VERTEX v[4];
986 DRAWOBJECT d;
987
988 uc6_read_object_data(&d);
989
990 if (d.imageFmt == G_IM_FMT_YUV && (settings.hacks&hack_Ogre64)) //Ogre Battle needs to copy YUV texture to frame buffer
991 {
992 ul_x = d.objX / gSP.objMatrix.baseScaleX + gSP.objMatrix.X;
993 lr_x = (d.objX + d.imageW / d.scaleW) / gSP.objMatrix.baseScaleX + gSP.objMatrix.X;
994 ul_y = d.objY / gSP.objMatrix.baseScaleY + gSP.objMatrix.Y;
995 lr_y = (d.objY + d.imageH / d.scaleH) / gSP.objMatrix.baseScaleY + gSP.objMatrix.Y;
996 DrawYUVImageToFrameBuffer((uint16_t)ul_x, (uint16_t)ul_y, (uint16_t)lr_x, (uint16_t)lr_y);
997 return;
998 }
999
1000 uc6_init_tile(&d);
1001
1002 Z = set_sprite_combine_mode();
1003
1004 ul_x = d.objX / gSP.objMatrix.baseScaleX;
1005 lr_x = (d.objX + d.imageW / d.scaleW) / gSP.objMatrix.baseScaleX;
1006 ul_y = d.objY / gSP.objMatrix.baseScaleY;
1007 lr_y = (d.objY + d.imageH / d.scaleH) / gSP.objMatrix.baseScaleY;
1008 lr_u = 255.0f * rdp.cur_cache[0]->scale_x;
1009 lr_v = 255.0f * rdp.cur_cache[0]->scale_y;
1010
1011 if (d.imageFlags & G_BG_FLAG_FLIPS) //flipS
1012 {
1013 ul_u = lr_u;
1014 lr_u = 0.5f;
1015 }
1016 else
1017 ul_u = 0.5f;
1018 if (d.imageFlags & G_BG_FLAG_FLIPT) //flipT
1019 {
1020 ul_v = lr_v;
1021 lr_v = 0.5f;
1022 }
1023 else
1024 ul_v = 0.5f;
1025
1026 /* Make the vertices */
1027
1028 v[0].x = ul_x;
1029 v[0].y = ul_y;
1030 v[0].z = Z;
1031 v[0].q = 1.0f;
1032 v[0].u[0] = ul_u;
1033 v[0].v[0] = ul_v;
1034
1035 v[1].x = lr_x;
1036 v[1].y = ul_y;
1037 v[1].z = Z;
1038 v[1].q = 1.0f;
1039 v[1].u[0] = lr_u;
1040 v[1].v[0] = ul_v;
1041
1042 v[2].x = ul_x;
1043 v[2].y = lr_y;
1044 v[2].z = Z;
1045 v[2].q = 1.0f;
1046 v[2].u[0] = ul_u;
1047 v[2].v[0] = lr_v;
1048
1049 v[3].x = lr_x;
1050 v[3].y = lr_y;
1051 v[3].z = Z;
1052 v[3].q = 1.0f;
1053 v[3].u[0] = lr_u;
1054 v[3].v[0] = lr_v;
1055
1056 for (i = 0; i < 4; i++)
1057 {
1058 v[i].x = ((v[i].x + gSP.objMatrix.X) * rdp.scale_x) + rdp.offset_x;
1059 v[i].y = ((v[i].y + gSP.objMatrix.Y) * rdp.scale_y) + rdp.offset_y;
1060 }
1061
1062 uc6_draw_polygons (v);
1063 }
1064
uc6_obj_loadtxtr(uint32_t w0,uint32_t w1)1065 static void uc6_obj_loadtxtr(uint32_t w0, uint32_t w1)
1066 {
1067 rdp.s2dex_tex_loaded = true;
1068 g_gdp.flags |= UPDATE_TEXTURE;
1069
1070 glide64gSPObjLoadTxtr(w1);
1071 }
1072
uc6_obj_ldtx_sprite(uint32_t w0,uint32_t w1)1073 static void uc6_obj_ldtx_sprite(uint32_t w0, uint32_t w1)
1074 {
1075 uint32_t addr = w1;
1076 uc6_obj_loadtxtr(__RSP.w0, __RSP.w1);
1077 __RSP.w1 = addr + 24;
1078 uc6_obj_sprite(__RSP.w0, __RSP.w1);
1079 }
1080
uc6_obj_ldtx_rect(uint32_t w0,uint32_t w1)1081 static void uc6_obj_ldtx_rect(uint32_t w0, uint32_t w1)
1082 {
1083 uint32_t addr = w1;
1084 uc6_obj_loadtxtr(__RSP.w0, __RSP.w1);
1085 __RSP.w1 = addr + 24;
1086 uc6_obj_rectangle(__RSP.w0, __RSP.w1);
1087 }
1088
uc6_ldtx_rect_r(uint32_t w0,uint32_t w1)1089 static void uc6_ldtx_rect_r(uint32_t w0, uint32_t w1)
1090 {
1091 uint32_t addr = w1;
1092 uc6_obj_loadtxtr(__RSP.w0, __RSP.w1);
1093 __RSP.w1 = addr + 24;
1094 uc6_obj_rectangle_r(__RSP.w0, __RSP.w1);
1095 }
1096
uc6_loaducode(uint32_t w0,uint32_t w1)1097 static void uc6_loaducode(uint32_t w0, uint32_t w1)
1098 {
1099 /* copy the microcode data */
1100 uint32_t addr = RSP_SegmentToPhysical(w1);
1101 uint32_t size = (w0 & 0xFFFF) + 1;
1102 memcpy (microcode, gfx_info.RDRAM+addr, size);
1103
1104 microcheck ();
1105 }
1106
uc6_sprite2d(uint32_t w0,uint32_t w1)1107 static void uc6_sprite2d(uint32_t w0, uint32_t w1)
1108 {
1109 uint16_t stride;
1110 uint32_t addr, tlut;
1111 int i;
1112 DRAWIMAGE d;
1113 uint32_t a = __RSP.PC[__RSP.PCi] & BMASK;
1114 uint32_t cmd0 = ((uint32_t*)gfx_info.RDRAM)[a>>2]; //check next command
1115
1116 if ( (cmd0>>24) != 0xBE )
1117 return;
1118
1119 addr = RSP_SegmentToPhysical(w1) >> 1;
1120
1121 d.imagePtr = RSP_SegmentToPhysical(((uint32_t*)gfx_info.RDRAM)[(addr+0)>>1]); // 0,1
1122 stride = (((uint16_t *)gfx_info.RDRAM)[(addr+4)^1]); // 4
1123 d.imageW = (((uint16_t *)gfx_info.RDRAM)[(addr+5)^1]); // 5
1124 d.imageH = (((uint16_t *)gfx_info.RDRAM)[(addr+6)^1]); // 6
1125 d.imageFmt = ((uint8_t *)gfx_info.RDRAM)[(((addr+7)<<1)+0)^3]; // 7
1126 d.imageSiz = ((uint8_t *)gfx_info.RDRAM)[(((addr+7)<<1)+1)^3]; // |
1127 d.imagePal = 0;
1128 d.imageX = (((uint16_t *)gfx_info.RDRAM)[(addr+8)^1]); // 8
1129 d.imageY = (((uint16_t *)gfx_info.RDRAM)[(addr+9)^1]); // 9
1130 tlut = ((uint32_t*)gfx_info.RDRAM)[(addr + 2) >> 1]; // 2, 3
1131
1132 /*low-level implementation of sprite2d apparently calls setothermode command to set tlut mode
1133 *However, description of sprite2d microcode just says that
1134 *TlutPointer should be Null when CI images will not be used.
1135 *HLE implementation sets rdp.tlut_mode=2 if TlutPointer is not null, and rdp.tlut_mode=0 otherwise
1136 *Alas, it is not sufficient, since WCW Nitro uses non-Null TlutPointer for rgba textures.
1137 *So, additional check added.
1138 */
1139 rdp.tlut_mode = 0;
1140 if (tlut)
1141 {
1142 load_palette (RSP_SegmentToPhysical(tlut), 0, 256);
1143 if (d.imageFmt > G_IM_FMT_RGBA)
1144 rdp.tlut_mode = 2;
1145 else
1146 rdp.tlut_mode = 0;
1147 }
1148
1149 if (d.imageW == 0)
1150 return;// d.imageW = stride;
1151
1152 cmd0 = ((uint32_t*)gfx_info.RDRAM)[a>>2]; //check next command
1153 while (1)
1154 {
1155 uint32_t texsize, maxTexSize;
1156 if ( (cmd0>>24) == 0xBE )
1157 {
1158 uint32_t cmd1 = ((uint32_t*)gfx_info.RDRAM)[(a>>2)+1];
1159 __RSP.PC[__RSP.PCi] = (a+8) & BMASK;
1160
1161 d.scaleX = ((cmd1 >> 16)&0xFFFF)/1024.0f;
1162 d.scaleY = (cmd1 & 0xFFFF)/1024.0f;
1163
1164 //the code below causes wrong background height in super robot spirit, so it is disabled.
1165 //need to find, for which game this hack was made
1166 //if( (cmd1&0xFFFF) < 0x100 )
1167 // d.scaleY = d.scaleX;
1168 d.flipX = (uint8_t)((cmd0>>8)&0xFF);
1169 d.flipY = (uint8_t)(cmd0&0xFF);
1170
1171 a = __RSP.PC[__RSP.PCi] & BMASK;
1172 __RSP.PC[__RSP.PCi] = (a+8) & BMASK;
1173 cmd0 = ((uint32_t*)gfx_info.RDRAM)[a>>2]; //check next command
1174 }
1175 if ( (cmd0>>24) == 0xBD )
1176 {
1177 uint32_t cmd1 = ((uint32_t*)gfx_info.RDRAM)[(a>>2)+1];
1178
1179 d.frameX = ((int16_t)((cmd1>>16)&0xFFFF)) / 4.0f;
1180 d.frameY = ((int16_t)(cmd1&0xFFFF)) / 4.0f;
1181 d.frameW = (uint16_t) (d.imageW / d.scaleX);
1182 d.frameH = (uint16_t) (d.imageH / d.scaleY);
1183 if (settings.hacks&hack_WCWnitro)
1184 {
1185 int scaleY = (int)d.scaleY;
1186 d.imageH /= scaleY;
1187 d.imageY /= scaleY;
1188 stride *= scaleY;
1189 d.scaleY = 1.0f;
1190 }
1191 #if 0
1192 FRDP ("imagePtr: %08lx\n", d.imagePtr);
1193 FRDP ("frameX: %f, frameW: %d, frameY: %f, frameH: %d\n", d.frameX, d.frameW, d.frameY, d.frameH);
1194 FRDP ("imageX: %d, imageW: %d, imageY: %d, imageH: %d\n", d.imageX, d.imageW, d.imageY, d.imageH);
1195 FRDP ("imageFmt: %d, imageSiz: %d, imagePal: %d, imageStride: %d\n", d.imageFmt, d.imageSiz, d.imagePal, stride);
1196 FRDP ("scaleX: %f, scaleY: %f\n", d.scaleX, d.scaleY);
1197 #endif
1198 }
1199 else
1200 return;
1201
1202 texsize = (d.imageW * d.imageH) << d.imageSiz >> 1;
1203 maxTexSize = rdp.tlut_mode < G_TT_RGBA16 ? 4096 : 2048;
1204
1205 if (texsize > maxTexSize)
1206 {
1207 if (d.scaleX != 1)
1208 d.scaleX *= (float)stride/(float)d.imageW;
1209 d.imageW = stride;
1210 d.imageH += d.imageY;
1211 DrawImage(&d);
1212 }
1213 else
1214 {
1215 float Z, ul_x, ul_y, lr_x, lr_y, lr_u, lr_v;
1216 struct gDPTile *tile;
1217 VERTEX v[4];
1218 uint16_t line = d.imageW;
1219
1220 if (line & 7) line += 8; // round up
1221 line >>= 3;
1222 if (d.imageSiz == 0)
1223 {
1224 if (line%2)
1225 line++;
1226 line >>= 1;
1227 }
1228 else
1229 {
1230 line <<= (d.imageSiz-1);
1231 }
1232 if (line == 0)
1233 line = 1;
1234
1235 glide64gDPSetTextureImage(
1236 g_gdp.ti_format, /* format */
1237 g_gdp.ti_size, /* siz */
1238 stride, /* width */
1239 d.imagePtr /* address */
1240 );
1241
1242 g_gdp.tile[7].tmem = 0;
1243 g_gdp.tile[7].line = line;//(d.imageW>>3);
1244 g_gdp.tile[7].size = d.imageSiz;
1245 __RSP.w0 = (d.imageX << 14) | (d.imageY << 2);
1246 __RSP.w1 = 0x07000000 | ((d.imageX+d.imageW-1) << 14) | ((d.imageY+d.imageH-1) << 2);
1247 rdp_loadtile(__RSP.w0, __RSP.w1);
1248
1249 glide64gDPSetTile(
1250 d.imageFmt,
1251 d.imageSiz,
1252 line, /* (d.imageW>>3) */
1253 0,
1254 0,
1255 0,
1256 0,
1257 0,
1258 0,
1259 0,
1260 0,
1261 0);
1262
1263 glide64gDPSetTileSize(
1264 0, /* tile */
1265 d.imageX, /* uls */
1266 d.imageY, /* ult */
1267 d.imageX+d.imageW-1, /* lrs */
1268 d.imageY+d.imageH-1 /* lrt */
1269 );
1270
1271 Z = set_sprite_combine_mode ();
1272
1273 if (d.flipX)
1274 {
1275 ul_x = d.frameX + d.frameW;
1276 lr_x = d.frameX;
1277 }
1278 else
1279 {
1280 ul_x = d.frameX;
1281 lr_x = d.frameX + d.frameW;
1282 }
1283 if (d.flipY)
1284 {
1285 ul_y = d.frameY + d.frameH;
1286 lr_y = d.frameY;
1287 }
1288 else
1289 {
1290 ul_y = d.frameY;
1291 lr_y = d.frameY + d.frameH;
1292 }
1293
1294 #if 0
1295 if (rdp.cur_cache[0]->splits > 1)
1296 {
1297 lr_u = (float)(d.imageW-1);
1298 lr_v = (float)(d.imageH-1);
1299 }
1300 else
1301 #endif
1302 {
1303 lr_u = 255.0f*rdp.cur_cache[0]->scale_x;
1304 lr_v = 255.0f*rdp.cur_cache[0]->scale_y;
1305 }
1306
1307 /* Make the vertices */
1308
1309 v[0].x = ul_x;
1310 v[0].y = ul_y;
1311 v[0].z = Z;
1312 v[0].q = 1.0f;
1313 v[0].u[0] = 0.5f;
1314 v[0].v[0] = 0.5f;
1315
1316 v[1].x = lr_x;
1317 v[1].y = ul_y;
1318 v[1].z = Z;
1319 v[1].q = 1.0f;
1320 v[1].u[0] = lr_u;
1321 v[1].v[0] = 0.5f;
1322
1323 v[2].x = ul_x;
1324 v[2].y = lr_y;
1325 v[2].z = Z;
1326 v[2].q = 1.0f;
1327 v[2].u[0] = 0.5f;
1328 v[2].v[0] = lr_v;
1329
1330 v[3].x = lr_x;
1331 v[3].y = lr_y;
1332 v[3].z = Z;
1333 v[3].q = 1.0f;
1334 v[3].u[0] = lr_u;
1335 v[3].v[0] = lr_v;
1336
1337 for (i=0; i<4; i++)
1338 {
1339 v[i].x = (v[i].x * rdp.scale_x) + rdp.offset_x;
1340 v[i].y = (v[i].y * rdp.scale_y) + rdp.offset_y;
1341 }
1342
1343 apply_shading(v);
1344
1345 #if 0
1346 // Set vertex buffers
1347 if (rdp.cur_cache[0]->splits > 1)
1348 {
1349 VERTEX *vptr[3];
1350 for (i = 0; i < 3; i++)
1351 vptr[i] = &v[i];
1352 draw_split_triangle(vptr);
1353
1354 for (i = 0; i < 3; i++)
1355 vptr[i] = &v[i+1];
1356 draw_split_triangle(vptr);
1357 }
1358 else
1359 #endif
1360 {
1361 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
1362 rdp.vtxbuf2 = rdp.vtx2;
1363 rdp.vtx_buffer = 0;
1364 rdp.n_global = 3;
1365 memcpy (rdp.vtxbuf, v, sizeof(VERTEX)*3);
1366 do_triangle_stuff_2 (0, 1, 1);
1367
1368 rdp.vtxbuf = rdp.vtx1; // copy from v to rdp.vtx1
1369 rdp.vtxbuf2 = rdp.vtx2;
1370 rdp.vtx_buffer = 0;
1371 rdp.n_global = 3;
1372 memcpy (rdp.vtxbuf, v+1, sizeof(VERTEX)*3);
1373 do_triangle_stuff_2 (0, 1, 1);
1374 }
1375 g_gdp.flags |= UPDATE_ZBUF_ENABLED | UPDATE_VIEWPORT;
1376
1377 if (settings.fog && (rdp.flags & FOG_ENABLED))
1378 grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT, g_gdp.fog_color.total);
1379
1380 }
1381 a = __RSP.PC[__RSP.PCi] & BMASK;
1382 cmd0 = ((uint32_t*)gfx_info.RDRAM)[a>>2]; //check next command
1383 if (( (cmd0>>24) == 0xBD ) || ( (cmd0>>24) == 0xBE ))
1384 __RSP.PC[__RSP.PCi] = (a+8) & BMASK;
1385 else
1386 return;
1387 }
1388 }
1389