/***************************************************************************
  Psychic 5

  Functions to emulate the video hardware of the machine.

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

#include "driver.h"
#include "jalblend.c"

#define	BG_SCROLLX_LSB		0x308
#define	BG_SCROLLX_MSB		0x309
#define	BG_SCROLLY_LSB		0x30a
#define	BG_SCROLLY_MSB		0x30b
#define	BG_SCREEN_MODE		0x30c
#define	BG_PAL_INTENSITY_RG	0x1fe
#define	BG_PAL_INTENSITY_BU	0x1ff

static int ps5_vram_page;
static int bg_clip_mode;
static int title_screen;

/* Paged RAM 0 */
static UINT8 *psychic5_bg_videoram;
static UINT8 *ps5_dummy_bg_ram;

/* Paged RAM 1 */
static UINT8 *ps5_io_ram;
static UINT8 *ps5_palette_ram;
static UINT8 *psychic5_fg_videoram;

static tilemap *bg_tilemap, *fg_tilemap;

MACHINE_RESET( psychic5 )
{
	bg_clip_mode = -10;
	flip_screen_set(0);
}

WRITE8_HANDLER( psychic5_vram_page_select_w )
{
	ps5_vram_page = data;
}

READ8_HANDLER( psychic5_vram_page_select_r )
{
	return ps5_vram_page;
}

WRITE8_HANDLER( psychic5_title_screen_w )
{
	title_screen = data & 0x01;
}

void psychic5_paletteram_w(int color_offs, int offset, int data)
{
	int r,g,b,a,val;

	ps5_palette_ram[offset] = data;

	/* red component */
	val  = (ps5_palette_ram[offset & ~1] >> 4) & 0x0f ;
	r = (val << 4) | val ;

	/* green component */
	val  = (ps5_palette_ram[offset & ~1]) & 0x0f ;
	g = (val << 4) | val ;

	/* blue component */
	val  = (ps5_palette_ram[offset | 1] >> 4) & 0x0f ;
	b = (val << 4) | val ;

	/* "alpha" component */
	val  = (ps5_palette_ram[offset | 1] & 0x0f) & 0x0f ;
	a = (val << 4) | val ;

	jal_blend_table[(offset / 2)-color_offs] = a ;

	palette_set_color((offset / 2)-color_offs,r,g,b);
}

static void set_background_palette_intensity(void)
{
	int i,r,g,b,val,lo,hi,ir,ig,ib,ix;

	/* red,green,blue intensites */
	ir = ps5_palette_ram[BG_PAL_INTENSITY_RG] >> 4 ;  ir = (ir << 4) | ir ;
	ig = ps5_palette_ram[BG_PAL_INTENSITY_RG] & 15 ;  ig = (ig << 4) | ig ;
	ib = ps5_palette_ram[BG_PAL_INTENSITY_BU] >> 4 ;  ib = (ib << 4) | ib ;
	ix = ps5_palette_ram[0x1ff] & 0x0f ;

	/* for all of the background palette */
	for (i = 0; i < 0x100; i++)
	{
		lo = ps5_palette_ram[0x400+i*2];
		hi = ps5_palette_ram[0x400+i*2+1];

		/* red component */
		val  = (lo  >> 4) & 0x0f;
		r = (val << 4) | val ;

		/* green component */
		val  = (lo  & 15) & 0x0f;
		g = (val << 4) | val ;

		/* blue component */
		val =  (hi  >> 4) & 0x0f;
		b = (val << 4) | val ;

		/* Grey background enable */
		if (ps5_io_ram[BG_SCREEN_MODE] & 0x02)
		{
			val = (UINT8)((r + g + b) / 3);		/* Grey */

			if (ix != 0x0)						/* Tint the grey */
			{
				UINT32 result = jal_blend_func(MAKE_RGB(val,val,val), MAKE_RGB(ir, ig, ib), jal_blend_table[0xff]) ;
				palette_set_color(0x100+i, RGB_RED(result), RGB_GREEN(result), RGB_BLUE(result)) ;
			}
			else								/* Just leave plain grey */
			{
				palette_set_color(0x100+i,val,val,val);
			}
		}
		else
		{
			/* Seems fishy, but the title screen would be black otherwise... */
			if (!title_screen)
			{
				if (ix != 0x0)		/* Tint the world */
				{
					UINT32 result = jal_blend_func(MAKE_RGB(r, g, b), MAKE_RGB(ir, ig, ib), jal_blend_table[0xff]) ;
					palette_set_color(0x100+i, RGB_RED(result), RGB_GREEN(result), RGB_BLUE(result)) ;
				}
				else				/* Leave the world as-is */
				{
					palette_set_color(0x100+i,r,g,b) ;
				}
			}
		}
	}
}


