/* Nintendo 64 Video Hardware */ #include "driver.h" #include "includes/n64.h" #define LOG_RDP_EXECUTION 0 #if LOG_RDP_EXECUTION static FILE *rdp_exec; #endif /* defined in systems/n64.c */ extern UINT32 *rdram; extern UINT32 *rsp_imem; extern UINT32 *rsp_dmem; extern void dp_full_sync(void); extern UINT32 vi_origin; extern UINT32 vi_width; extern UINT32 vi_control; extern UINT32 dp_start; extern UINT32 dp_end; extern UINT32 dp_current; extern UINT32 dp_status; static UINT32 rdp_cmd_data[0x1000]; static int rdp_cmd_ptr = 0; static int rdp_cmd_cur = 0; typedef struct { int lx, rx; int s, ds; int t, dt; int w, dw; int r, dr; int g, dg; int b, db; int a, da; int z, dz; } SPAN; static SPAN span[1024]; /*****************************************************************************/ #define BYTE_ADDR_XOR BYTE4_XOR_BE(0) #define WORD_ADDR_XOR (WORD_XOR_BE(0) >> 1) typedef struct { UINT8 r, g, b, a; } COLOR; typedef struct { UINT16 xl, yl, xh, yh; // 10.2 fixed-point } RECTANGLE; typedef struct { int tilenum; UINT16 xl, yl, xh, yh; // 10.2 fixed-point INT16 s, t; // 10.5 fixed-point INT16 dsdx, dtdy; // 5.10 fixed-point } TEX_RECTANGLE; typedef struct { int format, size; UINT32 line; UINT32 tmem; int palette; // TODO: clamp & mirror parameters int ct, mt, cs, ms; int mask_t, shift_t, mask_s, shift_s; UINT16 sl, tl, sh, th; // 10.2 fixed-point } TILE; typedef struct { int sub_a_rgb0; int sub_b_rgb0; int mul_rgb0; int add_rgb0; int sub_a_a0; int sub_b_a0; int mul_a0; int add_a0; int sub_a_rgb1; int sub_b_rgb1; int mul_rgb1; int add_rgb1; int sub_a_a1; int sub_b_a1; int mul_a1; int add_a1; } COMBINE_MODES; typedef struct { int cycle_type; int persp_tex_en; int detail_tex_en; int sharpen_tex_en; int tex_lod_en; int en_tlut; int tlut_type; int sample_type; int mid_texel; int bi_lerp0; int bi_lerp1; int convert_one; int key_en; int rgb_dither_sel; int alpha_dither_sel; int blend_m1a_0; int blend_m1a_1; int blend_m1b_0; int blend_m1b_1; int blend_m2a_0; int blend_m2a_1; int blend_m2b_0; int blend_m2b_1; int force_blend; int alpha_cvg_select; int cvg_times_alpha; int z_mode; int cvg_dest; int color_on_cvg; int image_read_en; int z_update_en; int z_compare_en; int antialias_en; int z_source_sel; int dither_alpha_en; int alpha_compare_en; } OTHER_MODES; /*****************************************************************************/ #define PIXEL_SIZE_4BIT 0 #define PIXEL_SIZE_8BIT 1 #define PIXEL_SIZE_16BIT 2 #define PIXEL_SIZE_32BIT 3 #define CYCLE_TYPE_1 0 #define CYCLE_TYPE_2 1 #define CYCLE_TYPE_COPY 2 #define CYCLE_TYPE_FILL 3 static COMBINE_MODES combine; static OTHER_MODES other_modes; static COLOR blend_color; static COLOR prim_color; static COLOR env_color; static COLOR fog_color; static COLOR combined_color; static COLOR texel0_color; static COLOR texel1_color; static COLOR shade_color; static COLOR one_color = { 0xff, 0xff, 0xff, 0xff }; static COLOR zero_color = { 0x00, 0x00, 0x00, 0x00 }; // combiner inputs static UINT8 *combiner_rgbsub_a_r[2]; static UINT8 *combiner_rgbsub_a_g[2]; static UINT8 *combiner_rgbsub_a_b[2]; static UINT8 *combiner_rgbsub_b_r[2]; static UINT8 *combiner_rgbsub_b_g[2]; static UINT8 *combiner_rgbsub_b_b[2]; static UINT8 *combiner_rgbmul_r[2]; static UINT8 *combiner_rgbmul_g[2]; static UINT8 *combiner_rgbmul_b[2]; static UINT8 *combiner_rgbadd_r[2]; static UINT8 *combiner_rgbadd_g[2]; static UINT8 *combiner_rgbadd_b[2]; static UINT8 *combiner_alphasub_a[2]; static UINT8 *combiner_alphasub_b[2]; static UINT8 *combiner_alphamul[2]; static UINT8 *combiner_alphaadd[2]; // blender input static UINT8 *blender1a_r[2]; static UINT8 *blender1a_g[2]; static UINT8 *blender1a_b[2]; static UINT8 *blender1b_a[2]; static UINT8 *blender2a_r[2]; static UINT8 *blender2a_g[2]; static UINT8 *blender2a_b[2]; static UINT8 *blender2b_a[2]; static COLOR pixel_color; static COLOR inv_pixel_color; static COLOR blended_pixel_color; static COLOR memory_color; static UINT32 fill_color; // packed 16-bit or 32-bit, depending on framebuffer format static UINT16 primitive_z; static UINT16 primitive_delta_z; static int fb_format; static int fb_size; int fb_width; static UINT32 fb_address; static UINT32 zb_address; static int ti_format; static int ti_size; static int ti_width; static UINT32 ti_address; static TILE tile[8]; static RECTANGLE clip; static UINT8 *texture_cache; static UINT32 tlut[256]; #define CLAMP(S, T) \ do \ { \ if (clamp_s) \ { \ if (S < (tsl >> 2)) S = (tsl >> 2); \ if (S > (tsh >> 2)) S = (tsh >> 2); \ } \ if (mirror_s) \ { \ if (S < (tsl >> 2)) S = abs(S - (tsl >> 2)); \ if (S > (tsh >> 2)) S = abs(S - (tsh >> 2)); \ } \ if (mask_s != 0) \ { \ S &= (((UINT32)(0xffffffff) >> (32-mask_s))); \ } \ if (clamp_t) \ { \ if (T < (ttl >> 2)) T = (ttl >> 2); \ if (T > (tth >> 2)) T = (tth >> 2); \ } \ if (mirror_t) \ { \ if (T < (ttl >> 2)) T = abs(T - (ttl >> 2)); \ if (T > (tth >> 2)) T = abs(T - (tth >> 2)); \ } \ if (mask_t != 0) \ { \ T &= (((UINT32)(0xffffffff) >> (32-mask_t))); \ } \ } \ while (0) /*****************************************************************************/ VIDEO_START(n64) { #if LOG_RDP_EXECUTION rdp_exec = fopen("rdp_execute.txt", "wt"); #endif texture_cache = auto_malloc(0x100000); combiner_rgbsub_a_r[0] = combiner_rgbsub_a_r[1] = &one_color.r; combiner_rgbsub_a_g[0] = combiner_rgbsub_a_g[1] = &one_color.g; combiner_rgbsub_a_b[0] = combiner_rgbsub_a_b[1] = &one_color.b; combiner_rgbsub_b_r[0] = combiner_rgbsub_b_r[1] = &one_color.r; combiner_rgbsub_b_g[0] = combiner_rgbsub_b_g[1] = &one_color.g; combiner_rgbsub_b_b[0] = combiner_rgbsub_b_b[1] = &one_color.b; combiner_rgbmul_r[0] = combiner_rgbmul_r[1] = &one_color.r; combiner_rgbmul_g[0] = combiner_rgbmul_g[1] = &one_color.g; combiner_rgbmul_b[0] = combiner_rgbmul_b[1] = &one_color.b; combiner_rgbadd_r[0] = combiner_rgbadd_r[1] = &one_color.r; combiner_rgbadd_g[0] = combiner_rgbadd_g[1] = &one_color.g; combiner_rgbadd_b[0] = combiner_rgbadd_b[1] = &one_color.b; combiner_alphasub_a[0] = combiner_alphasub_a[1] = &one_color.a; combiner_alphasub_b[0] = combiner_alphasub_b[1] = &one_color.a; combiner_alphamul[0] = combiner_alphamul[1] = &one_color.a; combiner_alphaadd[0] = combiner_alphaadd[1] = &one_color.a; blender1a_r[0] = blender1a_r[1] = &pixel_color.r; blender1a_g[0] = blender1a_g[1] = &pixel_color.r; blender1a_b[0] = blender1a_b[1] = &pixel_color.r; blender1b_a[0] = blender1b_a[1] = &pixel_color.r; blender2a_r[0] = blender2a_r[1] = &pixel_color.r; blender2a_g[0] = blender2a_g[1] = &pixel_color.r; blender2a_b[0] = blender2a_b[1] = &pixel_color.r; blender2b_a[0] = blender2b_a[1] = &pixel_color.r; } VIDEO_UPDATE(n64) { int i, j; int height = (vi_control & 0x40) ? 479 : 239; switch (vi_control & 0x3) { case 0: // blank/no signal { break; } case 2: // RGBA5551 { UINT16 *frame_buffer = (UINT16*)&rdram[vi_origin / 4]; if (frame_buffer) { for (j=0; j > 11) & 0x1f) << 3; int g = ((pix >> 6) & 0x1f) << 3; int b = ((pix >> 1) & 0x1f) << 3; d[i^1] = (r << 16) | (g << 8) | b; } } } break; } case 3: // RGBA8888 { UINT32 *frame_buffer = (UINT32*)&rdram[vi_origin / 4]; if (frame_buffer) { for (j=0; j < height; j++) { UINT32 *d = BITMAP_ADDR32(bitmap, j, 0); for (i=0; i < fb_width; i++) { UINT32 pix = *frame_buffer++; *d++ = pix & 0xffffff; } } } break; } default: fatalerror("Unknown framebuffer format %d\n", vi_control & 0x3); } return 0; } /*****************************************************************************/ INLINE void SET_SUBA_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code) { switch (code & 0xf) { case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break; case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break; case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break; case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break; case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break; case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break; case 6: *input_r = &one_color.r; *input_g = &one_color.g; *input_b = &one_color.b; break; case 7: break; //TODO fatalerror("SET_SUBA_RGB_INPUT: noise\n"); break; case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: { *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break; } } } INLINE void SET_SUBB_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code) { switch (code & 0xf) { case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break; case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break; case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break; case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break; case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break; case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break; case 6: fatalerror("SET_SUBB_RGB_INPUT: key_center\n"); break; case 7: fatalerror("SET_SUBB_RGB_INPUT: convert_k4\n"); break; case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: { *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break; } } } INLINE void SET_MUL_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code) { switch (code & 0x1f) { case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break; case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break; case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break; case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break; case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break; case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break; case 6: fatalerror("SET_MUL_RGB_INPUT: key scale\n"); break; case 7: *input_r = &combined_color.a; *input_g = &combined_color.a; *input_b = &combined_color.a; break; case 8: *input_r = &texel0_color.a; *input_g = &texel0_color.a; *input_b = &texel0_color.a; break; case 9: *input_r = &texel1_color.a; *input_g = &texel1_color.a; *input_b = &texel1_color.a; break; case 10: *input_r = &prim_color.a; *input_g = &prim_color.a; *input_b = &prim_color.a; break; case 11: *input_r = &shade_color.a; *input_g = &shade_color.a; *input_b = &shade_color.a; break; case 12: *input_r = &env_color.a; *input_g = &env_color.a; *input_b = &env_color.a; break; case 13: break;//TODO fatalerror("SET_MUL_RGB_INPUT: lod fraction\n"); break; case 14: break;//TODO fatalerror("SET_MUL_RGB_INPUT: primitive lod fraction\n"); break; case 15: break;//TODO fatalerror("SET_MUL_RGB_INPUT: convert k5\n"); break; case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: { *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break; } } } INLINE void SET_ADD_RGB_INPUT(UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, int code) { switch (code & 0x7) { case 0: *input_r = &combined_color.r; *input_g = &combined_color.g; *input_b = &combined_color.b; break; case 1: *input_r = &texel0_color.r; *input_g = &texel0_color.g; *input_b = &texel0_color.b; break; case 2: *input_r = &texel1_color.r; *input_g = &texel1_color.g; *input_b = &texel1_color.b; break; case 3: *input_r = &prim_color.r; *input_g = &prim_color.g; *input_b = &prim_color.b; break; case 4: *input_r = &shade_color.r; *input_g = &shade_color.g; *input_b = &shade_color.b; break; case 5: *input_r = &env_color.r; *input_g = &env_color.g; *input_b = &env_color.b; break; case 6: *input_r = &one_color.r; *input_g = &one_color.g; *input_b = &one_color.b; break; case 7: *input_r = &zero_color.r; *input_g = &zero_color.g; *input_b = &zero_color.b; break; } } INLINE void SET_SUB_ALPHA_INPUT(UINT8 **input, int code) { switch (code & 0x7) { case 0: *input = &combined_color.a; break; case 1: *input = &texel0_color.a; break; case 2: *input = &texel1_color.a; break; case 3: *input = &prim_color.a; break; case 4: *input = &shade_color.a; break; case 5: *input = &env_color.a; break; case 6: *input = &one_color.a; break; case 7: *input = &zero_color.a; break; } } INLINE void SET_MUL_ALPHA_INPUT(UINT8 **input, int code) { switch (code & 0x7) { case 0: break;//TODO fatalerror("SET_MUL_ALPHA_INPUT: lod fraction\n"); break; case 1: *input = &texel0_color.a; break; case 2: *input = &texel1_color.a; break; case 3: *input = &prim_color.a; break; case 4: *input = &shade_color.a; break; case 5: *input = &env_color.a; break; case 6: break;//TODO fatalerror("SET_MUL_ALPHA_INPUT: primitive lod fraction\n"); break; case 7: *input = &zero_color.a; break; } } INLINE COLOR COLOR_COMBINER(int cycle) { COLOR c; UINT32 r, g, b, a; r = (((int)((UINT8)(*combiner_rgbsub_a_r[cycle]) - (UINT8)(*combiner_rgbsub_b_r[cycle])) * *combiner_rgbmul_r[cycle]) >> 8) + *combiner_rgbadd_r[cycle]; g = (((int)((UINT8)(*combiner_rgbsub_a_g[cycle]) - (UINT8)(*combiner_rgbsub_b_g[cycle])) * *combiner_rgbmul_g[cycle]) >> 8) + *combiner_rgbadd_g[cycle]; b = (((int)((UINT8)(*combiner_rgbsub_a_b[cycle]) - (UINT8)(*combiner_rgbsub_b_b[cycle])) * *combiner_rgbmul_b[cycle]) >> 8) + *combiner_rgbadd_b[cycle]; a = (((int)((UINT8)(*combiner_alphasub_a[cycle]) - (UINT8)(*combiner_alphasub_b[cycle])) * *combiner_alphamul[cycle]) >> 8) + *combiner_alphaadd[cycle]; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (a > 255) a = 255; c.r = r; c.g = g; c.b = b; c.a = a; return c; } INLINE void SET_BLENDER_INPUT(int cycle, int which, UINT8 **input_r, UINT8 **input_g, UINT8 **input_b, UINT8 **input_a, int a, int b) { switch (a & 0x3) { case 0: { if (cycle == 0) { *input_r = &pixel_color.r; *input_g = &pixel_color.g; *input_b = &pixel_color.b; } else { *input_r = &blended_pixel_color.r; *input_g = &blended_pixel_color.g; *input_b = &blended_pixel_color.b; } break; } case 1: { //fatalerror("SET_BLENDER_INPUT: cycle %d, input A: memory color\n", cycle); // TODO *input_r = &memory_color.r; *input_g = &memory_color.g; *input_b = &memory_color.b; break; } case 2: { *input_r = &blend_color.r; *input_g = &blend_color.g; *input_b = &blend_color.b; break; } case 3: { *input_r = &fog_color.r; *input_g = &fog_color.g; *input_b = &fog_color.b; break; } } if (which == 0) { switch (b & 0x3) { case 0: *input_a = &pixel_color.a; break; case 1: *input_a = &one_color.a; break; case 2: *input_a = &shade_color.a; break; case 3: *input_a = &zero_color.a; break; } } else { switch (b & 0x3) { case 0: *input_a = &inv_pixel_color.a; break; case 1: *input_a = &memory_color.a; break; case 2: *input_a = &one_color.a; break; case 3: *input_a = &zero_color.a; break; } } } static const UINT8 dither_matrix_4x4[16] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 }; #define DITHER_RB(val,dith) ((((val) << 1) - ((val) >> 4) + ((val) >> 7) + (dith)) >> 1) #define DITHER_G(val,dith) ((((val) << 2) - ((val) >> 4) + ((val) >> 6) + (dith)) >> 2) INLINE void BLENDER1_16(UINT16 *fb, COLOR c, int dith) { int r, g, b; pixel_color.r = c.r; inv_pixel_color.r = 0xff - c.r; pixel_color.g = c.g; inv_pixel_color.g = 0xff - c.g; pixel_color.b = c.b; inv_pixel_color.b = 0xff - c.b; pixel_color.a = c.a; inv_pixel_color.a = 0xff - c.a; if (other_modes.image_read_en) { UINT16 mem = *fb; memory_color.r = ((mem >> 11) & 0x1f) << 3; memory_color.g = ((mem >> 6) & 0x1f) << 3; memory_color.b = ((mem >> 1) & 0x1f) << 3; memory_color.a = 0; } r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8); g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8); b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8); //r = g = b = 0xff; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (other_modes.rgb_dither_sel != 3) { r = DITHER_RB(r, dith); g = DITHER_G (g, dith); b = DITHER_RB(b, dith); } if (c.a != 0) { *fb = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1); } } INLINE void BLENDER2_16(UINT16 *fb, COLOR c1, COLOR c2, int dith) { int r, g, b; pixel_color.r = c1.r; inv_pixel_color.r = 0xff - c1.r; pixel_color.g = c1.g; inv_pixel_color.g = 0xff - c1.g; pixel_color.b = c1.b; inv_pixel_color.b = 0xff - c1.b; pixel_color.a = c1.a; inv_pixel_color.a = 0xff - c1.a; if (other_modes.image_read_en) { UINT16 mem = *fb; memory_color.r = ((mem >> 11) & 0x1f) << 3; memory_color.g = ((mem >> 6) & 0x1f) << 3; memory_color.b = ((mem >> 1) & 0x1f) << 3; memory_color.a = 0; } r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8); g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8); b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8); blended_pixel_color.r = r; blended_pixel_color.g = g; blended_pixel_color.b = b; pixel_color.r = c2.r; inv_pixel_color.r = 0xff - c2.r; pixel_color.g = c2.g; inv_pixel_color.g = 0xff - c2.g; pixel_color.b = c2.b; inv_pixel_color.b = 0xff - c2.b; pixel_color.a = c2.a; inv_pixel_color.a = 0xff - c2.a; r = (((int)(*blender1a_r[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_r[1]) * (int)(*blender2b_a[1])) >> 8); g = (((int)(*blender1a_g[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_g[1]) * (int)(*blender2b_a[1])) >> 8); b = (((int)(*blender1a_b[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_b[1]) * (int)(*blender2b_a[1])) >> 8); r = c1.r; g = c1.g; b = c1.b; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (other_modes.rgb_dither_sel != 3) { r = DITHER_RB(r, dith); g = DITHER_G (g, dith); b = DITHER_RB(b, dith); } { *fb = ((r >> 3) << 11) | ((g >> 3) << 6) | ((b >> 3) << 1); } } /*****************************************************************************/ static void fill_rectangle_16bit(RECTANGLE *rect) { UINT16 *fb = (UINT16*)&rdram[(fb_address / 4)]; int index, i, j; int x1 = rect->xh / 4; int x2 = rect->xl / 4; int y1 = rect->yh / 4; int y2 = rect->yl / 4; int clipx1, clipx2, clipy1, clipy2; UINT16 fill_color1, fill_color2; fill_color1 = (fill_color >> 16) & 0xffff; fill_color2 = (fill_color >> 0) & 0xffff; // TODO: clip clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; // clip if (x1 < clipx1) { x1 = clipx1; } if (y1 < clipy1) { y1 = clipy1; } if (x2 >= clipx2) { x2 = clipx2-1; } if (y2 >= clipy2) { y2 = clipy2-1; } if (other_modes.cycle_type == CYCLE_TYPE_FILL) { for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { fb[(index + i) ^ 1] = (i & 1) ? fill_color1 : fill_color2; } } } else if (other_modes.cycle_type == CYCLE_TYPE_1) { shade_color.r = prim_color.r; shade_color.g = prim_color.g; shade_color.b = prim_color.b; shade_color.a = prim_color.a; for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { COLOR c = COLOR_COMBINER(0); //BLENDER1_16(&fb[(index + i) ^ 1], c); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; BLENDER1_16(&fb[(index + i) ^ WORD_ADDR_XOR], c, dith); } } } } else if (other_modes.cycle_type == CYCLE_TYPE_2) { shade_color.r = prim_color.r; shade_color.g = prim_color.g; shade_color.b = prim_color.b; shade_color.a = prim_color.a; for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { COLOR c1 = COLOR_COMBINER(0); COLOR c2 = COLOR_COMBINER(1); //BLENDER1_16(&fb[(index + i) ^ 1], c); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; BLENDER2_16(&fb[(index + i) ^ WORD_ADDR_XOR], c1, c2, dith); } } } } else { fatalerror("fill_rectangle_16bit: cycle type copy"); } } #define XOR_SWAP_BYTE 4 #define XOR_SWAP_WORD 2 #define XOR_SWAP_DWORD 1 INLINE void FETCH_TEXEL(COLOR *color, int s, int t, UINT32 twidth, UINT32 tformat, UINT32 tsize, UINT32 tbase) { if (t < 0) t = 0; if (s < 0) s = 0; switch (tformat) { case 0: // RGBA { switch (tsize) { case 0: color->r = color->g = color->b = color->a = 0xff; break; case 1: // FIXME?: Extreme-G 2 does this color->r = color->g = color->b = color->a = 0xff; break; case PIXEL_SIZE_16BIT: { UINT16 *tc = (UINT16*)texture_cache; int taddr = ((tbase/2) + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_WORD : 0); UINT16 c = tc[taddr ^ WORD_ADDR_XOR]; color->r = ((c >> 11) & 0x1f) << 3; color->g = ((c >> 6) & 0x1f) << 3; color->b = ((c >> 1) & 0x1f) << 3; color->a = (c & 1) ? 0xff : 0; break; } case PIXEL_SIZE_32BIT: { UINT32 *tc = (UINT32*)texture_cache; int taddr = ((tbase/4) + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_DWORD : 0); UINT32 c = tc[taddr]; color->r = ((c >> 24) & 0xff); color->g = ((c >> 16) & 0xff); color->b = ((c >> 8) & 0xff); color->a = ((c >> 0) & 0xff); break; } default: color->r = color->g = color->b = color->a = 0xff; fatalerror("FETCH_TEXEL: unknown RGBA texture size %d\n", tsize); break; } break; } case 2: // Color Index { switch (tsize) { case PIXEL_SIZE_4BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 p = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4); UINT16 c = tlut[p ^ WORD_ADDR_XOR]; if (other_modes.tlut_type == 0) { color->r = ((c >> 11) & 0x1f) << 3; color->g = ((c >> 6) & 0x1f) << 3; color->b = ((c >> 1) & 0x1f) << 3; color->a = (c & 1) ? 0xff : 0; } else { color->r = color->g = color->b = (c >> 8) & 0xff; color->a = c & 0xff; } break; } case PIXEL_SIZE_8BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 p = tc[taddr ^ BYTE_ADDR_XOR]; UINT16 c = tlut[p ^ WORD_ADDR_XOR]; if (other_modes.tlut_type == 0) { color->r = ((c >> 11) & 0x1f) << 3; color->g = ((c >> 6) & 0x1f) << 3; color->b = ((c >> 1) & 0x1f) << 3; color->a = (c & 1) ? 0xff : 0; } else { color->r = color->g = color->b = (c >> 8) & 0xff; color->a = c & 0xff; } break; } case 2: // FIXME?: Clay Fighter Sculptor's Cut does this.. color->r = color->g = color->b = color->a = 0xff; break; default: color->r = color->g = color->b = color->a = 0xff; fatalerror("FETCH_TEXEL: unknown CI texture size %d\n", tsize); break; } break; } case 3: // Intensity + Alpha { switch (tsize) { case PIXEL_SIZE_4BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 p = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4); UINT8 i = ((p & 0xe) << 4) | ((p & 0xe) << 1) | (p & 0xe >> 2); color->r = i; color->g = i; color->b = i; color->a = (p & 0x1) ? 0xff : 0; break; } case PIXEL_SIZE_8BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 p = tc[taddr ^ BYTE_ADDR_XOR]; UINT8 i = (p >> 4) | (p & 0xf0); color->r = i; color->g = i; color->b = i; color->a = (p & 0xf) | ((p << 4) & 0xf0); break; } case PIXEL_SIZE_16BIT: { UINT16 *tc = (UINT16*)texture_cache; int taddr = (tbase + ((t) * (twidth/2)) + (s)) ^ ((t & 1) ? XOR_SWAP_WORD : 0); UINT16 c = tc[taddr ^ WORD_ADDR_XOR]; UINT8 i = (c >> 8); color->r = i; color->g = i; color->b = i; color->a = c & 0xff; break; } default: color->r = color->g = color->b = color->a = 0xff; fatalerror("FETCH_TEXEL: unknown IA texture size %d\n", tsize); break; } break; } case 4: // Intensity { switch (tsize) { case PIXEL_SIZE_4BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s) / 2)) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 c = ((s) & 1) ? (tc[taddr ^ BYTE_ADDR_XOR] & 0xf) : (tc[taddr ^ BYTE_ADDR_XOR] >> 4); c |= (c << 4); color->r = c; color->g = c; color->b = c; color->a = c; break; } case PIXEL_SIZE_8BIT: { UINT8 *tc = (UINT8*)texture_cache; int taddr = (tbase + ((t) * twidth) + ((s))) ^ ((t & 1) ? XOR_SWAP_BYTE : 0); UINT8 c = tc[taddr ^ BYTE_ADDR_XOR]; color->r = c; color->g = c; color->b = c; color->a = c; break; } default: color->r = color->g = color->b = color->a = 0xff; fatalerror("FETCH_TEXEL: unknown I texture size %d\n", tsize); break; } break; } default: { color->r = color->g = color->b = color->a = 0xff; fatalerror("FETCH_TEXEL: unknown texture format %d\n", tformat); break; } } } #if 1 #define TEXTURE_PIPELINE(TEX, SSS, SST, NOBILINEAR) \ do \ { \ if (other_modes.sample_type && !NOBILINEAR) \ { \ COLOR t0, t1, t2, t3; \ int sss1, sst1, sss2, sst2; \ \ /* bilinear */ \ \ sss1 = (SSS >> 10) - (tsl >> 2); \ sss2 = sss1 + 1; \ \ sst1 = (SST >> 10) - (ttl >> 2); \ sst2 = sst1 + 1; \ \ CLAMP(sss1, sst1); \ CLAMP(sss2, sst2); \ \ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); \ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); \ FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase); \ FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase); \ \ TEX.r = (((( (t0.r * (0x3ff - (SSS & 0x3ff))) + (t1.r * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (((( (t2.r * (0x3ff - (SSS & 0x3ff))) + (t3.r * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \ \ TEX.g = (((( (t0.g * (0x3ff - (SSS & 0x3ff))) + (t1.g * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (((( (t2.g * (0x3ff - (SSS & 0x3ff))) + (t3.g * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \ \ TEX.b = (((( (t0.b * (0x3ff - (SSS & 0x3ff))) + (t1.b * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (((( (t2.b * (0x3ff - (SSS & 0x3ff))) + (t3.b * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \ \ TEX.a = (((( (t0.a * (0x3ff - (SSS & 0x3ff))) + (t1.a * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (((( (t2.a * (0x3ff - (SSS & 0x3ff))) + (t3.a * ((SSS & 0x3ff))) ) >> 10) * ((SST & 0x3ff))) >> 10); \ } \ else \ { \ int sss1, sst1; \ sss1 = (SSS >> 10) - (tsl >> 2); \ if ((SSS & 0x3ff) >= 0x200) sss1++; \ \ sst1 = (SST >> 10) - (ttl >> 2); \ if ((SST & 0x3ff) >= 0x200) sst1++; \ \ CLAMP(sss1, sst1); \ \ /* point sample */ \ FETCH_TEXEL(&TEX, sss1, sst1, twidth, tformat, tsize, tbase); \ } \ } \ while(0) #endif // This is the implementation with 3-sample bilinear filtering, which should be more correct, but not yet working properly // TODO: check the correct texel samples and weighting values #if 0 #define TEXTURE_PIPELINE(TEX, SSS, SST, NOBILINEAR) \ do \ { \ if (other_modes.sample_type && !NOBILINEAR) \ { \ COLOR t0, t1, t2; \ int sss1, sst1, sss2, sst2; \ \ /* bilinear */ \ \ sss1 = (SSS >> 10) - (tsl >> 2); \ sss2 = sss1 + 1; \ \ sst1 = (SST >> 10) - (ttl >> 2); \ sst2 = sst1 + 1; \ \ CLAMP(sss1, sst1); \ CLAMP(sss2, sst2); \ \ FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); \ FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); \ FETCH_TEXEL(&t2, sss2, sst2, twidth, tformat, tsize, tbase); \ \ TEX.r = (((( (t0.r * (0x3ff - (SSS & 0x3ff))) + (t1.r * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (( (t2.r) * ((SST & 0x3ff))) >> 10); \ \ TEX.g = (((( (t0.g * (0x3ff - (SSS & 0x3ff))) + (t1.g * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (( (t2.g) * ((SST & 0x3ff))) >> 10); \ \ TEX.b = (((( (t0.b * (0x3ff - (SSS & 0x3ff))) + (t1.b * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (( (t2.b) * ((SST & 0x3ff))) >> 10); \ \ TEX.a = (((( (t0.a * (0x3ff - (SSS & 0x3ff))) + (t1.a * ((SSS & 0x3ff))) ) >> 10) * (0x3ff - (SST & 0x3ff))) >> 10) + \ (( (t2.a) * ((SST & 0x3ff))) >> 10); \ } \ else \ { \ int sss1, sst1; \ sss1 = (SSS >> 10) - (tsl >> 2); \ if ((SSS & 0x3ff) >= 0x200) sss1++; \ \ sst1 = (SST >> 10) - (ttl >> 2); \ if ((SST & 0x3ff) >= 0x200) sst1++; \ \ CLAMP(sss1, sst1); \ \ /* point sample */ \ FETCH_TEXEL(&TEX, sss1, sst1, twidth, tformat, tsize, tbase); \ } \ } \ while(0) #endif #define TEXTURE_PIPELINE1(SSS, SST, NOBILINEAR) \ do \ { \ TEXTURE_PIPELINE(texel0_color, SSS, SST, NOBILINEAR); \ } \ while(0) #define TEXTURE_PIPELINE2(SSS, SST, NOBILINEAR) \ do \ { \ TEXTURE_PIPELINE(texel0_color, SSS, SST, NOBILINEAR); \ TEXTURE_PIPELINE(texel1_color, SSS, SST, NOBILINEAR); \ } \ while(0) static void texture_rectangle_16bit(TEX_RECTANGLE *rect) { UINT16 *fb = (UINT16*)&rdram[(fb_address / 4)]; int i, j; int x1, x2, y1, y2; int tsl, tsh, ttl, tth; int s, t; int twidth, tformat, tsize, tbase; int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t; int clipx1, clipx2, clipy1, clipy2; x1 = (rect->xh / 4); x2 = (rect->xl / 4); y1 = (rect->yh / 4); y2 = (rect->yl / 4); if (other_modes.cycle_type == CYCLE_TYPE_FILL || other_modes.cycle_type == CYCLE_TYPE_COPY) { rect->dsdx /= 4; x2 += 1; y2 += 1; } clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; // clip if (x1 < clipx1) { x1 = clipx1; } if (y1 < clipy1) { y1 = clipy1; } if (x2 >= clipx2) { x2 = clipx2-1; } if (y2 >= clipy2) { y2 = clipy2-1; } tsl = tile[rect->tilenum].sl; tsh = tile[rect->tilenum].sh; ttl = tile[rect->tilenum].tl; tth = tile[rect->tilenum].th; twidth = tile[rect->tilenum].line; tformat = tile[rect->tilenum].format; tsize = tile[rect->tilenum].size; tbase = tile[rect->tilenum].tmem; // FIXME?: clamping breaks at least Rampage World Tour clamp_t = 0; //tile[rect->tilenum].ct; clamp_s = 0; //tile[rect->tilenum].cs; mirror_t = tile[rect->tilenum].mt; mirror_s = tile[rect->tilenum].ms; mask_t = tile[rect->tilenum].mask_t; mask_s = tile[rect->tilenum].mask_s; t = (int)(rect->t) << 5; if (other_modes.cycle_type == CYCLE_TYPE_1 || other_modes.cycle_type == CYCLE_TYPE_2) { } if (other_modes.cycle_type == CYCLE_TYPE_1) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { COLOR c; //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; //CLAMP(ss, st); //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase); TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); c = COLOR_COMBINER(0); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; BLENDER1_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c, dith); } s += rect->dsdx; } t += rect->dtdy; } } else if (other_modes.cycle_type == CYCLE_TYPE_2) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { COLOR c1, c2; //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; //CLAMP(ss, st); //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase); //FETCH_TEXEL(&texel1_color, ss, st, twidth, tformat, tsize, tbase); TEXTURE_PIPELINE2(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); c1 = COLOR_COMBINER(0); c2 = COLOR_COMBINER(1); //BLENDER2_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c1, c2); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; BLENDER2_16(&fb[(fb_index + i) ^ WORD_ADDR_XOR], c1, c2, dith); } s += rect->dsdx; } t += rect->dtdy; } } else if (other_modes.cycle_type == CYCLE_TYPE_COPY) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { /* if (clamp_s) { if (s < (tsl << 8)) s = (tsl << 8); if (s > (tsh << 8)) s = (tsh << 8); } if (clamp_t) { if (t < (ttl << 8)) t = (ttl << 8); if (t > (tth << 8)) t = (tth << 8); } if (mask_s) { s &= (((UINT32)(0xffffffff) >> (32-mask_s)) << 10) | 0x3ff; } if (mask_t) { t &= (((UINT32)(0xffffffff) >> (32-mask_t)) << 10) | 0x3ff; } FETCH_TEXEL(&c, (s-tile[rect->tilenum].sl) >> 10, (t-tile[rect->tilenum].tl) >> 10, twidth, tformat, tsize, tbase); */ //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; //CLAMP(ss, st); //FETCH_TEXEL(&c, ss, st, twidth, tformat, tsize, tbase); TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); if (texel0_color.a != 0) { fb[(fb_index + i) ^ WORD_ADDR_XOR] = ((texel0_color.r >> 3) << 11) | ((texel0_color.g >> 3) << 6) | ((texel0_color.b >> 3) << 1); } s += rect->dsdx; } t += rect->dtdy; } } else { fatalerror("texture_rectangle_16bit: unknown cycle type %d\n", other_modes.cycle_type); } } /*****************************************************************************/ INLINE void BLENDER1_32(UINT32 *fb, COLOR c) { int r, g, b; pixel_color.r = c.r; inv_pixel_color.r = 0xff - c.r; pixel_color.g = c.g; inv_pixel_color.g = 0xff - c.g; pixel_color.b = c.b; inv_pixel_color.b = 0xff - c.b; pixel_color.a = c.a; inv_pixel_color.a = 0xff - c.a; if (other_modes.image_read_en) { UINT32 mem = *fb; memory_color.r = ((mem >> 16) & 0xff); memory_color.g = ((mem >> 8) & 0xff); memory_color.b = ((mem >> 0) & 0xff); memory_color.a = 0; } r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8); g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8); b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8); //r = g = b = 0xff; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; *fb = (r << 16) | (g << 8) | b; } INLINE void BLENDER2_32(UINT32 *fb, COLOR c1, COLOR c2) { int r, g, b; pixel_color.r = c1.r; inv_pixel_color.r = 0xff - c1.r; pixel_color.g = c1.g; inv_pixel_color.g = 0xff - c1.g; pixel_color.b = c1.b; inv_pixel_color.b = 0xff - c1.b; pixel_color.a = c1.a; inv_pixel_color.a = 0xff - c1.a; if (other_modes.image_read_en) { UINT32 mem = *fb; memory_color.r = ((mem >> 16) & 0xff); memory_color.g = ((mem >> 8) & 0xff); memory_color.b = ((mem >> 0) & 0xff); memory_color.a = 0; } r = (((int)(*blender1a_r[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_r[0]) * (int)(*blender2b_a[0])) >> 8); g = (((int)(*blender1a_g[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_g[0]) * (int)(*blender2b_a[0])) >> 8); b = (((int)(*blender1a_b[0]) * (int)(*blender1b_a[0])) >> 8) + (((int)(*blender2a_b[0]) * (int)(*blender2b_a[0])) >> 8); blended_pixel_color.r = r; blended_pixel_color.g = g; blended_pixel_color.b = b; pixel_color.r = c2.r; inv_pixel_color.r = 0xff - c2.r; pixel_color.g = c2.g; inv_pixel_color.g = 0xff - c2.g; pixel_color.b = c2.b; inv_pixel_color.b = 0xff - c2.b; pixel_color.a = c2.a; inv_pixel_color.a = 0xff - c2.a; r = (((int)(*blender1a_r[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_r[1]) * (int)(*blender2b_a[1])) >> 8); g = (((int)(*blender1a_g[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_g[1]) * (int)(*blender2b_a[1])) >> 8); b = (((int)(*blender1a_b[1]) * (int)(*blender1b_a[1])) >> 8) + (((int)(*blender2a_b[1]) * (int)(*blender2b_a[1])) >> 8); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; *fb = (r << 16) | (g << 8) | b; } static void fill_rectangle_32bit(RECTANGLE *rect) { UINT32 *fb = (UINT32*)&rdram[(fb_address / 4)]; int index, i, j; int x1 = rect->xh / 4; int x2 = rect->xl / 4; int y1 = rect->yh / 4; int y2 = rect->yl / 4; int clipx1, clipx2, clipy1, clipy2; // TODO: clip clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; // clip if (x1 < clipx1) { x1 = clipx1; } if (y1 < clipy1) { y1 = clipy1; } if (x2 >= clipx2) { x2 = clipx2-1; } if (y2 >= clipy2) { y2 = clipy2-1; } if (other_modes.cycle_type == CYCLE_TYPE_FILL) { for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { fb[(index + i) ^ 1] = fill_color; } } } else if (other_modes.cycle_type == CYCLE_TYPE_1) { shade_color.r = prim_color.r; shade_color.g = prim_color.g; shade_color.b = prim_color.b; shade_color.a = prim_color.a; for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { COLOR c = COLOR_COMBINER(0); BLENDER1_32(&fb[(index + i)], c); } } } else if (other_modes.cycle_type == CYCLE_TYPE_2) { shade_color.r = prim_color.r; shade_color.g = prim_color.g; shade_color.b = prim_color.b; shade_color.a = prim_color.a; for (j=y1; j <= y2; j++) { index = j * fb_width; for (i=x1; i <= x2; i++) { COLOR c1 = COLOR_COMBINER(0); COLOR c2 = COLOR_COMBINER(1); BLENDER2_32(&fb[(index + i)], c1, c2); } } } else { fatalerror("fill_rectangle_32bit: cycle type copy"); } } static void texture_rectangle_32bit(TEX_RECTANGLE *rect) { UINT32 *fb = (UINT32*)&rdram[(fb_address / 4)]; int i, j; int x1, x2, y1, y2; int tsl, tsh, ttl, tth; int s, t; int twidth, tformat, tsize, tbase; int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t; int clipx1, clipx2, clipy1, clipy2; x1 = (rect->xh / 4); x2 = (rect->xl / 4); y1 = (rect->yh / 4); y2 = (rect->yl / 4); if (other_modes.cycle_type == CYCLE_TYPE_FILL || other_modes.cycle_type == CYCLE_TYPE_COPY) { rect->dsdx /= 4; x2 += 1; y2 += 1; } clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; // clip if (x1 < clipx1) { x1 = clipx1; } if (y1 < clipy1) { y1 = clipy1; } if (x2 >= clipx2) { x2 = clipx2-1; } if (y2 >= clipy2) { y2 = clipy2-1; } tsl = tile[rect->tilenum].sl; tsh = tile[rect->tilenum].sh; ttl = tile[rect->tilenum].tl; tth = tile[rect->tilenum].th; twidth = tile[rect->tilenum].line; tformat = tile[rect->tilenum].format; tsize = tile[rect->tilenum].size; tbase = tile[rect->tilenum].tmem; // FIXME?: clamping breaks at least Rampage World Tour clamp_t = 0; //tile[rect->tilenum].ct; clamp_s = 0; //tile[rect->tilenum].cs; mirror_t = tile[rect->tilenum].mt; mirror_s = tile[rect->tilenum].ms; mask_t = tile[rect->tilenum].mask_t; mask_s = tile[rect->tilenum].mask_s; t = (int)(rect->t) << 5; if (other_modes.cycle_type == CYCLE_TYPE_1 || other_modes.cycle_type == CYCLE_TYPE_2) { } if (other_modes.cycle_type == CYCLE_TYPE_1) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { COLOR c; //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; //CLAMP(ss, st); //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase); TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); c = COLOR_COMBINER(0); BLENDER1_32(&fb[(fb_index + i)], c); s += rect->dsdx; } t += rect->dtdy; } } else if (other_modes.cycle_type == CYCLE_TYPE_2) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { COLOR c1, c2; //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; //CLAMP(ss, st); //FETCH_TEXEL(&texel0_color, ss, st, twidth, tformat, tsize, tbase); //FETCH_TEXEL(&texel1_color, ss, st, twidth, tformat, tsize, tbase); TEXTURE_PIPELINE2(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); c1 = COLOR_COMBINER(0); c2 = COLOR_COMBINER(1); BLENDER2_32(&fb[(fb_index + i)], c1, c2); s += rect->dsdx; } t += rect->dtdy; } } else if (other_modes.cycle_type == CYCLE_TYPE_COPY) { for (j = y1; j < y2; j++) { int fb_index = j * fb_width; s = (int)(rect->s) << 5; for (i = x1; i < x2; i++) { /* if (clamp_s) { if (s < (tsl << 8)) s = (tsl << 8); if (s > (tsh << 8)) s = (tsh << 8); } if (clamp_t) { if (t < (ttl << 8)) t = (ttl << 8); if (t > (tth << 8)) t = (tth << 8); } if (mask_s) { s &= (((UINT32)(0xffffffff) >> (32-mask_s)) << 10) | 0x3ff; } if (mask_t) { t &= (((UINT32)(0xffffffff) >> (32-mask_t)) << 10) | 0x3ff; } FETCH_TEXEL(&c, (s-tile[rect->tilenum].sl) >> 10, (t-tile[rect->tilenum].tl) >> 10, twidth, tformat, tsize, tbase); */ //ss = (s >> 10) - (tsl >> 2); //if ((s & 0x3ff) >= 0x200) ss++; //st = (t >> 10) - (ttl >> 2); //if ((t & 0x3ff) >= 0x200) st++; TEXTURE_PIPELINE1(s, t, (rect->dsdx == (1 << 10)) && (rect->dtdy == (1 << 10))); //CLAMP(ss, st); //FETCH_TEXEL(&c, ss, st, twidth, tformat, tsize, tbase); if (texel0_color.a != 0) { fb[(fb_index + i) ^ WORD_ADDR_XOR] = (texel0_color.r << 16) | (texel0_color.g << 8) | (texel0_color.b << 0); } s += rect->dsdx; } t += rect->dtdy; } } else { fatalerror("texture_rectangle_32bit: unknown cycle type %d\n", other_modes.cycle_type); } } static void render_spans_32(int start, int end, int tilenum, int shade, int texture, int zbuffer, int flip) { UINT32 *fb = (UINT32*)&rdram[fb_address / 4]; UINT16 *zb = (UINT16*)&rdram[zb_address / 4]; int i, j; int tsl, tsh, ttl, tth; int twidth, tformat, tsize, tbase; int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t; int clipx1, clipx2, clipy1, clipy2; clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; tsl = tile[tilenum].sl; tsh = tile[tilenum].sh; ttl = tile[tilenum].tl; tth = tile[tilenum].th; twidth = tile[tilenum].line; tformat = tile[tilenum].format; tsize = tile[tilenum].size; tbase = tile[tilenum].tmem; clamp_t = tile[tilenum].ct; clamp_s = tile[tilenum].cs; mirror_t = tile[tilenum].mt; mirror_s = tile[tilenum].ms; mask_t = tile[tilenum].mask_t; mask_s = tile[tilenum].mask_s; if (start < clipy1) { start = clipy1; } if (start >= clipy2) { start = clipy2-1; } if (end < clipy1) { end = clipy1; } if (end >= clipy2) { end = clipy2-1; } for (i=start; i <= end; i++) { int xstart = span[i].lx; int xend = span[i].rx; int r = span[i].r; int g = span[i].g; int b = span[i].b; int a = span[i].a; int z = span[i].z; int s = span[i].s; int t = span[i].t; int w = span[i].w; int dr = span[i].dr; int dg = span[i].dg; int db = span[i].db; int da = span[i].da; int dz = span[i].dz; int ds = span[i].ds; int dt = span[i].dt; int dw = span[i].dw; int drinc, dginc, dbinc, dainc, dzinc, dsinc, dtinc, dwinc; int x; int xinc; int fb_index = fb_width * i; int length; drinc = flip ? (dr) : -dr; dginc = flip ? (dg) : -dg; dbinc = flip ? (db) : -db; dainc = flip ? (da) : -da; dzinc = flip ? (dz) : -dz; dsinc = flip ? (ds) : -ds; dtinc = flip ? (dt) : -dt; dwinc = flip ? (dw) : -dw; xinc = flip ? 1 : -1; x = xend; length = flip ? (xstart - xend) : (xend - xstart); for (j=0; j <= length; j++) { int sr = r >> 16; int sg = g >> 16; int sb = b >> 16; int sa = a >> 16; int ss = s >> 16; int st = t >> 16; int sw = w >> 16; UINT16 sz = z >> 16; int oz; int sss = 0, sst = 0; if (x >= clipx1 && x < clipx2) { COLOR c1, c2; c1.r = c1.g = c1.b = c1.a = 0; c2.r = c2.g = c2.b = c2.a = 0; if ((z & 0xffff) >= 0x8000) sz++; if ((w & 0xffff) >= 0x8000) sw++; if (other_modes.persp_tex_en) { if (sw != 0) { sss = (((INT64)(ss) << 20) / sw); sst = (((INT64)(st) << 20) / sw); } } else { sss = ss; sst = st; } if (sr > 0xff) sr = 0xff; if (sg > 0xff) sg = 0xff; if (sb > 0xff) sb = 0xff; shade_color.r = sr; shade_color.g = sg; shade_color.b = sb; shade_color.a = sa; if (texture) { /*if (other_modes.sample_type) { // bilinear sss1 = (sss >> 10) - (tsl >> 2); sss2 = sss1 + 1; sst1 = (sst >> 10) - (ttl >> 2); sst2 = sst1 + 1; CLAMP(sss1, sst1); CLAMP(sss2, sst2); FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase); texel0_color.r = (((( (t0.r * (0x3ff - (sss & 0x3ff))) + (t1.r * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.r * (0x3ff - (sss & 0x3ff))) + (t3.r * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.g = (((( (t0.g * (0x3ff - (sss & 0x3ff))) + (t1.g * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.g * (0x3ff - (sss & 0x3ff))) + (t3.g * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.b = (((( (t0.b * (0x3ff - (sss & 0x3ff))) + (t1.b * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.b * (0x3ff - (sss & 0x3ff))) + (t3.b * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.a = (((( (t0.a * (0x3ff - (sss & 0x3ff))) + (t1.a * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.a * (0x3ff - (sss & 0x3ff))) + (t3.a * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); } else { sss1 = (sss >> 10) - (tsl >> 2); if ((sss & 0x3ff) >= 0x200) sss1++; sst1 = (sst >> 10) - (ttl >> 2); if ((sst & 0x3ff) >= 0x200) sst1++; CLAMP(sss1, sst1); // point sample FETCH_TEXEL(&texel0_color, sss1, sst1, twidth, tformat, tsize, tbase); }*/ if (other_modes.cycle_type == CYCLE_TYPE_1) { TEXTURE_PIPELINE1(sss, sst, 0); } else { TEXTURE_PIPELINE2(sss, sst, 0); } } if (other_modes.cycle_type == CYCLE_TYPE_1) { c1 = COLOR_COMBINER(0); } else if (other_modes.cycle_type == CYCLE_TYPE_2) { c1 = COLOR_COMBINER(0); c2 = COLOR_COMBINER(1); } oz = (UINT16)zb[(fb_index + x) ^ WORD_ADDR_XOR]; if (zbuffer) { if (sz < oz /*&& c.a != 0*/) { if (other_modes.cycle_type == CYCLE_TYPE_1) { BLENDER1_32(&fb[(fb_index + x)], c1); } else { BLENDER2_32(&fb[(fb_index + x)], c1, c2); } if (other_modes.z_compare_en && other_modes.z_update_en) { zb[(fb_index + x) ^ WORD_ADDR_XOR] = sz; } } } else { if (other_modes.cycle_type == CYCLE_TYPE_1) { BLENDER1_32(&fb[(fb_index + x)], c1); } else { BLENDER2_32(&fb[(fb_index + x)], c1, c2); } } } r += drinc; g += dginc; b += dbinc; a += dainc; z += dzinc; s += dsinc; t += dtinc; w += dwinc; x += xinc; } } } /*****************************************************************************/ static void render_spans_16(int start, int end, int tilenum, int shade, int texture, int zbuffer, int flip) { UINT16 *fb = (UINT16*)&rdram[fb_address / 4]; UINT16 *zb = (UINT16*)&rdram[zb_address / 4]; int i, j; int tsl, tsh, ttl, tth; int twidth, tformat, tsize, tbase; int clamp_s, clamp_t, mask_s, mask_t, mirror_s, mirror_t; int clipx1, clipx2, clipy1, clipy2; clipx1 = clip.xh / 4; clipx2 = clip.xl / 4; clipy1 = clip.yh / 4; clipy2 = clip.yl / 4; tsl = tile[tilenum].sl; tsh = tile[tilenum].sh; ttl = tile[tilenum].tl; tth = tile[tilenum].th; twidth = tile[tilenum].line; tformat = tile[tilenum].format; tsize = tile[tilenum].size; tbase = tile[tilenum].tmem; clamp_t = tile[tilenum].ct; clamp_s = tile[tilenum].cs; mirror_t = tile[tilenum].mt; mirror_s = tile[tilenum].ms; mask_t = tile[tilenum].mask_t; mask_s = tile[tilenum].mask_s; if (start < clipy1) { start = clipy1; } if (start >= clipy2) { start = clipy2-1; } if (end < clipy1) { end = clipy1; } if (end >= clipy2) { end = clipy2-1; } for (i=start; i <= end; i++) { int xstart = span[i].lx; int xend = span[i].rx; int r = span[i].r; int g = span[i].g; int b = span[i].b; int a = span[i].a; int z = span[i].z; int s = span[i].s; int t = span[i].t; int w = span[i].w; int dr = span[i].dr; int dg = span[i].dg; int db = span[i].db; int da = span[i].da; int dz = span[i].dz; int ds = span[i].ds; int dt = span[i].dt; int dw = span[i].dw; int drinc, dginc, dbinc, dainc, dzinc, dsinc, dtinc, dwinc; int x; int xinc; int fb_index = fb_width * i; int length; drinc = flip ? (dr) : -dr; dginc = flip ? (dg) : -dg; dbinc = flip ? (db) : -db; dainc = flip ? (da) : -da; dzinc = flip ? (dz) : -dz; dsinc = flip ? (ds) : -ds; dtinc = flip ? (dt) : -dt; dwinc = flip ? (dw) : -dw; /*if (flip) { if (xend > clipx2) { int d = xend-clipx2; r += d * drinc; g += d * dginc; b += d * dbinc; a += d * dainc; z += d * dzinc; s += d * dsinc; t += d * dtinc; w += d * dwinc; xend = clipx2; } if (xstart < clipx1) { xstart = clipx1; } } else { if (xstart > clipx2) { int d = xstart-clipx2; r += d * drinc; g += d * dginc; b += d * dbinc; a += d * dainc; z += d * dzinc; s += d * dsinc; t += d * dtinc; w += d * dwinc; xstart = clipx2; } if (xend < clipx1) { xend = clipx1; } }*/ xinc = flip ? 1 : -1; x = xend; length = flip ? (xstart - xend) : (xend - xstart); for (j=0; j <= length; j++) { int sr = r >> 16; int sg = g >> 16; int sb = b >> 16; int sa = a >> 16; int ss = s >> 16; int st = t >> 16; int sw = w >> 16; UINT16 sz = z >> 16; int oz; int sss = 0, sst = 0; COLOR c1, c2; c1.r = c1.g = c1.b = c1.a = 0; c2.r = c2.g = c2.b = c2.a = 0; if (x >= clipx1 && x < clipx2) { if ((z & 0xffff) >= 0x8000) sz++; if ((w & 0xffff) >= 0x8000) sw++; if (other_modes.persp_tex_en) { if (sw != 0) { sss = (((INT64)(ss) << 20) / sw); sst = (((INT64)(st) << 20) / sw); } } else { sss = ss; sst = st; } if (sr > 0xff) sr = 0xff; if (sg > 0xff) sg = 0xff; if (sb > 0xff) sb = 0xff; shade_color.r = sr; shade_color.g = sg; shade_color.b = sb; shade_color.a = sa; if (texture) { /*if (other_modes.sample_type) { // bilinear sss1 = (sss >> 10) - (tsl >> 2); sss2 = sss1 + 1; sst1 = (sst >> 10) - (ttl >> 2); sst2 = sst1 + 1; CLAMP(sss1, sst1); CLAMP(sss2, sst2); FETCH_TEXEL(&t0, sss1, sst1, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t1, sss2, sst1, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t2, sss1, sst2, twidth, tformat, tsize, tbase); FETCH_TEXEL(&t3, sss2, sst2, twidth, tformat, tsize, tbase); texel0_color.r = (((( (t0.r * (0x3ff - (sss & 0x3ff))) + (t1.r * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.r * (0x3ff - (sss & 0x3ff))) + (t3.r * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.g = (((( (t0.g * (0x3ff - (sss & 0x3ff))) + (t1.g * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.g * (0x3ff - (sss & 0x3ff))) + (t3.g * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.b = (((( (t0.b * (0x3ff - (sss & 0x3ff))) + (t1.b * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.b * (0x3ff - (sss & 0x3ff))) + (t3.b * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); texel0_color.a = (((( (t0.a * (0x3ff - (sss & 0x3ff))) + (t1.a * ((sss & 0x3ff))) ) >> 10) * (0x3ff - (sst & 0x3ff))) >> 10) + (((( (t2.a * (0x3ff - (sss & 0x3ff))) + (t3.a * ((sss & 0x3ff))) ) >> 10) * ((sst & 0x3ff))) >> 10); } else { sss1 = (sss >> 10) - (tsl >> 2); if ((sss & 0x3ff) >= 0x200) sss1++; sst1 = (sst >> 10) - (ttl >> 2); if ((sst & 0x3ff) >= 0x200) sst1++; CLAMP(sss1, sst1); // point sample FETCH_TEXEL(&texel0_color, sss1, sst1, twidth, tformat, tsize, tbase); }*/ if (other_modes.cycle_type == CYCLE_TYPE_1) { TEXTURE_PIPELINE1(sss, sst, 0); } else { TEXTURE_PIPELINE2(sss, sst, 0); } } if (other_modes.cycle_type == CYCLE_TYPE_1) { c1 = COLOR_COMBINER(0); } else if (other_modes.cycle_type == CYCLE_TYPE_2) { c1 = COLOR_COMBINER(0); c2 = COLOR_COMBINER(1); } oz = (UINT16)zb[(fb_index + x) ^ WORD_ADDR_XOR]; if (zbuffer) { if (sz < oz /*&& c.a != 0*/) { //BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; if (other_modes.cycle_type == CYCLE_TYPE_1) { BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, dith); } else { BLENDER2_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, c2, dith); } } if (other_modes.z_compare_en && other_modes.z_update_en) { zb[(fb_index + x) ^ WORD_ADDR_XOR] = sz; } } } else { //BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c); { int dith = dither_matrix_4x4[(((j) & 3) << 2) + ((i^WORD_ADDR_XOR) & 3)]; if (other_modes.cycle_type == CYCLE_TYPE_1) { BLENDER1_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, dith); } else { BLENDER2_16(&fb[(fb_index + x) ^ WORD_ADDR_XOR], c1, c2, dith); } } } } r += drinc; g += dginc; b += dbinc; a += dainc; z += dzinc; s += dsinc; t += dtinc; w += dwinc; x += xinc; } } } static void triangle(UINT32 w1, UINT32 w2, int shade, int texture, int zbuffer) { int j; int xleft, xright, xleft_inc, xright_inc; int xstart, xend; int r, g, b, a, z, s, t, w; int dr, dg, db, da; int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0; int drdy = 0, dgdy = 0, dbdy = 0, dady = 0, dzdy = 0, dsdy = 0, dtdy = 0, dwdy = 0; int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0; int tile; int flip = (w1 & 0x800000) ? 1 : 0; INT32 yl, ym, yh; INT32 xl, xm, xh; INT64 dxldy, dxhdy, dxmdy; UINT32 w3, w4, w5, w6, w7, w8; int shade_base = rdp_cmd_cur + 8; int texture_base = rdp_cmd_cur + 8; int zbuffer_base = rdp_cmd_cur + 8; if (shade) { texture_base += 16; zbuffer_base += 16; } if (texture) { zbuffer_base += 16; } w3 = rdp_cmd_data[rdp_cmd_cur+2]; w4 = rdp_cmd_data[rdp_cmd_cur+3]; w5 = rdp_cmd_data[rdp_cmd_cur+4]; w6 = rdp_cmd_data[rdp_cmd_cur+5]; w7 = rdp_cmd_data[rdp_cmd_cur+6]; w8 = rdp_cmd_data[rdp_cmd_cur+7]; yl = (w1 & 0x3fff) >> 2; ym = ((w2 >> 16) & 0x3fff) >> 2; yh = ((w2 >> 0) & 0x3fff) >> 2; xl = (INT32)(w3); xh = (INT32)(w5); xm = (INT32)(w7); dxldy = (INT32)(w4); dxhdy = (INT32)(w6); dxmdy = (INT32)(w8); if (yl & 0x800) yl |= 0xfffff000; if (ym & 0x800) ym |= 0xfffff000; if (yh & 0x800) yh |= 0xfffff000; yl += (w1 >> 1) & 1; ym += (w2 >> 17) & 1; yh += (w2 >> 1) & 1; tile = (w1 >> 16) & 0x7; r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0; s = 0; t = 0; w = 0; dr = 0; dg = 0; db = 0; da = 0; if (shade) { r = (rdp_cmd_data[shade_base+0 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+4 ] >> 16) & 0x0000ffff); g = ((rdp_cmd_data[shade_base+0 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+4 ] & 0x0000ffff); b = (rdp_cmd_data[shade_base+1 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+5 ] >> 16) & 0x0000ffff); a = ((rdp_cmd_data[shade_base+1 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+5 ] & 0x0000ffff); drdx = (rdp_cmd_data[shade_base+2 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+6 ] >> 16) & 0x0000ffff); dgdx = ((rdp_cmd_data[shade_base+2 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+6 ] & 0x0000ffff); dbdx = (rdp_cmd_data[shade_base+3 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+7 ] >> 16) & 0x0000ffff); dadx = ((rdp_cmd_data[shade_base+3 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+7 ] & 0x0000ffff); drde = (rdp_cmd_data[shade_base+8 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+12] >> 16) & 0x0000ffff); dgde = ((rdp_cmd_data[shade_base+8 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+12] & 0x0000ffff); dbde = (rdp_cmd_data[shade_base+9 ] & 0xffff0000) | ((rdp_cmd_data[shade_base+13] >> 16) & 0x0000ffff); dade = ((rdp_cmd_data[shade_base+9 ] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+13] & 0x0000ffff); drdy = (rdp_cmd_data[shade_base+10] & 0xffff0000) | ((rdp_cmd_data[shade_base+14] >> 16) & 0x0000ffff); dgdy = ((rdp_cmd_data[shade_base+10] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+14] & 0x0000ffff); dbdy = (rdp_cmd_data[shade_base+11] & 0xffff0000) | ((rdp_cmd_data[shade_base+15] >> 16) & 0x0000ffff); dady = ((rdp_cmd_data[shade_base+11] << 16) & 0xffff0000) | (rdp_cmd_data[shade_base+15] & 0x0000ffff); } if (texture) { s = (rdp_cmd_data[texture_base+0 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+4 ] >> 16) & 0x0000ffff); t = ((rdp_cmd_data[texture_base+0 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+4 ] & 0x0000ffff); w = (rdp_cmd_data[texture_base+1 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+5 ] >> 16) & 0x0000ffff); dsdx = (rdp_cmd_data[texture_base+2 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+6 ] >> 16) & 0x0000ffff); dtdx = ((rdp_cmd_data[texture_base+2 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+6 ] & 0x0000ffff); dwdx = (rdp_cmd_data[texture_base+3 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+7 ] >> 16) & 0x0000ffff); dsde = (rdp_cmd_data[texture_base+8 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+12] >> 16) & 0x0000ffff); dtde = ((rdp_cmd_data[texture_base+8 ] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+12] & 0x0000ffff); dwde = (rdp_cmd_data[texture_base+9 ] & 0xffff0000) | ((rdp_cmd_data[texture_base+13] >> 16) & 0x0000ffff); dsdy = (rdp_cmd_data[texture_base+10] & 0xffff0000) | ((rdp_cmd_data[texture_base+14] >> 16) & 0x0000ffff); dtdy = ((rdp_cmd_data[texture_base+10] << 16) & 0xffff0000) | (rdp_cmd_data[texture_base+14] & 0x0000ffff); dwdy = (rdp_cmd_data[texture_base+11] & 0xffff0000) | ((rdp_cmd_data[texture_base+15] >> 16) & 0x0000ffff); } if (zbuffer) { z = rdp_cmd_data[zbuffer_base+0]; dzdx = rdp_cmd_data[zbuffer_base+1]; dzde = rdp_cmd_data[zbuffer_base+2]; dzdy = rdp_cmd_data[zbuffer_base+3]; } xleft = xm; xright = xh; xleft_inc = dxmdy; xright_inc = dxhdy; for (j=yh; j < ym; j++) { xstart = xleft >> 16; xend = xright >> 16; if (j >= 0) { span[j].lx = xstart; span[j].rx = xend; span[j].s = s; span[j].ds = dsdx; span[j].t = t; span[j].dt = dtdx; span[j].w = w; span[j].dw = dwdx; span[j].r = r; span[j].dr = drdx; span[j].g = g; span[j].dg = dgdx; span[j].b = b; span[j].db = dbdx; span[j].a = a; span[j].da = dadx; span[j].z = z; span[j].dz = dzdx; } xleft += xleft_inc; xright += xright_inc; s += dsde; t += dtde; w += dwde; r += drde; g += dgde; b += dbde; a += dade; z += dzde; } xleft = xl; xleft_inc = dxldy; xright_inc = dxhdy; for (j=ym; j <= yl; j++) { xstart = xleft >> 16; xend = xright >> 16; if (j >= 0) { span[j].lx = xstart; span[j].rx = xend; span[j].s = s; span[j].ds = dsdx; span[j].t = t; span[j].dt = dtdx; span[j].w = w; span[j].dw = dwdx; span[j].r = r; span[j].dr = drdx; span[j].g = g; span[j].dg = dgdx; span[j].b = b; span[j].db = dbdx; span[j].a = a; span[j].da = dadx; span[j].z = z; span[j].dz = dzdx; } xleft += xleft_inc; xright += xright_inc; s += dsde; t += dtde; w += dwde; r += drde; g += dgde; b += dbde; a += dade; z += dzde; } switch (fb_size) { case PIXEL_SIZE_16BIT: render_spans_16(yh, yl, tile, shade, texture, zbuffer, flip); break; case PIXEL_SIZE_32BIT: render_spans_32(yh, yl, tile, shade, texture, zbuffer, flip); break; } } /*****************************************************************************/ INLINE UINT32 READ_RDP_DATA(UINT32 address) { if (dp_status & 0x1) // XBUS_DMEM_DMA enabled { return rsp_dmem[(address & 0xfff) / 4]; } else { return rdram[(address / 4)]; } } #if LOG_RDP_EXECUTION static const char *image_format[] = { "RGBA", "YUV", "CI", "IA", "I", "???", "???", "???" }; static const char *image_size[] = { "4-bit", "8-bit", "16-bit", "32-bit" }; #endif static const int rdp_command_length[64] = { 8, // 0x00, No Op 8, // 0x01, ??? 8, // 0x02, ??? 8, // 0x03, ??? 8, // 0x04, ??? 8, // 0x05, ??? 8, // 0x06, ??? 8, // 0x07, ??? 32, // 0x08, Non-Shaded Triangle 32+16, // 0x09, Non-Shaded, Z-Buffered Triangle 32+64, // 0x0a, Textured Triangle 32+64+16, // 0x0b, Textured, Z-Buffered Triangle 32+64, // 0x0c, Shaded Triangle 32+64+16, // 0x0d, Shaded, Z-Buffered Triangle 32+64+64, // 0x0e, Shaded+Textured Triangle 32+64+64+16,// 0x0f, Shaded+Textured, Z-Buffered Triangle 8, // 0x10, ??? 8, // 0x11, ??? 8, // 0x12, ??? 8, // 0x13, ??? 8, // 0x14, ??? 8, // 0x15, ??? 8, // 0x16, ??? 8, // 0x17, ??? 8, // 0x18, ??? 8, // 0x19, ??? 8, // 0x1a, ??? 8, // 0x1b, ??? 8, // 0x1c, ??? 8, // 0x1d, ??? 8, // 0x1e, ??? 8, // 0x1f, ??? 8, // 0x20, ??? 8, // 0x21, ??? 8, // 0x22, ??? 8, // 0x23, ??? 16, // 0x24, Texture_Rectangle 16, // 0x25, Texture_Rectangle_Flip 8, // 0x26, Sync_Load 8, // 0x27, Sync_Pipe 8, // 0x28, Sync_Tile 8, // 0x29, Sync_Full 8, // 0x2a, Set_Key_GB 8, // 0x2b, Set_Key_R 8, // 0x2c, Set_Convert 8, // 0x2d, Set_Scissor 8, // 0x2e, Set_Prim_Depth 8, // 0x2f, Set_Other_Modes 8, // 0x30, Load_TLUT 8, // 0x31, ??? 8, // 0x32, Set_Tile_Size 8, // 0x33, Load_Block 8, // 0x34, Load_Tile 8, // 0x35, Set_Tile 8, // 0x36, Fill_Rectangle 8, // 0x37, Set_Fill_Color 8, // 0x38, Set_Fog_Color 8, // 0x39, Set_Blend_Color 8, // 0x3a, Set_Prim_Color 8, // 0x3b, Set_Env_Color 8, // 0x3c, Set_Combine 8, // 0x3d, Set_Texture_Image 8, // 0x3e, Set_Mask_Image 8 // 0x3f, Set_Color_Image }; #if LOG_RDP_EXECUTION static int rdp_dasm(char *buffer) { int i; int tile; const char *format, *size; char sl[32], tl[32], sh[32], th[32]; char s[32], t[32], w[32]; char dsdx[32], dtdx[32], dwdx[32]; char dsdy[32], dtdy[32], dwdy[32]; char dsde[32], dtde[32], dwde[32]; char yl[32], yh[32], ym[32], xl[32], xh[32], xm[32]; char dxldy[32], dxhdy[32], dxmdy[32]; char rt[32], gt[32], bt[32], at[32]; char drdx[32], dgdx[32], dbdx[32], dadx[32]; char drdy[32], dgdy[32], dbdy[32], dady[32]; char drde[32], dgde[32], dbde[32], dade[32]; UINT32 r,g,b,a; UINT32 cmd[64]; UINT32 length; UINT32 command; length = rdp_cmd_ptr * 4; if (length < 8) { sprintf(buffer, "ERROR: length = %d\n", length); return 0; } cmd[0] = rdp_cmd_data[rdp_cmd_cur+0]; cmd[1] = rdp_cmd_data[rdp_cmd_cur+1]; tile = (cmd[1] >> 24) & 0x7; sprintf(sl, "%4.2f", (float)((cmd[0] >> 12) & 0xfff) / 4.0f); sprintf(tl, "%4.2f", (float)((cmd[0] >> 0) & 0xfff) / 4.0f); sprintf(sh, "%4.2f", (float)((cmd[1] >> 12) & 0xfff) / 4.0f); sprintf(th, "%4.2f", (float)((cmd[1] >> 0) & 0xfff) / 4.0f); format = image_format[(cmd[0] >> 21) & 0x7]; size = image_size[(cmd[0] >> 19) & 0x3]; r = (cmd[1] >> 24) & 0xff; g = (cmd[1] >> 16) & 0xff; b = (cmd[1] >> 8) & 0xff; a = (cmd[1] >> 0) & 0xff; command = (cmd[0] >> 24) & 0x3f; switch (command) { case 0x00: sprintf(buffer, "No Op"); break; case 0x08: // Tri_NoShade { int lft = (command >> 23) & 0x1; if (length != rdp_command_length[command]) { sprintf(buffer, "ERROR: Tri_NoShade length = %d\n", length); return 0; } cmd[2] = rdp_cmd_data[rdp_cmd_cur+2]; cmd[3] = rdp_cmd_data[rdp_cmd_cur+3]; cmd[4] = rdp_cmd_data[rdp_cmd_cur+4]; cmd[5] = rdp_cmd_data[rdp_cmd_cur+5]; cmd[6] = rdp_cmd_data[rdp_cmd_cur+6]; cmd[7] = rdp_cmd_data[rdp_cmd_cur+7]; sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); sprintf(xl, "%4.4f", (float)(cmd[2] / 65536.0f)); sprintf(dxldy, "%4.4f", (float)(cmd[3] / 65536.0f)); sprintf(xh, "%4.4f", (float)(cmd[4] / 65536.0f)); sprintf(dxhdy, "%4.4f", (float)(cmd[5] / 65536.0f)); sprintf(xm, "%4.4f", (float)(cmd[6] / 65536.0f)); sprintf(dxmdy, "%4.4f", (float)(cmd[7] / 65536.0f)); sprintf(buffer, "Tri_NoShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); break; } case 0x0a: // Tri_Tex { int lft = (command >> 23) & 0x1; if (length < rdp_command_length[command]) { sprintf(buffer, "ERROR: Tri_Tex length = %d\n", length); return 0; } for (i=2; i < 24; i++) { cmd[i] = rdp_cmd_data[rdp_cmd_cur+i]; } sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); sprintf(s, "%4.4f", (float)(INT32)((cmd[ 8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); sprintf(t, "%4.4f", (float)(INT32)(((cmd[ 8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); sprintf(w, "%4.4f", (float)(INT32)((cmd[ 9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); sprintf(dsde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); sprintf(dwde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); buffer+=sprintf(buffer, "Tri_Tex %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy); break; } case 0x0c: // Tri_Shade { int lft = (command >> 23) & 0x1; if (length != rdp_command_length[command]) { sprintf(buffer, "ERROR: Tri_Shade length = %d\n", length); return 0; } for (i=2; i < 24; i++) { cmd[i] = rdp_cmd_data[i]; } sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f); sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f); sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f); sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f); buffer+=sprintf(buffer, "Tri_Shade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady); break; } case 0x0e: // Tri_TexShade { int lft = (command >> 23) & 0x1; if (length < rdp_command_length[command]) { sprintf(buffer, "ERROR: Tri_TexShade length = %d\n", length); return 0; } for (i=2; i < 40; i++) { cmd[i] = rdp_cmd_data[rdp_cmd_cur+i]; } sprintf(yl, "%4.4f", (float)((cmd[0] >> 0) & 0x1fff) / 4.0f); sprintf(ym, "%4.4f", (float)((cmd[1] >> 16) & 0x1fff) / 4.0f); sprintf(yh, "%4.4f", (float)((cmd[1] >> 0) & 0x1fff) / 4.0f); sprintf(xl, "%4.4f", (float)((INT32)cmd[2] / 65536.0f)); sprintf(dxldy, "%4.4f", (float)((INT32)cmd[3] / 65536.0f)); sprintf(xh, "%4.4f", (float)((INT32)cmd[4] / 65536.0f)); sprintf(dxhdy, "%4.4f", (float)((INT32)cmd[5] / 65536.0f)); sprintf(xm, "%4.4f", (float)((INT32)cmd[6] / 65536.0f)); sprintf(dxmdy, "%4.4f", (float)((INT32)cmd[7] / 65536.0f)); sprintf(rt, "%4.4f", (float)(INT32)((cmd[8] & 0xffff0000) | ((cmd[12] >> 16) & 0xffff)) / 65536.0f); sprintf(gt, "%4.4f", (float)(INT32)(((cmd[8] & 0xffff) << 16) | (cmd[12] & 0xffff)) / 65536.0f); sprintf(bt, "%4.4f", (float)(INT32)((cmd[9] & 0xffff0000) | ((cmd[13] >> 16) & 0xffff)) / 65536.0f); sprintf(at, "%4.4f", (float)(INT32)(((cmd[9] & 0xffff) << 16) | (cmd[13] & 0xffff)) / 65536.0f); sprintf(drdx, "%4.4f", (float)(INT32)((cmd[10] & 0xffff0000) | ((cmd[14] >> 16) & 0xffff)) / 65536.0f); sprintf(dgdx, "%4.4f", (float)(INT32)(((cmd[10] & 0xffff) << 16) | (cmd[14] & 0xffff)) / 65536.0f); sprintf(dbdx, "%4.4f", (float)(INT32)((cmd[11] & 0xffff0000) | ((cmd[15] >> 16) & 0xffff)) / 65536.0f); sprintf(dadx, "%4.4f", (float)(INT32)(((cmd[11] & 0xffff) << 16) | (cmd[15] & 0xffff)) / 65536.0f); sprintf(drde, "%4.4f", (float)(INT32)((cmd[16] & 0xffff0000) | ((cmd[20] >> 16) & 0xffff)) / 65536.0f); sprintf(dgde, "%4.4f", (float)(INT32)(((cmd[16] & 0xffff) << 16) | (cmd[20] & 0xffff)) / 65536.0f); sprintf(dbde, "%4.4f", (float)(INT32)((cmd[17] & 0xffff0000) | ((cmd[21] >> 16) & 0xffff)) / 65536.0f); sprintf(dade, "%4.4f", (float)(INT32)(((cmd[17] & 0xffff) << 16) | (cmd[21] & 0xffff)) / 65536.0f); sprintf(drdy, "%4.4f", (float)(INT32)((cmd[18] & 0xffff0000) | ((cmd[22] >> 16) & 0xffff)) / 65536.0f); sprintf(dgdy, "%4.4f", (float)(INT32)(((cmd[18] & 0xffff) << 16) | (cmd[22] & 0xffff)) / 65536.0f); sprintf(dbdy, "%4.4f", (float)(INT32)((cmd[19] & 0xffff0000) | ((cmd[23] >> 16) & 0xffff)) / 65536.0f); sprintf(dady, "%4.4f", (float)(INT32)(((cmd[19] & 0xffff) << 16) | (cmd[23] & 0xffff)) / 65536.0f); sprintf(s, "%4.4f", (float)(INT32)((cmd[24] & 0xffff0000) | ((cmd[28] >> 16) & 0xffff)) / 65536.0f); sprintf(t, "%4.4f", (float)(INT32)(((cmd[24] & 0xffff) << 16) | (cmd[28] & 0xffff)) / 65536.0f); sprintf(w, "%4.4f", (float)(INT32)((cmd[25] & 0xffff0000) | ((cmd[29] >> 16) & 0xffff)) / 65536.0f); sprintf(dsdx, "%4.4f", (float)(INT32)((cmd[26] & 0xffff0000) | ((cmd[30] >> 16) & 0xffff)) / 65536.0f); sprintf(dtdx, "%4.4f", (float)(INT32)(((cmd[26] & 0xffff) << 16) | (cmd[30] & 0xffff)) / 65536.0f); sprintf(dwdx, "%4.4f", (float)(INT32)((cmd[27] & 0xffff0000) | ((cmd[31] >> 16) & 0xffff)) / 65536.0f); sprintf(dsde, "%4.4f", (float)(INT32)((cmd[32] & 0xffff0000) | ((cmd[36] >> 16) & 0xffff)) / 65536.0f); sprintf(dtde, "%4.4f", (float)(INT32)(((cmd[32] & 0xffff) << 16) | (cmd[36] & 0xffff)) / 65536.0f); sprintf(dwde, "%4.4f", (float)(INT32)((cmd[33] & 0xffff0000) | ((cmd[37] >> 16) & 0xffff)) / 65536.0f); sprintf(dsdy, "%4.4f", (float)(INT32)((cmd[34] & 0xffff0000) | ((cmd[38] >> 16) & 0xffff)) / 65536.0f); sprintf(dtdy, "%4.4f", (float)(INT32)(((cmd[34] & 0xffff) << 16) | (cmd[38] & 0xffff)) / 65536.0f); sprintf(dwdy, "%4.4f", (float)(INT32)((cmd[35] & 0xffff0000) | ((cmd[39] >> 16) & 0xffff)) / 65536.0f); buffer+=sprintf(buffer, "Tri_TexShade %d, XL: %s, XM: %s, XH: %s, YL: %s, YM: %s, YH: %s\n", lft, xl,xm,xh,yl,ym,yh); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " R: %s, G: %s, B: %s, A: %s\n", rt, gt, bt, at); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDX: %s, DGDX: %s, DBDX: %s, DADX: %s\n", drdx, dgdx, dbdx, dadx); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDE: %s, DGDE: %s, DBDE: %s, DADE: %s\n", drde, dgde, dbde, dade); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DRDY: %s, DGDY: %s, DBDY: %s, DADY: %s\n", drdy, dgdy, dbdy, dady); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " S: %s, T: %s, W: %s\n", s, t, w); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDX: %s, DTDX: %s, DWDX: %s\n", dsdx, dtdx, dwdx); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDE: %s, DTDE: %s, DWDE: %s\n", dsde, dtde, dwde); buffer+=sprintf(buffer, " "); buffer+=sprintf(buffer, " DSDY: %s, DTDY: %s, DWDY: %s\n", dsdy, dtdy, dwdy); break; } case 0x24: case 0x25: { if (length < 16) { sprintf(buffer, "ERROR: Texture_Rectangle length = %d\n", length); return 0; } cmd[2] = rdp_cmd_data[rdp_cmd_cur+2]; cmd[3] = rdp_cmd_data[rdp_cmd_cur+3]; sprintf(s, "%4.4f", (float)(INT16)((cmd[2] >> 16) & 0xffff) / 32.0f); sprintf(t, "%4.4f", (float)(INT16)((cmd[2] >> 0) & 0xffff) / 32.0f); sprintf(dsdx, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f); sprintf(dtdy, "%4.4f", (float)(INT16)((cmd[3] >> 16) & 0xffff) / 1024.0f); if (command == 0x24) sprintf(buffer, "Texture_Rectangle %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy); else sprintf(buffer, "Texture_Rectangle_Flip %d, %s, %s, %s, %s, %s, %s, %s, %s", tile, sh, th, sl, tl, s, t, dsdx, dtdy); break; } case 0x26: sprintf(buffer, "Sync_Load"); break; case 0x27: sprintf(buffer, "Sync_Pipe"); break; case 0x28: sprintf(buffer, "Sync_Tile"); break; case 0x29: sprintf(buffer, "Sync_Full"); break; case 0x2d: sprintf(buffer, "Set_Scissor %s, %s, %s, %s", sl, tl, sh, th); break; case 0x2e: sprintf(buffer, "Set_Prim_Depth %04X, %04X", (cmd[1] >> 16) & 0xffff, cmd[1] & 0xffff); break; case 0x2f: sprintf(buffer, "Set_Other_Modes %08X %08X", cmd[0], cmd[1]); break; case 0x30: sprintf(buffer, "Load_TLUT %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; case 0x32: sprintf(buffer, "Set_Tile_Size %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; case 0x33: sprintf(buffer, "Load_Block %d, %03X, %03X, %03X, %03X", tile, (cmd[0] >> 12) & 0xfff, cmd[0] & 0xfff, (cmd[1] >> 12) & 0xfff, cmd[1] & 0xfff); break; case 0x34: sprintf(buffer, "Load_Tile %d, %s, %s, %s, %s", tile, sl, tl, sh, th); break; case 0x35: sprintf(buffer, "Set_Tile %d, %s, %s, %d, %04X", tile, format, size, ((cmd[0] >> 9) & 0x1ff) * 8, (cmd[0] & 0x1ff) * 8); break; case 0x36: sprintf(buffer, "Fill_Rectangle %s, %s, %s, %s", sh, th, sl, tl); break; case 0x37: sprintf(buffer, "Set_Fill_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; case 0x38: sprintf(buffer, "Set_Fog_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; case 0x39: sprintf(buffer, "Set_Blend_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; case 0x3a: sprintf(buffer, "Set_Prim_Color %d, %d, R: %d, G: %d, B: %d, A: %d", (cmd[0] >> 8) & 0x1f, cmd[0] & 0xff, r, g, b, a); break; case 0x3b: sprintf(buffer, "Set_Env_Color R: %d, G: %d, B: %d, A: %d", r, g, b, a); break; case 0x3c: sprintf(buffer, "Set_Combine %08X %08X", cmd[0], cmd[1]); break; case 0x3d: sprintf(buffer, "Set_Texture_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break; case 0x3e: sprintf(buffer, "Set_Mask_Image %08X", cmd[1]); break; case 0x3f: sprintf(buffer, "Set_Color_Image %s, %s, %d, %08X", format, size, (cmd[0] & 0x1ff)+1, cmd[1]); break; default: sprintf(buffer, "??? (%08X %08X)", cmd[0], cmd[1]); break; } return rdp_command_length[command]; } #endif /*****************************************************************************/ //////////////////////// // RDP COMMANDS //////////////////////// static void rdp_invalid(UINT32 w1, UINT32 w2) { fatalerror("RDP: invalid command %d, %08X %08X\n", (w1 >> 24) & 0x3f, w1, w2); } static void rdp_noop(UINT32 w1, UINT32 w2) { } static void rdp_tri_noshade(UINT32 w1, UINT32 w2) { //fatalerror("RDP: unhandled command tri_noshade, %08X %08X\n", w1, w2); triangle(w1, w2, 0, 0, 0); } static void rdp_tri_noshade_z(UINT32 w1, UINT32 w2) { //fatalerror("RDP: unhandled command tri_noshade_z, %08X %08X\n", w1, w2); triangle(w1, w2, 0, 0, 1); } static void rdp_tri_tex(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_tex, %08X %08X\n", w1, w2); triangle(w1, w2, 0, 1, 0); } static void rdp_tri_tex_z(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_tex_z, %08X %08X\n", w1, w2); triangle(w1, w2, 0, 1, 1); } static void rdp_tri_shade(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_shade, %08X %08X\n", w1, w2); triangle(w1, w2, 1, 0, 0); } static void rdp_tri_shade_z(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_shade_z, %08X %08X\n", w1, w2); triangle(w1, w2, 1, 0, 1); } static void rdp_tri_texshade(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_texshade, %08X %08X\n", w1, w2); triangle(w1, w2, 1, 1, 0); } static void rdp_tri_texshade_z(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command tri_texshade_z, %08X %08X\n", w1, w2); triangle(w1, w2, 1, 1, 1); } static void rdp_tex_rect(UINT32 w1, UINT32 w2) { UINT32 w3, w4; TEX_RECTANGLE rect; w3 = rdp_cmd_data[rdp_cmd_cur+2]; w4 = rdp_cmd_data[rdp_cmd_cur+3]; rect.tilenum = (w2 >> 24) & 0x7; rect.xl = (w1 >> 12) & 0xfff; rect.yl = (w1 >> 0) & 0xfff; rect.xh = (w2 >> 12) & 0xfff; rect.yh = (w2 >> 0) & 0xfff; rect.s = (w3 >> 16) & 0xffff; rect.t = (w3 >> 0) & 0xffff; rect.dsdx = (w4 >> 16) & 0xffff; rect.dtdy = (w4 >> 0) & 0xffff; switch (fb_size) { case PIXEL_SIZE_16BIT: texture_rectangle_16bit(&rect); break; case PIXEL_SIZE_32BIT: texture_rectangle_32bit(&rect); break; } } static void rdp_tex_rect_flip(UINT32 w1, UINT32 w2) { UINT32 w3, w4; TEX_RECTANGLE rect; w3 = rdp_cmd_data[rdp_cmd_cur+2]; w4 = rdp_cmd_data[rdp_cmd_cur+3]; rect.tilenum = (w2 >> 24) & 0x7; rect.xl = (w1 >> 12) & 0xfff; rect.yl = (w1 >> 0) & 0xfff; rect.xh = (w2 >> 12) & 0xfff; rect.yh = (w2 >> 0) & 0xfff; rect.t = (w3 >> 16) & 0xffff; rect.s = (w3 >> 0) & 0xffff; rect.dtdy = (w4 >> 16) & 0xffff; rect.dsdx = (w4 >> 0) & 0xffff; switch (fb_size) { case PIXEL_SIZE_16BIT: texture_rectangle_16bit(&rect); break; case PIXEL_SIZE_32BIT: texture_rectangle_32bit(&rect); break; } } static void rdp_sync_load(UINT32 w1, UINT32 w2) { // Nothing to do? } static void rdp_sync_pipe(UINT32 w1, UINT32 w2) { // Nothing to do? } static void rdp_sync_tile(UINT32 w1, UINT32 w2) { // Nothing to do? } static void rdp_sync_full(UINT32 w1, UINT32 w2) { dp_full_sync(); } static void rdp_set_key_gb(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command set_key_gb, %08X %08X\n", w1, w2); } static void rdp_set_key_r(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command set_key_r, %08X %08X\n", w1, w2); } static void rdp_set_convert(UINT32 w1, UINT32 w2) { //osd_die("RDP: unhandled command set_convert, %08X %08X\n", w1, w2); } static void rdp_set_scissor(UINT32 w1, UINT32 w2) { clip.xh = (w1 >> 12) & 0xfff; clip.yh = (w1 >> 0) & 0xfff; clip.xl = (w2 >> 12) & 0xfff; clip.yl = (w2 >> 0) & 0xfff; // TODO: handle f & o? } static void rdp_set_prim_depth(UINT32 w1, UINT32 w2) { primitive_z = (UINT16)(w2 >> 16); primitive_delta_z = (UINT16)(w1); } static void rdp_set_other_modes(UINT32 w1, UINT32 w2) { other_modes.cycle_type = (w1 >> 20) & 0x3; other_modes.persp_tex_en = (w1 & 0x80000) ? 1 : 0; other_modes.detail_tex_en = (w1 & 0x40000) ? 1 : 0; other_modes.sharpen_tex_en = (w1 & 0x20000) ? 1 : 0; other_modes.tex_lod_en = (w1 & 0x10000) ? 1 : 0; other_modes.en_tlut = (w1 & 0x08000) ? 1 : 0; other_modes.tlut_type = (w1 & 0x04000) ? 1 : 0; other_modes.sample_type = (w1 & 0x02000) ? 1 : 0; other_modes.mid_texel = (w1 & 0x01000) ? 1 : 0; other_modes.bi_lerp0 = (w1 & 0x00800) ? 1 : 0; other_modes.bi_lerp1 = (w1 & 0x00400) ? 1 : 0; other_modes.convert_one = (w1 & 0x00200) ? 1 : 0; other_modes.key_en = (w1 & 0x00100) ? 1 : 0; other_modes.rgb_dither_sel = (w1 >> 6) & 0x3; other_modes.alpha_dither_sel = (w1 >> 4) & 0x3; other_modes.blend_m1a_0 = (w2 >> 30) & 0x3; other_modes.blend_m1a_1 = (w2 >> 28) & 0x3; other_modes.blend_m1b_0 = (w2 >> 26) & 0x3; other_modes.blend_m1b_1 = (w2 >> 24) & 0x3; other_modes.blend_m2a_0 = (w2 >> 22) & 0x3; other_modes.blend_m2a_1 = (w2 >> 20) & 0x3; other_modes.blend_m2b_0 = (w2 >> 18) & 0x3; other_modes.blend_m2b_1 = (w2 >> 16) & 0x3; other_modes.force_blend = (w2 & 0x4000) ? 1 : 0; other_modes.alpha_cvg_select = (w2 & 0x2000) ? 1 : 0; other_modes.cvg_times_alpha = (w2 & 0x1000) ? 1 : 0; other_modes.z_mode = (w2 >> 10) & 0x3; other_modes.cvg_dest = (w2 >> 8) & 0x3; other_modes.color_on_cvg = (w2 & 0x80) ? 1 : 0; other_modes.image_read_en = (w2 & 0x40) ? 1 : 0; other_modes.z_update_en = (w2 & 0x20) ? 1 : 0; other_modes.z_compare_en = (w2 & 0x10) ? 1 : 0; other_modes.antialias_en = (w2 & 0x08) ? 1 : 0; other_modes.z_source_sel = (w2 & 0x04) ? 1 : 0; other_modes.dither_alpha_en = (w2 & 0x02) ? 1 : 0; other_modes.alpha_compare_en = (w2 & 0x01) ? 1 : 0; SET_BLENDER_INPUT(0, 0, &blender1a_r[0], &blender1a_g[0], &blender1a_b[0], &blender1b_a[0], other_modes.blend_m1a_0, other_modes.blend_m1b_0); SET_BLENDER_INPUT(0, 1, &blender2a_r[0], &blender2a_g[0], &blender2a_b[0], &blender2b_a[0], other_modes.blend_m2a_0, other_modes.blend_m2b_0); SET_BLENDER_INPUT(1, 0, &blender1a_r[1], &blender1a_g[1], &blender1a_b[1], &blender1b_a[1], other_modes.blend_m1a_1, other_modes.blend_m1b_1); SET_BLENDER_INPUT(1, 1, &blender2a_r[1], &blender2a_g[1], &blender2a_b[1], &blender2b_a[1], other_modes.blend_m2a_1, other_modes.blend_m2b_1); // mame_printf_debug("blend: m1a = %d, m1b = %d, m2a = %d, m2b = %d\n", other_modes.blend_m1a_0, other_modes.blend_m1b_0, other_modes.blend_m2a_0, other_modes.blend_m2b_0); switch (other_modes.rgb_dither_sel) { case 0: break; case 1: break; //fatalerror("bayer matrix dither\n"); break; case 2: break; /////fatalerror("noise dither\n"); break; case 3: break; } } static void rdp_load_tlut(UINT32 w1, UINT32 w2) { int i; UINT16 sl, sh; // int tilenum = (w2 >> 24) & 0x7; sl = ((w1 >> 12) & 0xfff) / 4; sh = ((w2 >> 12) & 0xfff) / 4; switch (ti_format) { case 0: // RGBA { switch (ti_size) { case PIXEL_SIZE_16BIT: { UINT16 *src = (UINT16*)&rdram[ti_address / 4]; // UINT16 *tlut = (UINT16*)&texture_cache[tile[tilenum].tmem/2]; for (i=sl; i <= sh; i++) { tlut[i] = src[i]; // mame_printf_debug("TLUT %d = %04X\n", i, tlut[i]); } break; } default: fatalerror("RDP: load_tlut: size = %d\n", ti_size); } break; } default: fatalerror("RDP: load_tlut: format = %d\n", ti_format); } } static void rdp_set_tile_size(UINT32 w1, UINT32 w2) { int tilenum = (w2 >> 24) & 0x7; tile[tilenum].sl = (w1 >> 12) & 0xfff; tile[tilenum].tl = (w1 >> 0) & 0xfff; tile[tilenum].sh = (w2 >> 12) & 0xfff; tile[tilenum].th = (w2 >> 0) & 0xfff; } static void rdp_load_block(UINT32 w1, UINT32 w2) { int i, width; UINT16 sl, sh, tl, dxt; int tilenum = (w2 >> 24) & 0x7; UINT32 *src, *tc; int tb; if (ti_format != tile[tilenum].format || ti_size != tile[tilenum].size) fatalerror("RDP: load_block: format conversion required!\n"); sl = ((w1 >> 12) & 0xfff); tl = ((w1 >> 0) & 0xfff) << 11; sh = ((w2 >> 12) & 0xfff); dxt = ((w2 >> 0) & 0xfff); width = (sh - sl) + 1; switch (ti_size) { case PIXEL_SIZE_4BIT: width >>= 1; break; case PIXEL_SIZE_8BIT: break; case PIXEL_SIZE_16BIT: width <<= 1; break; case PIXEL_SIZE_32BIT: width <<= 2; break; } src = (UINT32*)&rdram[ti_address / 4]; tc = (UINT32*)texture_cache; tb = tile[tilenum].tmem; if (dxt != 0) { int j=0; for (i=0; i < width; i+=2) { int t = j >> 11; tc[((tb+i) + 0)] = src[((((tl * ti_width) / 4) + sl + i + 0) ^ ((t & 1) ? 1 : 0))]; tc[((tb+i) + 1)] = src[((((tl * ti_width) / 4) + sl + i + 1) ^ ((t & 1) ? 1 : 0))]; j += dxt; } } else { for (i=0; i < width / 4; i++) { tc[(tb+i)] = src[((tl * ti_width) / 4) + sl + i]; } } } static void rdp_load_tile(UINT32 w1, UINT32 w2) { int i, j; UINT16 sl, sh, tl, th; int width, height; int tilenum = (w2 >> 24) & 0x7; if (ti_format != tile[tilenum].format || ti_size != tile[tilenum].size) fatalerror("RDP: load_block: format conversion required!\n"); sl = ((w1 >> 12) & 0xfff) / 4; tl = ((w1 >> 0) & 0xfff) / 4; sh = ((w2 >> 12) & 0xfff) / 4; th = ((w2 >> 0) & 0xfff) / 4; width = (sh - sl) + 1; height = (th - tl) + 1; switch (ti_size) { case PIXEL_SIZE_8BIT: { UINT8 *src = (UINT8*)&rdram[ti_address / 4]; UINT8 *tc = (UINT8*)texture_cache; int tb = tile[tilenum].tmem; if (tb + (width * height) > 4096) { fatalerror("rdp_load_tile 8-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height); } for (j=0; j < height; j++) { int tline = tb + (tile[tilenum].line * j); int s = ((j + tl) * ti_width) + sl; for (i=0; i < width; i++) { tc[((tline+i) ^ BYTE_ADDR_XOR) ^ ((j & 1) ? 4 : 0)] = src[(s++) ^ BYTE_ADDR_XOR]; } } break; } case PIXEL_SIZE_16BIT: { UINT16 *src = (UINT16*)&rdram[ti_address / 4]; UINT16 *tc = (UINT16*)texture_cache; int tb = (tile[tilenum].tmem / 2); if (tb + (width * height) > 2048) { //fatalerror("rdp_load_tile 16-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height); } for (j=0; j < height; j++) { int tline = tb + ((tile[tilenum].line / 2) * j); int s = ((j + tl) * ti_width) + sl; for (i=0; i < width; i++) { tc[((tline+i) ^ WORD_ADDR_XOR) ^ ((j & 1) ? 2 : 0)] = src[(s++) ^ WORD_ADDR_XOR]; } } break; } case PIXEL_SIZE_32BIT: { UINT32 *src = (UINT32*)&rdram[ti_address / 4]; UINT32 *tc = (UINT32*)texture_cache; int tb = (tile[tilenum].tmem / 4); if (tb + (width * height) > 1024) { fatalerror("rdp_load_tile 32-bit: tmem %04X, width %d, height %d = %d\n", tile[tilenum].tmem, width, height, width*height); } for (j=0; j < height; j++) { int tline = tb + ((tile[tilenum].line / 4) * j); int s = ((j + tl) * ti_width) + sl; for (i=0; i < width; i++) { tc[(tline+i) ^ ((j & 1) ? 1 : 0)] = src[(s++)]; } } break; } default: fatalerror("RDP: load_tile: size = %d\n", ti_size); } } static void rdp_set_tile(UINT32 w1, UINT32 w2) { int tilenum = (w2 >> 24) & 0x7; tile[tilenum].format = (w1 >> 21) & 0x7; tile[tilenum].size = (w1 >> 19) & 0x3; tile[tilenum].line = ((w1 >> 9) & 0x1ff) * 8; tile[tilenum].tmem = ((w1 >> 0) & 0x1ff) * 8; tile[tilenum].ct = (w2 >> 19) & 0x1; tile[tilenum].mt = (w2 >> 18) & 0x1; tile[tilenum].mask_t = (w2 >> 14) & 0xf; tile[tilenum].shift_t = (w2 >> 10) & 0xf; tile[tilenum].cs = (w2 >> 9) & 0x1; tile[tilenum].ms = (w2 >> 8) & 0x1; tile[tilenum].mask_s = (w2 >> 4) & 0xf; tile[tilenum].shift_s = (w2 >> 0) & 0xf; // TODO: clamp & mirror parameters } static void rdp_fill_rect(UINT32 w1, UINT32 w2) { RECTANGLE rect; rect.xl = (w1 >> 12) & 0xfff; rect.yl = (w1 >> 0) & 0xfff; rect.xh = (w2 >> 12) & 0xfff; rect.yh = (w2 >> 0) & 0xfff; switch (fb_size) { case PIXEL_SIZE_16BIT: fill_rectangle_16bit(&rect); break; case PIXEL_SIZE_32BIT: fill_rectangle_32bit(&rect); break; } } static void rdp_set_fill_color(UINT32 w1, UINT32 w2) { fill_color = w2; } static void rdp_set_fog_color(UINT32 w1, UINT32 w2) { fog_color.r = (w2 >> 24) & 0xff; fog_color.g = (w2 >> 16) & 0xff; fog_color.b = (w2 >> 8) & 0xff; fog_color.a = (w2 >> 0) & 0xff; } static void rdp_set_blend_color(UINT32 w1, UINT32 w2) { blend_color.r = (w2 >> 24) & 0xff; blend_color.g = (w2 >> 16) & 0xff; blend_color.b = (w2 >> 8) & 0xff; blend_color.a = (w2 >> 0) & 0xff; } static void rdp_set_prim_color(UINT32 w1, UINT32 w2) { // TODO: prim min level, prim_level prim_color.r = (w2 >> 24) & 0xff; prim_color.g = (w2 >> 16) & 0xff; prim_color.b = (w2 >> 8) & 0xff; prim_color.a = (w2 >> 0) & 0xff; } static void rdp_set_env_color(UINT32 w1, UINT32 w2) { env_color.r = (w2 >> 24) & 0xff; env_color.g = (w2 >> 16) & 0xff; env_color.b = (w2 >> 8) & 0xff; env_color.a = (w2 >> 0) & 0xff; } static void rdp_set_combine(UINT32 w1, UINT32 w2) { combine.sub_a_rgb0 = (w1 >> 20) & 0xf; combine.mul_rgb0 = (w1 >> 15) & 0x1f; combine.sub_a_a0 = (w1 >> 12) & 0x7; combine.mul_a0 = (w1 >> 9) & 0x7; combine.sub_a_rgb1 = (w1 >> 5) & 0xf; combine.mul_rgb1 = (w1 >> 0) & 0x1f; combine.sub_b_rgb0 = (w2 >> 28) & 0xf; combine.sub_b_rgb1 = (w2 >> 24) & 0xf; combine.sub_a_a1 = (w2 >> 21) & 0x7; combine.mul_a1 = (w2 >> 18) & 0x7; combine.add_rgb0 = (w2 >> 15) & 0x7; combine.sub_b_a0 = (w2 >> 12) & 0x7; combine.add_a0 = (w2 >> 9) & 0x7; combine.add_rgb1 = (w2 >> 6) & 0x7; combine.sub_b_a1 = (w2 >> 3) & 0x7; combine.add_a1 = (w2 >> 0) & 0x7; SET_SUBA_RGB_INPUT(&combiner_rgbsub_a_r[0], &combiner_rgbsub_a_g[0], &combiner_rgbsub_a_b[0], combine.sub_a_rgb0); SET_SUBB_RGB_INPUT(&combiner_rgbsub_b_r[0], &combiner_rgbsub_b_g[0], &combiner_rgbsub_b_b[0], combine.sub_b_rgb0); SET_MUL_RGB_INPUT(&combiner_rgbmul_r[0], &combiner_rgbmul_g[0], &combiner_rgbmul_b[0], combine.mul_rgb0); SET_ADD_RGB_INPUT(&combiner_rgbadd_r[0], &combiner_rgbadd_g[0], &combiner_rgbadd_b[0], combine.add_rgb0); SET_SUB_ALPHA_INPUT(&combiner_alphasub_a[0], combine.sub_a_a0); SET_SUB_ALPHA_INPUT(&combiner_alphasub_b[0], combine.sub_b_a0); SET_MUL_ALPHA_INPUT(&combiner_alphamul[0], combine.mul_a0); SET_SUB_ALPHA_INPUT(&combiner_alphaadd[0], combine.add_a0); SET_SUBA_RGB_INPUT(&combiner_rgbsub_a_r[1], &combiner_rgbsub_a_g[1], &combiner_rgbsub_a_b[1], combine.sub_a_rgb1); SET_SUBB_RGB_INPUT(&combiner_rgbsub_b_r[1], &combiner_rgbsub_b_g[1], &combiner_rgbsub_b_b[1], combine.sub_b_rgb1); SET_MUL_RGB_INPUT(&combiner_rgbmul_r[1], &combiner_rgbmul_g[1], &combiner_rgbmul_b[1], combine.mul_rgb1); SET_ADD_RGB_INPUT(&combiner_rgbadd_r[1], &combiner_rgbadd_g[1], &combiner_rgbadd_b[1], combine.add_rgb1); SET_SUB_ALPHA_INPUT(&combiner_alphasub_a[1], combine.sub_a_a1); SET_SUB_ALPHA_INPUT(&combiner_alphasub_b[1], combine.sub_b_a1); SET_MUL_ALPHA_INPUT(&combiner_alphamul[1], combine.mul_a1); SET_SUB_ALPHA_INPUT(&combiner_alphaadd[1], combine.add_a1); } static void rdp_set_texture_image(UINT32 w1, UINT32 w2) { ti_format = (w1 >> 21) & 0x7; ti_size = (w1 >> 19) & 0x3; ti_width = (w1 & 0x3ff) + 1; ti_address = w2 & 0x01ffffff; } static void rdp_set_mask_image(UINT32 w1, UINT32 w2) { zb_address = w2 & 0x01ffffff; } static void rdp_set_color_image(UINT32 w1, UINT32 w2) { fb_format = (w1 >> 21) & 0x7; fb_size = (w1 >> 19) & 0x3; fb_width = (w1 & 0x3ff) + 1; fb_address = w2 & 0x01ffffff; //if (fb_format != 0) fatalerror("rdp_set_color_image: format = %d\n", fb_format); if (fb_format != 0) fb_format = 0; } /*****************************************************************************/ static void (* rdp_command_table[64])(UINT32 w1, UINT32 w2) = { /* 0x00 */ rdp_noop, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_tri_noshade, rdp_tri_noshade_z, rdp_tri_tex, rdp_tri_tex_z, rdp_tri_shade, rdp_tri_shade_z, rdp_tri_texshade, rdp_tri_texshade_z, /* 0x10 */ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, /* 0x20 */ rdp_invalid, rdp_invalid, rdp_invalid, rdp_invalid, rdp_tex_rect, rdp_tex_rect_flip, rdp_sync_load, rdp_sync_pipe, rdp_sync_tile, rdp_sync_full, rdp_set_key_gb, rdp_set_key_r, rdp_set_convert, rdp_set_scissor, rdp_set_prim_depth, rdp_set_other_modes, /* 0x30 */ rdp_load_tlut, rdp_invalid, rdp_set_tile_size, rdp_load_block, rdp_load_tile, rdp_set_tile, rdp_fill_rect, rdp_set_fill_color, rdp_set_fog_color, rdp_set_blend_color, rdp_set_prim_color, rdp_set_env_color, rdp_set_combine, rdp_set_texture_image, rdp_set_mask_image, rdp_set_color_image }; void rdp_process_list(void) { int i; UINT32 cmd, length, cmd_length; length = dp_end - dp_current; // load command data for (i=0; i < length; i += 4) { rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(dp_current + i); if (rdp_cmd_ptr >= 0x1000) { fatalerror("rdp_process_list: rdp_cmd_ptr overflow\n"); } } dp_current = dp_end; cmd = (rdp_cmd_data[0] >> 24) & 0x3f; cmd_length = (rdp_cmd_ptr + 1) * 4; // check if more data is needed if (cmd_length < rdp_command_length[cmd]) { return; } while (rdp_cmd_cur < rdp_cmd_ptr) { cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f; // if (((rdp_cmd_data[rdp_cmd_cur] >> 24) & 0xc0) != 0xc0) // { // fatalerror("rdp_process_list: invalid rdp command %08X at %08X\n", rdp_cmd_data[rdp_cmd_cur], dp_start+(rdp_cmd_cur * 4)); // } if (((rdp_cmd_ptr-rdp_cmd_cur) * 4) < rdp_command_length[cmd]) { return; //fatalerror("rdp_process_list: not enough rdp command data: cur = %d, ptr = %d, expected = %d\n", rdp_cmd_cur, rdp_cmd_ptr, rdp_command_length[cmd]); } #if LOG_RDP_EXECUTION { char string[4000]; rdp_dasm(string); fprintf(rdp_exec, "%08X: %08X %08X %s\n", dp_start+(rdp_cmd_cur * 4), rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1], string); } #endif // execute the command rdp_command_table[cmd](rdp_cmd_data[rdp_cmd_cur+0], rdp_cmd_data[rdp_cmd_cur+1]); rdp_cmd_cur += rdp_command_length[cmd] / 4; }; rdp_cmd_ptr = 0; rdp_cmd_cur = 0; dp_start = dp_end; }