taito/taito_f3_v.cpp: Improved line clipping effects and palette for landmakr/quizhuhu. (#10920)

This commit is contained in:
ywy 2023-03-01 10:37:44 -08:00 committed by GitHub
parent 230702d378
commit 440e546e37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 166 deletions

View File

@ -184,8 +184,8 @@ protected:
u8 *tsrc[256]{}, *tsrc_s[256]{};
int x_count[256]{};
u32 x_zoom[256]{};
u32 clip0[256]{};
u32 clip1[256]{};
u32 clip_in[256]{};
u32 clip_ex[256]{};
u16 pal_add[256]{};
};
@ -194,12 +194,10 @@ protected:
u16 alpha_level[256]{};
u16 spri[256]{};
u16 sprite_alpha[256]{};
u32 sprite_clip0[256]{};
u32 sprite_clip1[256]{};
s16 clip0_l[256]{};
s16 clip0_r[256]{};
s16 clip1_l[256]{};
s16 clip1_r[256]{};
u32 sprite_clip_in[256]{};
u32 sprite_clip_ex[256]{};
s16 clip_l[4][256]{};
s16 clip_r[4][256]{};
};
int m_game = 0;

View File

@ -77,13 +77,15 @@ Line ram memory map:
Where bit 2 of x enables effect on playfield 3
Where bit 3 of x enables effect on playfield 4
0x1000: Unknown control word?
(usually 0x00f0; gseeker, spcinvdj, twinqix, puchicar set 0x0000)
0x4000: Column scroll & clipping info
0x5000: Clip plane 0 (low bits)
0x5200: Clip plane 1 (low bits)
0x5400: Unused?
0x5600: Used by quizhuhu (taito logo and ingame text), and landmakr (winning text),
special clip used in tandem with b*00 bit 11? [unemulated]
0x5000: Clip plane 0 (low bits (high in 4400))
0x5200: Clip plane 1 (low bits (high in 4400))
0x5400: Clip plane 2 (low bits (high in 4600))
0x5600: Clip plane 3 (low bits (high in 4600))
0x6000: Sync register
0x6004: Sprite alpha control
@ -122,7 +124,7 @@ Line ram memory map:
0x7000: Pivot/vram layer enable
0x7200: Cram layer priority
0x7400: Sprite clipping
0x7400: Sprite clipping (like playfield priority clip bits but shifted)
0x7600: Sprite priority values
0xf000: Relative priority for sprites with pri value 0xc0
0x0f00: Relative priority for sprites with pri value 0x80
@ -150,15 +152,17 @@ Line ram memory map:
0xb200: Playfield 2 priority
0xb400: Playfield 3 priority
0xb600: Playfield 4 priority
0xf000 = Blend mode, 0x3000 = Normal, 0x7000 = Alpha A, 0xb000 = Alpha B, others disable line
0x0800 = Clip line (totally disable line)
0x0400 = Assumed unused
0x0200 = If set enable clip plane 1
0x0100 = If set enable clip plane 0
0x00c0 = Assumed unused
0x0020 = Enable clip inverse mode for plane 1
0x0010 = Enable clip inverse mode for plane 0
0x000f = Layer priority
0x0010 = Clip inverse mode for plane 0
0x0020 = Clip inverse mode for plane 1
0x0040 = Clip inverse mode for plane 2
0x0080 = Clip inverse mode for plane 3
0x0100 = If set enable clip plane 0
0x0200 = If set enable clip plane 1
0x0400 = If set enable clip plane 2
0x0800 = If set enable clip plane 3
0x1000 = Affects interpretation of inverse mode bits. If on, 1 = invert. if off, 0 = invert.
0xe000 = Blend mode, 0x3000 = Normal, 0x7000 = Alpha A, 0xb000 = Alpha B, others disable line
0xc000 - 0xffff: Unused.
@ -380,14 +384,28 @@ TILE_GET_INFO_MEMBER(taito_f3_state::get_tile_info)
const u32 tile = (m_pf_data[Layer][tile_index * 2 + 0] << 16) | (m_pf_data[Layer][tile_index * 2 + 1] & 0xffff);
const u8 abtype = (tile >> (16 + 9)) & 1;
// tiles can be configured to use 4, 5, or 6 bpp data.
// if tiles use more than 4bpp, the bottom bits of the color code must be masked out.
// This fixes (at least) the rain in round 6 of Arabian Magic.
const u8 extra_planes = ((tile >> (16 + 10)) & 3); // 0 = 4bpp, 1 = 5bpp, 2 = unused?, 3 = 6bpp
tileinfo.set(3,
tile & 0xffff,
(tile >> 16) & 0x1ff & (~extra_planes),
TILE_FLIPYX(tile >> 30));
// FIXME: some (5bpp?) games need the bottom bits of the color code to be masked out.
// (mt00895 arabian magic stage 6 rain (color 0x105->104), mt01925 rayforce explosion, mt01917 rayforce ships, mt00900 kaiser knuckle azteca throw)
// however, there are (6bpp) cases which *don't* want any adjustment that this breaks:
// (quizhuhu fade palette 0x7, landmakrj win message palette 0xBE)
// special case until better understood.
if (m_game == LANDMAKR || m_game == QUIZHUHU)
{
tileinfo.set(3,
tile & 0xffff,
(tile >> 16) & 0x1ff,
TILE_FLIPYX(tile >> 30));
}
else
{
tileinfo.set(3,
tile & 0xffff,
(tile >> 16) & 0x1ff & (~extra_planes),
TILE_FLIPYX(tile >> 30));
}
tileinfo.category = abtype & 1; /* alpha blending type */
tileinfo.pen_mask = (extra_planes << 4) | 0x0f;
}
@ -1284,10 +1302,10 @@ void taito_f3_state::init_alpha_blend_func()
m_tsrc_s[pf_num] = line_tmp->tsrc_s[y]; \
m_x_count[pf_num] = line_tmp->x_count[y]; \
m_x_zoom[pf_num] = line_tmp->x_zoom[y]; \
m_clip_al[pf_num] = line_tmp->clip0[y] & 0xffff; \
m_clip_ar[pf_num] = line_tmp->clip0[y] >> 16; \
m_clip_bl[pf_num] = line_tmp->clip1[y] & 0xffff; \
m_clip_br[pf_num] = line_tmp->clip1[y] >> 16; \
m_clip_al[pf_num] = line_tmp->clip_in[y] & 0xffff; \
m_clip_ar[pf_num] = line_tmp->clip_in[y] >> 16; \
m_clip_bl[pf_num] = line_tmp->clip_ex[y] & 0xffff; \
m_clip_br[pf_num] = line_tmp->clip_ex[y] >> 16; \
m_pal_add[pf_num] = line_tmp->pal_add[y]; \
}
@ -1373,10 +1391,10 @@ inline void taito_f3_state::draw_scanlines(
{
int cx = 0;
clip_als = m_sa_line_inf[0].sprite_clip0[y] & 0xffff;
clip_ars = m_sa_line_inf[0].sprite_clip0[y] >> 16;
clip_bls = m_sa_line_inf[0].sprite_clip1[y] & 0xffff;
clip_brs = m_sa_line_inf[0].sprite_clip1[y] >> 16;
clip_als = m_sa_line_inf[0].sprite_clip_in[y] & 0xffff;
clip_ars = m_sa_line_inf[0].sprite_clip_in[y] >> 16;
clip_bls = m_sa_line_inf[0].sprite_clip_ex[y] & 0xffff;
clip_brs = m_sa_line_inf[0].sprite_clip_ex[y] >> 16;
int length = xsize;
u32 *dsti = dsti0;
@ -1520,108 +1538,49 @@ void taito_f3_state::visible_tile_check(
/******************************************************************************/
void taito_f3_state::calculate_clip(int y, u16 pri, u32 *clip0, u32 *clip1, int *line_enable)
void taito_f3_state::calculate_clip(int y, u16 pri, u32 *clip_in, u32 *clip_ex, int *line_enable)
{
const f3_spritealpha_line_inf *sa_line_t = &m_sa_line_inf[0];
const f3_spritealpha_line_inf *sa_line = &m_sa_line_inf[0];
switch (pri)
{
case 0x0100: /* Clip plane 1 enable */
{
if (sa_line_t->clip0_l[y] > sa_line_t->clip0_r[y])
*line_enable = 0;
else
*clip0 = (sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y] << 16);
*clip1 = 0;
}
break;
case 0x0110: /* Clip plane 1 enable, inverted */
{
*clip1 = (sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y] << 16);
*clip0 = 0x7fff0000;
}
break;
case 0x0200: /* Clip plane 2 enable */
{
if (sa_line_t->clip1_l[y] > sa_line_t->clip1_r[y])
*line_enable = 0;
else
*clip0 = (sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y] << 16);
*clip1 = 0;
}
break;
case 0x0220: /* Clip plane 2 enable, inverted */
{
*clip1 = (sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y] << 16);
*clip0 = 0x7fff0000;
}
break;
case 0x0300: /* Clip plane 1 & 2 enable */
{
int clipl = 0, clipr = 0;
/* landmakr and quizhuhu use clip planes 2 and 3,
commandw enables all clip planes.
only up to 2 valid clips ever used in existing games? */
u16 normal_planes = (pri >> 8) & (pri >> 4);
u16 invert_planes = (pri >> 8) & ~(pri >> 4);
// when bit 0x1000 set, invert bit ON is normal clip, OFF is inverted
if (pri & 0x1000)
std::swap(normal_planes, invert_planes);
if (sa_line_t->clip1_l[y] > sa_line_t->clip0_l[y])
clipl = sa_line_t->clip1_l[y];
else
clipl = sa_line_t->clip0_l[y];
s16 clipl = 0, clipr = 0x7fff;
if (sa_line_t->clip1_r[y] < sa_line_t->clip0_r[y])
clipr = sa_line_t->clip1_r[y];
else
clipr = sa_line_t->clip0_r[y];
const auto calc_clip = [&sa_line, y, &clipl, &clipr](auto p) {
clipl = std::max(sa_line->clip_l[p][y], clipl);
clipr = std::min(sa_line->clip_r[p][y], clipr);
};
const auto calc_clip_inv = [&sa_line, y, &clipl, &clipr](auto p) {
clipl = std::min(sa_line->clip_l[p][y], clipl);
clipr = std::max(sa_line->clip_r[p][y], clipr);
};
if (clipl > clipr)
*line_enable = 0;
else
*clip0 = (clipl) | (clipr << 16);
*clip1 = 0;
}
break;
case 0x0310: /* Clip plane 1 & 2 enable, plane 1 inverted */
{
if (sa_line_t->clip1_l[y] > sa_line_t->clip1_r[y])
line_enable = nullptr;
else
*clip0 = (sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y] << 16);
if (normal_planes & 0b0001) { calc_clip(0); };
if (normal_planes & 0b0010) { calc_clip(1); };
if (normal_planes & 0b0100) { calc_clip(2); };
if (normal_planes & 0b1000) { calc_clip(3); };
if (clipl > clipr)
*line_enable = 0;
else
*clip_in = clipl | (clipr << 16);
*clip1 = (sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y] << 16);
}
break;
case 0x0320: /* Clip plane 1 & 2 enable, plane 2 inverted */
{
if (sa_line_t->clip0_l[y] > sa_line_t->clip0_r[y])
line_enable = nullptr;
else
*clip0 = (sa_line_t->clip0_l[y]) | (sa_line_t->clip0_r[y] << 16);
*clip1 = (sa_line_t->clip1_l[y]) | (sa_line_t->clip1_r[y] << 16);
}
break;
case 0x0330: /* Clip plane 1 & 2 enable, both inverted */
{
int clipl = 0, clipr = 0;
if (sa_line_t->clip1_l[y] < sa_line_t->clip0_l[y])
clipl = sa_line_t->clip1_l[y];
else
clipl = sa_line_t->clip0_l[y];
if (sa_line_t->clip1_r[y] > sa_line_t->clip0_r[y])
clipr = sa_line_t->clip1_r[y];
else
clipr = sa_line_t->clip0_r[y];
if (clipl > clipr)
*line_enable = 0;
else
*clip1 = (clipl) | (clipr << 16);
*clip0 = 0x7fff0000;
}
break;
default:
// popmessage("Illegal clip mode");
break;
}
// reset temp clip sides for the inverted/excluded window
clipl = 0x7fff; clipr = 0;
if (invert_planes & 0b0001) { calc_clip_inv(0); };
if (invert_planes & 0b0010) { calc_clip_inv(1); };
if (invert_planes & 0b0100) { calc_clip_inv(2); };
if (invert_planes & 0b1000) { calc_clip_inv(3); };
if (clipl > clipr)
*clip_ex = 0;
else
*clip_ex = clipl | (clipr << 16);
}
void taito_f3_state::get_spritealphaclip_info()
@ -1635,6 +1594,7 @@ void taito_f3_state::get_spritealphaclip_info()
u16 spri = 0;
u16 sprite_clip = 0;
u16 clip0_low = 0, clip0_high = 0, clip1_low = 0;
u16 clip2_low = 0, clip2_high = 0, clip3_low = 0;
int alpha_level = 0;
u16 sprite_alpha = 0;
@ -1664,13 +1624,20 @@ void taito_f3_state::get_spritealphaclip_info()
{
/* The zoom, column and row values can latch according to control ram */
{
if (m_line_ram[0x100 + y] & 1)
if (m_line_ram[0x100 + y] & 1) // 5000 control playfield 1
clip0_low = (m_line_ram[clip_base_low / 2] >> 0) & 0xffff;
if (m_line_ram[0x000 + y] & 4)
if (m_line_ram[0x000 + y] & 4) // 4000 control
clip0_high = (m_line_ram[clip_base_high / 2] >> 0) & 0xffff;
if (m_line_ram[0x100 + y] & 2)
if (m_line_ram[0x100 + y] & 2) // 5000 control playfield 2
clip1_low = (m_line_ram[(clip_base_low + 0x200) / 2] >> 0) & 0xffff;
if (m_line_ram[0x100 + y] & 4) // 5000 control playfield 3
clip2_low = (m_line_ram[(clip_base_low + 0x400) / 2] >> 0) & 0xffff;
if (m_line_ram[0x000 + y] & 8) // 4000 control
clip2_high = (m_line_ram[(clip_base_high + 0x200) / 2] >> 0) & 0xffff;
if (m_line_ram[0x100 + y] & 8) // 5000 control playfield 4
clip3_low = (m_line_ram[(clip_base_low + 0x600) / 2] >> 0) & 0xffff;
if (m_line_ram[(0x0600 / 2) + y] & 0x8)
spri = m_line_ram[spri_base / 2] & 0xffff;
if (m_line_ram[(0x0600 / 2) + y] & 0x4)
@ -1685,32 +1652,35 @@ void taito_f3_state::get_spritealphaclip_info()
line_t->alpha_level[y] = alpha_level;
line_t->spri[y] = spri;
line_t->sprite_alpha[y] = sprite_alpha;
line_t->clip0_l[y] = ((clip0_low & 0xff) | ((clip0_high & 0x1000) >> 4)) - 47;
line_t->clip0_r[y] = (((clip0_low & 0xff00) >> 8) | ((clip0_high & 0x2000) >> 5)) - 48;
line_t->clip1_l[y] = ((clip1_low & 0xff) | ((clip0_high & 0x4000) >> 6)) - 47;
line_t->clip1_r[y] = (((clip1_low & 0xff00) >> 8) | ((clip0_high & 0x8000) >> 7)) - 48;
if (line_t->clip0_l[y] < 0) line_t->clip0_l[y] = 0;
if (line_t->clip0_r[y] < 0) line_t->clip0_r[y] = 0;
if (line_t->clip1_l[y] < 0) line_t->clip1_l[y] = 0;
if (line_t->clip1_r[y] < 0) line_t->clip1_r[y] = 0;
line_t->clip_l[0][y] = ((clip0_low & 0xff) | ((clip0_high & 0x1000) >> 4)) - 47;
line_t->clip_r[0][y] = (((clip0_low & 0xff00) >> 8) | ((clip0_high & 0x2000) >> 5)) - 48;
line_t->clip_l[1][y] = ((clip1_low & 0xff) | ((clip0_high & 0x4000) >> 6)) - 47;
line_t->clip_r[1][y] = (((clip1_low & 0xff00) >> 8) | ((clip0_high & 0x8000) >> 7)) - 48;
line_t->clip_l[2][y] = ((clip2_low & 0xff) | ((clip2_high & 0x1000) >> 4)) - 47;
line_t->clip_r[2][y] = (((clip2_low & 0xff00) >> 8) | ((clip2_high & 0x2000) >> 5)) - 48;
line_t->clip_l[3][y] = ((clip3_low & 0xff) | ((clip2_high & 0x4000) >> 6)) - 47;
line_t->clip_r[3][y] = (((clip3_low & 0xff00) >> 8) | ((clip2_high & 0x8000) >> 7)) - 48;
if (line_t->clip_l[0][y] < 0) line_t->clip_l[0][y] = 0;
if (line_t->clip_r[0][y] < 0) line_t->clip_r[0][y] = 0;
if (line_t->clip_l[1][y] < 0) line_t->clip_l[1][y] = 0;
if (line_t->clip_r[1][y] < 0) line_t->clip_r[1][y] = 0;
if (line_t->clip_l[2][y] < 0) line_t->clip_l[2][y] = 0;
if (line_t->clip_r[2][y] < 0) line_t->clip_r[2][y] = 0;
if (line_t->clip_l[3][y] < 0) line_t->clip_l[3][y] = 0;
if (line_t->clip_r[3][y] < 0) line_t->clip_r[3][y] = 0;
/* Evaluate sprite clipping */
if (sprite_clip & 0x080)
{
line_t->sprite_clip0[y] = 0x7fff7fff;
line_t->sprite_clip1[y] = 0;
}
else if (sprite_clip & 0x33)
if (sprite_clip & 0xf0)
{
int line_enable = 1;
calculate_clip(y, ((sprite_clip & 0x33) << 4), &line_t->sprite_clip0[y], &line_t->sprite_clip1[y], &line_enable);
calculate_clip(y, ((sprite_clip & 0x1ff) << 4), &line_t->sprite_clip_in[y], &line_t->sprite_clip_ex[y], &line_enable);
if (line_enable == 0)
line_t->sprite_clip0[y] = 0x7fff7fff;
line_t->sprite_clip_in[y] = 0x7fff7fff;
}
else
{
line_t->sprite_clip0[y] = 0x7fff0000;
line_t->sprite_clip1[y] = 0;
line_t->sprite_clip_in[y] = 0x7fff0000;
line_t->sprite_clip_ex[y] = 0;
}
spri_base += inc;
@ -1836,18 +1806,16 @@ void taito_f3_state::get_line_ram_info(tilemap_t *tmap, int sx, int sy, int pos,
_y_zoom[y] = (line_zoom & 0xff) << 9;
/* Evaluate clipping */
if (pri & 0x0800)
line_enable = 0;
else if (pri & 0x0330)
if (pri & 0x0f00)
{
//fast path todo - remove line enable
calculate_clip(y, pri & 0x0330, &line_t->clip0[y], &line_t->clip1[y], &line_enable);
calculate_clip(y, pri & 0x1ff0, &line_t->clip_in[y], &line_t->clip_ex[y], &line_enable);
}
else
{
/* No clipping */
line_t->clip0[y] = 0x7fff0000;
line_t->clip1[y] = 0;
line_t->clip_in[y] = 0x7fff0000;
line_t->clip_ex[y] = 0;
}
line_t->x_zoom[y] = 0x10000 - (line_zoom & 0xff00);
@ -1913,7 +1881,7 @@ void taito_f3_state::get_line_ram_info(tilemap_t *tmap, int sx, int sy, int pos,
visible_tile_check(line_t, y, x_index_fx, y_index, pf_data_n);
/* If clipping enabled for this line have to disable 'all opaque' optimisation */
if (line_t->clip0[y] != 0x7fff0000 || line_t->clip1[y] != 0)
if (line_t->clip_in[y] != 0x7fff0000 || line_t->clip_ex[y] != 0)
line_t->alpha_mode[y] &= ~0x80;
/* set pixmap index */
@ -1985,18 +1953,16 @@ void taito_f3_state::get_vram_info(tilemap_t *vram_tilemap, tilemap_t *pixel_til
line_t->pri[y] = pri;
/* Evaluate clipping */
if (pri & 0x0800)
line_enable = 0;
else if (pri & 0x0330)
if (pri & 0x0f00)
{
//fast path todo - remove line enable
calculate_clip(y, pri & 0x0330, &line_t->clip0[y], &line_t->clip1[y], &line_enable);
calculate_clip(y, pri & 0x1ff0, &line_t->clip_in[y], &line_t->clip_ex[y], &line_enable);
}
else
{
/* No clipping */
line_t->clip0[y] = 0x7fff0000;
line_t->clip1[y] = 0;
line_t->clip_in[y] = 0x7fff0000;
line_t->clip_ex[y] = 0;
}
line_t->x_zoom[y] = 0x10000;