WRITE8_HANDLER( psychic5_bg_videoram_w )
{
	if (psychic5_bg_videoram[offset] != data)
	{
		psychic5_bg_videoram[offset] = data;
		tilemap_mark_tile_dirty(bg_tilemap, offset / 2);
	}
}

WRITE8_HANDLER( psychic5_fg_videoram_w )
{
	if (psychic5_fg_videoram[offset] != data)
	{
		psychic5_fg_videoram[offset] = data;
		tilemap_mark_tile_dirty(fg_tilemap, offset / 2);
	}
}

READ8_HANDLER( psychic5_paged_ram_r )
{
	int val;

	if (!ps5_vram_page)
	{
		if (offset < 0x1000)
			return psychic5_bg_videoram[offset];
		else
			return ps5_dummy_bg_ram[offset & 0xfff];
	}
	else
	{
		if (offset < 0x400)
		{
			val = 0;
			switch(offset)
			{
				case 0x00:
					val = input_port_0_r(0);
					break;
				case 0x01:
					val = input_port_1_r(0);
					break;
				case 0x02:
					val = input_port_2_r(0);
					break;
				case 0x03:
					val = input_port_3_r(0);
					break;
				case 0x04:
					val = input_port_4_r(0);
					break;
				default:
					val = ps5_io_ram[offset];
			}
			return (val);
		}
		else if (offset < 0x1000)
		{
			return ps5_palette_ram[offset-0x400];
		}
		else
		{
			return psychic5_fg_videoram[offset & 0xfff];
		}
	}
	return 0;
}

WRITE8_HANDLER( psychic5_paged_ram_w )
{
	if (!ps5_vram_page)
	{
		if (offset < 0x1000)
			psychic5_bg_videoram_w(offset,data);
		else
			ps5_dummy_bg_ram[offset & 0xfff] = data;
	}
	else
	{
		if (offset < 0x400)
		{
			ps5_io_ram[offset] = data;
		}
		else if (offset < 0x600)
		{
			psychic5_paletteram_w(000, offset-0x400, data);
		}
		else if (offset > 0x5ff && offset< 0x800)
		{
			ps5_palette_ram[offset-0x400] = data;
		}
		else if (offset > 0x7ff && offset < 0xa00)
		{
			psychic5_paletteram_w(256, offset-0x400, data);
		}
		else if (offset > 0x9ff && offset < 0xc00)
		{
			psychic5_paletteram_w(256, offset-0x400, data);
		}
		else if (offset < 0x1000)
		{
			ps5_palette_ram[offset-0x400] = data;
		}
		else
		{
			psychic5_fg_videoram_w(offset & 0xfff, data);
		}
	}
}

static void get_bg_tile_info(int tile_index)
{
	int offs = tile_index * 2;
	int attr = psychic5_bg_videoram[offs + 1];
	int code = psychic5_bg_videoram[offs] + ((attr & 0xc0) << 2);
	int color = attr & 0x0f;
	int flags = ((attr & 0x10) ? TILE_FLIPX : 0) + ((attr & 0x20) ? TILE_FLIPY : 0);

	SET_TILE_INFO(1, code, color, flags)
}

