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

							-= Seta Hardware =-

					driver by	Luca Elia (l.elia@tin.it)


Note:	if MAME_DEBUG is defined, pressing Z with:

		Q			shows layer 0
		W			shows layer 1
		A			shows the sprites

		Keys can be used together!


						[ 0, 1 Or 2 Scrolling Layers ]

	Each layer consists of 2 tilemaps: only one can be displayed at a
	given time (the games usually flip continuously between the two).
	The two tilemaps share the same scrolling registers.

		Layer Size:				1024 x 512
		Tiles:					16x16x4 (16x16x6 in some games)
		Tile Format:

			Offset + 0x0000:
							f--- ---- ---- ----		Flip X
							-e-- ---- ---- ----		Flip Y
							--dc ba98 7654 3210		Code

			Offset + 0x1000:

							fedc ba98 765- ----		-
							---- ---- ---4 3210		Color

			The other tilemap for this layer (always?) starts at
			Offset + 0x2000.


							[ 1024 Sprites ]

	Sprites are 16x16x4. They are just like those in "The Newzealand Story",
	"Revenge of DOH" etc (tnzs.c). Obviously they're hooked to a 16 bit
	CPU here, so they're mapped a bit differently in memory. Additionally,
	there are two banks of sprites. The game can flip between the two to
	do double buffering, writing to a bit of a control register(see below)


		Spriteram16_2 + 0x000.w

						f--- ---- ---- ----		Flip X
						-e-- ---- ---- ----		Flip Y
						--dc b--- ---- ----		-
						---- --98 7654 3210		Code (Lower bits)

		Spriteram16_2 + 0x400.w

						fedc b--- ---- ----		Color
						---- -a9- ---- ----		Code (Upper Bits)
						---- ---8 7654 3210		X

		Spriteram16   + 0x000.w

						fedc ba98 ---- ----		-
						---- ---- 7654 3210		Y



							[ Floating Tilemap ]

	There's a floating tilemap made of vertical colums composed of 2x16
	"sprites". Each 32 consecutive "sprites" define a column.

	For column I:

		Spriteram16_2 + 0x800 + 0x40 * I:

						f--- ---- ---- ----		Flip X
						-e-- ---- ---- ----		Flip Y
						--dc b--- ---- ----		-
						---- --98 7654 3210		Code (Lower bits)

		Spriteram16_2 + 0xc00 + 0x40 * I:

						fedc b--- ---- ----		Color
						---- -a9- ---- ----		Code (Upper Bits)
						---- ---8 7654 3210		-

	Each column	has a variable horizontal position and a vertical scrolling
	value (see also the Sprite Control Registers). For column I:


		Spriteram16   + 0x400 + 0x20 * I:

						fedc ba98 ---- ----		-
						---- ---- 7654 3210		Y

		Spriteram16   + 0x408 + 0x20 * I:

						fedc ba98 ---- ----		-
						---- ---- 7654 3210		Low Bits Of X



						[ Sprites Control Registers ]


		Spriteram16   + 0x601.b

						7--- ----		0
						-6-- ----		Flip Screen
						--5- ----		0
						---4 ----		1 (Sprite Enable?)
						---- 3210		???

		Spriteram16   + 0x603.b

						7--- ----		0
						-6-- ----		Sprite Bank
						--5- ----		0 = Sprite Buffering (blandia,msgundam,qzkklogy)
						---4 ----		0
						---- 3210		Columns To Draw (1 is the special value for 16)

		Spriteram16   + 0x605.b

						7654 3210		High Bit Of X For Columns 7-0

		Spriteram16   + 0x607.b

						7654 3210		High Bit Of X For Columns f-8




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

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

/* Variables only used here */

static struct tilemap *tilemap_0, *tilemap_1;	// Layer 0
static struct tilemap *tilemap_2, *tilemap_3;	// Layer 1
static int tilemaps_flip;

/* Variables for taito_x video hardware */

size_t supes_videoram_size;
size_t supes_attribram_size;
data16_t *supes_videoram;
data16_t *supes_attribram;

static UINT16 tilemask;

/* Variables used elsewhere */

int seta_tiles_offset;

data16_t *seta_vram_0, *seta_vctrl_0;
data16_t *seta_vram_2, *seta_vram_3, *seta_vctrl_2;
data16_t *seta_vregs;

data16_t *seta_workram; // Used for zombraid crosshair hack

static int twineagl_tilebank[4];
static int	seta_samples_bank;

struct x_offset
{
	/* 2 values, for normal and flipped */
	const char *gamename;
	int sprite_offs[2];
	int tilemap_offs[2];
};

