[SNES] Improved Mode 7 math precision (but still some issues remain) and added a few elements to PPU struct

This commit is contained in:
Fabio Priuli 2009-08-08 17:00:55 +00:00
parent e8a98bf880
commit 0102fbe6ab
3 changed files with 84 additions and 51 deletions

View File

@ -422,6 +422,7 @@ struct SNES_PPU_STRUCT
UINT32 map;
UINT8 map_size;
UINT8 tile_size;
UINT8 mosaic_enabled; // actually used only for layers 0->3!
struct
{
UINT16 horizontal;
@ -462,13 +463,23 @@ struct SNES_PPU_STRUCT
} beam;
struct
{
INT16 matrix_a;
INT16 matrix_b;
INT16 matrix_c;
INT16 matrix_d;
INT16 origin_x;
INT16 origin_y;
UINT8 repeat;
UINT8 hflip;
UINT8 vflip;
UINT16 matrix_a;
UINT16 matrix_b;
UINT16 matrix_c;
UINT16 matrix_d;
UINT16 origin_x;
UINT16 origin_y;
} mode7;
UINT8 mosaic_size;
UINT8 main_color_mask;
UINT8 sub_color_mask;
UINT8 sub_add_mode;
UINT8 direct_color;
UINT16 mosaic_table[16][4096];
UINT8 clipmasks[6][SNES_SCR_WIDTH + 8];
UINT8 update_windows;
UINT8 update_offsets;

View File

@ -739,6 +739,11 @@ WRITE8_HANDLER( snes_w_io )
break;
case MOSAIC: /* Size and screen designation for mosaic */
/* FIXME: We don't support horizontal mosaic yet */
snes_ppu.mosaic_size = (data & 0xf0) >> 4;
snes_ppu.layer[0].mosaic_enabled = data & 0x01;
snes_ppu.layer[1].mosaic_enabled = data & 0x02;
snes_ppu.layer[2].mosaic_enabled = data & 0x04;
snes_ppu.layer[3].mosaic_enabled = data & 0x08;
break;
case BG1SC: /* Address for storing SC data BG1 SC size designation */
case BG2SC: /* Address for storing SC data BG2 SC size designation */
@ -889,6 +894,9 @@ WRITE8_HANDLER( snes_w_io )
}
return;
case M7SEL: /* Mode 7 initial settings */
snes_ppu.mode7.repeat = (data >> 6) & 3;
snes_ppu.mode7.vflip = data & 0x02;
snes_ppu.mode7.hflip = data & 0x01;
break;
case M7A: /* Mode 7 COS angle/x expansion (DW) */
snes_ppu.mode7.matrix_a = ((snes_ppu.mode7.matrix_a >> 8) & 0xff) + (data << 8);
@ -936,6 +944,10 @@ WRITE8_HANDLER( snes_w_io )
break;
case CGWSEL: /* Initial settings for Fixed colour addition or screen addition */
/* FIXME: We don't support direct select for modes 3 & 4 or subscreen window stuff */
snes_ppu.main_color_mask = (data >> 6) & 0x03;
snes_ppu.sub_color_mask = (data >> 4) & 0x03;
snes_ppu.sub_add_mode = data & 0x02;
snes_ppu.direct_color = data & 0x01;
#ifdef SNES_DBG_REG_W
if( (data & 0x2) != (snes_ram[CGWSEL] & 0x2) )
mame_printf_debug( "Add/Sub Layer: %s\n", ((data & 0x2) >> 1) ? "Subscreen" : "Fixed colour" );
@ -1538,7 +1550,7 @@ WRITE8_HANDLER( snes_w_bank7 )
static void snes_init_ram(running_machine *machine)
{
const address_space *cpu0space = cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM);
int i;
int i, j;
/* Init DSP1 */
DSP1_reset(machine);
@ -1571,6 +1583,15 @@ static void snes_init_ram(running_machine *machine)
vram_read_offset = 2;
joy1l = joy1h = joy2l = joy2h = joy3l = joy3h = 0;
/* Inititialize mosaic table */
for (j = 0; j < 16; j++)
{
for (i = 0; i < 4096; i++)
{
snes_ppu.mosaic_table[j][i] = (i / (j + 1)) * (j + 1);
}
}
// set up some known register power-up defaults
snes_ram[WRIO] = 0xff;
snes_ram[VMAIN] = 0x80;

View File

