/***************************************************************************

  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_HANDLER( dday_countdown_timer_r )
{
	dday_state *state = space->machine().driver_data<dday_state>();
	return ((state->m_timer_value / 10) << 4) | (state->m_timer_value % 10);
}

static TIMER_CALLBACK( countdown_timer_callback )
{
	dday_state *state = machine.driver_data<dday_state>();
	state->m_timer_value--;

	if (state->m_timer_value < 0)
		state->m_timer_value = 99;
}

static void start_countdown_timer(running_machine &machine)
{
	dday_state *state = machine.driver_data<dday_state>();

	state->m_timer_value = 0;

	machine.scheduler().timer_pulse(attotime::from_seconds(1), FUNC(countdown_timer_callback));
}


/***************************************************************************

  Convert the color PROMs into a more useable format.

***************************************************************************/

PALETTE_INIT( dday )
{
	int i;

	palette_set_shadow_factor(machine, 1.0 / 8);

	/* allocate the colortable */
	machine.colortable = colortable_alloc(machine, 0x100);

	/* 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]);

		colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
	}

	for (i = 0; i < 0x100; i++)
		colortable_entry_set_value(machine.colortable, i, i);

	/* HACK!!! This table is handgenerated, but it matches the screenshot.
       I have no clue how it really works */
	colortable_entry_set_value(machine.colortable, 0*8+0+0, 0x00);
	colortable_entry_set_value(machine.colortable, 0*8+0+1, 0x01);
	colortable_entry_set_value(machine.colortable, 0*8+0+2, 0x15);
	colortable_entry_set_value(machine.colortable, 0*8+0+3, 0x02);
	colortable_entry_set_value(machine.colortable, 0*8+4+0, 0x00);
	colortable_entry_set_value(machine.colortable, 0*8+4+1, 0x01);
	colortable_entry_set_value(machine.colortable, 0*8+4+2, 0x15);
	colortable_entry_set_value(machine.colortable, 0*8+4+3, 0x02);

	colortable_entry_set_value(machine.colortable, 1*8+0+0, 0x04);
	colortable_entry_set_value(machine.colortable, 1*8+0+1, 0x05);
	colortable_entry_set_value(machine.colortable, 1*8+0+2, 0x03);
	colortable_entry_set_value(machine.colortable, 1*8+0+3, 0x07);
	colortable_entry_set_value(machine.colortable, 1*8+4+0, 0x04);
	colortable_entry_set_value(machine.colortable, 1*8+4+1, 0x05);
	colortable_entry_set_value(machine.colortable, 1*8+4+2, 0x03);
	colortable_entry_set_value(machine.colortable, 1*8+4+3, 0x07);

	colortable_entry_set_value(machine.colortable, 2*8+0+0, 0x08);
	colortable_entry_set_value(machine.colortable, 2*8+0+1, 0x15);
	colortable_entry_set_value(machine.colortable, 2*8+0+2, 0x0a);
	colortable_entry_set_value(machine.colortable, 2*8+0+3, 0x03);
	colortable_entry_set_value(machine.colortable, 2*8+4+0, 0x08);
	colortable_entry_set_value(machine.colortable, 2*8+4+1, 0x15);
	colortable_entry_set_value(machine.colortable, 2*8+4+2, 0x0a);
	colortable_entry_set_value(machine.colortable, 2*8+4+3, 0x03);

	colortable_entry_set_value(machine.colortable, 3*8+0+0, 0x08);
	colortable_entry_set_value(machine.colortable, 3*8+0+1, 0x15);
	colortable_entry_set_value(machine.colortable, 3*8+0+2, 0x0a);
	colortable_entry_set_value(machine.colortable, 3*8+0+3, 0x03);
	colortable_entry_set_value(machine.colortable, 3*8+4+0, 0x08);
	colortable_entry_set_value(machine.colortable, 3*8+4+1, 0x15);
	colortable_entry_set_value(machine.colortable, 3*8+4+2, 0x0a);
	colortable_entry_set_value(machine.colortable, 3*8+4+3, 0x03);

	colortable_entry_set_value(machine.colortable, 4*8+0+0, 0x10);
	colortable_entry_set_value(machine.colortable, 4*8+0+1, 0x11);
	colortable_entry_set_value(machine.colortable, 4*8+0+2, 0x12);
	colortable_entry_set_value(machine.colortable, 4*8+0+3, 0x07);
	colortable_entry_set_value(machine.colortable, 4*8+4+0, 0x10);
	colortable_entry_set_value(machine.colortable, 4*8+4+1, 0x11);
	colortable_entry_set_value(machine.colortable, 4*8+4+2, 0x12);
	colortable_entry_set_value(machine.colortable, 4*8+4+3, 0x07);

	colortable_entry_set_value(machine.colortable, 5*8+0+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 5*8+0+1, 0x15);
	colortable_entry_set_value(machine.colortable, 5*8+0+2, 0x16);
	colortable_entry_set_value(machine.colortable, 5*8+0+3, 0x1b);
	colortable_entry_set_value(machine.colortable, 5*8+4+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 5*8+4+1, 0x15);
	colortable_entry_set_value(machine.colortable, 5*8+4+2, 0x16);
	colortable_entry_set_value(machine.colortable, 5*8+4+3, 0x1b);

	colortable_entry_set_value(machine.colortable, 6*8+0+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 6*8+0+1, 0x15);
	colortable_entry_set_value(machine.colortable, 6*8+0+2, 0x1a);
	colortable_entry_set_value(machine.colortable, 6*8+0+3, 0x1b);
	colortable_entry_set_value(machine.colortable, 6*8+4+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 6*8+4+1, 0x15);
	colortable_entry_set_value(machine.colortable, 6*8+4+2, 0x1a);
	colortable_entry_set_value(machine.colortable, 6*8+4+3, 0x1b);

	colortable_entry_set_value(machine.colortable, 7*8+0+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 7*8+0+1, 0x02);
	colortable_entry_set_value(machine.colortable, 7*8+0+2, 0x04);
	colortable_entry_set_value(machine.colortable, 7*8+0+3, 0x1b);
	colortable_entry_set_value(machine.colortable, 7*8+4+0, 0x1d);
	colortable_entry_set_value(machine.colortable, 7*8+4+1, 0x02);
	colortable_entry_set_value(machine.colortable, 7*8+4+2, 0x04);
	colortable_entry_set_value(machine.colortable, 7*8+4+3, 0x1b);
}