/* note that drgnunit, stg and qzkklogy run on the same board, yet they need different alignment */
static struct x_offset game_offsets[] =
{
	/* only sprites */
	{ "tndrcade", { -1,  0 } },				// correct (wall at beginning of game)
	{ "tndrcadj", { -1,  0 } },				// correct (wall at beginning of game)
	{ "wits",     {  0,  0 } },				// unknown
	{ "thunderl", {  0,  0 } },				// unknown
	{ "wiggie",   {  0,  0 } },				// some problems but they seem y co-ordinate related?
	{ "blockcar", {  0,  0 } },				// unknown
	{ "umanclub", {  0,  0 } },				// unknown
	{ "atehate",  {  0,  0 } },				// correct (test grid)
	{ "kiwame",   {  0,-16 } },				// correct (test grid)
	{ "krzybowl", {  0,  0 } },				// correct (test grid)

	/* 1 layer */
	{ "twineagl", {  0,  0 }, {  0, -3 } },	// unknown
	{ "downtown", {  1,  0 }, { -1,  0 } },	// sprites correct (test grid), tilemap unknown but at least -1 non-flipped to fix glitches later in the game
	{ "usclssic", {  1,  2 }, {  0, -1 } },	// correct (test grid and bg)
	{ "calibr50", { -1,  2 }, { -3, -2 } },	// correct (test grid and roof in animation at beginning of game)
	{ "arbalest", {  0,  1 }, { -2, -1 } },	// correct (test grid and landing pad at beginning of game)
	{ "metafox",  {  0,  0 }, { 16,-19 } },	// sprites unknown, tilemap correct (test grid)
	{ "drgnunit", {  2,  2 }, { -2, -2 } },	// correct (test grid and I/O test)
	{ "stg",      {  0,  0 }, { -2, -2 } },	// sprites correct? (panel), tilemap correct (test grid)
	{ "qzkklogy", {  1,  1 }, { -1, -1 } },	// correct (timer, test grid)
	{ "qzkklgy2", {  0,  0 }, { -1, -3 } },	// sprites unknown, tilemaps correct (test grid)

	/* 2 layers */
	{ "rezon",    {  0,  0 }, { -2, -2 } },	// correct (test grid)
	{ "blandia",  {  0,  8 }, { -2,  6 } },	// correct (test grid, startup bg)
	{ "blandiap", {  0,  8 }, { -2,  6 } },	// correct (test grid, startup bg)
	{ "zingzip",  {  0,  0 }, { -1, -2 } },	// sprites unknown, tilemaps correct (test grid)
	{ "eightfrc", {  3,  4 }, {  0,  0 } },	// unknown
	{ "daioh",    {  1,  1 }, { -1, -1 } },	// correct? (launch window and test grid are right, but planet is wrong)
	{ "msgundam", {  0,  0 }, { -2, -2 } },	// correct (test grid, banpresto logo)
	{ "msgunda1", {  0,  0 }, { -2, -2 } },	// correct (test grid, banpresto logo)
	{ "oisipuzl", {  0,  0 }, { -1, -1 } },	// correct (test mode) flip screen not supported?
	{ "triplfun", {  0,  0 }, { -1, -1 } },	// correct (test mode) flip screen not supported?
	{ "wrofaero", {  0,  0 }, {  0,  0 } },	// unknown
	{ "jjsquawk", {  1,  1 }, { -1, -1 } },	// correct (test mode)
	{ "kamenrid", {  0,  0 }, { -2, -2 } },	// correct (map, banpresto logo)
	{ "extdwnhl", {  0,  0 }, { -2, -2 } },	// correct (test grid, background images)
	{ "sokonuke", {  0,  0 }, { -2, -2 } },	// correct (game selection, test grid)
	{ "gundhara", {  0,  0 }, {  0,  0 } },	// unknown, flip screen not supported?
	{ "zombraid", {  0,  0 }, { -2, -2 } },	// correct for normal, flip screen not working yet
	{ "madshark", {  0,  0 }, {  0,  0 } },	// unknown (wrong when flipped, but along y)
	{ "utoukond", {  0,  0 }, { -2,  0 } }, // unknown (wrong when flipped, but along y)
	{ NULL }
};

static struct x_offset *global_offsets;



