#include "driver.h"
#include "vidhrdw/generic.h"
#include "cpu/z80/z80.h"
#include "snk.h"


int snk_bg_tilemap_baseaddr = 0;
int snk_blink_parity = 0;

#define MAX_VRAM_SIZE (64*64*2) /* 0x2000 */

#define IKARI_FLIP 0
/************************************************************************************/

VIDEO_START( aso )
{
	snk_blink_parity = 0;
	return 0;
}

VIDEO_START( sgladiat )
{
	dirtybuffer = auto_malloc( MAX_VRAM_SIZE );
	if(!dirtybuffer) return 1;
	tmpbitmap = auto_bitmap_alloc( 512, 256 );
	if(!tmpbitmap) return 1;
	memset( dirtybuffer, 0xff, MAX_VRAM_SIZE );
	return 0;
}

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

static void hal21_draw_background( struct mame_bitmap *bitmap, int scrollx, int scrolly, int attr, int mode, int flip )
{
	const struct GfxElement *gfx = Machine->gfx[1];
	struct rectangle *clip = &Machine->visible_area;
	int x, y;

	int offsx = scrollx>>3 & 0x3f;
	int offsy = scrolly>>3 & 0x3f;
	int dx = scrollx & 7;
	int dy = scrolly & 7;
	int bank, c = attr & 0x0f, color[2] = {8, 8};

	if(mode)
	{
		bank = attr<<4 & 0x300;
		if(c==7) c = 15;
	}
	else
	{
		bank = attr<<3 & 0x100;
		if(c>11) { fillbitmap(bitmap,Machine->pens[(c<<4)|8], clip); return; }
		if(c<8 || color[0]<14 || bank)
		{
			c ^= 0x8;
			color[0] = c;
			color[1] = (c & 0x8) ? c : 8;
		}
	}

	for(x=0; x<64; x++)
	{
		int sx = (x<<3)-dx;
		if(flip) sx = 0x100-sx; else sx += 16;
		sx &= 0x1ff;

		for(y=0; y<32; y++)
		{
			int offs = (((offsx+x)&0x3f)<<6)|((offsy+y)&0x1f);
			int tile = bank | videoram[offs];

			int sy = (y<<3)-dy;
			if(flip) sy = 0x100-sy; else sy += 8;
			sy &= 0x0ff;

			if(!mode) c = (tile & ~0x3f) ? color[0] : color[1];

			drawgfx(bitmap,gfx,tile,c,flip,flip,sx,sy,clip,TRANSPARENCY_NONE,0);
		}
	}
}


static void sgladiat_draw_background( struct mame_bitmap *bitmap, int scrollx, int scrolly, int flip )
{
	const struct GfxElement *gfx = Machine->gfx[1];
	struct rectangle *clip = &Machine->visible_area;
	int x, y;
	int sx,sy;

	for(x=0; x<64; x++)
	{
		sx = x<<3;
		if(flip) sx = 0x100-sx;
		sx &= 0x1ff;

		for(y=0; y<32; y++)
		{
			int offs = (x<<5)|y;
			int tile = videoram[offs];

//			if(tile != dirtybuffer[offs])
			{
//				dirtybuffer[offs] = tile;

				sy = y<<3;
				if(flip) sy = -sy;
				sy &= 0x0ff;

				drawgfx(tmpbitmap,gfx,tile,0,flip,flip,sx,sy,0,TRANSPARENCY_NONE,0);
			}
		}
	}
	if(!flip) {scrollx = 15-scrollx; scrolly = 8-scrolly;}
	copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,clip,TRANSPARENCY_NONE,0);
}


static void tnk3_draw_background( struct mame_bitmap *bitmap, int scrollx, int scrolly,
					int x_size, int y_size, int bg_type, int flip )
{
	const struct GfxElement *gfx = Machine->gfx[1];
	struct rectangle *clip = &Machine->visible_area;
	int x, y;
	int sx,sy;

	/* to be moved to memmap */
	videoram = &memory_region(REGION_CPU1)[snk_bg_tilemap_baseaddr];

	for(x=0; x<x_size; x++)
	{
		sx = x*(512/x_size);
		if(flip) sx = 0x100-sx;
		sx &= 0x1ff;

		for(y=0; y<y_size; y++)
		{
			int offs = (x*y_size+y)<<1;
			int attr = videoram[offs+1];
			int tile = videoram[offs];
			int color;

//			if(tile != dirtybuffer[offs] || attr != dirtybuffer[offs+1])
			{
//				dirtybuffer[offs+1] = attr;
//				dirtybuffer[offs]   = tile;

				if(bg_type == 0)
				{
					/* type tnk3 */
					tile |= attr<<4 & 0x300;
					color = (attr & 0xf)^8;
				}
				else
				{
					/* type ikari */
					tile |= attr<<8 & 0x300;
					color = attr>>4;
				}

				sy = y*(512/y_size);
				if(flip) sy = 0x100-sy;
				sy &= 0x1ff;

				drawgfx(tmpbitmap,gfx,tile,color,flip,flip,sx,sy,0,TRANSPARENCY_NONE,0);
			}
		}
	}
	if(!flip) {scrollx = 15-scrollx; scrolly = 8-scrolly;}
	copyscrollbitmap(bitmap,tmpbitmap,1,&scrollx,1,&scrolly,clip,TRANSPARENCY_NONE,0);
}

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

