mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
taito/taito_f3_v.cpp: Oprimised for performance. (#12312)
* Changed per-pixed blend Z buffers from array-of-structures to structure-of-arrays. * Allow vectorization of line blending operations. * Restored empty line optimization by tracking tilemap row use. * Consolidate sprite frame buffers (still pulls from it multiple times for each priority group). * Rearranged various operations to improve performance.
This commit is contained in:
parent
b213bd7594
commit
53d8868bf9
@ -242,10 +242,10 @@ protected:
|
||||
};
|
||||
|
||||
struct mix_pix { // per-pixel information for the blending circuit
|
||||
u16 src_pal{0};
|
||||
u16 dst_pal{0};
|
||||
u8 src_blend{0x00};
|
||||
u8 dst_blend{0xff};
|
||||
u16 src_pal[H_TOTAL];
|
||||
u16 dst_pal[H_TOTAL];
|
||||
u8 src_blend[H_TOTAL];
|
||||
u8 dst_blend[H_TOTAL];
|
||||
};
|
||||
|
||||
struct f3_line_inf;
|
||||
@ -255,16 +255,17 @@ protected:
|
||||
bool x_sample_enable{false};
|
||||
u16 mix_value{0};
|
||||
u8 prio{0};
|
||||
u8 blend_mode;
|
||||
|
||||
u8 debug_index{0};
|
||||
u8 index{0};
|
||||
|
||||
void set_mix(u16 v) { mix_value = v; prio = v & 0xf; }
|
||||
void set_prio(u8 p) { mix_value = (mix_value & 0xfff0) | p; prio = p; }
|
||||
void set_mix(u16 v) { mix_value = v; prio = v & 0xf; blend_mode = BIT(mix_value, 14, 2); };
|
||||
void set_prio(u8 p) { mix_value = (mix_value & 0xfff0) | p; prio = p; };
|
||||
void set_blend(u8 b) { mix_value = (mix_value & 0x3fff) | (b << 14); blend_mode = b; };
|
||||
auto clip_inv() const { return std::bitset<4>(mix_value >> 4); }
|
||||
auto clip_enable() const { return std::bitset<4>(mix_value >> 8); }
|
||||
bool clip_inv_mode() const { return mix_value & 0x1000; }
|
||||
bool layer_enable() const;
|
||||
u8 blend_mask() const { return BIT(mix_value, 14, 2); }
|
||||
bool blend_a() const { return mix_value & 0x4000; }
|
||||
bool blend_b() const { return mix_value & 0x8000; }
|
||||
|
||||
@ -275,8 +276,8 @@ protected:
|
||||
int y_index(int y) const;
|
||||
int x_index(int x) const;
|
||||
bool blend_select(const u8 *line_flags, int x) const { return false; }
|
||||
bool inactive_group(u16 color) const { return false; }
|
||||
|
||||
bool used(int y) const { return true; }
|
||||
static const char *debug_name() { return "MX"; }
|
||||
};
|
||||
|
||||
@ -290,8 +291,8 @@ protected:
|
||||
|
||||
bool blend_select(const u8 *line_flags, int x) const { return blend_select_v; }
|
||||
bool layer_enable() const;
|
||||
bool inactive_group(u16 color) const { return BIT(color, 10, 2) != index; }
|
||||
|
||||
bool used(int y) const { return BIT((*sprite_pri_usage)[y], debug_index); }
|
||||
static const char *debug_name() { return "SP"; };
|
||||
};
|
||||
|
||||
@ -337,16 +338,16 @@ protected:
|
||||
};
|
||||
|
||||
struct pri_mode {
|
||||
u8 src_prio{0};
|
||||
u8 dst_prio{0};
|
||||
u8 src_blendmode{0xff};
|
||||
u8 dst_blendmode{0xff};
|
||||
u8 src_prio[H_TOTAL]{};
|
||||
u8 dst_prio[H_TOTAL]{};
|
||||
u8 src_blendmode[H_TOTAL]{};
|
||||
u8 dst_blendmode[H_TOTAL]{};
|
||||
};
|
||||
|
||||
struct f3_line_inf {
|
||||
int y{0};
|
||||
int screen_y{0};
|
||||
pri_mode pri_alp[432]{};
|
||||
pri_mode pri_alp{};
|
||||
// 5000/4000
|
||||
clip_plane_inf clip[NUM_CLIPPLANES];
|
||||
// 6000 - pivot_control, sprite alpha
|
||||
@ -376,16 +377,18 @@ protected:
|
||||
bool m_sprite_trails = false;
|
||||
u16 *m_pf_data[8]{};
|
||||
int m_sprite_lag = 0;
|
||||
u8 m_textram_row_usage[64]{};
|
||||
u8 m_sprite_pri_row_usage[256]{};
|
||||
u8 m_tilemap_row_usage[32][8]{};
|
||||
bitmap_ind8 m_pri_alp_bitmap;
|
||||
bitmap_ind16 m_sprite_framebuffers[NUM_SPRITEGROUPS]{};
|
||||
bitmap_ind16 m_sprite_framebuffer{};
|
||||
u16 m_width_mask = 0;
|
||||
u8 m_twidth_mask = 0;
|
||||
u8 m_twidth_mask_bit = 0;
|
||||
std::unique_ptr<tempsprite[]> m_spritelist;
|
||||
const tempsprite *m_sprite_end = nullptr;
|
||||
bool m_sprite_bank = 0;
|
||||
//f3_line_inf m_line_inf;
|
||||
//f3_line_inf m_line_data{};
|
||||
const F3config *m_game_config = nullptr;
|
||||
|
||||
u16 spriteram_r(offs_t offset);
|
||||
@ -421,12 +424,15 @@ protected:
|
||||
void draw_sprites(const rectangle &cliprect);
|
||||
void get_pf_scroll(int pf_num, fixed8 ®_sx, fixed8 ®_sy);
|
||||
void read_line_ram(f3_line_inf &line, int y);
|
||||
void render_line(pen_t *dst, const mix_pix (&z)[432]);
|
||||
void render_line(pen_t *dst, const mix_pix &z);
|
||||
void scanline_draw(bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
template<typename Mix>
|
||||
std::vector<clip_plane_inf> calc_clip(const clip_plane_inf (&clip)[NUM_CLIPPLANES], const Mix line);
|
||||
std::vector<clip_plane_inf> calc_clip(const clip_plane_inf (&clip)[NUM_CLIPPLANES], const Mix &layer);
|
||||
inline bool used(const pivot_inf &layer, int y) const;
|
||||
inline bool used(const sprite_inf &layer, int y) const;
|
||||
inline bool used(const playfield_inf &layer, int y) const;
|
||||
template<typename Mix>
|
||||
bool mix_line(Mix &gfx, mix_pix *z, pri_mode *pri, const f3_line_inf &line, const clip_plane_inf &range);
|
||||
bool mix_line(const Mix &gfx, mix_pix &z, pri_mode &pri, const f3_line_inf &line, const clip_plane_inf &range);
|
||||
|
||||
private:
|
||||
optional_device<taito_en_device> m_taito_en;
|
||||
|
@ -352,9 +352,27 @@ const taito_f3_state::F3config taito_f3_state::f3_config_table[] = {
|
||||
|
||||
void taito_f3_state::device_post_load()
|
||||
{
|
||||
/* force a reread of the dynamic tiles in the pixel layer */
|
||||
// force a reread of the dynamic tiles in the pixel layer
|
||||
m_gfxdecode->gfx(0)->mark_all_dirty();
|
||||
m_gfxdecode->gfx(1)->mark_all_dirty();
|
||||
|
||||
// refresh tile usage indexes
|
||||
std::fill_n(*m_tilemap_row_usage, 32 * 8, 0);
|
||||
std::fill_n(m_textram_row_usage, 64, 0);
|
||||
// playfield blank tiles
|
||||
for (int offset = 1; offset < 0x4000; offset += 2) {
|
||||
const int row = m_extend ? BIT(offset, 7, 5) : BIT(offset, 6, 5);
|
||||
const int tmap = m_extend ? offset >> 12 : offset >> 11;
|
||||
if (m_pf_ram[offset] != 0)
|
||||
m_tilemap_row_usage[row][tmap] += 1;
|
||||
}
|
||||
// textram blank tiles
|
||||
for (int offset = 0; offset < 0x1000; offset++) {
|
||||
const u8 tile = BIT(m_textram[offset], 0, 8);
|
||||
const int row = BIT(offset, 6, 6);
|
||||
if (tile != 0)
|
||||
m_textram_row_usage[row] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -471,6 +489,7 @@ void taito_f3_state::create_tilemaps(bool extend)
|
||||
if (m_tilemap[i])
|
||||
m_tilemap[i]->set_transparent_pen(0);
|
||||
}
|
||||
std::fill_n(*m_tilemap_row_usage, 32 * 8, 0);
|
||||
|
||||
if (m_extend) {
|
||||
m_width_mask = 0x3ff; // 10 bits
|
||||
@ -505,11 +524,9 @@ void taito_f3_state::video_start()
|
||||
m_sprite_end = &m_spritelist[0];
|
||||
m_vram_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(taito_f3_state::get_tile_info_text)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
|
||||
m_pixel_layer = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(taito_f3_state::get_tile_info_pixel)), TILEMAP_SCAN_COLS, 8, 8, 64, 32);
|
||||
std::fill_n(m_textram_row_usage, 64, 0);
|
||||
|
||||
m_screen->register_screen_bitmap(m_pri_alp_bitmap);
|
||||
for (auto &sp_bitmap : m_sprite_framebuffers) {
|
||||
m_screen->register_screen_bitmap(sp_bitmap);
|
||||
}
|
||||
m_screen->register_screen_bitmap(m_sprite_framebuffer);
|
||||
|
||||
m_vram_layer->set_transparent_pen(0);
|
||||
m_pixel_layer->set_transparent_pen(0);
|
||||
@ -541,15 +558,27 @@ u16 taito_f3_state::pf_ram_r(offs_t offset)
|
||||
|
||||
void taito_f3_state::pf_ram_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
// [.ttt yyyy yxxx xxa|h] non-extend
|
||||
// [.tty yyyy xxxx xxa|h] extend
|
||||
const u16 prev_tile = m_pf_ram[offset];
|
||||
|
||||
COMBINE_DATA(&m_pf_ram[offset]);
|
||||
|
||||
if (m_game_config->extend) {
|
||||
if (offset < 0x4000) {
|
||||
m_tilemap[offset >> 12]->mark_tile_dirty((offset & 0xfff) >> 1);
|
||||
if (offset < 0x4000) {
|
||||
if (offset & 1) {
|
||||
const int row = m_extend ? BIT(offset, 7, 5) : BIT(offset, 6, 5);
|
||||
const int tmap = m_extend ? offset >> 12 : offset >> 11;
|
||||
if ((prev_tile == 0) && (m_pf_ram[offset] != 0))
|
||||
m_tilemap_row_usage[row][tmap] += 1;
|
||||
else if ((prev_tile != 0) && (m_pf_ram[offset] == 0))
|
||||
m_tilemap_row_usage[row][tmap] -= 1;
|
||||
}
|
||||
} else {
|
||||
if (offset < 0x4000)
|
||||
|
||||
if (m_game_config->extend) {
|
||||
m_tilemap[offset >> 12]->mark_tile_dirty((offset & 0xfff) >> 1);
|
||||
} else {
|
||||
m_tilemap[offset >> 11]->mark_tile_dirty((offset & 0x7ff) >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,8 +609,17 @@ u16 taito_f3_state::textram_r(offs_t offset)
|
||||
|
||||
void taito_f3_state::textram_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
const u8 prev_tile = BIT(m_textram[offset], 0, 8);
|
||||
|
||||
COMBINE_DATA(&m_textram[offset]);
|
||||
|
||||
const int row = BIT(offset, 6, 6);
|
||||
const u8 tile = BIT(m_textram[offset], 0, 8);
|
||||
if (prev_tile == 0 && tile != 0)
|
||||
m_textram_row_usage[row] += 1;
|
||||
else if (prev_tile != 0 && tile == 0)
|
||||
m_textram_row_usage[row] -= 1;
|
||||
|
||||
m_vram_layer->mark_tile_dirty(offset);
|
||||
|
||||
// dirty the pixel layer too, since it uses palette etc. from text layer
|
||||
@ -669,7 +707,7 @@ void taito_f3_state::read_line_ram(f3_line_inf &line, int y)
|
||||
if (const offs_t where = latched_addr(0, i)) {
|
||||
const u16 colscroll = m_line_ram[where];
|
||||
line.pf[i].colscroll = colscroll & 0x1ff;
|
||||
line.pf[i].alt_tilemap = colscroll & 0x200;
|
||||
line.pf[i].alt_tilemap = !m_extend && colscroll & 0x200;
|
||||
line.clip[2*(i-2) + 0].set_upper(BIT(colscroll, 12), BIT(colscroll, 13));
|
||||
line.clip[2*(i-2) + 1].set_upper(BIT(colscroll, 14), BIT(colscroll, 15));
|
||||
}
|
||||
@ -698,15 +736,14 @@ void taito_f3_state::read_line_ram(f3_line_inf &line, int y)
|
||||
}
|
||||
|
||||
for (int sp_group = 0; sp_group < NUM_SPRITEGROUPS; sp_group++) {
|
||||
line.sp[sp_group].mix_value &= 0x3fff;
|
||||
line.sp[sp_group].mix_value |= BIT(line_6000, sp_group * 2, 2) << 14;
|
||||
line.sp[sp_group].set_blend(BIT(line_6000, sp_group * 2, 2));
|
||||
}
|
||||
}
|
||||
if (const offs_t where = latched_addr(2, 1)) { // blend values
|
||||
const u16 blend_vals = m_line_ram[where];
|
||||
for (int idx = 0; idx < 4; idx++) {
|
||||
const u8 alpha = BIT(blend_vals, 4 * idx, 4);
|
||||
line.blend[idx] = std::min(255, (0xf - alpha) * 32);
|
||||
line.blend[idx] = std::min(8, (0xf - alpha));
|
||||
}
|
||||
}
|
||||
if (const offs_t where = latched_addr(2, 2)) { // mosaic, palette depth effects
|
||||
@ -764,8 +801,8 @@ void taito_f3_state::read_line_ram(f3_line_inf &line, int y)
|
||||
}
|
||||
|
||||
for (int group = 0; group < NUM_SPRITEGROUPS; group++) {
|
||||
line.sp[group].mix_value = (line.sp[group].mix_value & 0xc00f)
|
||||
| BIT(sprite_mix, 0, 10) << 4;
|
||||
line.sp[group].set_mix((line.sp[group].mix_value & 0xc00f)
|
||||
| BIT(sprite_mix, 0, 10) << 4);
|
||||
line.sp[group].blend_select_v = BIT(sprite_mix, 12 + group, 1);
|
||||
}
|
||||
}
|
||||
@ -856,14 +893,14 @@ template<typename Mix>
|
||||
std::vector<taito_f3_state::clip_plane_inf>
|
||||
taito_f3_state::calc_clip(
|
||||
const clip_plane_inf (&clip)[NUM_CLIPPLANES],
|
||||
const Mix line)
|
||||
const Mix &layer)
|
||||
{
|
||||
constexpr s16 INF_L = H_START;
|
||||
constexpr s16 INF_R = H_START + H_VIS;
|
||||
|
||||
std::bitset<4> normal_planes = line->clip_enable() & ~line->clip_inv();
|
||||
std::bitset<4> invert_planes = line->clip_enable() & line->clip_inv();
|
||||
if (!line->clip_inv_mode())
|
||||
std::bitset<4> normal_planes = layer.clip_enable() & ~layer.clip_inv();
|
||||
std::bitset<4> invert_planes = layer.clip_enable() & layer.clip_inv();
|
||||
if (!layer.clip_inv_mode())
|
||||
std::swap(normal_planes, invert_planes);
|
||||
|
||||
// start with a visible region spanning the entire space
|
||||
@ -922,7 +959,7 @@ static int mosaic(int x, u8 sample)
|
||||
|
||||
inline bool taito_f3_state::mixable::layer_enable() const
|
||||
{
|
||||
return (mix_value & 0x2000) && blend_mask() != 0b11;
|
||||
return (mix_value & 0x2000) && blend_mode != 0b11;
|
||||
}
|
||||
inline int taito_f3_state::mixable::x_index(int x) const
|
||||
{
|
||||
@ -934,7 +971,7 @@ inline int taito_f3_state::mixable::y_index(int y) const
|
||||
}
|
||||
inline bool taito_f3_state::sprite_inf::layer_enable() const
|
||||
{
|
||||
return (mix_value & 0x2000) && blend_mask() != 0b00;
|
||||
return (mix_value & 0x2000) && blend_mode != 0b00;
|
||||
}
|
||||
inline u16 taito_f3_state::playfield_inf::palette_adjust(u16 pal) const
|
||||
{
|
||||
@ -958,68 +995,75 @@ inline int taito_f3_state::pivot_inf::y_index(int y) const
|
||||
}
|
||||
|
||||
template<typename Mix>
|
||||
bool taito_f3_state::mix_line(Mix &gfx, mix_pix *z, pri_mode *pri, const f3_line_inf &line, const clip_plane_inf &range)
|
||||
bool taito_f3_state::mix_line(const Mix &gfx, mix_pix &z, pri_mode &pri, const f3_line_inf &line, const clip_plane_inf &range)
|
||||
{
|
||||
const int y = gfx.y_index(line.y);
|
||||
const u16 *src = &gfx.bitmap.src->pix(y);
|
||||
const u8 *flags = gfx.bitmap.flags ? &gfx.bitmap.flags->pix(y) : nullptr;
|
||||
|
||||
for (int x = range.l; x < range.r; x++) {
|
||||
if (gfx.blend_mask() == pri[x].src_blendmode)
|
||||
if (gfx.blend_mode == pri.src_blendmode[x])
|
||||
continue; // note that layers cannot blend against the same blend mode
|
||||
|
||||
const int real_x = gfx.x_sample_enable ? mosaic(x, line.x_sample) : x;
|
||||
const int gfx_x = gfx.x_index(real_x);
|
||||
|
||||
// this check is for ensuring sprite group draw ordering
|
||||
// (benchmarked: do not combine with color 0 check)
|
||||
const u16 color = src[gfx_x];
|
||||
if (gfx.inactive_group(color))
|
||||
continue;
|
||||
|
||||
// tilemap transparent flag
|
||||
if (flags && !(flags[gfx_x] & 0xf0))
|
||||
continue;
|
||||
|
||||
if (gfx.prio > pri[x].src_prio) {
|
||||
if (gfx.prio > pri.src_prio[x]) {
|
||||
// submit src pix
|
||||
if (const u16 pal = gfx.palette_adjust(src[gfx_x])) {
|
||||
if (color) {
|
||||
const u16 pal = gfx.palette_adjust(color);
|
||||
// could be pulled out of loop for pivot and sprite
|
||||
u8 sel = gfx.blend_select(flags, gfx_x);
|
||||
|
||||
switch (gfx.blend_mask()) {
|
||||
switch (gfx.blend_mode) {
|
||||
case 0b01: // normal blend
|
||||
sel = 2 + sel;
|
||||
[[fallthrough]];
|
||||
case 0b10: // reverse blend
|
||||
if (line.blend[sel] == 0)
|
||||
continue; // could be early return for pivot and sprite
|
||||
z[x].src_blend = line.blend[sel];
|
||||
z.src_blend[x] = line.blend[sel];
|
||||
break;
|
||||
case 0b00: case 0b11: default: // opaque layer
|
||||
if (line.blend[sel] + line.blend[2 + sel] == 0)
|
||||
continue; // could be early return for pivot and sprite
|
||||
z[x].src_blend = line.blend[2 + sel];
|
||||
z[x].dst_blend = line.blend[sel];
|
||||
pri[x].dst_prio = gfx.prio;
|
||||
z[x].dst_pal = pal;
|
||||
z.src_blend[x] = line.blend[2 + sel];
|
||||
z.dst_blend[x] = line.blend[sel];
|
||||
pri.dst_prio[x] = gfx.prio;
|
||||
z.dst_pal[x] = pal;
|
||||
break;
|
||||
}
|
||||
|
||||
// lock in source color for blending and update the prio test buffer
|
||||
z[x].src_pal = pal;
|
||||
pri[x].src_blendmode = gfx.blend_mask();
|
||||
pri[x].src_prio = gfx.prio;
|
||||
z.src_pal[x] = pal;
|
||||
pri.src_blendmode[x] = gfx.blend_mode;
|
||||
pri.src_prio[x] = gfx.prio;
|
||||
}
|
||||
} else if (gfx.prio >= pri[x].dst_prio) {
|
||||
} else if (gfx.prio >= pri.dst_prio[x]) {
|
||||
// submit dest pix
|
||||
if (const u16 pal = gfx.palette_adjust(src[gfx_x])) {
|
||||
if (gfx.prio != pri[x].dst_prio)
|
||||
z[x].dst_pal = pal;
|
||||
if (color) {
|
||||
const u16 pal = gfx.palette_adjust(color);
|
||||
if (gfx.prio != pri.dst_prio[x])
|
||||
z.dst_pal[x] = pal;
|
||||
else // prio conflict = color line conflict? (dariusg, bubblem)
|
||||
z[x].dst_pal = 0;
|
||||
pri[x].dst_prio = gfx.prio;
|
||||
|
||||
z.dst_pal[x] = 0;
|
||||
pri.dst_prio[x] = gfx.prio;
|
||||
const bool sel = gfx.blend_select(flags, gfx_x);
|
||||
switch (pri[x].src_blendmode) {
|
||||
switch (pri.src_blendmode[x]) {
|
||||
case 0b01:
|
||||
z[x].dst_blend = line.blend[sel];
|
||||
z.dst_blend[x] = line.blend[sel];
|
||||
break;
|
||||
case 0b10: case 0b00: case 0b11: default:
|
||||
z[x].dst_blend = line.blend[2 + sel];
|
||||
z.dst_blend[x] = line.blend[2 + sel];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1030,27 +1074,67 @@ bool taito_f3_state::mix_line(Mix &gfx, mix_pix *z, pri_mode *pri, const f3_line
|
||||
constexpr int DEBUG_Y = 180 + V_START;
|
||||
if (TAITOF3_VIDEO_DEBUG && line.y == DEBUG_Y) {
|
||||
logerror("[%X] %s%d: %d,%d (%d)\n {pal: %x/%x, blend: %x/%x, prio: %x/%x}\n",
|
||||
gfx.prio, gfx.debug_name(), gfx.debug_index,
|
||||
gfx.prio, gfx.debug_name(), gfx.index,
|
||||
gfx.blend_b(), gfx.blend_a(), gfx.blend_select(flags, 82),
|
||||
z[DEBUG_X].src_pal, z[DEBUG_X].dst_pal,
|
||||
z[DEBUG_X].src_blend, z[DEBUG_X].dst_blend,
|
||||
pri[DEBUG_X].src_prio, pri[DEBUG_X].dst_prio);
|
||||
z.src_pal[DEBUG_X], z.dst_pal[DEBUG_X],
|
||||
z.src_blend[DEBUG_X], z.dst_blend[DEBUG_X],
|
||||
pri.src_prio[DEBUG_X], pri.dst_prio[DEBUG_X]);
|
||||
}
|
||||
|
||||
return false; // TODO: determine when we can stop drawing?
|
||||
}
|
||||
|
||||
void taito_f3_state::render_line(pen_t *dst, const mix_pix (&z)[H_TOTAL])
|
||||
void taito_f3_state::render_line(pen_t *RESTRICT dst, const mix_pix &z)
|
||||
{
|
||||
const pen_t *clut = &m_palette->pen(0);
|
||||
for (int x = H_START; x < H_START + H_VIS; x++) {
|
||||
const mix_pix mix = z[x];
|
||||
rgb_t s_rgb = clut[mix.src_pal];
|
||||
rgb_t d_rgb = clut[mix.dst_pal];
|
||||
dst[x] = (s_rgb.scale8(mix.src_blend) + d_rgb.scale8(mix.dst_blend)).set_a(255);
|
||||
const pen_t *clut = m_palette->pens();
|
||||
for (unsigned int x = H_START; x < H_START + H_VIS; x++) {
|
||||
rgb_t s_rgb = clut[z.src_pal[x]];
|
||||
rgb_t d_rgb = clut[z.dst_pal[x]];
|
||||
|
||||
// source_color * src_blend + dest_color * dst_blend
|
||||
u16 r1 = s_rgb.r();
|
||||
u16 g1 = s_rgb.g();
|
||||
u16 b1 = s_rgb.b();
|
||||
u16 r2 = d_rgb.r();
|
||||
u16 g2 = d_rgb.g();
|
||||
u16 b2 = d_rgb.b();
|
||||
r1 *= z.src_blend[x]; // these blend contributions have fixed3 precision
|
||||
g1 *= z.src_blend[x]; // i.e. 0 (b0'000) to 8 (b1'000) represents 0.0 to 1.0
|
||||
b1 *= z.src_blend[x];
|
||||
r2 *= z.dst_blend[x];
|
||||
g2 *= z.dst_blend[x];
|
||||
b2 *= z.dst_blend[x];
|
||||
r1 += r2;
|
||||
g1 += g2;
|
||||
b1 += b2;
|
||||
|
||||
r1 >>= 3;
|
||||
g1 >>= 3;
|
||||
b1 >>= 3;
|
||||
r1 = std::min<u16>(r1, 255);
|
||||
g1 = std::min<u16>(g1, 255);
|
||||
b1 = std::min<u16>(b1, 255);
|
||||
|
||||
dst[x] = rgb_t(r1, g1, b1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool taito_f3_state::used(const pivot_inf &layer, int y) const
|
||||
{
|
||||
const int y_adj = m_flipscreen ? 0x1ff - layer.y_index(y) : layer.y_index(y);
|
||||
return layer.use_pix() || (m_textram_row_usage[y_adj >> 3] > 0);
|
||||
}
|
||||
inline bool taito_f3_state::used(const sprite_inf &layer, int y) const
|
||||
{
|
||||
return m_sprite_pri_row_usage[y] & (1 << layer.index);
|
||||
}
|
||||
inline bool taito_f3_state::used(const playfield_inf &layer, int y) const
|
||||
{
|
||||
const int y_adj = m_flipscreen ? 0x1ff - layer.y_index(y) : layer.y_index(y);
|
||||
return m_tilemap_row_usage[y_adj >> 4][layer.index + (2 * layer.alt_tilemap)] > 0;
|
||||
}
|
||||
|
||||
void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
auto prio = [] (const auto &obj) -> u8 { return obj->prio; };
|
||||
@ -1058,16 +1142,15 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
// acquire sprite rendering layers, playfield tilemaps, playfield scroll
|
||||
f3_line_inf line_data{};
|
||||
for (int i=0; i < NUM_SPRITEGROUPS; i++) {
|
||||
line_data.sp[i].bitmap = draw_source(&m_sprite_framebuffers[i]);
|
||||
line_data.sp[i].sprite_pri_usage = &m_sprite_pri_row_usage;
|
||||
line_data.sp[i].debug_index = i;
|
||||
line_data.sp[i].bitmap = draw_source(&m_sprite_framebuffer);
|
||||
line_data.sp[i].index = i;
|
||||
}
|
||||
for (int pf = 0; pf < NUM_PLAYFIELDS; ++pf) {
|
||||
get_pf_scroll(pf, line_data.pf[pf].reg_sx, line_data.pf[pf].reg_sy);
|
||||
|
||||
line_data.pf[pf].reg_fx_y = line_data.pf[pf].reg_sy;
|
||||
line_data.pf[pf].width_mask = m_width_mask;
|
||||
line_data.pf[pf].debug_index = pf;
|
||||
line_data.pf[pf].index = pf;
|
||||
}
|
||||
if (m_flipscreen) {
|
||||
line_data.pivot.reg_sx = m_control_1[4] - 12;
|
||||
@ -1077,7 +1160,7 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
line_data.pivot.reg_sy = -m_control_1[5];
|
||||
}
|
||||
|
||||
for (int screen_y = 0; screen_y != 256; screen_y += 1) {
|
||||
for (unsigned int screen_y = 0; screen_y != 256; screen_y += 1) {
|
||||
const int y = m_flipscreen ? (255 - screen_y) : screen_y;
|
||||
read_line_ram(line_data, y);
|
||||
line_data.y = screen_y;
|
||||
@ -1099,10 +1182,15 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
line_data.pivot.bitmap = draw_source(m_vram_layer);
|
||||
}
|
||||
|
||||
mix_pix line_buf[H_TOTAL]{};
|
||||
pri_mode line_pri[H_TOTAL]{};
|
||||
// set up line blend pixel and priority buffers
|
||||
mix_pix line_buf{};
|
||||
pri_mode line_pri{};
|
||||
// background palette -- what contributions should this default to?
|
||||
std::fill_n(line_buf, H_TOTAL, mix_pix{0, line_data.bg_palette, 0x0, 0xff});
|
||||
std::fill_n(line_buf.dst_pal, H_TOTAL, line_data.bg_palette);
|
||||
std::fill_n(line_buf.dst_blend, H_TOTAL, 8); // 100%
|
||||
// set an invalid blend mode as it affects mixing
|
||||
std::fill_n(line_pri.src_blendmode, H_TOTAL, 0xff);
|
||||
std::fill_n(line_pri.dst_blendmode, H_TOTAL, 0xff);
|
||||
|
||||
// sort layers
|
||||
std::array<std::variant<pivot_inf*, sprite_inf*, playfield_inf*>,
|
||||
@ -1123,10 +1211,11 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
for (auto gfx : layers) {
|
||||
std::visit(
|
||||
[this, &line_data, &line_buf, &line_pri] (auto &&arg) {
|
||||
if (arg->layer_enable() && arg->used(line_data.y)) {
|
||||
const auto clip_ranges = calc_clip(line_data.clip, arg);
|
||||
const auto &layer = *arg;
|
||||
if (layer.layer_enable() && used(layer, line_data.y)) {
|
||||
const auto clip_ranges = calc_clip(line_data.clip, layer);
|
||||
for (const auto &clip : clip_ranges) {
|
||||
mix_line(*arg, &line_buf[0], &line_pri[0], line_data, clip);
|
||||
mix_line(layer, line_buf, line_pri, line_data, clip);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1135,9 +1224,9 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
if (TAITOF3_VIDEO_DEBUG == 1) {
|
||||
if (y == 100) {
|
||||
logerror("{pal: %x/%x, blend: %x/%x, prio: %x/%x}\n",
|
||||
line_buf[180].src_pal, line_buf[180].dst_pal,
|
||||
line_buf[180].src_blend, line_buf[180].dst_blend,
|
||||
line_pri[180].src_prio, line_pri[180].dst_prio);
|
||||
line_buf.src_pal[180], line_buf.dst_pal[180],
|
||||
line_buf.src_blend[180], line_buf.dst_blend[180],
|
||||
line_pri.src_prio[180], line_pri.dst_prio[180]);
|
||||
logerror("-' [%hhu,%hhu,%hhu,%hhu] '------------------------- 100\n", line_data.blend[0],
|
||||
line_data.blend[1], line_data.blend[2], line_data.blend[3]);
|
||||
}
|
||||
@ -1159,7 +1248,7 @@ void taito_f3_state::scanline_draw(bitmap_rgb32 &bitmap, const rectangle &clipre
|
||||
|
||||
inline void taito_f3_state::f3_drawgfx(const tempsprite &sprite, const rectangle &cliprect)
|
||||
{
|
||||
bitmap_ind16 &dest_bmp = m_sprite_framebuffers[sprite.pri];
|
||||
bitmap_ind16 &dest_bmp = m_sprite_framebuffer;
|
||||
|
||||
gfx_element *gfx = m_gfxdecode->gfx(2);
|
||||
const u8 *code_base = gfx->get_data(sprite.code % gfx->elements());
|
||||
@ -1178,7 +1267,6 @@ inline void taito_f3_state::f3_drawgfx(const tempsprite &sprite, const rectangle
|
||||
dy8 += sprite.scale_y;
|
||||
if (dy < cliprect.min_y || dy > cliprect.max_y)
|
||||
continue;
|
||||
u8 *pri = &m_pri_alp_bitmap.pix(dy);
|
||||
u16 *dest = &dest_bmp.pix(dy);
|
||||
auto &usage = m_sprite_pri_row_usage[dy];
|
||||
const u8 *src = &code_base[(y ^ flipy) * 16];
|
||||
@ -1193,9 +1281,8 @@ inline void taito_f3_state::f3_drawgfx(const tempsprite &sprite, const rectangle
|
||||
if (dx == dx8 >> 8) // if the next pixel would be in the same column, skip this one
|
||||
continue;
|
||||
const u8 c = src[(x ^ flipx)] & m_sprite_pen_mask;
|
||||
if (c && !pri[dx]) {
|
||||
if (c && !dest[dx]) {
|
||||
dest[dx] = gfx->colorbase() + (sprite.color<<4 | c);
|
||||
pri[dx] = 1;
|
||||
usage |= 1<<sprite.pri;
|
||||
}
|
||||
}
|
||||
@ -1348,11 +1435,8 @@ void taito_f3_state::get_sprite_info()
|
||||
void taito_f3_state::draw_sprites(const rectangle &cliprect)
|
||||
{
|
||||
if (!m_sprite_trails) {
|
||||
m_pri_alp_bitmap.fill(0);
|
||||
std::fill_n(m_sprite_pri_row_usage, 256, 0);
|
||||
for (auto &sp_bitmap : m_sprite_framebuffers) {
|
||||
sp_bitmap.fill(0);
|
||||
}
|
||||
m_sprite_framebuffer.fill(0);
|
||||
}
|
||||
|
||||
for (const auto *spr = m_sprite_end; spr-- != &m_spritelist[0]; ) {
|
||||
|
Loading…
Reference in New Issue
Block a user