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

  vidhrdw.c

  Functions to emulate the video hardware of the machine.

  Convention: "sl" stands for "searchlight"

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

#include "driver.h"


unsigned char *dday_bgvideoram;
unsigned char *dday_fgvideoram;
unsigned char *dday_textvideoram;
unsigned char *dday_colorram;

static struct tilemap *fg_tilemap, *bg_tilemap, *text_tilemap, *sl_tilemap;
struct mame_bitmap *main_bitmap;
static int control;
static int sl_image;
static int sl_enable;
static int timer_value;


/* 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. */

READ_HANDLER( dday_countdown_timer_r )
{
    return ((timer_value / 10) << 4) | (timer_value % 10);
}

static void countdown_timer_callback(int param)
{
	timer_value--;

	if (timer_value < 0)
	{
		timer_value = 99;
	}
}

static void start_countdown_timer(void)
{
	timer_value = 0;

	timer_pulse(TIME_IN_SEC(1), 0, countdown_timer_callback);
}


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

  Convert the color PROMs into a more useable format.

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

PALETTE_INIT( dday )
{
	int i;


	palette_set_shadow_factor(1.0/8);	/* this matches the previos version of the driver (>>3) */

	for (i = 0; i < Machine->drv->total_colors; i++)
	{
		int bit0,bit1,bit2,bit3,r,g,b;


		/* red component */
		bit0 = (color_prom[i] >> 0) & 0x01;
		bit1 = (color_prom[i] >> 1) & 0x01;
		bit2 = (color_prom[i] >> 2) & 0x01;
		bit3 = (color_prom[i] >> 3) & 0x01;
		r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
		/* green component */
		bit0 = (color_prom[i + Machine->drv->total_colors] >> 0) & 0x01;
		bit1 = (color_prom[i + Machine->drv->total_colors] >> 1) & 0x01;
		bit2 = (color_prom[i + Machine->drv->total_colors] >> 2) & 0x01;
		bit3 = (color_prom[i + Machine->drv->total_colors] >> 3) & 0x01;
		g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
		/* blue component */
		bit0 = (color_prom[i + 2*Machine->drv->total_colors] >> 0) & 0x01;
		bit1 = (color_prom[i + 2*Machine->drv->total_colors] >> 1) & 0x01;
		bit2 = (color_prom[i + 2*Machine->drv->total_colors] >> 2) & 0x01;
		bit3 = (color_prom[i + 2*Machine->drv->total_colors] >> 3) & 0x01;
		b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;

		palette_set_color(i,r,g,b);
	}


	/* HACK!!! This table is handgenerated, but it matches the screenshot.
	   I have no clue how it really works */

	colortable[0*8+0] = 0;
	colortable[0*8+1] = 1;
	colortable[0*8+2] = 21;
	colortable[0*8+3] = 2;
	colortable[0*8+4+0] = 0;
	colortable[0*8+4+1] = 1;
	colortable[0*8+4+2] = 21;
	colortable[0*8+4+3] = 2;

	colortable[1*8+0] = 4;
	colortable[1*8+1] = 5;
	colortable[1*8+2] = 3;
	colortable[1*8+3] = 7;
	colortable[1*8+4+0] = 4;
	colortable[1*8+4+1] = 5;
	colortable[1*8+4+2] = 3;
	colortable[1*8+4+3] = 7;

	colortable[2*8+0] = 8;
	colortable[2*8+1] = 21;
	colortable[2*8+2] = 10;
	colortable[2*8+3] = 3;
	colortable[2*8+4+0] = 8;
	colortable[2*8+4+1] = 21;
	colortable[2*8+4+2] = 10;
	colortable[2*8+4+3] = 3;

	colortable[3*8+0] = 8;
	colortable[3*8+1] = 21;
	colortable[3*8+2] = 10;
	colortable[3*8+3] = 3;
	colortable[3*8+4+0] = 8;
	colortable[3*8+4+1] = 21;
	colortable[3*8+4+2] = 10;
	colortable[3*8+4+3] = 3;

	colortable[4*8+0] = 16;
	colortable[4*8+1] = 17;
	colortable[4*8+2] = 18;
	colortable[4*8+3] = 7;
	colortable[4*8+4+0] = 16;
	colortable[4*8+4+1] = 17;
	colortable[4*8+4+2] = 18;
	colortable[4*8+4+3] = 7;

	colortable[5*8+0] = 29;
	colortable[5*8+1] = 21;
	colortable[5*8+2] = 22;
	colortable[5*8+3] = 27;
	colortable[5*8+4+0] = 29;
	colortable[5*8+4+1] = 21;
	colortable[5*8+4+2] = 22;
	colortable[5*8+4+3] = 27;

	colortable[6*8+0] = 29;
	colortable[6*8+1] = 21;
	colortable[6*8+2] = 26;
	colortable[6*8+3] = 27;
	colortable[6*8+4+0] = 29;
	colortable[6*8+4+1] = 21;
	colortable[6*8+4+2] = 26;
	colortable[6*8+4+3] = 27;

	colortable[7*8+0] = 29;
	colortable[7*8+1] = 2;
	colortable[7*8+2] = 4;
	colortable[7*8+3] = 27;
	colortable[7*8+4+0] = 29;
	colortable[7*8+4+1] = 2;
	colortable[7*8+4+2] = 4;
	colortable[7*8+4+3] = 27;
}


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

  Callbacks for the TileMap code

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