WRITE16_HANDLER( seta_vregs_w )
{
	COMBINE_DATA(&seta_vregs[offset]);
	switch (offset)
	{
		case 0/2:

/*		fedc ba98 76-- ----
		---- ---- --5- ----		Sound Enable
		---- ---- ---4 ----		toggled in IRQ1 by many games, irq acknowledge?
								[original comment for the above: ?? 1 in oisipuzl, sokonuke (layers related)]
		---- ---- ---- 3---		Coin #1 Lock Out
		---- ---- ---- -2--		Coin #0 Lock Out
		---- ---- ---- --1-		Coin #1 Counter
		---- ---- ---- ---0		Coin #0 Counter		*/
			if (ACCESSING_LSB)
			{
				seta_coin_lockout_w (data & 0x0f);
				seta_sound_enable_w (data & 0x20);
				coin_counter_w(0,data & 0x01);
				coin_counter_w(1,data & 0x02);
			}
			break;

		case 2/2:
			if (ACCESSING_LSB)
			{
				int new_bank;

				/* Partly handled in vh_screenrefresh:

						fedc ba98 76-- ----
						---- ---- --54 3---		Samples Bank (in blandia, eightfrc, zombraid)
						---- ---- ---- -2--
						---- ---- ---- --1-		Sprites Above Frontmost Layer
						---- ---- ---- ---0		Layer 0 Above Layer 1
				*/

				new_bank = (data >> 3) & 0x7;

				if (new_bank != seta_samples_bank)
				{
					unsigned char *rom = memory_region(REGION_SOUND1);
					int samples_len = memory_region_length(REGION_SOUND1);
					int addr;

					seta_samples_bank = new_bank;

					if (samples_len == 0x240000)	/* blandia, eightfrc */
					{
						addr = 0x40000 * new_bank;
						if (new_bank >= 3)	addr += 0x40000;

						if ( (samples_len > 0x100000) && ((addr+0x40000) <= samples_len) )
							memcpy(&rom[0xc0000],&rom[addr],0x40000);
						else
							logerror("PC %06X - Invalid samples bank %02X !\n", activecpu_get_pc(), new_bank);
					}
					else if (samples_len == 0x480000)	/* zombraid */
					{
						/* bank 1 is never explicitly selected, 0 is used in its place */
						if (new_bank == 0) new_bank = 1;
						addr = 0x80000 * new_bank;
						if (new_bank > 0) addr += 0x80000;

						memcpy(&rom[0x80000],&rom[addr],0x80000);
					}
				}

			}
			break;


		case 4/2:	// ?
			break;
	}
}




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

						Callbacks for the TileMap code

							  [ Tiles Format ]

Offset + 0x0000:
					f--- ---- ---- ----		Flip X
					-e-- ---- ---- ----		Flip Y
					--dc ba98 7654 3210		Code

Offset + 0x1000:

					fedc ba98 765- ----		-
					---- ---- ---4 3210		Color


					  [ TileMaps Control Registers]

Offset + 0x0:								Scroll X
Offset + 0x2:								Scroll Y
Offset + 0x4:
					fedc ba98 7654 3210		-
					---- ---- ---- 3---		Tilemap Select (There Are 2 Tilemaps Per Layer)
					---- ---- ---- -21-		0 (1 only in eightfrc, when flip is on!)
					---- ---- ---- ---0		?

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

INLINE void twineagl_tile_info( int tile_index, data16_t *vram )
{
	data16_t code =	vram[ tile_index ];
	data16_t attr =	vram[ tile_index + 0x800 ];
	if ((code & 0x3e00) == 0x3e00)
		code = (code & 0xc07f) | ((twineagl_tilebank[(code & 0x0180) >> 7] >> 1) << 7);
	SET_TILE_INFO( 1, (code & 0x3fff), attr & 0x1f, TILE_FLIPXY((code & 0xc000) >> 14) )
}

static void twineagl_get_tile_info_0( int tile_index ) { twineagl_tile_info( tile_index, seta_vram_0 + 0x0000 ); }
static void twineagl_get_tile_info_1( int tile_index ) { twineagl_tile_info( tile_index, seta_vram_0 + 0x1000 ); }


INLINE void get_tile_info( int tile_index, int layer, data16_t *vram )
{
	data16_t code =	vram[ tile_index ];
	data16_t attr =	vram[ tile_index + 0x800 ];
	SET_TILE_INFO( 1 + layer, seta_tiles_offset + (code & 0x3fff), attr & 0x1f, TILE_FLIPXY((code & 0xc000) >> 14) )
}

static void get_tile_info_0( int tile_index ) { get_tile_info( tile_index, 0, seta_vram_0 + 0x0000 ); }
static void get_tile_info_1( int tile_index ) { get_tile_info( tile_index, 0, seta_vram_0 + 0x1000 ); }
static void get_tile_info_2( int tile_index ) { get_tile_info( tile_index, 1, seta_vram_2 + 0x0000 ); }
static void get_tile_info_3( int tile_index ) { get_tile_info( tile_index, 1, seta_vram_2 + 0x1000 ); }


WRITE16_HANDLER( seta_vram_0_w )
{
	data16_t oldword = seta_vram_0[offset];
	data16_t newword = COMBINE_DATA(&seta_vram_0[offset]);
	if (oldword != newword)
	{
		if (offset & 0x1000)
			tilemap_mark_tile_dirty(tilemap_1, offset & 0x7ff);
		else
			tilemap_mark_tile_dirty(tilemap_0, offset & 0x7ff);
	}
}