static void get_fg_tile_info(int tile_index)
{
	int offs = tile_index * 2;
	int attr = psychic5_fg_videoram[offs + 1];
	int code = psychic5_fg_videoram[offs] + ((attr & 0xc0) << 2);
	int color = attr & 0x0f;
	int flags = ((attr & 0x10) ? TILE_FLIPX : 0) + ((attr & 0x20) ? TILE_FLIPY : 0);

	SET_TILE_INFO(2, code, color, flags)
}

VIDEO_START( psychic5 )
{
	psychic5_bg_videoram = auto_malloc(0x1000);
	psychic5_fg_videoram = auto_malloc(0x1000);
	ps5_dummy_bg_ram = auto_malloc(0x1000);
	ps5_io_ram = auto_malloc(0x400);
	ps5_palette_ram = auto_malloc(0xc00);
	jal_blend_table = auto_malloc(0xc00);

	memset(psychic5_bg_videoram, 0,0x1000);
	memset(psychic5_fg_videoram,0,0x1000);
	memset(ps5_dummy_bg_ram,0,0x1000);
	memset(ps5_io_ram,0,0x400);
	memset(ps5_palette_ram,0,0xc00);
	memset(jal_blend_table,0,0xc00) ;

	bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_cols,
		TILEMAP_OPAQUE, 16, 16, 64, 32);

	if ( !bg_tilemap )
		return 1;

	fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_cols,
		TILEMAP_TRANSPARENT, 8, 8, 32, 32);

	if ( !fg_tilemap )
		return 1;

	tilemap_set_transparent_pen(fg_tilemap, 15);

    return 0;
}

#define DRAW_SPRITE(code, sx, sy) jal_blend_drawgfx(bitmap, Machine->gfx[0], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 15);
/* #define DRAW_SPRITE(code, sx, sy) drawgfx(bitmap, Machine->gfx[0], code, color, flipx, flipy, sx, sy, cliprect, TRANSPARENCY_PEN, 15); */

void psychic5_draw_sprites( mame_bitmap *bitmap, const rectangle *cliprect )
{
	int offs;

	if (title_screen)
		return;
	else
		bg_clip_mode = -10;

	for (offs = 11; offs < spriteram_size; offs += 16)
	{
		int tileofs0, tileofs1, tileofs2, tileofs3, temp1, temp2;
		int attr = spriteram[offs + 2];
		int code = spriteram[offs + 3] + ((attr & 0xc0) << 2);
		int color = spriteram[offs + 4] & 0x0f;
		int flipx = attr & 0x10;
		int flipy = attr & 0x20;
		int sx = spriteram[offs + 1];
		int sy = spriteram[offs];
		int size32 = attr & 0x08;

		if (attr & 0x01) sx -= 256;
		if (attr & 0x04) sy -= 256;

		if (flip_screen)
		{
			sx = 224 - sx;
			sy = 224 - sy;
			flipx = !flipx;
			flipy = !flipy;
		}

		if (flipy)
		{
			tileofs0 = 1; tileofs1 = 0;	tileofs2 = 3; tileofs3 = 2;
		}
		else
		{
			tileofs0 = 0; tileofs1 = 1;	tileofs2 = 2; tileofs3 = 3;
		}

		if (flipx)
		{
			temp1 = tileofs0;
			temp2 = tileofs1;
			tileofs0 = tileofs2;
			tileofs1 = tileofs3;
			tileofs2 = temp1;
			tileofs3 = temp2;
		}

		if (size32)
		{
			DRAW_SPRITE(code + tileofs0, sx, sy)
			DRAW_SPRITE(code + tileofs1, sx, sy + 16)
			DRAW_SPRITE(code + tileofs2, sx + 16, sy)
			DRAW_SPRITE(code + tileofs3, sx + 16, sy + 16)
		}
		else
		{
			if (flip_screen)
				DRAW_SPRITE(code, sx + 16, sy + 16)
			else
				DRAW_SPRITE(code, sx, sy)
		}
	}
}

