// license:BSD-3-Clause
// copyright-holders:Zsolt Vasvari
/***************************************************************************
video.c
Functions to emulate the video hardware of the machine.
Convention: "sl" stands for "searchlight"
***************************************************************************/
#include "emu.h"
#include "sound/ay8910.h"
#include "includes/dday.h"
/* Note: There seems to be no way to reset this timer via hardware.
The game uses a difference method to reset it to 99.
Thanks Zwaxy for the timer info. */
READ8_MEMBER(dday_state::dday_countdown_timer_r)
{
return ((m_timer_value / 10) << 4) | (m_timer_value % 10);
}
TIMER_CALLBACK_MEMBER(dday_state::countdown_timer_callback)
{
m_timer_value--;
if (m_timer_value < 0)
m_timer_value = 99;
}
void dday_state::start_countdown_timer()
{
m_timer_value = 0;
m_countdown_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
}
/***************************************************************************
Convert the color PROMs into a more useable format.
***************************************************************************/
PALETTE_INIT_MEMBER(dday_state, dday)
{
const uint8_t *color_prom = memregion("proms")->base();
int i;
palette.set_shadow_factor(1.0 / 8);
/* create a lookup table for the palette */
for (i = 0; i < 0x100; i++)
{
int r = pal4bit(color_prom[i + 0x000]);
int g = pal4bit(color_prom[i + 0x100]);
int b = pal4bit(color_prom[i + 0x200]);
palette.set_indirect_color(i, rgb_t(r, g, b));
}
for (i = 0; i < 0x100; i++)
palette.set_pen_indirect(i, i);
/* HACK!!! This table is handgenerated, but it matches the screenshot.
I have no clue how it really works */
palette.set_pen_indirect(0*8+0+0, 0x00);
palette.set_pen_indirect(0*8+0+1, 0x01);
palette.set_pen_indirect(0*8+0+2, 0x15);
palette.set_pen_indirect(0*8+0+3, 0x02);
palette.set_pen_indirect(0*8+4+0, 0x00);
palette.set_pen_indirect(0*8+4+1, 0x01);
palette.set_pen_indirect(0*8+4+2, 0x15);
palette.set_pen_indirect(0*8+4+3, 0x02);
palette.set_pen_indirect(1*8+0+0, 0x04);
palette.set_pen_indirect(1*8+0+1, 0x05);
palette.set_pen_indirect(1*8+0+2, 0x03);
palette.set_pen_indirect(1*8+0+3, 0x07);
palette.set_pen_indirect(1*8+4+0, 0x04);
palette.set_pen_indirect(1*8+4+1, 0x05);
palette.set_pen_indirect(1*8+4+2, 0x03);
palette.set_pen_indirect(1*8+4+3, 0x07);
palette.set_pen_indirect(2*8+0+0, 0x08);
palette.set_pen_indirect(2*8+0+1, 0x15);
palette.set_pen_indirect(2*8+0+2, 0x0a);
palette.set_pen_indirect(2*8+0+3, 0x03);
palette.set_pen_indirect(2*8+4+0, 0x08);
palette.set_pen_indirect(2*8+4+1, 0x15);
palette.set_pen_indirect(2*8+4+2, 0x0a);
palette.set_pen_indirect(2*8+4+3, 0x03);
palette.set_pen_indirect(3*8+0+0, 0x08);
palette.set_pen_indirect(3*8+0+1, 0x15);
palette.set_pen_indirect(3*8+0+2, 0x0a);
palette.set_pen_indirect(3*8+0+3, 0x03);
palette.set_pen_indirect(3*8+4+0, 0x08);
palette.set_pen_indirect(3*8+4+1, 0x15);
palette.set_pen_indirect(3*8+4+2, 0x0a);
palette.set_pen_indirect(3*8+4+3, 0x03);
palette.set_pen_indirect(4*8+0+0, 0x10);
palette.set_pen_indirect(4*8+0+1, 0x11);
palette.set_pen_indirect(4*8+0+2, 0x12);
palette.set_pen_indirect(4*8+0+3, 0x07);
palette.set_pen_indirect(4*8+4+0, 0x10);
palette.set_pen_indirect(4*8+4+1, 0x11);
palette.set_pen_indirect(4*8+4+2, 0x12);
palette.set_pen_indirect(4*8+4+3, 0x07);
palette.set_pen_indirect(5*8+0+0, 0x1d);
palette.set_pen_indirect(5*8+0+1, 0x15);
palette.set_pen_indirect(5*8+0+2, 0x16);
palette.set_pen_indirect(5*8+0+3, 0x1b);
palette.set_pen_indirect(5*8+4+0, 0x1d);
palette.set_pen_indirect(5*8+4+1, 0x15);
palette.set_pen_indirect(5*8+4+2, 0x16);
palette.set_pen_indirect(5*8+4+3, 0x1b);
palette.set_pen_indirect(6*8+0+0, 0x1d);
palette.set_pen_indirect(6*8+0+1, 0x15);
palette.set_pen_indirect(6*8+0+2, 0x1a);
palette.set_pen_indirect(6*8+0+3, 0x1b);
palette.set_pen_indirect(6*8+4+0, 0x1d);
palette.set_pen_indirect(6*8+4+1, 0x15);
palette.set_pen_indirect(6*8+4+2, 0x1a);
palette.set_pen_indirect(6*8+4+3, 0x1b);
palette.set_pen_indirect(7*8+0+0, 0x1d);
palette.set_pen_indirect(7*8+0+1, 0x02);
palette.set_pen_indirect(7*8+0+2, 0x04);
palette.set_pen_indirect(7*8+0+3, 0x1b);
palette.set_pen_indirect(7*8+4+0, 0x1d);
palette.set_pen_indirect(7*8+4+1, 0x02);
palette.set_pen_indirect(7*8+4+2, 0x04);
palette.set_pen_indirect(7*8+4+3, 0x1b);
}
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(dday_state::get_bg_tile_info)
{
int code;
code = m_bgvideoram[tile_index];
SET_TILE_INFO_MEMBER(0, code, code >> 5, 0);
}
TILE_GET_INFO_MEMBER(dday_state::get_fg_tile_info)
{
int code, flipx;
flipx = m_colorram[tile_index & 0x03e0] & 0x01;
code = m_fgvideoram[flipx ? tile_index ^ 0x1f : tile_index];
SET_TILE_INFO_MEMBER(2, code, code >> 5, flipx ? TILE_FLIPX : 0);
}
TILE_GET_INFO_MEMBER(dday_state::get_text_tile_info)
{
int code;
code = m_textvideoram[tile_index];
SET_TILE_INFO_MEMBER(1, code, code >> 5, 0);
}
TILE_GET_INFO_MEMBER(dday_state::get_sl_tile_info)
{
int code, sl_flipx, flipx;
uint8_t* sl_map;
sl_map = &memregion("user1")->base()[(m_sl_image & 0x07) * 0x0200];
flipx = (tile_index >> 4) & 0x01;
sl_flipx = (m_sl_image >> 3) & 0x01;
/* bit 4 is really a flip indicator. Need to shift bits 5-9 to the right by 1 */
tile_index = ((tile_index & 0x03e0) >> 1) | (tile_index & 0x0f);
code = sl_map[flipx ? tile_index ^ 0x0f : tile_index];
if ((sl_flipx != flipx) && (code & 0x80))
/* no mirroring, draw dark spot */
code = 1;
SET_TILE_INFO_MEMBER(3, code & 0x3f, 0, flipx ? TILE_FLIPX : 0);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
void dday_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dday_state::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dday_state::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_text_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dday_state::get_text_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_sl_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(dday_state::get_sl_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_screen->register_screen_bitmap(m_main_bitmap);
m_bg_tilemap->set_transmask(0, 0x00f0, 0xff0f); /* pens 0-3 have priority over the foreground layer */
m_fg_tilemap->set_transparent_pen(0);
m_text_tilemap->set_transparent_pen(0);
m_countdown_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dday_state::countdown_timer_callback), this));
start_countdown_timer();
}
WRITE8_MEMBER(dday_state::dday_bgvideoram_w)
{
m_bgvideoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
WRITE8_MEMBER(dday_state::dday_fgvideoram_w)
{
m_fgvideoram[offset] = data;
m_fg_tilemap->mark_tile_dirty(offset);
m_fg_tilemap->mark_tile_dirty(offset ^ 0x1f); /* for flipx case */
}
WRITE8_MEMBER(dday_state::dday_textvideoram_w)
{
m_textvideoram[offset] = data;
m_text_tilemap->mark_tile_dirty(offset);
}
WRITE8_MEMBER(dday_state::dday_colorram_w)
{
int i;
offset &= 0x03e0;
m_colorram[offset & 0x3e0] = data;
for (i = 0; i < 0x20; i++)
m_fg_tilemap->mark_tile_dirty(offset + i);
}
READ8_MEMBER(dday_state::dday_colorram_r)
{
return m_colorram[offset & 0x03e0];
}
WRITE8_MEMBER(dday_state::dday_sl_control_w)
{
if (m_sl_image != data)
{
m_sl_image = data;
m_sl_tilemap->mark_all_dirty();
}
}
WRITE8_MEMBER(dday_state::dday_control_w)
{
//if (data & 0xac) logerror("Control = %02X\n", data & 0xac);
/* bit 0 is coin counter 1 */
machine().bookkeeping().coin_counter_w(0, data & 0x01);
/* bit 1 is coin counter 2 */
machine().bookkeeping().coin_counter_w(1, data & 0x02);
/* bit 4 is sound enable */
if (!(data & 0x10) && (m_control & 0x10))
m_ay1->reset();
machine().sound().system_enable(data & 0x10);
/* bit 6 is search light enable */
m_sl_enable = data & 0x40;
m_control = data;
}
/***************************************************************************
Display refresh
***************************************************************************/
uint32_t dday_state::screen_update_dday(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER1, 0);
m_fg_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
m_bg_tilemap->draw(screen, m_main_bitmap, cliprect, TILEMAP_DRAW_LAYER0, 0);
m_text_tilemap->draw(screen, m_main_bitmap, cliprect, 0, 0);
if (m_sl_enable)
{
/* apply shadow */
int x, y;
bitmap_ind16 &sl_bitmap = m_sl_tilemap->pixmap();
for (x = cliprect.min_x; x <= cliprect.max_x; x++)
for (y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint16_t src_pixel = m_main_bitmap.pix16(y, x);
if (sl_bitmap.pix16(y, x) == 0xff)
src_pixel += m_palette->entries();
bitmap.pix16(y, x) = src_pixel;
}
}
else
copybitmap(bitmap, m_main_bitmap, 0, 0, 0, 0, cliprect);
return 0;
}