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

  vidhrdw.c

  Functions to emulate the video hardware of the machine.

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

#include "driver.h"
#include "vidhrdw/generic.h"
#include "artwork.h"

static int use_tmpbitmap;
static data_t screen_red;
static int screen_red_enabled;		/* 1 for games that can turn the screen red */
static data_t color_map_select;
static int background_color;

static int overlay_type;	/* 0=none, 1=geometric, 2=file */
static const void *init_overlay;

static mem_write_handler videoram_w_p;
static void (*vh_screenrefresh_p)(struct osd_bitmap *bitmap,int full_refresh);
static void (*plot_pixel_p)(int x, int y, int col);

static WRITE_HANDLER( bw_videoram_w );
static WRITE_HANDLER( schaser_videoram_w );
static WRITE_HANDLER( lupin3_videoram_w );
static WRITE_HANDLER( polaris_videoram_w );
static WRITE_HANDLER( invadpt2_videoram_w );
static WRITE_HANDLER( astinvad_videoram_w );
static WRITE_HANDLER( spaceint_videoram_w );
static WRITE_HANDLER( helifire_videoram_w );

static void vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh);
static void seawolf_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh);
static void blueshrk_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh);
static void desertgu_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh);
static void phantom2_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh);

static void plot_pixel_8080 (int x, int y, int col);
static void plot_pixel_8080_tmpbitmap (int x, int y, int col);

/* smoothed pure colors, overlays are not so contrasted */

#define RED				0xff,0x20,0x20,OVERLAY_DEFAULT_OPACITY
#define GREEN 			0x20,0xff,0x20,OVERLAY_DEFAULT_OPACITY
#define YELLOW			0xff,0xff,0x20,OVERLAY_DEFAULT_OPACITY
#define CYAN			0x20,0xff,0xff,OVERLAY_DEFAULT_OPACITY

#define	END  {{ -1, -1, -1, -1}, 0,0,0,0}


static const struct artwork_element invaders_overlay[]=
{
	{{  16,  71,   0, 255}, GREEN },
	{{   0,  15,  16, 133}, GREEN },
	{{ 192, 223,   0, 255}, RED   },
	END
};

//static const struct artwork_element invdpt2m_overlay[]=
//{
//	{{  16,  71,   0, 255}, GREEN  },
//	{{   0,  15,  16, 133}, GREEN  },
//	{{  72, 191,   0, 255}, YELLOW },
//	{{ 192, 223,   0, 255}, RED    },
//	END
//};

static const struct artwork_element invrvnge_overlay[]=
{
	{{   0,  71,   0, 255}, GREEN },
	{{ 192, 223,   0, 255}, RED   },
	END
};

static const struct artwork_element invad2ct_overlay[]=
{
	{{	 0,  47,   0, 255}, YELLOW },
	{{	25,  70,   0, 255}, GREEN  },
	{{	48, 139,   0, 255}, CYAN   },
	{{ 117, 185,   0, 255}, GREEN  },
	{{ 163, 231,   0, 255}, YELLOW },
	{{ 209, 255,   0, 255}, RED    },
	END
};


void init_8080bw(void)
{
	videoram_w_p = bw_videoram_w;
	vh_screenrefresh_p = vh_screenrefresh;
	use_tmpbitmap = 0;
	screen_red = 0;
	screen_red_enabled = 0;
	overlay_type = 0;
	color_map_select = 0;
	flip_screen_w(0,0);
}

void init_invaders(void)
{
	init_8080bw();
	init_overlay = invaders_overlay;
	overlay_type = 1;
}

void init_invaddlx(void)
{
	init_8080bw();
	//init_overlay = invdpt2m_overlay;
	//overlay_type = 1;
}

void init_invrvnge(void)
{
	init_8080bw();
	init_overlay = invrvnge_overlay;
	overlay_type = 1;
}

void init_invad2ct(void)
{
	init_8080bw();
	init_overlay = invad2ct_overlay;
	overlay_type = 1;
}

void init_schaser(void)
{
	init_8080bw();
	videoram_w_p = schaser_videoram_w;
	background_color = 2;	/* blue */
}

void init_rollingc(void)
{
	init_8080bw();
	videoram_w_p = schaser_videoram_w;
	background_color = 0;	/* black */
}

void init_helifire(void)
{
	init_8080bw();
	videoram_w_p = helifire_videoram_w;
}

void init_polaris(void)
{
	init_8080bw();
	videoram_w_p = polaris_videoram_w;
}

void init_lupin3(void)
{
	init_8080bw();
	videoram_w_p = lupin3_videoram_w;
	background_color = 0;	/* black */
}

void init_invadpt2(void)
{
	init_8080bw();
	videoram_w_p = invadpt2_videoram_w;
	screen_red_enabled = 1;
}

void init_seawolf(void)
{
	init_8080bw();
	vh_screenrefresh_p = seawolf_vh_screenrefresh;
	use_tmpbitmap = 1;
}