static void psychic5_draw_background( mame_bitmap *bitmap, const rectangle *cliprect )
{
	int bg_scrollx = (ps5_io_ram[BG_SCROLLX_LSB] + ((ps5_io_ram[BG_SCROLLX_MSB] & 0x03) << 8)) & 0x3ff;
	int bg_scrolly = (ps5_io_ram[BG_SCROLLY_LSB] + ((ps5_io_ram[BG_SCROLLY_MSB] & 0x01) << 8)) & 0x1ff;

	tilemap_set_scrollx(bg_tilemap, 0, bg_scrollx);
	tilemap_set_scrolly(bg_tilemap, 0, bg_scrolly);

	set_background_palette_intensity();

	if (ps5_io_ram[BG_SCREEN_MODE] & 0x01)  /* background enable */
	{
		if (title_screen)
		{
			rectangle clip = *cliprect;

			int sx1 = spriteram[12];		/* sprite 0 */
			int sy1 = spriteram[11];
			int tile = spriteram[14];
			int sy2 = spriteram[11+128];	/* sprite 8 */

			if (bg_clip_mode >=0 && bg_clip_mode < 3 && sy1==240) bg_clip_mode = 0;
			if (bg_clip_mode > 2 && bg_clip_mode < 5 && sy2==240) bg_clip_mode = -10;
			if (bg_clip_mode > 4 && bg_clip_mode < 7 && sx1==240) bg_clip_mode = 0;
			if (bg_clip_mode > 6 && bg_clip_mode < 9 && (sx1==240 || sx1==0)) bg_clip_mode = -10;

			if (sy1!=240 && sy1!=0 && bg_clip_mode<=0)
			{
				if (sy1 > 128)
					bg_clip_mode = 1;
				else
					bg_clip_mode = 2;
			}

			if (sy2!=240 && sy2!=0 && bg_clip_mode<=0)
			{
				if (sy2 > 128)
					bg_clip_mode = 3;
				else
					bg_clip_mode = 4;
			}

			if (sx1!=240 && sx1!=0 && bg_clip_mode<=0 && tile==0x3c)
			{
				if (sx1 > 128)
					bg_clip_mode = 5;
				else
					bg_clip_mode = 6;
			}

			if (sx1!=240 && sx1!=0 && bg_clip_mode<=0 && tile==0x1c)
			{
				if (sx1 > 128)
					bg_clip_mode = 7;
				else
					bg_clip_mode = 8;
			}

			if (bg_clip_mode)
			{
				if (bg_clip_mode == 1)
					clip.min_y = sy1;
				else if (bg_clip_mode == 2)
 					clip.max_y = sy1;
				else if (bg_clip_mode == 3)
					clip.max_y = sy2;
				else if (bg_clip_mode == 4)
					clip.min_y = sy2;
				else if (bg_clip_mode == 5)
					clip.min_x = sx1;
				else if (bg_clip_mode == 6)
 					clip.max_x = sx1;
				else if (bg_clip_mode == 7)
					clip.max_x = sx1;
				else if (bg_clip_mode == 8)
					clip.min_x = sx1;
				else if (bg_clip_mode == -10)
				{
					clip.min_x = 0;
					clip.min_y = 0;
					clip.max_x = 0;
					clip.max_y = 0;
				}

				fillbitmap(bitmap, get_black_pen(), cliprect);
				tilemap_draw(bitmap, &clip, bg_tilemap, 0, 0);
			}
			else
				tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
		}
		else
			tilemap_draw(bitmap, cliprect, bg_tilemap, 0, 0);
	}
	else
		fillbitmap(bitmap, get_black_pen(), cliprect);
}

VIDEO_UPDATE( psychic5 )
{
	psychic5_draw_background(bitmap, cliprect);
	psychic5_draw_sprites(bitmap, cliprect);
	tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0);
}