WRITE16_HANDLER( seta_vram_2_w )
{
	data16_t oldword = seta_vram_2[offset];
	data16_t newword = COMBINE_DATA(&seta_vram_2[offset]);
	if (oldword != newword)
	{
		if (offset & 0x1000)
			tilemap_mark_tile_dirty(tilemap_3, offset & 0x7ff);
		else
			tilemap_mark_tile_dirty(tilemap_2, offset & 0x7ff);
	}
}

WRITE16_HANDLER( twineagl_tilebank_w )
{
	if (ACCESSING_LSB)
	{
		data &= 0xff;
		if (twineagl_tilebank[offset] != data)
		{
			twineagl_tilebank[offset] = data;
			tilemap_mark_all_tiles_dirty(ALL_TILEMAPS);
		}
	}
}



static void find_offsets(void)
{
	global_offsets = game_offsets;
	while (global_offsets->gamename && strcmp(Machine->gamedrv->name,global_offsets->gamename))
		global_offsets++;
}

/* Taito_x video hardware */
VIDEO_START( taitox )
{
	tilemask = 0x3fff;
	return 0;
}

/* 2 layers */
VIDEO_START( seta_2_layers )
{
	/* Each layer consists of 2 tilemaps: only one can be displayed
	   at any given time */

	/* layer 0 */
	tilemap_0 = tilemap_create(	get_tile_info_0, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );

	tilemap_1 = tilemap_create(	get_tile_info_1, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );


	/* layer 1 */
	tilemap_2 = tilemap_create(	get_tile_info_2, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );

	tilemap_3 = tilemap_create(	get_tile_info_3, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );

	if (tilemap_0 && tilemap_1 && tilemap_2 && tilemap_3)
	{
		tilemaps_flip = 0;

		tilemap_set_transparent_pen(tilemap_0,0);
		tilemap_set_transparent_pen(tilemap_1,0);
		tilemap_set_transparent_pen(tilemap_2,0);
		tilemap_set_transparent_pen(tilemap_3,0);

		find_offsets();
		seta_samples_bank = -1;	// set the samples bank to an out of range value at start-up

		return 0;
	}
	else return 1;
}


/* 1 layer */
VIDEO_START( seta_1_layer )
{
	/* Each layer consists of 2 tilemaps: only one can be displayed
	   at any given time */

	/* layer 0 */
	tilemap_0 = tilemap_create(	get_tile_info_0, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );

	tilemap_1 = tilemap_create(	get_tile_info_1, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );


	/* NO layer 1 */
	tilemap_2 = 0;
	tilemap_3 = 0;

	if (tilemap_0 && tilemap_1)
	{
		tilemaps_flip = 0;

		tilemap_set_transparent_pen(tilemap_0,0);
		tilemap_set_transparent_pen(tilemap_1,0);

		find_offsets();
		seta_samples_bank = -1;	// set the samples bank to an out of range value at start-up

		return 0;
	}
	else return 1;
}

VIDEO_START( twineagl_1_layer )
{
	/* Each layer consists of 2 tilemaps: only one can be displayed
	   at any given time */

	/* layer 0 */
	tilemap_0 = tilemap_create(	twineagl_get_tile_info_0, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );

	tilemap_1 = tilemap_create(	twineagl_get_tile_info_1, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 16,16, 64,32 );


	/* NO layer 1 */
	tilemap_2 = 0;
	tilemap_3 = 0;

	if (tilemap_0 && tilemap_1)
	{
		tilemaps_flip = 0;

		tilemap_set_transparent_pen(tilemap_0,0);
		tilemap_set_transparent_pen(tilemap_1,0);

		find_offsets();
		seta_samples_bank = -1;	// set the samples bank to an out of range value at start-up

		return 0;
	}
	else return 1;
}


/* NO layers, only sprites */
VIDEO_START( seta_no_layers )
{
	tilemap_0 = 0;
	tilemap_1 = 0;
	tilemap_2 = 0;
	tilemap_3 = 0;
	find_offsets();
	seta_samples_bank = -1;	// set the samples bank to an out of range value at start-up
	return 0;
}

VIDEO_START( oisipuzl_2_layers )
{
	if (video_start_seta_2_layers())
		return 1;
	tilemaps_flip = 1;
	return 0;
}


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


							Palette Init Functions


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


/* 2 layers, 6 bit deep. The color codes have a 16 color granularity.

   One layer only uses the first 16 colors of the palette (repeated
   4 times to fill the 64 colors) and regardless of the color code!

   The other uses the first 64 colors of the palette regardless of
   the color code too!

   I think that's because this game's a prototype..
*/
PALETTE_INIT( blandia )
{
	int color, pen;
	for( color = 0; color < 32; color++ )
		for( pen = 0; pen < 64; pen++ )
		{
			colortable[color * 64 + pen + 16*32]       = (pen%16) + 16*32*1;
			colortable[color * 64 + pen + 16*32+64*32] = pen      + 16*32*2;
		}
}