/***************************************************************************

  Callbacks for the TileMap code

***************************************************************************/

static TILE_GET_INFO( get_bg_tile_info )
{
	dday_state *state = machine.driver_data<dday_state>();
	int code;

	code = state->m_bgvideoram[tile_index];
	SET_TILE_INFO(0, code, code >> 5, 0);
}

static TILE_GET_INFO( get_fg_tile_info )
{
	dday_state *state = machine.driver_data<dday_state>();
	int code, flipx;

	flipx = state->m_colorram[tile_index & 0x03e0] & 0x01;
	code = state->m_fgvideoram[flipx ? tile_index ^ 0x1f : tile_index];
	SET_TILE_INFO(2, code, code >> 5, flipx ? TILE_FLIPX : 0);
}

static TILE_GET_INFO( get_text_tile_info )
{
	dday_state *state = machine.driver_data<dday_state>();
	int code;

	code = state->m_textvideoram[tile_index];
	SET_TILE_INFO(1, code, code >> 5, 0);
}

static TILE_GET_INFO( get_sl_tile_info )
{
	dday_state *state = machine.driver_data<dday_state>();
	int code, sl_flipx, flipx;
	UINT8* sl_map;

	sl_map = &machine.region("user1")->base()[(state->m_sl_image & 0x07) * 0x0200];

	flipx = (tile_index >> 4) & 0x01;
	sl_flipx = (state->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(3, code & 0x3f, 0, flipx ? TILE_FLIPX : 0);
}


/***************************************************************************

  Start the video hardware emulation.

***************************************************************************/

VIDEO_START( dday )
{
	dday_state *state = machine.driver_data<dday_state>();
	state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
	state->m_fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
	state->m_text_tilemap = tilemap_create(machine, get_text_tile_info, tilemap_scan_rows, 8, 8, 32, 32);
	state->m_sl_tilemap = tilemap_create(machine, get_sl_tile_info, tilemap_scan_rows, 8, 8, 32, 32);

	state->m_main_bitmap = machine.primary_screen->alloc_compatible_bitmap();

	tilemap_set_transmask(state->m_bg_tilemap, 0, 0x00f0, 0xff0f); /* pens 0-3 have priority over the foreground layer */
	tilemap_set_transparent_pen(state->m_fg_tilemap, 0);
	tilemap_set_transparent_pen(state->m_text_tilemap, 0);

	start_countdown_timer(machine);
}

WRITE8_HANDLER( dday_bgvideoram_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();

	state->m_bgvideoram[offset] = data;
	tilemap_mark_tile_dirty(state->m_bg_tilemap, offset);
}

WRITE8_HANDLER( dday_fgvideoram_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();

	state->m_fgvideoram[offset] = data;
	tilemap_mark_tile_dirty(state->m_fg_tilemap, offset);
	tilemap_mark_tile_dirty(state->m_fg_tilemap, offset ^ 0x1f);  /* for flipx case */
}

WRITE8_HANDLER( dday_textvideoram_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();

	state->m_textvideoram[offset] = data;
	tilemap_mark_tile_dirty(state->m_text_tilemap, offset);
}

WRITE8_HANDLER( dday_colorram_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();
	int i;

	offset &= 0x03e0;

	state->m_colorram[offset & 0x3e0] = data;

	for (i = 0; i < 0x20; i++)
		tilemap_mark_tile_dirty(state->m_fg_tilemap, offset + i);
}

READ8_HANDLER( dday_colorram_r )
{
	dday_state *state = space->machine().driver_data<dday_state>();
	return state->m_colorram[offset & 0x03e0];
}


WRITE8_HANDLER( dday_sl_control_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();

	if (state->m_sl_image != data)
	{
		state->m_sl_image = data;
		tilemap_mark_all_tiles_dirty(state->m_sl_tilemap);
	}
}


WRITE8_HANDLER( dday_control_w )
{
	dday_state *state = space->machine().driver_data<dday_state>();

	//if (data & 0xac)  logerror("Control = %02X\n", data & 0xac);

	/* bit 0 is coin counter 1 */
	coin_counter_w(space->machine(), 0, data & 0x01);

	/* bit 1 is coin counter 2 */
	coin_counter_w(space->machine(), 1, data & 0x02);

	/* bit 4 is sound enable */
	if (!(data & 0x10) && (state->m_control & 0x10))
		state->m_ay1->reset();

	space->machine().sound().system_enable(data & 0x10);

	/* bit 6 is search light enable */
	state->m_sl_enable = data & 0x40;

	state->m_control = data;
}

/***************************************************************************

  Display refresh

***************************************************************************/

SCREEN_UPDATE( dday )
{
	dday_state *state = screen->machine().driver_data<dday_state>();

	tilemap_draw(state->m_main_bitmap, cliprect, state->m_bg_tilemap, TILEMAP_DRAW_LAYER1, 0);
	tilemap_draw(state->m_main_bitmap, cliprect, state->m_fg_tilemap, 0, 0);
	tilemap_draw(state->m_main_bitmap, cliprect, state->m_bg_tilemap, TILEMAP_DRAW_LAYER0, 0);
	tilemap_draw(state->m_main_bitmap, cliprect, state->m_text_tilemap, 0, 0);

	if (state->m_sl_enable)
	{
		/* apply shadow */
		int x, y;

		bitmap_t *sl_bitmap = tilemap_get_pixmap(state->m_sl_tilemap);

		for (x = cliprect->min_x; x <= cliprect->max_x; x++)
			for (y = cliprect->min_y; y <= cliprect->max_y; y++)
			{
				UINT16 src_pixel = *BITMAP_ADDR16(state->m_main_bitmap, y, x);

				if (*BITMAP_ADDR16(sl_bitmap, y, x) == 0xff)
					src_pixel += screen->machine().total_colors();

				*BITMAP_ADDR16(bitmap, y, x) = src_pixel;
			}
	}
	else
		copybitmap(bitmap, state->m_main_bitmap, 0, 0, 0, 0, cliprect);

	return 0;
}