static void get_bg_tile_info(int tile_index)
{
	int code;

	code = dday_bgvideoram[tile_index];
	SET_TILE_INFO(0, code, code >> 5, 0);
}

static void get_fg_tile_info(int tile_index)
{
	int code, flipx;

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

static void get_text_tile_info(int tile_index)
{
	int code;

	code = dday_textvideoram[tile_index];
	SET_TILE_INFO(1, code, code >> 5, 0)
}

static void get_sl_tile_info(int tile_index)
{
	int code, sl_flipx, flipx;
	UINT8* sl_map;

	sl_map = &memory_region(REGION_USER1)[(sl_image & 0x07) * 0x0200];

	flipx = (tile_index >> 4) & 0x01;
	sl_flipx = (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)
	{
		if (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 )
{
	bg_tilemap   = tilemap_create(get_bg_tile_info,  tilemap_scan_rows,TILEMAP_SPLIT,8,8,32,32);
	fg_tilemap   = tilemap_create(get_fg_tile_info,  tilemap_scan_rows,TILEMAP_TRANSPARENT,8,8,32,32);
	text_tilemap = tilemap_create(get_text_tile_info,tilemap_scan_rows,TILEMAP_TRANSPARENT,8,8,32,32);
	sl_tilemap   = tilemap_create(get_sl_tile_info,  tilemap_scan_rows,TILEMAP_OPAQUE,8,8,32,32);

	main_bitmap = auto_bitmap_alloc(Machine->drv->screen_width,Machine->drv->screen_height);

	if (!bg_tilemap || !fg_tilemap || !text_tilemap || !sl_tilemap || !main_bitmap)
		return 1;

	tilemap_set_transmask(bg_tilemap,0,0x00f0,0xff0f); /* pens 0-3 have priority over the foreground layer */

	tilemap_set_transparent_pen(fg_tilemap, 0);

	tilemap_set_transparent_pen(text_tilemap, 0);

	control = 0;
	sl_enable = 0;
	sl_image = 0;

	start_countdown_timer();

	return 0;
}

WRITE_HANDLER( dday_bgvideoram_w )
{
	dday_bgvideoram[offset] = data;
	tilemap_mark_tile_dirty(bg_tilemap, offset);
}

WRITE_HANDLER( dday_fgvideoram_w )
{
	dday_fgvideoram[offset] = data;
	tilemap_mark_tile_dirty(fg_tilemap, offset);
	tilemap_mark_tile_dirty(fg_tilemap, offset ^ 0x1f);  /* for flipx case */
}

WRITE_HANDLER( dday_textvideoram_w )
{
	dday_textvideoram[offset] = data;
	tilemap_mark_tile_dirty(text_tilemap, offset);
}

WRITE_HANDLER( dday_colorram_w )
{
	int i;


	offset &= 0x03e0;

    dday_colorram[offset & 0x3e0] = data;

    for (i = 0; i < 0x20; i++)
    {
		tilemap_mark_tile_dirty(fg_tilemap, offset + i);
	}
}

READ_HANDLER( dday_colorram_r )
{
    return dday_colorram[offset & 0x03e0];
}


WRITE_HANDLER( dday_sl_control_w )
{
	if (sl_image != data)
	{
		sl_image = data;

		tilemap_mark_all_tiles_dirty(sl_tilemap);
	}
}


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

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

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

	/* bit 4 is sound enable */
	if (!(data & 0x10) && (control & 0x10))
	{
		AY8910_reset(0);
		AY8910_reset(1);
	}

	mixer_sound_enable_global_w(data & 0x10);

	/* bit 6 is search light enable */
	sl_enable = data & 0x40;

	control = data;
}

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

  Display refresh

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

VIDEO_UPDATE( dday )
{
	tilemap_draw(main_bitmap,cliprect,bg_tilemap,TILEMAP_BACK,0);
	tilemap_draw(main_bitmap,cliprect,fg_tilemap,0,0);
	tilemap_draw(main_bitmap,cliprect,bg_tilemap,TILEMAP_FRONT,0);
	tilemap_draw(main_bitmap,cliprect,text_tilemap,0,0);

	if (sl_enable)
	{
		/* apply shadow */

		struct mame_bitmap *sl_bitmap;
		int x, y;


		sl_bitmap = tilemap_get_pixmap(sl_tilemap);

		for (x = cliprect->min_x; x <= cliprect->max_x; x++)
		{
			for (y = cliprect->min_y; y <= cliprect->max_y; y++)
			{
				UINT32 src_pixel;


				src_pixel = read_pixel(main_bitmap, x, y);

				if (read_pixel(sl_bitmap, x, y) == 255)
				{
					src_pixel += Machine->drv->total_colors;
				}

				plot_pixel(bitmap, x, y, src_pixel);
			}
		}
	}
	else
	{
		copybitmap(bitmap,main_bitmap,0,0,0,0,cliprect,TRANSPARENCY_NONE,0);
	}
}
