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

							  -= Tetris Plus 2 =-

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


Note:	if MAME_DEBUG is defined, pressing Z with:

		Q		shows the background
		W		shows the foreground
		A		shows the sprites

		Keys can be used together!


	[ 2 Scrolling Layers ]

	The Background is a 64 x 64 Tilemap with 16 x 16 x 8 tiles (1024 x 1024).
	The Foreground is a 64 x 64 Tilemap with 8 x 8 x 8 tiles (512 x 512).
	Each tile needs 4 bytes.

	[ 1024? Sprites ]

	Sprites are "nearly" tile based: if the data in the ROMs is decoded
	as 8x8 tiles, and each 32 consecutive tiles are drawn like a column
	of 256 pixels, it turns out that every 32 x 32 tiles form a picture
	of 256 x 256 pixels (a "page").

	Sprites are portions of any size from those page's graphics rendered
	to screen.

To Do:

-	There is a 3rd unimplemented layer capable of rotation (not used by
	the game, can be tested in service mode).
-	Priority RAM is not taken into account.

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

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


extern UINT16 tetrisp2_systemregs[0x10];

/* Variables needed by driver: */

data16_t *tetrisp2_vram_bg, *tetrisp2_scroll_bg;
data16_t *tetrisp2_vram_fg, *tetrisp2_scroll_fg;
data16_t *tetrisp2_vram_rot, *tetrisp2_rotregs;

data16_t *tetrisp2_priority;


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


									Palette


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

/* BBBBBGGGGGRRRRRx xxxxxxxxxxxxxxxx */
WRITE16_HANDLER( tetrisp2_palette_w )
{
	data = COMBINE_DATA(&paletteram16[offset]);
	if ((offset & 1) == 0)
	{
		int r = (data >>  1) & 0x1f;
		int g = (data >>  6) & 0x1f;
		int b = (data >> 11) & 0x1f;
		palette_set_color(offset/2,(r << 3) | (r >> 2),(g << 3) | (g >> 2),(b << 3) | (b >> 2));
	}
}


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


									Priority


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

READ16_HANDLER( tetrisp2_priority_r )
{
	return tetrisp2_priority[offset];
}

WRITE16_HANDLER( tetrisp2_priority_w )
{
	if (ACCESSING_MSB)
	{
		data |= ((data & 0xff00) >> 8);
		tetrisp2_priority[offset] = data;
	}
}


WRITE16_HANDLER( rockn_priority_w )
{
	if (ACCESSING_MSB)
	{
		tetrisp2_priority[offset] = data;
	}
}


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


									Tilemaps


	Offset:		Bits:					Value:

		0.w								Code
		2.w		fedc ba98 7654 ----
				---- ---- ---- 3210		Color


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

static struct tilemap *tilemap_bg, *tilemap_fg, *tilemap_rot;

#define NX_0  (0x40)
#define NY_0  (0x40)

static void get_tile_info_bg(int tile_index)
{
	data16_t code_hi = tetrisp2_vram_bg[ 2 * tile_index + 0];
	data16_t code_lo = tetrisp2_vram_bg[ 2 * tile_index + 1];
	SET_TILE_INFO(
			1,
			code_hi,
			code_lo & 0xf,
			0)
}