void init_blueshrk(void)
{
	init_8080bw();
	vh_screenrefresh_p = blueshrk_vh_screenrefresh;
	use_tmpbitmap = 1;
}

void init_desertgu(void)
{
	init_8080bw();
	vh_screenrefresh_p = desertgu_vh_screenrefresh;
	use_tmpbitmap = 1;
}

void init_astinvad(void)
{
	init_8080bw();
	videoram_w_p = astinvad_videoram_w;
	screen_red_enabled = 1;
}

void init_spaceint(void)
{
	init_8080bw();
	videoram_w_p = spaceint_videoram_w;
}

void init_spcenctr(void)
{
	extern struct GameDriver driver_spcenctr;

	init_8080bw();
	init_overlay = driver_spcenctr.name;
	overlay_type = 2;
}

void init_phantom2(void)
{
	init_8080bw();
	vh_screenrefresh_p = phantom2_vh_screenrefresh;
	use_tmpbitmap = 1;
}


int invaders_vh_start(void)
{
	/* create overlay if one of was specified in init_X */
	if (overlay_type)
	{
		int start_pen;
		int max_pens;


		start_pen = 2;
		max_pens = Machine->drv->total_colors-start_pen;

		if (overlay_type == 1)
			overlay_create((const struct artwork_element *)init_overlay, start_pen, max_pens);
		else
			overlay_load((const char *)init_overlay, start_pen, max_pens);
	}

	if (use_tmpbitmap && (generic_bitmapped_vh_start() != 0))
		return 1;

	if (use_tmpbitmap)
	{
		plot_pixel_p = plot_pixel_8080_tmpbitmap;
	}
	else
	{
		plot_pixel_p = plot_pixel_8080;
	}

	/* make sure that the screen matches the videoram, this fixes invad2ct */
	//schedule_full_refresh();

	return 0;
}


void invaders_vh_stop(void)
{
	if (use_tmpbitmap)  generic_bitmapped_vh_stop();
}


void invaders_flip_screen_w(int data)
{
	set_vh_global_attribute(&color_map_select, data);

	if (input_port_3_r(0) & 0x01)
	{
		flip_screen_w(0, data);
	}
}


void invaders_screen_red_w(int data)
{
	if (screen_red_enabled)
	{
		set_vh_global_attribute(&screen_red, data);
	}
}


static void plot_pixel_8080 (int x, int y, int col)
{
	if (flip_screen)
	{
		x = 255-x;
		y = 223-y;
	}

	plot_pixel(Machine->scrbitmap,x,y,Machine->pens[col]);
}

static void plot_pixel_8080_tmpbitmap (int x, int y, int col)
{
	if (flip_screen)
	{
		x = 255-x;
		y = 223-y;
	}

	plot_pixel(tmpbitmap,x,y,Machine->pens[col]);
}

static INLINE void plot_byte(int x, int y, int data, int fore_color, int back_color)
{
	int i;

	for (i = 0; i < 8; i++)
	{
		plot_pixel_p (x, y, (data & 0x01) ? fore_color : back_color);

		x++;
		data >>= 1;
	}
}


WRITE_HANDLER( invaders_videoram_w )
{
	videoram_w_p(offset, data);
}


static WRITE_HANDLER( bw_videoram_w )
{
	int x,y;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	plot_byte(x, y, data, 1, 0);
}

static WRITE_HANDLER( schaser_videoram_w )
{
	int x,y,col;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	col = colorram[offset & 0x1f1f] & 0x07;

	plot_byte(x, y, data, col, background_color);
}

static WRITE_HANDLER( lupin3_videoram_w )
{
	int x,y,col;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	col = ~colorram[offset & 0x1f1f] & 0x07;

	plot_byte(x, y, data, col, background_color);
}

static WRITE_HANDLER( polaris_videoram_w )
{
	int x,y,back_color,foreground_color;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	/* for the background color, bit 0 if the map PROM is connected to blue gun.
	   red is 0 */

	back_color = (memory_region(REGION_PROMS)[(((y+32)/8)*32) + (x/8)] & 1) ? 6 : 4;
	foreground_color = ~colorram[offset & 0x1f1f] & 0x07;

	plot_byte(x, y, data, foreground_color, back_color);
}

static WRITE_HANDLER( helifire_videoram_w )
{
	int x,y,back_color,foreground_color;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	back_color = 0;
	foreground_color = colorram[offset] & 0x07;

	if (x < 0x78)
	{
		back_color = 4;	/* blue */
	}

	plot_byte(x, y, data, foreground_color, back_color);
}


WRITE_HANDLER( schaser_colorram_w )
{
	int i;


	offset &= 0x1f1f;

	colorram[offset] = data;

	/* redraw region with (possibly) changed color */
	for (i = 0; i < 8; i++, offset += 0x20)
	{
		videoram_w_p(offset, videoram[offset]);
	}
}

READ_HANDLER( schaser_colorram_r )
{
	return colorram[offset & 0x1f1f];
}