@ -154,7 +154,7 @@ INLINE void snes_draw_blend(UINT16 offset, UINT16 *colour, UINT8 mode, UINT8 cli
UINT16 r, g, b;
if( mode == SNES_BLEND_ADD )
{
if( snes_ram[CGWSEL] & 0x2 ) /* Subscreen*/
if( snes_ppu.sub_add_mode ) /* Subscreen*/
{
r = (*colour & 0x1f) + (scanlines[SUBSCREEN].buffer[offset] & 0x1f);
g = ((*colour & 0x3e0) >> 5) + ((scanlines[SUBSCREEN].buffer[offset] & 0x3e0) >> 5);
@ -185,7 +185,7 @@ INLINE void snes_draw_blend(UINT16 offset, UINT16 *colour, UINT8 mode, UINT8 cli
}
else if( mode == SNES_BLEND_SUB )
{
if( snes_ram[CGWSEL] & 0x2 ) /* Subscreen */
if( snes_ppu.sub_add_mode ) /* Subscreen */
{
r = (*colour & 0x1f) - (scanlines[SUBSCREEN].buffer[offset] & 0x1f);
g = ((*colour & 0x3e0) >> 5) - ((scanlines[SUBSCREEN].buffer[offset] & 0x3e0) >> 5);
@ -276,12 +276,12 @@ INLINE void snes_draw_tile(UINT8 screen, UINT8 planes, UINT8 layer, UINT16 tilea
c = snes_cgram[pal + colour];
if (screen == MAINSCREEN) /* Only blend main screens */
snes_draw_blend(ii, &c, snes_ppu.layer[layer].blend, (snes_ram[CGWSEL] & 0x30) >> 4);
if (snes_ram[MOSAIC] & (1 << layer)) // handle horizontal mosaic
if (snes_ppu.layer[layer].mosaic_enabled) // handle horizontal mosaic
{
int x_mos;
//TODO: 512 modes has the h values doubled.
for (x_mos = 0; x_mos < (((snes_ram[MOSAIC] & 0xf0) >> 4) + 1) ; x_mos++)
for (x_mos = 0; x_mos < (snes_ppu.mosaic_size + 1) ; x_mos++)
{
scanlines[screen].buffer[ii + x_mos] = c;
scanlines[screen].zbuf[ii + x_mos] = priority;
@ -459,6 +459,8 @@ INLINE void snes_update_line( UINT8 screen, UINT8 color_depth, UINT8 hires, UINT
/* scrolling */
UINT32 basevmap;
UINT16 vscroll, hscroll, vtilescroll;
// UINT16 offset_per_tile_valid;
// UINT8 offset_per_tile_mode;
UINT8 vshift, hshift, tile_size;
/* variables depending on color_depth */
UINT8 color_shift = 0;
@ -499,6 +501,7 @@ INLINE void snes_update_line( UINT8 screen, UINT8 color_depth, UINT8 hires, UINT
/* Jump to base map address */
tmap = snes_ppu.layer[layer].map;
/* Offset vertically */
tmap += table_vscroll[snes_ppu.layer[layer].map_size & 3][(vtilescroll >> 5) & 3];
/* Scroll vertically */
@ -555,7 +558,6 @@ INLINE void snes_update_line( UINT8 screen, UINT8 color_depth, UINT8 hires, UINT
pal += (layer << 5);
}
tile_line = line;
if (vflip)
{
@ -625,11 +627,13 @@ INLINE void snes_update_line( UINT8 screen, UINT8 color_depth, UINT8 hires, UINT
* 2009-08: Missing MOSAIC in Mode 7
* (different behaviors in BG1 & BG2)
*********************************************/
#define MODE7_CLIP(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff))
static void snes_update_line_mode7(UINT8 screen, UINT8 priority_a, UINT8 priority_b, UINT8 layer, UINT16 curline )
{
UINT32 tiled;
INT16 ma, mb, mc, md;
INT16 xc, yc, tx, ty, sx, sy, hs, vs, xpos, xdir;
INT32 xc, yc, tx, ty, sx, sy, hs, vs, xpos, xdir;
UINT8 priority = priority_a;
UINT8 colour = 0;
@ -651,23 +655,23 @@ static void snes_update_line_mode7(UINT8 screen, UINT8 priority_a, UINT8 priorit
vs = snes_ppu.layer[layer].offset.vertical;
/* Sign extend */
xc <<= 3;
xc >>= 3;
yc <<= 3;
yc >>= 3;
hs <<= 3;
hs >>= 3;
vs <<= 3;
vs >>= 3;
xc <<= 19;
xc >>= 19;
yc <<= 19;
yc >>= 19;
hs <<= 19;
hs >>= 19;
vs <<= 19;
vs >>= 19;
/* Vertical flip */
if (snes_ram[M7SEL] & 0x2)
if (snes_ppu.mode7.vflip)
sy = 255 - curline;
else
sy = curline;
/* Horizontal flip */
if (snes_ram[M7SEL] & 0x1)
if (snes_ppu.mode7.hflip)
{
xpos = 255;
xdir = -1;
@ -681,37 +685,34 @@ static void snes_update_line_mode7(UINT8 screen, UINT8 priority_a, UINT8 priorit
/* Let's do some mode7 drawing huh? */
for (sx = 0; sx < 256; sx++, xpos += xdir)
{
tx = (((ma * ((sx + hs) - xc)) + (mb * ((sy + vs) - yc))) >> 8) + xc;
ty = (((mc * ((sx + hs) - xc)) + (md * ((sy + vs) - yc))) >> 8) + yc;
switch (snes_ram[M7SEL] & 0xc0)
tx = (((ma * MODE7_CLIP(hs - xc)) & ~0x3f) + ((mb * MODE7_CLIP(vs - yc)) & ~0x3f) + (xc << 8) + ((ma * sx) & ~0x3f) + ((mb * sy) & ~0x3f)) >> 8;
ty = (((mc * MODE7_CLIP(hs - xc)) & ~0x3f) + ((md * MODE7_CLIP(vs - yc)) & ~0x3f) + (yc << 8) + ((mc * sx) & ~0x3f) + ((md * sy) & ~0x3f)) >> 8;
switch (snes_ppu.mode7.repeat)
{
case 0x00: /* Repeat if outside screen area */
case 0x01: /* Repeat if outside screen area */
tx &= 0x3ff;
ty &= 0x3ff;
tiled = snes_vram[((tx >> 3) * 2) + ((ty >> 3) * 128 * 2)] << 7;
colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
tiled = snes_vram[(((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2] << 7;
colour = snes_vram[tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1];
break;
case 0x80: /* Single colour backdrop screen if outside screen area */
if ((tx & 0x7fff) < 1024 && (ty & 0x7fff) < 1024)
case 0x02: /* Single colour backdrop screen if outside screen area */
if ((tx > 0) && (tx < 1024) && (ty > 0) && (ty < 1024))
{
tiled = snes_vram[((tx >> 3) * 2) + ((ty >> 3) * 128 * 2)] << 7;
colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
tiled = snes_vram[(((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2] << 7;
colour = snes_vram[tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1];
}
else
{
colour = 0;
}
break;
case 0xc0: /* Character 0x00 repeat if outside screen area */
if ((tx & 0x7fff) < 1024 && (ty & 0x7fff) < 1024)
{
tiled = snes_vram[(((tx & 0x3ff) >> 3) * 2) + (((ty & 0x3ff) >> 3) * 128 * 2)] << 7;
colour = snes_vram[tiled + ((tx & 0x7) * 2) + ((ty & 0x7) * 16) + 1];
}
case 0x03: /* Character 0x00 repeat if outside screen area */
if ((tx > 0) && (tx < 1024) && (ty > 0) && (ty < 1024))
tiled = snes_vram[(((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2] << 7;
else
{
colour = snes_vram[((sx & 0x7) * 2) + ((sy & 0x7) * 16) + 1];
}
tiled = 0;
colour = snes_vram[tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1];
break;
}
@ -722,14 +723,14 @@ static void snes_update_line_mode7(UINT8 screen, UINT8 priority_a, UINT8 priorit
colour &= 0x7f;
}
colour &= snes_ppu.clipmasks[0][xpos];
colour &= snes_ppu.clipmasks[layer][xpos];
/* Draw pixel if appropriate */
if (scanlines[screen].zbuf[xpos] < priority && colour > 0)
if (scanlines[screen].zbuf[xpos] <= priority && colour > 0)
{
UINT16 clr;
/* Direct select, but only outside EXTBG! */
if (snes_ram[CGWSEL] & 0x1 && layer == 1)
if (snes_ppu.direct_color && layer == 1)
clr = ((colour & 0x7) << 2) | ((colour & 0x38) << 4) | ((colour & 0xc0) << 7);
else
clr = snes_cgram[colour];