WRITE16_HANDLER( tetrisp2_vram_bg_w )
{
	data16_t old_data	=	tetrisp2_vram_bg[offset];
	data16_t new_data	=	COMBINE_DATA(&tetrisp2_vram_bg[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_bg,offset/2);
}



#define NX_1  (0x40)
#define NY_1  (0x40)

static void get_tile_info_fg(int tile_index)
{
	data16_t code_hi = tetrisp2_vram_fg[ 2 * tile_index + 0];
	data16_t code_lo = tetrisp2_vram_fg[ 2 * tile_index + 1];
	SET_TILE_INFO(
			3,
			code_hi,
			code_lo & 0xf,
			0)
}

WRITE16_HANDLER( tetrisp2_vram_fg_w )
{
	data16_t old_data	=	tetrisp2_vram_fg[offset];
	data16_t new_data	=	COMBINE_DATA(&tetrisp2_vram_fg[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_fg,offset/2);
}


static void get_tile_info_rot(int tile_index)
{
	data16_t code_hi = tetrisp2_vram_rot[ 2 * tile_index + 0];
	data16_t code_lo = tetrisp2_vram_rot[ 2 * tile_index + 1];
	SET_TILE_INFO(
			2,
			code_hi,
			code_lo & 0xf,
			0)
}

WRITE16_HANDLER( tetrisp2_vram_rot_w )
{
	data16_t old_data	=	tetrisp2_vram_rot[offset];
	data16_t new_data	=	COMBINE_DATA(&tetrisp2_vram_rot[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_rot,offset/2);
}


VIDEO_START( tetrisp2 )
{
	tilemap_bg = tilemap_create(	get_tile_info_bg,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16,16,NX_0,NY_0);

	tilemap_fg = tilemap_create(	get_tile_info_fg,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								8,8,NX_1,NY_1);

	tilemap_rot = tilemap_create(	get_tile_info_rot,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16,16,NX_0*2,NY_0*2);

	if (!tilemap_bg || !tilemap_fg || !tilemap_rot)	return 1;

	tilemap_set_transparent_pen(tilemap_bg,0);
	tilemap_set_transparent_pen(tilemap_fg,0);
	tilemap_set_transparent_pen(tilemap_rot,0);

	return 0;
}

VIDEO_START( rockntread )
{
	tilemap_bg = tilemap_create(	get_tile_info_bg,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16, 16, 256, 16);	/* rockn ms(main),1,2,3,4*/

	tilemap_fg = tilemap_create(	get_tile_info_fg,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								8, 8, 64, 64);

	tilemap_rot = tilemap_create(	get_tile_info_rot,tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16, 16, 128, 128);

	if (!tilemap_bg || !tilemap_fg || !tilemap_rot)	return 1;

	tilemap_set_transparent_pen(tilemap_bg, 0);
	tilemap_set_transparent_pen(tilemap_fg, 0);
	tilemap_set_transparent_pen(tilemap_rot, 0);

	return 0;
}

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


								Sprites Drawing

	Offset:		Bits:					Meaning:

	0.w			fedc ba98 ---- ----
				---- ---- 7654 ----		Priority
				---- ---- ---- 3---
				---- ---- ---- -2--		Draw this sprite
				---- ---- ---- --1-		Flip Y
				---- ---- ---- ---0		Flip X

	2.w			fedc ba98 ---- ----		Tile's Y position in the tile page (*)
				---- ---- 7654 3210		Tile's X position in the tile page (*)

	4.w			fedc ---- ---- ----		Color
				---- ba98 7--- ----
				---- ---- -654 3210		Tile Page (32x32 tiles = 256x256 pixels each)

	6.w			fedc ba98 ---- ----
				---- ---- 7654 ----		Y Size - 1 (*)
				---- ---- ---- 3210		X Size - 1 (*)

	8.w			fedc ba-- ---- ----
				---- --98 7654 3210		Y (Signed)

	A.w			fedc b--- ---- ----
				---- -a98 7654 3210		X (Signed)

	C.w			fedc ba98 7654 3210		ZOOM X (unused)

	E.w			fedc ba98 7654 3210		ZOOM Y (unused)

(*)	1 pixel granularity

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

static void tetrisp2_draw_sprites(struct mame_bitmap *bitmap, const struct rectangle *cliprect, data16_t *sprram_top, size_t sprram_size, int gfxnum)
{
	int x, y, tx, ty, sx, sy, flipx, flipy;
	int xsize, ysize, xnum, ynum;
	int xstart, ystart, xend, yend, xinc, yinc;
	int code, attr, color, size;
	int flipscreen;
	UINT32 primask;
	data16_t *priority_ram;

	int min_x = cliprect->min_x;
	int max_x = cliprect->max_x;
	int min_y = cliprect->min_y;
	int max_y = cliprect->max_y;

	data16_t		*source	=	sprram_top;
	const data16_t	*finish	=	sprram_top + (sprram_size - 0x10) / 2;

	priority_ram = tetrisp2_priority;

	flipscreen = (tetrisp2_systemregs[0x00] & 0x02);

	for (; source <= finish; source += 0x10/2 )
	{
		struct rectangle clip;

		attr	=	source[ 0 ];

		if ((attr & 0x0004) == 0)			continue;

		flipx	=	attr & 1;
		flipy	=	attr & 2;

		code	=	source[ 1 ];
		color	=	source[ 2 ];

		tx		=	(code >> 0) & 0xff;
		ty		=	(code >> 8) & 0xff;

		code	=	(tx / 8) +
					(ty / 8) * (0x100/8) +
					(color & 0x7f) * (0x100/8) * (0x100/8);

		color	=	(color >> 12) & 0xf;

		size	=	source[ 3 ];

		xsize	=	((size >> 0) & 0xff) + 1;
		ysize	=	((size >> 8) & 0xff) + 1;

		xnum	=	( ((tx + xsize) & ~7) + (((tx + xsize) & 7) ? 8 : 0) - (tx & ~7) ) / 8;
		ynum	=	( ((ty + ysize) & ~7) + (((ty + ysize) & 7) ? 8 : 0) - (ty & ~7) ) / 8;

		sy		=	source[ 4 ];
		sx		=	source[ 5 ];

		sx		=	(sx & 0x3ff) - (sx & 0x400);
		sy		=	(sy & 0x1ff) - (sy & 0x200);

		/* Flip Screen */
		if (flipscreen)
		{
			sx = max_x + 1 - sx - xsize;	flipx = !flipx;
			sy = max_y + 1 - sy - ysize;	flipy = !flipy;
		}

		/* Clip the sprite if its width or height is not an integer
		   multiple of 8 pixels (1 tile) */

		clip.min_x	=	sx;
		clip.max_x	=	sx + xsize - 1;
		clip.min_y	=	sy;
		clip.max_y	=	sy + ysize - 1;

		if (clip.min_x > max_x)	continue;
		if (clip.max_x < min_x)	continue;

		if (clip.min_y > max_y)	continue;
		if (clip.max_y < min_y)	continue;

		if (clip.min_x < min_x)	clip.min_x = min_x;
		if (clip.max_x > max_x)	clip.max_x = max_x;

		if (clip.min_y < min_y)	clip.min_y = min_y;
		if (clip.max_y > max_y)	clip.max_y = max_y;

		if (flipx)	{ xstart = xnum-1;  xend = -1;    xinc = -1;  sx -= xnum*8 - xsize - (tx & 7); }
		else		{ xstart = 0;       xend = xnum;  xinc = +1;  sx -= tx & 7; }

		if (flipy)	{ ystart = ynum-1;  yend = -1;    yinc = -1;  sy -= ynum*8 - ysize - (ty & 7); }
		else		{ ystart = 0;       yend = ynum;  yinc = +1;  sy -= ty & 7; }

		primask = 0;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1500) / 2] & 0x38) primask |= 1 << 0;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1400) / 2] & 0x38) primask |= 1 << 1;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1100) / 2] & 0x38) primask |= 1 << 2;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x1000) / 2] & 0x38) primask |= 1 << 3;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0500) / 2] & 0x38) primask |= 1 << 4;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0400) / 2] & 0x38) primask |= 1 << 5;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0100) / 2] & 0x38) primask |= 1 << 6;
		if (priority_ram[((attr & 0x00f0) | 0x0a00 | 0x0000) / 2] & 0x38) primask |= 1 << 7;

		for (y = ystart; y != yend; y += yinc)
		{
			for (x = xstart; x != xend; x += xinc)
			{
				pdrawgfx(bitmap, Machine->gfx[gfxnum],
						code++,
						color,
						flipx, flipy,
						sx + x * 8, sy + y * 8,
						&clip,
						TRANSPARENCY_PEN, 0, primask);
			}
			code	+=	(0x100/8) - xnum;
		}
	}	/* end sprite loop */
}


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


								Screen Drawing


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

