// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, Phil Stroffolino, Mirko Buffoni
/***************************************************************************
System 16 / 18 bootleg video
Bugs to check against real HW
System16A Tilemap bootlegs
- Shinobi (Datsu bootleg) has a black bar down the right hand side,
which turns red on the high score table. This is in the Text layer.
According to other games this should be the correct alignment for
this bootleg HW.
- After inserting a coin in Passing Shot (2p version) the layers are
misaligned by 1 pixel (happens on non-bootlegs too)
- Causing a 'fault' in the Passing Shot 2p bootleg (not hitting the ball
on your serve) causes the tilemaps to be erased and not updated
properly (mirroring?, bootleg protection?, missed case in bootleg?)
System18 Tilemap bootlegs
- Alien Storm Credit text for Player 1 is not displayed after inserting
a coin.
***************************************************************************/
#include "emu.h"
#include "includes/system16.h"
#include "video/resnet.h"
#include "video/segaic16.h"
void segas1x_bootleg_state::setup_system16_bootleg_spritebanking( )
{
if (m_spritebank_type == 0)
{
static constexpr uint8_t alternate_banklist[] = { 0,255,255,255, 255,255,255,3, 255,255,255,2, 255,1,0,255 };
for (int i = 0; i < 16; i++)
m_sprites->set_bank(i, alternate_banklist[i]);
}
}
#define MAXCOLOURS 0x2000 /* 8192 */
/***************************************************************************/
TILEMAP_MAPPER_MEMBER(segas1x_bootleg_state::sys16_bg_map)
{
int page = 0;
if (row < 32)
{
/* top */
if (col < 64)
page = 0;
else
page = 1;
}
else
{
/* bottom */
if (col < 64)
page = 2;
else
page = 3;
}
row = row % 32;
col = col % 64;
return page * 64 * 32 + row * 64 + col;
}
TILEMAP_MAPPER_MEMBER(segas1x_bootleg_state::sys16_text_map)
{
return row * 64 + col + (64 - 40);
}
/*
Color generation details
Each color is made up of 5 bits, connected through one or more resistors like so:
Bit 0 = 1 x 3.9K ohm
Bit 1 = 1 x 2.0K ohm
Bit 2 = 1 x 1.0K ohm
Bit 3 = 2 x 1.0K ohm
Bit 4 = 4 x 1.0K ohm
Another data bit is connected by a tristate buffer to the color output through a 470 ohm resistor.
The buffer allows the resistor to have no effect (tristate), halve brightness (pull-down) or double brightness (pull-up).
The data bit source is a PPI pin in some of the earlier hardware (Hang-On, Pre-System 16) or bit 15 of each
color RAM entry (Space Harrier, System 16B and most later boards).
*/
static const int resistances_normal[6] = {3900, 2000, 1000, 1000/2, 1000/4, 0};
static const int resistances_sh[6] = {3900, 2000, 1000, 1000/2, 1000/4, 470};
#ifdef UNUSED_CODE
WRITE16_MEMBER(segas1x_bootleg_state::sys16_paletteram_w)
{
uint16_t newword;
COMBINE_DATA(&m_generic_paletteram_16[offset]);
newword = m_generic_paletteram_16[offset];
/* sBGR BBBB GGGG RRRR */
/* x000 4321 4321 4321 */
{
int r, g, b, rs, gs, bs/*, rh, gh, bh*/;
int r0 = (newword >> 12) & 1;
int r1 = (newword >> 0) & 1;
int r2 = (newword >> 1) & 1;
int r3 = (newword >> 2) & 1;
int r4 = (newword >> 3) & 1;
int g0 = (newword >> 13) & 1;
int g1 = (newword >> 4) & 1;
int g2 = (newword >> 5) & 1;
int g3 = (newword >> 6) & 1;
int g4 = (newword >> 7) & 1;
int b0 = (newword >> 14) & 1;
int b1 = (newword >> 8) & 1;
int b2 = (newword >> 9) & 1;
int b3 = (newword >> 10) & 1;
int b4 = (newword >> 11) & 1;
/* Normal colors */
r = combine_weights(m_weights[0][0], r0, r1, r2, r3, r4, 0);
g = combine_weights(m_weights[0][1], g0, g1, g2, g3, g4, 0);
b = combine_weights(m_weights[0][2], b0, b1, b2, b3, b4, 0);
/* Shadow colors */
rs = combine_weights(m_weights[1][0], r0, r1, r2, r3, r4, 0);
gs = combine_weights(m_weights[1][1], g0, g1, g2, g3, g4, 0);
bs = combine_weights(m_weights[1][2], b0, b1, b2, b3, b4, 0);
/* Highlight colors */
//rh = combine_weights(m_weights[1][0], r0, r1, r2, r3, r4, 1);
//gh = combine_weights(m_weights[1][1], g0, g1, g2, g3, g4, 1);
//bh = combine_weights(m_weights[1][2], b0, b1, b2, b3, b4, 1);
m_palette->set_pen_color(offset, rgb_t(r, g, b) );
m_palette->set_pen_color(offset + m_palette->entries()/2, rgb_t(rs,gs,bs));
}
}
#endif
void segas1x_bootleg_state::update_page( )
{
int all_dirty = 0;
int i, offset;
if (m_old_tile_bank[1] != m_tile_bank[1])
{
all_dirty = 1;
m_old_tile_bank[1] = m_tile_bank[1];
}
if (m_old_tile_bank[0] != m_tile_bank[0])
{
all_dirty = 1;
m_old_tile_bank[0] = m_tile_bank[0];
m_text_layer->mark_all_dirty();
}
if (all_dirty)
{
m_background[0]->mark_all_dirty();
m_foreground[0]->mark_all_dirty();
if (m_system18)
{
m_background[1]->mark_all_dirty();
m_foreground[1]->mark_all_dirty();
}
}
else {
for (i = 0; i < 4; i++)
{
int page0 = 64 * 32 * i;
if (m_old_bg_page[0][i] != m_bg_page[0][i])
{
m_old_bg_page[0][i] = m_bg_page[0][i];
for (offset = page0; offset < page0 + 64 * 32; offset++)
{
m_background[0]->mark_tile_dirty(offset);
}
}
if (m_old_fg_page[0][i] != m_fg_page[0][i])
{
m_old_fg_page[0][i] = m_fg_page[0][i];
for (offset = page0; offset < page0 + 64 * 32; offset++)
{
m_foreground[0]->mark_tile_dirty(offset);
}
}
if (m_system18)
{
if (m_old_bg_page[1][i] != m_bg_page[1][i])
{
m_old_bg_page[1][i] = m_bg_page[1][i];
for (offset = page0; offset < page0 + 64 * 32; offset++)
{
m_background[1]->mark_tile_dirty(offset);
}
}
if (m_old_fg_page[1][i] != m_fg_page[1][i])
{
m_old_fg_page[1][i] = m_fg_page[1][i];
for (offset = page0; offset < page0 + 64 * 32; offset++)
{
m_foreground[1]->mark_tile_dirty(offset);
}
}
}
}
}
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_bg_tile_info)
{
const uint16_t *source = (m_bg_page[0][tile_index >> 11] << 11) + m_tileram;
int data = source[tile_index & 0x7ff];
int tile_number = (data & 0xfff) | (((data & m_tilebank_switch) ? m_tile_bank[1] : m_tile_bank[0]) << 12);
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_fg_tile_info)
{
const uint16_t *source = (m_fg_page[0][tile_index >> 11] << 11) + m_tileram;
int data = source[tile_index & 0x7ff];
int tile_number = (data & 0xfff) | (((data & m_tilebank_switch) ? m_tile_bank[1] : m_tile_bank[0]) << 12);
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_bg2_tile_info)
{
const uint16_t *source = (m_bg_page[1][tile_index >> 11] << 11) + m_tileram;
int data = source[tile_index & 0x7ff];
int tile_number = (data & 0xfff) | (m_tile_bank[(data & 0x1000) >> 12] << 12);
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_fg2_tile_info)
{
const uint16_t *source = (m_fg_page[1][tile_index >> 11] << 11) + m_tileram;
int data = source[tile_index & 0x7ff];
int tile_number = (data & 0xfff) | (m_tile_bank[(data & 0x1000) >> 12] << 12);
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
WRITE16_MEMBER(segas1x_bootleg_state::sys16_tileram_w)
{
uint16_t oldword = m_tileram[offset];
COMBINE_DATA(&m_tileram[offset]);
if (oldword != m_tileram[offset])
{
int page = offset >> 11;
offset = offset & 0x7ff;
if (m_bg_page[0][0] == page) m_background[0]->mark_tile_dirty(offset);
if (m_bg_page[0][1] == page) m_background[0]->mark_tile_dirty(offset | (1 << 11));
if (m_bg_page[0][2] == page) m_background[0]->mark_tile_dirty(offset | (2 << 11));
if (m_bg_page[0][3] == page) m_background[0]->mark_tile_dirty(offset | (3 << 11));
if (m_fg_page[0][0] == page) m_foreground[0]->mark_tile_dirty(offset);
if (m_fg_page[0][1] == page) m_foreground[0]->mark_tile_dirty(offset | (1 << 11));
if (m_fg_page[0][2] == page) m_foreground[0]->mark_tile_dirty(offset | (2 << 11));
if (m_fg_page[0][3] == page) m_foreground[0]->mark_tile_dirty(offset | (3 << 11));
if (m_system18)
{
if (m_bg_page[1][0] == page) m_background[1]->mark_tile_dirty(offset);
if (m_bg_page[1][1] == page) m_background[1]->mark_tile_dirty(offset | (1 << 11));
if (m_bg_page[1][2] == page) m_background[1]->mark_tile_dirty(offset | (2 << 11));
if (m_bg_page[1][3] == page) m_background[1]->mark_tile_dirty(offset | (3 << 11));
if (m_fg_page[1][0] == page) m_foreground[1]->mark_tile_dirty(offset);
if (m_fg_page[1][1] == page) m_foreground[1]->mark_tile_dirty(offset | (1 << 11));
if (m_fg_page[1][2] == page) m_foreground[1]->mark_tile_dirty(offset | (2 << 11));
if (m_fg_page[1][3] == page) m_foreground[1]->mark_tile_dirty(offset | (3 << 11));
}
}
}
/***************************************************************************/
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_text_tile_info)
{
const uint16_t *source = m_textram;
int tile_number = source[tile_index];
int pri = tile_number >> 8;
if (!m_shinobl_kludge)
{
SET_TILE_INFO_MEMBER(0,
(tile_number & 0x1ff) | (m_tile_bank[0] << 12),
(tile_number >> 9) % 8,
0);
}
else
{
SET_TILE_INFO_MEMBER(0,
(tile_number & 0xff) | (m_tile_bank[0] << 12),
(tile_number >> 8) % 8,
0);
}
if (pri >= m_textlayer_lo_min && pri <= m_textlayer_lo_max)
tileinfo.category = 1;
if (pri >= m_textlayer_hi_min && pri <= m_textlayer_hi_max)
tileinfo.category = 0;
}
WRITE16_MEMBER(segas1x_bootleg_state::sys16_textram_w)
{
COMBINE_DATA(&m_textram[offset]);
m_text_layer->mark_tile_dirty(offset);
}
/***************************************************************************/
VIDEO_START_MEMBER(segas1x_bootleg_state,system16)
{
/* Normal colors */
compute_resistor_weights(0, 255, -1.0,
6, resistances_normal, m_weights[0][0], 0, 0,
6, resistances_normal, m_weights[0][1], 0, 0,
6, resistances_normal, m_weights[0][2], 0, 0
);
/* Shadow/Highlight colors */
compute_resistor_weights(0, 255, -1.0,
6, resistances_sh, m_weights[1][0], 0, 0,
6, resistances_sh, m_weights[1][1], 0, 0,
6, resistances_sh, m_weights[1][2], 0, 0
);
if (!m_bg1_trans)
m_background[0] = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_bg_map)),
8,8,
64*2,32*2);
else
m_background[0] = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_bg_map)),
8,8,
64*2,32*2);
m_foreground[0] = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_bg_map)),
8,8,
64*2,32*2);
m_text_layer = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_text_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_text_map)),
8,8,
40,28);
if (m_bg1_trans) m_background[0]->set_transparent_pen(0);
m_foreground[0]->set_transparent_pen(0);
m_text_layer->set_transparent_pen(0);
m_tile_bank[0] = 0;
m_tile_bank[1] = 1;
m_fg_scrollx = 0;
m_fg_scrolly = 0;
m_bg_scrollx = 0;
m_bg_scrolly = 0;
m_refreshenable = 1;
/* common defaults */
m_tilebank_switch = 0x1000;
// Defaults for sys16 games
m_textlayer_lo_min = 0;
m_textlayer_lo_max = 0x7f;
m_textlayer_hi_min = 0x80;
m_textlayer_hi_max = 0xff;
m_system18 = 0;
if (m_sprites.found())
setup_system16_bootleg_spritebanking();
}
VIDEO_START_MEMBER(segas1x_bootleg_state,system18old)
{
VIDEO_START_CALL_MEMBER(system16);
m_bg1_trans = 1;
m_background[1] = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_bg_map)),
8,8,
64*2,32*2);
m_foreground[1] = &machine().tilemap().create(
*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_fg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(segas1x_bootleg_state::sys16_bg_map)),
8,8,
64*2,32*2);
m_foreground[1]->set_transparent_pen(0);
if (m_splittab_fg_x)
{
m_foreground[0] ->set_scroll_rows(64);
m_foreground[1] ->set_scroll_rows(64);
}
if (m_splittab_bg_x)
{
m_background[0] ->set_scroll_rows(64);
m_background[1] ->set_scroll_rows(64);
}
m_textlayer_lo_min = 0;
m_textlayer_lo_max = 0x1f;
m_textlayer_hi_min = 0x20;
m_textlayer_hi_max = 0xff;
m_system18 = 1;
}
/*****************************************************************************************
System 16A bootleg video
The System16A bootlegs have extra RAM for 2 tilemaps. The game code copies data from
the usual 'tilemap ram' area to this new RAM and sets scroll registers as appropriate
using additional registers not present on the original System 16A hardware.
For some unknown reason the 2p Passing Shot bootleg end up blanking this area at times,
this could be an emulation flaw or a problem with the original bootlegs. Inserting a
coin at the incorrect time can also cause missing graphics on the initial entry screen.
See note at top of driver
Sprites:
ToDo
*****************************************************************************************/
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_s16a_bootleg_tile_infotxt)
{
int data, tile_number;
data = m_textram[tile_index];
tile_number = data & 0x1ff;
SET_TILE_INFO_MEMBER(0,
tile_number,
((data >> 9) & 0x7),
0);
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_s16a_bootleg_tile_info0)
{
int data, tile_number;
data = m_bg0_tileram[tile_index];
tile_number = data & 0x1fff;
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
TILE_GET_INFO_MEMBER(segas1x_bootleg_state::get_s16a_bootleg_tile_info1)
{
int data, tile_number;
data = m_bg1_tileram[tile_index];
tile_number = data & 0x1fff;
SET_TILE_INFO_MEMBER(0,
tile_number,
(data >> 6) & 0x7f,
0);
}
WRITE16_MEMBER(segas1x_bootleg_state::s16a_bootleg_bgscrolly_w)
{
m_bg_scrolly = data;
}
WRITE16_MEMBER(segas1x_bootleg_state::s16a_bootleg_bgscrollx_w)
{
m_bg_scrollx = data;
}
WRITE16_MEMBER(segas1x_bootleg_state::s16a_bootleg_fgscrolly_w)
{
m_fg_scrolly = data;
}
WRITE16_MEMBER(segas1x_bootleg_state::s16a_bootleg_fgscrollx_w)
{
m_fg_scrollx = data;
}
WRITE16_MEMBER(segas1x_bootleg_state::s16a_bootleg_tilemapselect_w)
{
COMBINE_DATA(&m_tilemapselect);
//printf("system16 bootleg tilemapselect %04x\n", m_tilemapselect);
}
VIDEO_START_MEMBER(segas1x_bootleg_state,s16a_bootleg)
{
/* Normal colors */
compute_resistor_weights(0, 255, -1.0,
6, resistances_normal, m_weights[0][0], 0, 0,
6, resistances_normal, m_weights[0][1], 0, 0,
6, resistances_normal, m_weights[0][2], 0, 0
);
/* Shadow/Highlight colors */
compute_resistor_weights(0, 255, -1.0,
6, resistances_sh, m_weights[1][0], 0, 0,
6, resistances_sh, m_weights[1][1], 0, 0,
6, resistances_sh, m_weights[1][2], 0, 0
);
m_text_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_s16a_bootleg_tile_infotxt)), TILEMAP_SCAN_ROWS, 8,8, 64,32);
// the system16a bootlegs have simple tilemaps instead of the paged system
m_bg_tilemaps[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_s16a_bootleg_tile_info0)), TILEMAP_SCAN_ROWS, 8,8, 64,32);
m_bg_tilemaps[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(segas1x_bootleg_state::get_s16a_bootleg_tile_info1)), TILEMAP_SCAN_ROWS, 8,8, 64,32);
m_text_tilemap->set_transparent_pen(0);
m_bg_tilemaps[0]->set_transparent_pen(0);
m_bg_tilemaps[1]->set_transparent_pen(0);
}
VIDEO_START_MEMBER(segas1x_bootleg_state,s16a_bootleg_wb3bl)
{
VIDEO_START_CALL_MEMBER(s16a_bootleg);
setup_system16_bootleg_spritebanking();
}
VIDEO_START_MEMBER(segas1x_bootleg_state,s16a_bootleg_shinobi)
{
VIDEO_START_CALL_MEMBER(s16a_bootleg);
setup_system16_bootleg_spritebanking();
}
VIDEO_START_MEMBER(segas1x_bootleg_state,s16a_bootleg_passsht)
{
VIDEO_START_CALL_MEMBER(s16a_bootleg);
setup_system16_bootleg_spritebanking();
}
// Passing Shot (2 player), Shinobi (Datsu), Wonderboy 3
uint32_t segas1x_bootleg_state::screen_update_s16a_bootleg(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// passing shot
int offset_txtx = 192;
int offset_txty = 0;
int offset_bg1x = 190;
int offset_bg1y = 0;
int offset_bg0x = 187;
int offset_bg0y = 0;
bitmap.fill(m_palette->black_pen(), cliprect);
// start the sprites drawing
m_sprites->draw_async(cliprect);
// I can't bring myself to care about dirty tile marking on something which runs at a bazillion % speed anyway, clean code is better
m_bg_tilemaps[0]->mark_all_dirty();
m_bg_tilemaps[1]->mark_all_dirty();
m_text_tilemap->mark_all_dirty();
m_text_tilemap->set_scrollx(0, offset_txtx);
m_text_tilemap->set_scrolly(0, offset_txty);
if ((m_tilemapselect & 0xff) == 0x12)
{
m_bg_tilemaps[1]->set_scrollx(0, m_bg_scrollx + offset_bg1x);
m_bg_tilemaps[1]->set_scrolly(0, m_bg_scrolly + offset_bg1y + m_back_yscroll);
m_bg_tilemaps[0]->set_scrollx(0, m_fg_scrollx + offset_bg0x);
m_bg_tilemaps[0]->set_scrolly(0, m_fg_scrolly + offset_bg0y + m_fore_yscroll);
m_bg_tilemaps[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0);
m_bg_tilemaps[1]->draw(screen, bitmap, cliprect, 0, 0);
m_text_tilemap->set_scrolly(0, m_text_yscroll);
m_text_tilemap->draw(screen, bitmap, cliprect, 0, 0);
}
else if ((m_tilemapselect & 0xff) == 0x21)
{
m_bg_tilemaps[0]->set_scrollx(0, m_bg_scrollx + 187 );
m_bg_tilemaps[0]->set_scrolly(0, m_bg_scrolly + m_back_yscroll );
m_bg_tilemaps[1]->set_scrollx(0, m_fg_scrollx + 187 );
m_bg_tilemaps[1]->set_scrolly(0, m_fg_scrolly + 1 + m_fore_yscroll );
m_bg_tilemaps[1]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0);
m_bg_tilemaps[0]->draw(screen, bitmap, cliprect, 0, 0);
m_text_tilemap->set_scrolly(0, m_text_yscroll);
m_text_tilemap->draw(screen, bitmap, cliprect, 0, 0);
}
// mix in sprites
bitmap_ind16 &sprites = m_sprites->bitmap();
for (const sparse_dirty_rect *rect = m_sprites->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
for (int y = rect->min_y; y <= rect->max_y; y++)
{
uint16_t *dest = &bitmap.pix(y);
uint16_t *src = &sprites.pix(y);
// uint8_t *pri = &screen.priority().pix(y);
for (int x = rect->min_x; x <= rect->max_x; x++)
{
// only process written pixels
uint16_t pix = src[x];
if (pix != 0xffff)
{
// compare sprite priority against tilemap priority
// int priority = (pix >> 12) & 3;
if (1)
{
// if the color is set to maximum, shadow pixels underneath us
if ((pix & 0x03f0) == 0x03f0)
dest[x] += m_palette_entries;
// otherwise, just add in sprite palette base
else
dest[x] = 0x400 | (pix & 0x3ff);
}
}
}
}
return 0;
}
/* The Passing Shot 4 Player bootleg has weird scroll registers (different offsets, ^0x7 xor) */
uint32_t segas1x_bootleg_state::screen_update_s16a_bootleg_passht4b(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// passing shot
int offset_txtx = 192;
int offset_txty = 0;
int offset_bg1x = 3;
int offset_bg1y = 32;
int offset_bg0x = 5;
int offset_bg0y = 32;
bitmap.fill(m_palette->black_pen(), cliprect);
// start the sprites drawing
m_sprites->draw_async(cliprect);
// I can't bring myself to care about dirty tile marking on something which runs at a bazillion % speed anyway, clean code is better
m_bg_tilemaps[0]->mark_all_dirty();
m_bg_tilemaps[1]->mark_all_dirty();
m_text_tilemap->mark_all_dirty();
m_text_tilemap->set_scrollx(0, offset_txtx);
m_text_tilemap->set_scrolly(0, offset_txty);
if ((m_tilemapselect & 0xff) == 0x12)
{
m_bg_tilemaps[1]->set_scrollx(0, (m_bg_scrollx ^ 0x7) + offset_bg1x);
m_bg_tilemaps[1]->set_scrolly(0, m_bg_scrolly + offset_bg1y);
m_bg_tilemaps[0]->set_scrollx(0, (m_fg_scrollx ^ 0x7) + offset_bg0x);
m_bg_tilemaps[0]->set_scrolly(0, m_fg_scrolly + offset_bg0y);
m_bg_tilemaps[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0);
m_bg_tilemaps[1]->draw(screen, bitmap, cliprect, 0, 0);
m_text_tilemap->draw(screen, bitmap, cliprect, 0, 0);
}
// mix in sprites
bitmap_ind16 &sprites = m_sprites->bitmap();
for (const sparse_dirty_rect *rect = m_sprites->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
for (int y = rect->min_y; y <= rect->max_y; y++)
{
uint16_t *dest = &bitmap.pix(y);
uint16_t *src = &sprites.pix(y);
// uint8_t *pri = &screen.priority().pix(y);
for (int x = rect->min_x; x <= rect->max_x; x++)
{
// only process written pixels
uint16_t pix = src[x];
if (pix != 0xffff)
{
// compare sprite priority against tilemap priority
// int priority = (pix >> 12) & 3;
if (1)
{
// if the color is set to maximum, shadow pixels underneath us
if ((pix & 0x03f0) == 0x03f0)
dest[x] += m_palette_entries;
// otherwise, just add in sprite palette base
else
dest[x] = 0x400 | (pix & 0x3ff);
}
}
}
}
return 0;
}
/***************************************************************************/
uint32_t segas1x_bootleg_state::screen_update_system16(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (!m_refreshenable)
{
bitmap.fill(0, cliprect);
return 0;
}
// start the sprites drawing
if (m_sprites.found())
m_sprites->draw_async(cliprect);
update_page();
screen.priority().fill(0, cliprect);
m_background[0]->set_scrollx(0, -320 - m_bg_scrollx);
m_background[0]->set_scrolly(0, -256 + m_bg_scrolly + m_back_yscroll);
m_foreground[0]->set_scrollx(0, -320 - m_fg_scrollx);
m_foreground[0]->set_scrolly(0, -256 + m_fg_scrolly + m_fore_yscroll);
m_text_layer->set_scrollx(0, 0);
m_text_layer->set_scrolly(0, 0 + m_text_yscroll);
/* Background */
m_background[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0x00);
/* Foreground */
m_foreground[0]->draw(screen, bitmap, cliprect, 0, 0x03);
m_foreground[0]->draw(screen, bitmap, cliprect, 1, 0x07);
/* Text Layer */
if (m_textlayer_lo_max != 0)
{
m_text_layer->draw(screen, bitmap, cliprect, 1, 7);// needed for Body Slam
}
m_text_layer->draw(screen, bitmap, cliprect, 0, 0xf);
//draw_sprites(machine(), bitmap, cliprect,0);
// mix in sprites
if (!m_sprites.found())
return 0;
bitmap_ind16 &sprites = m_sprites->bitmap();
for (const sparse_dirty_rect *rect = m_sprites->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
for (int y = rect->min_y; y <= rect->max_y; y++)
{
uint16_t *dest = &bitmap.pix(y);
uint16_t *src = &sprites.pix(y);
// uint8_t *pri = &screen.priority().pix(y);
for (int x = rect->min_x; x <= rect->max_x; x++)
{
// only process written pixels
uint16_t pix = src[x];
if (pix != 0xffff)
{
// compare sprite priority against tilemap priority
// int priority = (pix >> 12) & 3;
if (1)
{
// if the color is set to maximum, shadow pixels underneath us
if ((pix & 0x03f0) == 0x03f0)
dest[x] += m_palette_entries;
// otherwise, just add in sprite palette base
else
dest[x] = 0x400 | (pix & 0x3ff);
}
}
}
}
return 0;
}
uint32_t segas1x_bootleg_state::screen_update_system18old(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (!m_refreshenable)
{
bitmap.fill(m_palette->black_pen(), cliprect);
return 0;
}
// start the sprites drawing
m_sprites->draw_async(cliprect);
update_page();
screen.priority().fill(0);
bitmap.fill(0, cliprect);
m_background[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0);
m_background[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE | 1, 0); //??
m_background[0]->draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE | 2, 0); //??
m_background[0]->draw(screen, bitmap, cliprect, 1, 0x1);
m_background[0]->draw(screen, bitmap, cliprect, 2, 0x3);
m_foreground[0]->draw(screen, bitmap, cliprect, 0, 0x3);
m_foreground[0]->draw(screen, bitmap, cliprect, 1, 0x7);
m_text_layer->draw(screen, bitmap, cliprect, 1, 0x7);
m_text_layer->draw(screen, bitmap, cliprect, 0, 0xf);
// mix in sprites
bitmap_ind16 &sprites = m_sprites->bitmap();
for (const sparse_dirty_rect *rect = m_sprites->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
for (int y = rect->min_y; y <= rect->max_y; y++)
{
uint16_t *dest = &bitmap.pix(y);
uint16_t *src = &sprites.pix(y);
// uint8_t *pri = &screen.priority().pix(y);
for (int x = rect->min_x; x <= rect->max_x; x++)
{
// only process written pixels
uint16_t pix = src[x];
if (pix != 0xffff)
{
// compare sprite priority against tilemap priority
// int priority = (pix >> 12) & 3;
if (1)
{
// if the color is set to maximum, shadow pixels underneath us
if ((pix & 0x03f0) == 0x03f0)
dest[x] += m_palette_entries;
// otherwise, just add in sprite palette base
else
dest[x] = 0x400 | (pix & 0x3ff);
}
}
}
}
return 0;
}