void tnk3_draw_sprites( struct mame_bitmap *bitmap, int scrollx, int scrolly,
				unsigned char *source, int size, int mode, int flip )
{
	struct GfxElement *gfx = Machine->gfx[(mode<4) ? 2:mode&3];
	struct rectangle *clip = &Machine->visible_area;
	UINT8 *sprptr = source, *endptr = sprptr + size;

	for(; sprptr<endptr; sprptr+=4)
	{
		if(*(UINT32*)sprptr == 0 || *(UINT32*)sprptr == -1) continue;

		{
			int attr = sprptr[3];
			int tile = sprptr[1];
			int sx = (sprptr[2]|(attr<<1 & 0x100))-scrollx;
			int sy = (sprptr[0]|(attr<<4 & 0x100))-scrolly;
			int fy = flip;

			if(mode==6) tile |= (attr<<3 & 0x300);
			else tile |= (attr<<2 & 0x100);

			sx = 256-sx;

			if(mode<4)
			{
				if(flip) {sx = 73-sx; sy = 254-sy;}
				else
				if(mode==1) sx += 1;

				if(mode==3)
				{
					tile |= (attr<<4 & 0x200);
					if(snk_gamegroup == 0) sx += 2;	//tnk3
				}
				else if(mode==2) fy ^= attr>>5 & 1;
				else tile |= (~attr<<4 & 0x200);
			}
#if IKARI_FLIP
			else
			if(mode==6)
			{
				if(flip) {sx = 272-sx; sy = 216-sy;}
			}
			else
//			if(mode==7)
			{
				if(flip) {sx = 256-sx; sy = 200-sy;}
			}
#endif

			sx &= 0x1ff; if(sx > 512-16) sx -= 512;
			if(mode) {sy &= 0x1ff; if(sy > 512-16) sy -= 512;}
			else     {sy &= 0x0ff; if(sy > 256-16) sy -= 256;}

			drawgfx(bitmap,gfx,tile,attr & 0x0f,flip,fy,sx,sy,clip,
				(mode == 2) ? TRANSPARENCY_PEN:TRANSPARENCY_PEN_TABLE,7);
		}
	}
}

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

void tnk3_draw_text( struct mame_bitmap *bitmap, int bank, unsigned char *source, int mode, int flip )
{
	const struct GfxElement *gfx = Machine->gfx[0];
	struct rectangle *clip = &Machine->visible_area;
	int x, y;
	int sx,sy;

	for(x=0; x<32+mode; x++)
	{
		sx = (x+2)<<3;
		if(x>33) sx -= 36*8;
		if(flip) sx = 35*8-sx;

		for(y=0; y<27; y++)
		{
			int color;
			int tile;
			if(x>33) tile = source[((x+28)<<5)|y];
			else     tile = source[(x<<5)|y];

			if(x<32) if(tile == 0x20 || tile == 0xff) continue;

			if(bank == -1) color = 8;
			else
			{
				color = tile>>5;
				tile |= bank<<8;
			}

			sy = (y+1)<<3;
			if(flip) sy = 28*8-sy;

			if(x<32)
				drawgfx(bitmap,gfx,tile,color,flip,flip,sx,sy,clip,TRANSPARENCY_PEN,15);
			else
				drawgfx(bitmap,gfx,tile,color,flip,flip,sx,sy,clip,TRANSPARENCY_NONE,0);
		}
	}
}

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