/* layers have 6 bits per pixel, but the color code has a 16 colors granularity,
   even if the low 2 bits are ignored (so there are only 4 different palettes) */
PALETTE_INIT( gundhara )
{
	int color, pen;
	for( color = 0; color < 32; color++ )
		for( pen = 0; pen < 64; pen++ )
		{
			colortable[color * 64 + pen + 32*16 + 32*64*0] = (((color&~3) * 16 + pen)%(32*16)) + 32*16*2;
			colortable[color * 64 + pen + 32*16 + 32*64*1] = (((color&~3) * 16 + pen)%(32*16)) + 32*16*1;
		}
}



/* layers have 6 bits per pixel, but the color code has a 16 colors granularity */
PALETTE_INIT( jjsquawk )
{
	int color, pen;
	for( color = 0; color < 32; color++ )
		for( pen = 0; pen < 64; pen++ )
		{
			colortable[color * 64 + pen + 32*16 + 32*64*0] = ((color * 16 + pen)%(32*16)) + 32*16*2;
			colortable[color * 64 + pen + 32*16 + 32*64*1] = ((color * 16 + pen)%(32*16)) + 32*16*1;
		}
}


/* layer 0 is 6 bit per pixel, but the color code has a 16 colors granularity */
PALETTE_INIT( zingzip )
{
	int color, pen;
	for( color = 0; color < 32; color++ )
		for( pen = 0; pen < 64; pen++ )
			colortable[color * 64 + pen + 32*16*2] = ((color * 16 + pen)%(32*16)) + 32*16*2;
}




PALETTE_INIT( usclssic )
{
	int color, pen;
	unsigned char *PROM = memory_region(REGION_PROMS);
	int x;

	/* DECODE PROM - we don't use the colours yet */
	for (x = 0x000; x < 0x200 ; x++)
	{
		int r,g,b;
		int data;

		data = (PROM[x*2] <<8) | PROM[x*2+1];

		r = (data >> 10) & 0x1f;
		g = (data >>  5) & 0x1f;
		b = (data >>  0) & 0x1f;

		r = (r << 3) | (r >> 2);
		g = (g << 3) | (g >> 2);
		b = (b << 3) | (b >> 2);

		if (x>=0x100) palette_set_color(x,r,g,b);
		else palette_set_color(x+0x300,r,g,b);
	}

	for( color = 0; color < 32; color++ )
		for( pen = 0; pen < 64; pen++ )
			colortable[color * 64 + pen + 512] =  ((((color & 0x1f) * 16 + pen)%512)+512);

}





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


								Sprites Drawing


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

/* Taito_x video hardware */
static void taitox_draw_tilemap (struct mame_bitmap *bitmap,int bankbase,int attribfix,int cocktail)
{
	int i,j;
	UINT32 x1, y1;

	/* Refresh the background tile plane */
	for (i=0; i<(0x400/2); i+=(0x40/2))
	{
		x1 = supes_attribram[0x408/2 + (i>>1)] | (attribfix &0x100);
		y1 = supes_attribram[0x400/2 + (i>>1)];

		attribfix >>= 1;

		for (j=i; j<(i + 0x40/2); j++)
		{
			int tile;

			tile = supes_videoram[0x800/2 + bankbase + j] & tilemask;
			if (tile)
			{
				int x, y;

				x = ((x1 + ((j &0x1) << 4)) + 16) &0x1ff;

				if ( !cocktail )
					y = (265 - (y1 - ((j &0x1e) << 3))) &0xff;
				else
					y = ((y1 - ((j &0x1e) << 3)) - 7) &0xff;

//				if ((x>0) && (y>0) && (x<388) && (y<272))
				{
					UINT32 flipx = supes_videoram[0x800/2 + bankbase + j] &0x8000;
					UINT32 flipy = supes_videoram[0x800/2 + bankbase + j] &0x4000;
					UINT32 color = supes_videoram[0xc00/2 + bankbase + j] >> 11;

					if (cocktail)
					{
						flipx ^= 0x8000;
						flipy ^= 0x4000;
					}

					/* Some tiles are transparent, e.g. the gate, so we use TRANSPARENCY_PEN */
					drawgfx(bitmap,Machine->gfx[0],
						tile,
						color,
						flipx,flipy,
						x,y,
						&Machine->visible_area,
						TRANSPARENCY_PEN,0);
				}
			}
		}
	}
}


