// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino, Paul Leaman
// thanks-to: Steven Frew (the author of Slutte)
/***************************************************************************
Bionic Commando Video Hardware
This board handles tile/tile and tile/sprite priority with a PROM. Its
working is complicated and hardcoded in the driver.
The PROM is a 256x4 chip, with address inputs wired as follows:
A0 bg opaque
A1 \
A2 | fg pen
A3 |
A4 /
A5 fg has priority over sprites (bit 5 of tile attribute)
A6 fg has not priority over bg (bits 6 & 7 of tile attribute both set)
A7 sprite opaque
The output selects the active layer, it can be:
0 bg
1 fg
2 sprite
***************************************************************************/
#include "emu.h"
#include "includes/bionicc.h"
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(bionicc_state::get_bg_tile_info)
{
int attr = m_bgvideoram[2 * tile_index + 1];
SET_TILE_INFO_MEMBER(1,
(m_bgvideoram[2 * tile_index] & 0xff) + ((attr & 0x07) << 8),
(attr & 0x18) >> 3,
TILE_FLIPXY((attr & 0xc0) >> 6));
}
TILE_GET_INFO_MEMBER(bionicc_state::get_fg_tile_info)
{
int attr = m_fgvideoram[2 * tile_index + 1];
int flags;
if ((attr & 0xc0) == 0xc0)
{
tileinfo.category = 1;
tileinfo.group = 0;
flags = 0;
}
else
{
tileinfo.category = 0;
tileinfo.group = (attr & 0x20) >> 5;
flags = TILE_FLIPXY((attr & 0xc0) >> 6);
}
SET_TILE_INFO_MEMBER(2,
(m_fgvideoram[2 * tile_index] & 0xff) + ((attr & 0x07) << 8),
(attr & 0x18) >> 3,
flags);
}
TILE_GET_INFO_MEMBER(bionicc_state::get_tx_tile_info)
{
int attr = m_txvideoram[tile_index + 0x400];
SET_TILE_INFO_MEMBER(0,
(m_txvideoram[tile_index] & 0xff) + ((attr & 0x00c0) << 2),
attr & 0x3f,
0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void bionicc_state::video_start()
{
m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(bionicc_state::get_tx_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(bionicc_state::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64);
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(bionicc_state::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
m_tx_tilemap->set_transparent_pen(3);
m_fg_tilemap->set_transmask(0, 0xffff, 0x8000); /* split type 0 is completely transparent in front half */
m_fg_tilemap->set_transmask(1, 0xffc1, 0x803e); /* split type 1 has pens 1-5 opaque in front half */
m_bg_tilemap->set_transparent_pen(15);
}
PALETTE_DECODER_MEMBER( bionicc_state, RRRRGGGGBBBBIIII )
{
uint8_t bright = (raw & 0x0f);
uint8_t r = ((raw >> 12) & 0x0f) * 0x11;
uint8_t g = ((raw >> 8) & 0x0f) * 0x11;
uint8_t b = ((raw >> 4) & 0x0f) * 0x11;
if ((bright & 0x08) == 0)
{
r = r * (0x07 + bright) / 0x0e;
g = g * (0x07 + bright) / 0x0e;
b = b * (0x07 + bright) / 0x0e;
}
return rgb_t(r, g, b);
}
/***************************************************************************
Memory handlers
***************************************************************************/
WRITE16_MEMBER(bionicc_state::bgvideoram_w)
{
COMBINE_DATA(&m_bgvideoram[offset]);
m_bg_tilemap->mark_tile_dirty(offset / 2);
}
WRITE16_MEMBER(bionicc_state::fgvideoram_w)
{
COMBINE_DATA(&m_fgvideoram[offset]);
m_fg_tilemap->mark_tile_dirty(offset / 2);
}
WRITE16_MEMBER(bionicc_state::txvideoram_w)
{
COMBINE_DATA(&m_txvideoram[offset]);
m_tx_tilemap->mark_tile_dirty(offset & 0x3ff);
}
WRITE16_MEMBER(bionicc_state::scroll_w)
{
data = COMBINE_DATA(&m_scroll[offset]);
switch (offset)
{
case 0:
m_fg_tilemap->set_scrollx(0, data);
break;
case 1:
m_fg_tilemap->set_scrolly(0, data);
break;
case 2:
m_bg_tilemap->set_scrollx(0, data);
break;
case 3:
m_bg_tilemap->set_scrolly(0, data);
break;
}
}
WRITE16_MEMBER(bionicc_state::gfxctrl_w)
{
if (ACCESSING_BITS_8_15)
{
flip_screen_set(data & 0x0100);
m_bg_tilemap->enable(data & 0x2000); /* guess */
m_fg_tilemap->enable(data & 0x1000); /* guess */
machine().bookkeeping().coin_counter_w(0, data & 0x8000);
machine().bookkeeping().coin_counter_w(1, data & 0x4000);
}
}
/***************************************************************************
Display refresh
***************************************************************************/
uint32_t bionicc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(m_palette->black_pen(), cliprect);
m_fg_tilemap->draw(screen, bitmap, cliprect, 1 | TILEMAP_DRAW_LAYER1, 0); /* nothing in FRONT */
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
m_fg_tilemap->draw(screen, bitmap, cliprect, 0 | TILEMAP_DRAW_LAYER1, 0);
m_spritegen->draw_sprites(bitmap, cliprect, m_gfxdecode, 3, m_spriteram->buffer(), m_spriteram->bytes(), flip_screen(), 0 );
m_fg_tilemap->draw(screen, bitmap, cliprect, 0 | TILEMAP_DRAW_LAYER0, 0);
m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
return 0;
}