diff options
Diffstat (limited to 'src/mame/video/n64.c')
-rw-r--r-- | src/mame/video/n64.c | 3479 |
1 files changed, 3479 insertions, 0 deletions
diff --git a/src/mame/video/n64.c b/src/mame/video/n64.c new file mode 100644 index 00000000000..31e54dbc5e5 --- /dev/null +++ b/src/mame/video/n64.c @@ -0,0 +1,3479 @@ +/* + 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 <height; j++) + { + UINT32 *d = BITMAP_ADDR32(bitmap, j, 0); + for (i=0; i < fb_width; i++) + { + UINT16 pix = *frame_buffer++; + int r = ((pix >> 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; +} |