static void taitox_draw_sprites (struct mame_bitmap *bitmap,int bankbase,int cocktail)
{
	int sprite,i,x,y,color,flipx,flipy;

	/* Refresh the sprite plane */
	for (i=0x3fe/2; i>=0; i--)
	{
		sprite = supes_videoram[i + bankbase] & tilemask;

		if (sprite)
		{
			x = (supes_videoram [0x400/2 + bankbase + i] + 16) &0x1ff;

			if (!cocktail)
				y = (250 - supes_attribram[i]) &0xff;
			else
				y = (10  + supes_attribram[i]) &0xff;

//			if ((x>0) && (y>0) && (x<388) && (y<272))
			{
				flipx = supes_videoram[bankbase + i] &0x8000;
				flipy = supes_videoram[bankbase + i] &0x4000;
				color = supes_videoram[bankbase + i + 0x400/2] >> 11;

				if (cocktail)
				{
					flipx ^= 0x8000;
					flipy ^= 0x4000;
				}

				drawgfx(bitmap,Machine->gfx[0],
					sprite,
					color,
					flipx,flipy,
					x,y,
					&Machine->visible_area,
					TRANSPARENCY_PEN,0);
			}
		}
	}
}
/* End of taito_x video hardware */


static void seta_draw_sprites_map(struct mame_bitmap *bitmap,const struct rectangle *cliprect)
{
	int offs, col;
	int xoffs, yoffs;

	int total_color_codes	=	Machine->drv->gfxdecodeinfo[0].total_color_codes;

	int ctrl	=	spriteram16[ 0x600/2 ];
	int ctrl2	=	spriteram16[ 0x602/2 ];

	int flip	=	ctrl & 0x40;
	int numcol	=	ctrl2 & 0x000f;

	/* Sprites Banking and/or Sprites Buffering */
	data16_t *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );

	int upper	=	( spriteram16[ 0x604/2 ] & 0xFF ) +
					( spriteram16[ 0x606/2 ] & 0xFF ) * 256;

	int max_y	=	0xf0;

	int col0;		/* Kludge, needed for krzybowl and kiwame */
	switch (ctrl & 0x0f)
	{
		case 0x01:	col0	=	0x4;	break;	// krzybowl
		case 0x06:	col0	=	0x8;	break;	// kiwame

		default:	col0	=	0x0;
	}

	xoffs = 0;
	yoffs = flip ? 1 : -1;

	/* Number of columns to draw - the value 1 seems special, meaning:
	   draw every column */
	if (numcol == 1)	numcol = 16;


	/* The first column is the frontmost, see twineagl test mode */
	for ( col = numcol - 1 ; col >= 0; col -- )
	{
		int x	=	spriteram16[(col * 0x20 + 0x08 + 0x400)/2] & 0xff;
		int y	=	spriteram16[(col * 0x20 + 0x00 + 0x400)/2] & 0xff;

		/* draw this column */
		for ( offs = 0 ; offs < 0x40/2; offs += 2/2 )
		{
			int	code	=	src[((col+col0)&0xf) * 0x40/2 + offs + 0x800/2];
			int	color	=	src[((col+col0)&0xf) * 0x40/2 + offs + 0xc00/2];

			int	flipx	=	code & 0x8000;
			int	flipy	=	code & 0x4000;

			int bank	=	(color & 0x0600) >> 9;

/*
twineagl:	010 02d 0f 10	(ship)
tndrcade:	058 02d 07 18	(start of game - yes, flip on!)
arbalest:	018 02d 0f 10	(logo)
metafox :	018 021 0f f0	(bomb)
zingzip :	010 02c 00 0f	(bomb)
wrofaero:	010 021 00 ff	(test mode)
thunderl:	010 06c 00 ff	(always?)
krzybowl:	011 028 c0 ff	(game)
kiwame  :	016 021 7f 00	(logo)
oisipuzl:	059 020 00 00	(game - yes, flip on!)
*/

			int sx		=	  x + xoffs  + (offs & 1) * 16;
			int sy		=	-(y + yoffs) + (offs / 2) * 16;

			if (upper & (1 << col))	sx += 256;

			if (flip)
			{
				sy = max_y - sy;
				flipx = !flipx;
				flipy = !flipy;
			}

			color	=	( color >> (16-5) ) % total_color_codes;
			code	=	(code & 0x3fff) + (bank * 0x4000);

			drawgfx(bitmap,Machine->gfx[0],
					code,
					color,
					flipx, flipy,
					((sx + 0x10) & 0x1ff) - 0x10,((sy + 8) & 0x0ff) - 8,
					cliprect,TRANSPARENCY_PEN,0);
		}
	/* next column */
	}

}