WRITE_HANDLER( helifire_colorram_w )
{
	colorram[offset] = data;

	/* redraw region with (possibly) changed color */
	videoram_w_p(offset, videoram[offset]);
}


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

  Draw the game screen in the given osd_bitmap.
  Do NOT call osd_update_display() from this function, it will be called by
  the main emulation engine.

***************************************************************************/
void invaders_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	vh_screenrefresh_p(bitmap, full_refresh);
}


static void vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	if (palette_recalc() || full_refresh)
	{
		int offs;

		for (offs = 0;offs < videoram_size;offs++)
			videoram_w_p(offs, videoram[offs]);
	}


	if (use_tmpbitmap)
		copybitmap(bitmap,tmpbitmap,0,0,0,0,&Machine->visible_area,TRANSPARENCY_NONE,0);
}


static void draw_sight(int x_center, int y_center)
{
	int x,y;


    if (x_center<2)   x_center=2;
    if (x_center>253) x_center=253;

    if (y_center<2)   y_center=2;
    if (y_center>253) y_center=253;

	for(y = y_center-10; y < y_center+11; y++)
		if((y >= 0) && (y < 256))
			plot_pixel_8080(x_center,y,1);

	for(x = x_center-20; x < x_center+21; x++)
		if((x >= 0) && (x < 256))
			plot_pixel_8080(x,y_center,1);
}


static void seawolf_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	/* update the bitmap (and erase old cross) */
	vh_screenrefresh(bitmap, full_refresh);

    draw_sight(((input_port_0_r(0) & 0x1f) * 8) + 4, 31);
}

static void blueshrk_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	/* update the bitmap (and erase old cross) */
	vh_screenrefresh(bitmap, full_refresh);

    draw_sight(((input_port_0_r(0) & 0x7f) * 2) - 12, 31);
}

static void desertgu_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	/* update the bitmap (and erase old cross) */
	vh_screenrefresh(bitmap, full_refresh);

	draw_sight(((input_port_0_r(0) & 0x7f) * 2) - 30,
			   ((input_port_2_r(0) & 0x7f) * 2) - 30);
}

static void phantom2_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
{
	unsigned char *clouds;
	int x, y;


	/* update the bitmap */
	vh_screenrefresh(bitmap, full_refresh);


	/* draw the clouds */
	clouds = memory_region(REGION_PROMS);

	for (y = 0; y < 128; y++)
	{
		unsigned char *offs = &memory_region(REGION_PROMS)[y * 0x10];

		for (x = 0; x < 128; x++)
		{
			if (offs[x >> 3] & (1 << (x & 0x07)))
			{
				plot_pixel_8080(x*2,   y*2,   1);
				plot_pixel_8080(x*2+1, y*2,   1);
				plot_pixel_8080(x*2,   y*2+1, 1);
				plot_pixel_8080(x*2+1, y*2+1, 1);
			}
		}
	}
}


void invadpt2_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable,const unsigned char *color_prom)
{
	int i;


	for (i = 0;i < Machine->drv->total_colors;i++)
	{
		/* this bit arrangment is a little unusual but are confirmed by screen shots */

		*(palette++) = 0xff * ((i >> 0) & 1);
		*(palette++) = 0xff * ((i >> 2) & 1);
		*(palette++) = 0xff * ((i >> 1) & 1);
	}
}

void helifire_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable,const unsigned char *color_prom)
{
	int i;


	for (i = 0;i < Machine->drv->total_colors;i++)
	{
		*(palette++) = 0xff * ((i >> 0) & 1);
		*(palette++) = 0xff * ((i >> 1) & 1);
		*(palette++) = 0xff * ((i >> 2) & 1);
	}
}


static WRITE_HANDLER( invadpt2_videoram_w )
{
	int x,y,col;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	/* 32 x 32 colormap */
	if (!screen_red)
		col = memory_region(REGION_PROMS)[(color_map_select ? 0x400 : 0 ) + (((y+32)/8)*32) + (x/8)] & 7;
	else
		col = 1;	/* red */

	plot_byte(x, y, data, col, 0);
}

static WRITE_HANDLER( astinvad_videoram_w )
{
	int x,y,col;

	videoram[offset] = data;

	y = offset / 32;
	x = 8 * (offset % 32);

	if (!screen_red)
	{
		if (flip_screen)
			col = memory_region(REGION_PROMS)[((y+32)/8)*32+(x/8)] >> 4;
		else
			col = memory_region(REGION_PROMS)[(31-y/8)*32+(31-x/8)] & 0x0f;
	}
	else
		col = 1; /* red */

	plot_byte(x, y, data, col, 0);
}

static WRITE_HANDLER( spaceint_videoram_w )
{
	int i,x,y,col;

	videoram[offset] = data;

	y = 8 * (offset / 256);
	x = offset % 256;

	/* this is wrong */
	col = memory_region(REGION_PROMS)[(y/16)+16*((x+16)/32)];

	for (i = 0; i < 8; i++)
	{
		plot_pixel_p(x, y, (data & 0x01) ? col : 0);

		y++;
		data >>= 1;
	}
}