VIDEO_UPDATE( tetrisp2 )
{
	static int flipscreen_old = -1;
	int flipscreen;
	int asc_pri;
	int scr_pri;
	int rot_pri;
	int rot_ofsx, rot_ofsy;

	flipscreen = (tetrisp2_systemregs[0x00] & 0x02);

	/* Black background color */
	fillbitmap(bitmap, Machine->pens[0x0000], cliprect);
	fillbitmap(priority_bitmap, 0, NULL);

	/* Flip Screen */
	if (flipscreen != flipscreen_old)
	{
		flipscreen_old = flipscreen;
		tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
	}

	/* Flip Screen */
	if (flipscreen)
	{
		rot_ofsx = 0x053f;
		rot_ofsy = 0x04df;
	}
	else
	{
		rot_ofsx = 0x400;
		rot_ofsy = 0x400;
	}

	tilemap_set_scrollx(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 0 ] + 0x0014) + tetrisp2_scroll_bg[ 2 ] ) & 0xffff));
	tilemap_set_scrolly(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 3 ] + 0x0000) + tetrisp2_scroll_bg[ 5 ] ) & 0xffff));

	tilemap_set_scrollx(tilemap_fg, 0, tetrisp2_scroll_fg[ 2 ]);
	tilemap_set_scrolly(tilemap_fg, 0, tetrisp2_scroll_fg[ 5 ]);

	tilemap_set_scrollx(tilemap_rot, 0, (tetrisp2_rotregs[ 0 ] - rot_ofsx));
	tilemap_set_scrolly(tilemap_rot, 0, (tetrisp2_rotregs[ 2 ] - rot_ofsy));

	asc_pri = scr_pri = rot_pri = 0;

	if((tetrisp2_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
		asc_pri++;
	else
		rot_pri++;

	if((tetrisp2_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
		asc_pri++;
	else
		scr_pri++;

	if((tetrisp2_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
		scr_pri++;
	else
		rot_pri++;

	if (rot_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	if (rot_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	if (rot_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	tetrisp2_draw_sprites(bitmap,cliprect, spriteram16, spriteram_size, 0);
}

VIDEO_UPDATE( rockntread )
{
	static int flipscreen_old = -1;
	int flipscreen;
	int asc_pri;
	int scr_pri;
	int rot_pri;
	int rot_ofsx, rot_ofsy;

	flipscreen = (tetrisp2_systemregs[0x00] & 0x02);

	/* Black background color */
	fillbitmap(bitmap, Machine->pens[0x0000], cliprect);
	fillbitmap(priority_bitmap, 0, NULL);

	/* Flip Screen */
	if (flipscreen != flipscreen_old)
	{
		flipscreen_old = flipscreen;
		tilemap_set_flip(ALL_TILEMAPS, flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
	}

	/* Flip Screen */
	if (flipscreen)
	{
		rot_ofsx = 0x053f;
		rot_ofsy = 0x04df;
	}
	else
	{
		rot_ofsx = 0x400;
		rot_ofsy = 0x400;
	}

	tilemap_set_scrollx(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 0 ] + 0x0014) + tetrisp2_scroll_bg[ 2 ] ) & 0xffff));
	tilemap_set_scrolly(tilemap_bg, 0, (((tetrisp2_scroll_bg[ 3 ] + 0x0000) + tetrisp2_scroll_bg[ 5 ] ) & 0xffff));

	tilemap_set_scrollx(tilemap_fg, 0, tetrisp2_scroll_fg[ 2 ]);
	tilemap_set_scrolly(tilemap_fg, 0, tetrisp2_scroll_fg[ 5 ]);

	tilemap_set_scrollx(tilemap_rot, 0, (tetrisp2_rotregs[ 0 ] - rot_ofsx));
	tilemap_set_scrolly(tilemap_rot, 0, (tetrisp2_rotregs[ 2 ] - rot_ofsy));

	asc_pri = scr_pri = rot_pri = 0;

	if((tetrisp2_priority[0x2b00 / 2] & 0x00ff) == 0x0034)
		asc_pri++;
	else
		rot_pri++;

	if((tetrisp2_priority[0x2e00 / 2] & 0x00ff) == 0x0034)
		asc_pri++;
	else
		scr_pri++;

	if((tetrisp2_priority[0x3a00 / 2] & 0x00ff) == 0x000c)
		scr_pri++;
	else
		rot_pri++;

	if (rot_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 0)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	if (rot_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 1)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	if (rot_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_rot, 0, 1 << 1);
	else if (scr_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_bg,  0, 1 << 0);
	else if (asc_pri == 2)
		tilemap_draw(bitmap,cliprect, tilemap_fg,  0, 1 << 2);

	tetrisp2_draw_sprites(bitmap,cliprect, spriteram16, spriteram_size, 0);
}