static void seta_draw_sprites(struct mame_bitmap *bitmap,const struct rectangle *cliprect)
{
	int offs;
	int xoffs, yoffs;

	int total_color_codes	=	Machine->drv->gfxdecodeinfo[0].total_color_codes;

	int ctrl	=	spriteram16[ 0x600/2 ];
	int ctrl2	=	spriteram16[ 0x602/2 ];

	int flip	=	ctrl & 0x40;

	/* Sprites Banking and/or Sprites Buffering */
	data16_t *src = spriteram16_2 + ( ((ctrl2 ^ (~ctrl2<<1)) & 0x40) ? 0x2000/2 : 0 );

	int max_y	=	0xf0;


	seta_draw_sprites_map(bitmap,cliprect);


	xoffs = global_offsets->sprite_offs[flip ? 1 : 0];
	yoffs = -2;

	for ( offs = (0x400-2)/2 ; offs >= 0/2; offs -= 2/2 )
	{
		int	code	=	src[offs + 0x000/2];
		int	x		=	src[offs + 0x400/2];

		int	y		=	spriteram16[offs + 0x000/2] & 0xff;

		int	flipx	=	code & 0x8000;
		int	flipy	=	code & 0x4000;

		int bank	=	(x & 0x0600) >> 9;
		int color	=	( x >> (16-5) ) % total_color_codes;

		if (flip)
		{
			y = (0x100 - Machine->drv->screen_height) + max_y - y;
			flipx = !flipx;
			flipy = !flipy;
		}

		code = (code & 0x3fff) + (bank * 0x4000);

		y = max_y - y;

		drawgfx(bitmap,Machine->gfx[0],
				code,
				color,
				flipx, flipy,
				((x + xoffs + 0x10) & 0x1ff) - 0x10,((y - yoffs + 8) & 0x0ff) - 8,
				cliprect,TRANSPARENCY_PEN,0);
	}

}





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


								Screen Drawing


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