VIDEO_UPDATE( aso )
{
	UINT8 *ram = memory_region(REGION_CPU1);
	int attr = (int)hal21_vreg[0];
	int msbs = (int)hal21_vreg[1];
	int spsy = (int)hal21_vreg[2];
	int spsx = (int)hal21_vreg[3];
	int bgsy = (int)hal21_vreg[4];
	int bgsx = (int)hal21_vreg[5];
	int flip;

	if(snk_gamegroup)
	{
		flip = ((readinputport(4) & 0x20) == 0);
		bgsx |= msbs<<7 & 0x100;
		bgsy |= msbs<<4 & 0x100;
		hal21_draw_background(bitmap, bgsx, bgsy, attr, 0, flip);

		attr = snk_blink_parity;
		snk_blink_parity ^= 0xdf;
		{
			int i;
			for(i=6; i<0x80; i+=8) palette_set_color(i, attr, attr, attr);
		}

		spsx |= msbs<<8 & 0x100;
		spsy |= msbs<<5 & 0x100;
		tnk3_draw_sprites(bitmap, spsx+29, spsy+9, spriteram, 0x100, 2, flip);
	}
	else
	{
		flip = msbs>>5 & 1;	// flip?
		bgsx |= ~msbs<<7 & 0x100;
		bgsy |= msbs<<4 & 0x100;
		hal21_draw_background(bitmap, bgsx, bgsy, attr, 1, flip);
		spsx |= msbs<<8 & 0x100;
		spsy |= msbs<<5 & 0x100;
		tnk3_draw_sprites(bitmap, spsx+29, spsy+9, spriteram, 60*4, 1, flip);
	}

	tnk3_draw_text(bitmap, msbs>>6 & 1, &ram[0xf800], 4, flip);
}

VIDEO_UPDATE( sgladiat )
{
	UINT8 *ram = memory_region(REGION_CPU1);
	int scrollx, scrolly,attributes = ram[0xd300];
	int flip = ((readinputport(4) & 0x20) == 0);

	scrollx = ram[0xd700]|(attributes<<7 & 0x100);
	scrolly = ram[0xd600];
	sgladiat_draw_background( bitmap, scrollx, scrolly, flip );
	scrollx = ram[0xd500]|(attributes<<8 & 0x100);
	scrolly = ram[0xd400];
	tnk3_draw_sprites(bitmap, scrollx+29, scrolly+9, spriteram, 50*4, 0, flip);
	tnk3_draw_text( bitmap, 0, &ram[0xf000], 0, flip );
}

VIDEO_UPDATE( tnk3 )
{
	UINT8 *ram = memory_region(REGION_CPU1);
	int scrollx,scrolly,attributes = ram[0xc800];
	int flip = attributes>>7 & 1;	// flip?

	/*
		X-------
		-X------	character bank (for text layer)
		--X-----
		---X----	scrolly MSB (background)
		----X---	scrolly MSB (sprites)
		-----X--
		------X-	scrollx MSB (background)
		-------X	scrollx MSB (sprites)
	*/

	/* to be moved to memmap */
	spriteram = &ram[0xd000];

	scrollx = ram[0xcc00]|(attributes<<7 & 0x100);
	scrolly = ram[0xcb00]|(attributes<<4 & 0x100);
	tnk3_draw_background( bitmap, scrollx, scrolly, 64, 64, 0, flip );
	scrollx = ram[0xca00]|(attributes<<8 & 0x100);
	scrolly = ram[0xc900]|(attributes<<5 & 0x100);
	tnk3_draw_sprites( bitmap, scrollx+29, scrolly+9, spriteram, 50*4, 3, flip );
	tnk3_draw_text( bitmap, attributes>>6 & 1, &ram[0xf800], 4, flip );
}

VIDEO_UPDATE( ikari )
{
	unsigned char *ram = memory_region(REGION_CPU1);
#if IKARI_FLIP
	int flip = ((readinputport(5) & 0x80) == 0); //fake
#else
	int flip = 0;
#endif

	{
		int attributes = ram[0xc900];
		int scrollx = ram[0xc880]|(attributes<<7 & 0x100);
		int scrolly = ram[0xc800]|(attributes<<8 & 0x100);
#if IKARI_FLIP
		if(flip) scrolly -= 48;
#endif
		tnk3_draw_background( bitmap, scrollx, scrolly, 32, 32, 1, flip );
	}

	{
		int attributes   = ram[0xcd00];
		int sp16_scrollx = ram[0xca80]|(attributes<<4 & 0x100);
		int sp16_scrolly = ram[0xca00]|(attributes<<6 & 0x100);
		int sp32_scrollx = ram[0xcb80]|(attributes<<3 & 0x100);
		int sp32_scrolly = ram[0xcb00]|(attributes<<5 & 0x100);
		tnk3_draw_sprites(bitmap, sp16_scrollx+29, sp16_scrolly+9,  &ram[0xe800], 25*4, 6, flip);
		tnk3_draw_sprites(bitmap, sp32_scrollx+15, sp32_scrolly+25, &ram[0xe000], 25*4, 7, flip);
		tnk3_draw_sprites(bitmap, sp16_scrollx+29, sp16_scrolly+9,  &ram[0xe800+25*4], 25*4, 6, flip);
	}

	tnk3_draw_text( bitmap, -1, &ram[0xf800], 4, flip );
}