static void zombraid_drawcrosshairs( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
{
	int p1_x = seta_workram[0xC4AA/2];
	int p1_y = 0x08+0xff - seta_workram[0xC4AC/2];
	int p2_x = seta_workram[0xC4AE/2];
	int p2_y = 0x08+0xff - seta_workram[0xC4B0/2];

	draw_crosshair(bitmap,p1_x,p1_y,cliprect);
	draw_crosshair(bitmap,p2_x,p2_y,cliprect);
}


/* For games without tilemaps */
VIDEO_UPDATE( seta_no_layers )
{
	fillbitmap(bitmap,Machine->pens[0x1f0],cliprect);
	seta_draw_sprites(bitmap,cliprect);
}


/* For games with 1 or 2 tilemaps */
VIDEO_UPDATE( seta )
{
	int layers_ctrl = -1;
	int enab_0, enab_1, x_0, x_1, y_0, y_1;

	int order	= 	0;
	int flip	=	(spriteram16[ 0x600/2 ] & 0x40) >> 6;

	int vis_dimy = Machine->visible_area.max_y - Machine->visible_area.min_y + 1;

	flip ^= tilemaps_flip;

	tilemap_set_flip(ALL_TILEMAPS, flip ? (TILEMAP_FLIPX|TILEMAP_FLIPY) : 0 );

	x_0		=	seta_vctrl_0[ 0/2 ];
	y_0		=	seta_vctrl_0[ 2/2 ];
	enab_0	=	seta_vctrl_0[ 4/2 ];

	/* Only one tilemap per layer is enabled! */
	tilemap_set_enable(tilemap_0, (!(enab_0 & 0x0008)) /*&& (enab_0 & 0x0001)*/ );
	tilemap_set_enable(tilemap_1, ( (enab_0 & 0x0008)) /*&& (enab_0 & 0x0001)*/ );

	/* the hardware wants different scroll values when flipped */

	/*	bg x scroll	     flip
		metafox		0000 025d = 0, $400-$1a3 = $400 - $190 - $13
		eightfrc	ffe8 0272
					fff0 0260 = -$10, $400-$190 -$10
					ffe8 0272 = -$18, $400-$190 -$18 + $1a		*/

	x_0 += 0x10 - global_offsets->tilemap_offs[flip ? 1 : 0];
	y_0 -= (256 - vis_dimy)/2;
	if (flip)
	{
		x_0 = -x_0 - 512;
		y_0 = y_0 - vis_dimy;
	}

	tilemap_set_scrollx (tilemap_0, 0, x_0);
	tilemap_set_scrollx (tilemap_1, 0, x_0);
	tilemap_set_scrolly (tilemap_0, 0, y_0);
	tilemap_set_scrolly (tilemap_1, 0, y_0);

	if (tilemap_2)
	{
		x_1		=	seta_vctrl_2[ 0/2 ];
		y_1		=	seta_vctrl_2[ 2/2 ];
		enab_1	=	seta_vctrl_2[ 4/2 ];

		tilemap_set_enable(tilemap_2, (!(enab_1 & 0x0008)) /*&& (enab_1 & 0x0001)*/ );
		tilemap_set_enable(tilemap_3, ( (enab_1 & 0x0008)) /*&& (enab_1 & 0x0001)*/ );

		x_1 += 0x10 - global_offsets->tilemap_offs[flip ? 1 : 0];
		y_1 -= (256 - vis_dimy)/2;
		if (flip)
		{
			x_1 = -x_1 - 512;
			y_1 = y_1 - vis_dimy;
		}

		tilemap_set_scrollx (tilemap_2, 0, x_1);
		tilemap_set_scrollx (tilemap_3, 0, x_1);
		tilemap_set_scrolly (tilemap_2, 0, y_1);
		tilemap_set_scrolly (tilemap_3, 0, y_1);

		order	=	seta_vregs[ 2/2 ];
	}


#ifdef MAME_DEBUG
if (keyboard_pressed(KEYCODE_Z))
{	int msk = 0;
	if (keyboard_pressed(KEYCODE_Q))	msk |= 1;
	if (keyboard_pressed(KEYCODE_W))	msk |= 2;
	if (keyboard_pressed(KEYCODE_A))	msk |= 8;
	if (msk != 0) layers_ctrl &= msk;

	if (tilemap_2)		usrintf_showmessage("VR:%04X-%04X-%04X L0:%04X L1:%04X",seta_vregs[0],seta_vregs[1],seta_vregs[2],seta_vctrl_0[4/2],seta_vctrl_2[4/2]);
	else if (tilemap_0)	usrintf_showmessage("L0:%04X",seta_vctrl_0[4/2]);
}
#endif

	fillbitmap(bitmap,Machine->pens[0],cliprect);

	if (order & 1)	// swap the layers?
	{
		if (tilemap_2)
		{
			if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_2, TILEMAP_IGNORE_TRANSPARENCY, 0);
			if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_3, TILEMAP_IGNORE_TRANSPARENCY, 0);
		}

		if (order & 2)	// layer-sprite priority?
		{
			if (layers_ctrl & 8)	seta_draw_sprites(bitmap,cliprect);
			if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_0,  0, 0);
			if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_1,  0, 0);
		}
		else
		{
			if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_0,  0, 0);
			if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_1,  0, 0);
			if (layers_ctrl & 8)	seta_draw_sprites(bitmap,cliprect);
		}
	}
	else
	{
		if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_0,  TILEMAP_IGNORE_TRANSPARENCY, 0);
		if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect, tilemap_1,  TILEMAP_IGNORE_TRANSPARENCY, 0);

		if (order & 2)	// layer-sprite priority?
		{
			if (layers_ctrl & 8)	seta_draw_sprites(bitmap,cliprect);

			if (tilemap_2)
			{
				if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_2,  0, 0);
				if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_3,  0, 0);
			}
		}
		else
		{
			if (tilemap_2)
			{
				if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_2,  0, 0);
				if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect, tilemap_3,  0, 0);
			}

			if (layers_ctrl & 8)	seta_draw_sprites(bitmap,cliprect);
		}
	}

	if (!(strcmp(Machine->gamedrv->name,"zombraid")))
	{
		zombraid_drawcrosshairs(bitmap,cliprect);
	}
}


/* Taito_x video hardware */
VIDEO_UPDATE( taitox )
{
	int bankbase;
	int attribfix;
	int cocktail;

#ifdef MAME_DEBUG
	static UINT8 dislayer[2];	/* Layer toggles for investigating Gigandes rd.5 */
#endif

#ifdef MAME_DEBUG
	if (keyboard_pressed_memory (KEYCODE_X))
	{
		dislayer[0] ^= 1;
		usrintf_showmessage("tilemap: %01x",dislayer[0]);
	}
	if (keyboard_pressed_memory (KEYCODE_C))
	{
		dislayer[1] ^= 1;
		usrintf_showmessage("sprites: %01x",dislayer[1]);
	}
#endif

	/* set bank base */
	if (supes_attribram[ 0x602/2 ] &0x40)
		bankbase = 0x2000/2;
	else
		bankbase = 0x0;

	/* attribute fix */
	attribfix = ((supes_attribram[ 0x604/2 ] &0xff) << 8) |
				((supes_attribram[ 0x606/2 ] &0xff) << 16);

	/* cocktail mode */
	cocktail = supes_attribram[ 0x600/2 ] &0x40;

	fillbitmap (bitmap,Machine->pens[0x1f0],&Machine->visible_area);

#ifdef MAME_DEBUG
	if (dislayer[0]==0)
#endif
	taitox_draw_tilemap (bitmap,bankbase,attribfix,cocktail);

#ifdef MAME_DEBUG
	if (dislayer[1]==0)
#endif
	taitox_draw_sprites (bitmap,bankbase,cocktail);
}

