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

                      -= Billiard Academy Real Break =-

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

    This hardware provides for:

        -   2 scrolling background layers, 1024 x 512 in size
            made of 16 x 16 tiles with 256 colors

        -   1 text layer (fixed?), 512 x 256 in size
            made of 8 x 8 tiles with 16 colors

        -   0x300 sprites made of 16x16 tiles, both 256 or 16 colors
            per tile and from 1 to 32x32 (more?) tiles per sprite.
            Sprites can zoom / shrink


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

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

data16_t *realbrk_vram_0, *realbrk_vram_1, *realbrk_vram_2, *realbrk_vregs;

static int disable_video;

WRITE16_HANDLER( realbrk_flipscreen_w )
{
	if (ACCESSING_LSB)
	{
		coin_counter_w(0,	data & 0x0001);
		coin_counter_w(1,	data & 0x0004);

		flip_screen_set(	data & 0x0080);
	}

	if (ACCESSING_MSB)
	{
		disable_video	=	data & 0x8000;
	}
}

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

                                Tilemaps


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

static struct tilemap	*tilemap_0,*tilemap_1,	// Backgrounds
						*tilemap_2;				// Text


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

                            Background Tilemaps

    Offset:     Bits:                   Value:

        0.w     f--- ---- ---- ----     Flip Y
                -e-- ---- ---- ----     Flip X
                --dc ba98 7--- ----
                ---- ---- -654 3210     Color

        2.w                             Code

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

static void get_tile_info_0(int tile_index)
{
	data16_t attr = realbrk_vram_0[tile_index * 2 + 0];
	data16_t code = realbrk_vram_0[tile_index * 2 + 1];
	SET_TILE_INFO(
			0,
			code,
			attr & 0x7f,
			TILE_FLIPYX( attr >> 14 ))
}

static void get_tile_info_1(int tile_index)
{
	data16_t attr = realbrk_vram_1[tile_index * 2 + 0];
	data16_t code = realbrk_vram_1[tile_index * 2 + 1];
	SET_TILE_INFO(
			0,
			code,
			attr & 0x7f,
			TILE_FLIPYX( attr >> 14 ))
}

WRITE16_HANDLER( realbrk_vram_0_w )
{
	data16_t old_data	=	realbrk_vram_0[offset];
	data16_t new_data	=	COMBINE_DATA(&realbrk_vram_0[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_0,offset/2);
}

WRITE16_HANDLER( realbrk_vram_1_w )
{
	data16_t old_data	=	realbrk_vram_1[offset];
	data16_t new_data	=	COMBINE_DATA(&realbrk_vram_1[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_1,offset/2);
}

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

                                Text Tilemap

    Offset:     Bits:                   Value:

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

    The full palette of 0x8000 colors can be used by this tilemap since
    a video register selects the higher bits of the color code.

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

static void get_tile_info_2(int tile_index)
{
	data16_t code = realbrk_vram_2[tile_index];
	SET_TILE_INFO(
			1,
			code & 0x0fff,
			((code & 0xf000) >> 12) | ((realbrk_vregs[0xa/2] & 0x7f) << 4),
			0)
}

WRITE16_HANDLER( realbrk_vram_2_w )
{
	data16_t old_data	=	realbrk_vram_2[offset];
	data16_t new_data	=	COMBINE_DATA(&realbrk_vram_2[offset]);
	if (old_data != new_data)	tilemap_mark_tile_dirty(tilemap_2,offset);
}



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


                            Video Hardware Init


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

VIDEO_START(realbrk)
{
	/* Backgrounds */
	tilemap_0 = tilemap_create(	get_tile_info_0, tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16,16,
								0x40, 0x20);

	tilemap_1 = tilemap_create(	get_tile_info_1, tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								16,16,
								0x40, 0x20);

	/* Text */
	tilemap_2 = tilemap_create(	get_tile_info_2, tilemap_scan_rows,
								TILEMAP_TRANSPARENT,
								8,8,
								0x40, 0x20);

	if ( !tilemap_0 || !tilemap_1 || !tilemap_2 )
		return 1;

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

	return 0;
}

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

                                Sprites Drawing

    Sprites RAM is 0x4000 bytes long with each sprite needing 16 bytes.

    Not all sprites must be displayed: there is a list of words at offset
    0x3000. If the high bit of a word is 0 the low bits form the index
    of a sprite to be drawn. 0x300 items of the list seem to be used.

    Each sprite is made of several 16x16 tiles (from 1 to 32x32) and
    can be zoomed / shrinked in size.

    There are two set of tiles: with 256 or 16 colors.

    Offset:     Bits:                   Value:

        0.w                             Y

        2.w                             X

        4.w     fedc ba98 ---- ----     Number of tiles along Y, minus 1 (5 bits or more ?)
                ---- ---- 7654 3210     Number of tiles along X, minus 1 (5 bits or more ?)

        6.w     fedc ba98 ---- ----     Zoom factor along Y (0x40 = no zoom)
                ---- ---- 7654 3210     Zoom factor along X (0x40 = no zoom)

        8.w     fe-- ---- ---- ----
                --d- ---- ---- ----     Flip Y
                ---c ---- ---- ----     Flip X
                ---- ba98 7654 3210     Priority?

        A.w     fedc b--- ---- ----
                ---- -a98 7654 3210     Color

        C.w     fedc ba9- ---- ----
                ---- ---8 ---- ----
                ---- ---- 7654 321-
                ---- ---- ---- ---0     1 = Use 16 color sprites, 0 = Use 256 color sprites

        E.w                             Code

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

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

	int max_x		=	Machine->drv->screen_width;
	int max_y		=	Machine->drv->screen_height;

	for ( offs = 0x3000/2; offs < 0x3600/2; offs += 2/2 )
	{
		int sx, sy, dim, zoom, flip, color, attr, code, flipx, flipy, gfx;

		int x, xdim, xnum, xstart, xend, xinc;
		int y, ydim, ynum, ystart, yend, yinc;

		data16_t *s;

		if (spriteram16[offs] & 0x8000)	continue;

		s		=		&spriteram16[(spriteram16[offs] & 0x3ff) * 16/2];

		sy		=		s[ 0 ];
		sx		=		s[ 1 ];
		dim		=		s[ 2 ];
		zoom	=		s[ 3 ];
		flip	=		s[ 4 ];
		color	=		s[ 5 ];
		attr	=		s[ 6 ];
		code	=		s[ 7 ];

		xnum	=		((dim >> 0) & 0x1f) + 1;
		ynum	=		((dim >> 8) & 0x1f) + 1;

		flipx	=		flip & 0x0100;
		flipy	=		flip & 0x0200;

		gfx		=		(attr & 0x0001) + 2;

		sx		=		((sx & 0x1ff) - (sx & 0x200)) << 16;
		sy		=		((sy & 0x0ff) - (sy & 0x100)) << 16;

		xdim	=		((zoom & 0x00ff) >> 0) << (16-6+4);
		ydim	=		((zoom & 0xff00) >> 8) << (16-6+4);

		if (flip_screen_x)	{	flipx = !flipx;		sx = (max_x << 16) - sx - xnum * xdim;	}
		if (flip_screen_y)	{	flipy = !flipy;		sy = (max_y << 16) - sy - ynum * ydim;	}

		if (flipx)	{ xstart = xnum-1;  xend = -1;    xinc = -1; }
		else		{ xstart = 0;       xend = xnum;  xinc = +1; }

		if (flipy)	{ ystart = ynum-1;  yend = -1;    yinc = -1; }
		else		{ ystart = 0;       yend = ynum;  yinc = +1; }

		for (y = ystart; y != yend; y += yinc)
		{
			for (x = xstart; x != xend; x += xinc)
			{
				int currx = (sx + x * xdim) / 0x10000;
				int curry = (sy + y * ydim) / 0x10000;

				int scalex = (sx + (x + 1) * xdim) / 0x10000 - currx;
				int scaley = (sy + (y + 1) * ydim) / 0x10000 - curry;

				drawgfxzoom(	bitmap,Machine->gfx[gfx],
								code++,
								color,
								flipx, flipy,
								currx, curry,
								cliprect,TRANSPARENCY_PEN,0,
								scalex << 12, scaley << 12);
			}
		}
	}
}


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

                                Screen Drawing

    Video Registers:

    Offset:     Bits:                   Value:

    0.w                                 Background 0 Scroll Y

    2.w                                 Background 0 Scroll X

    4.w                                 Background 1 Scroll Y

    6.w                                 Background 1 Scroll X

    8.w         fedc ba98 ---- ----     ? bit f = flip
                ---- ---- 7654 3210

    A.w         fedc ba98 7--- ----
                ---- ---- -654 3210     Color codes high bits for the text tilemap

    C.w         f--- ---- ---- ----
                -edc ba98 7654 3210     Index of the background color

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

WRITE16_HANDLER( realbrk_vregs_w )
{
	data16_t old_data = realbrk_vregs[offset];
	data16_t new_data = COMBINE_DATA(&realbrk_vregs[offset]);
	if (new_data != old_data)
	{
		if (offset == 0xa/2)
			tilemap_mark_all_tiles_dirty(tilemap_0);
	}
}

VIDEO_UPDATE(realbrk)
{
	int layers_ctrl = -1;

	tilemap_set_scrolly(tilemap_0, 0, realbrk_vregs[0x0/2]);
	tilemap_set_scrollx(tilemap_0, 0, realbrk_vregs[0x2/2]);

	tilemap_set_scrolly(tilemap_1, 0, realbrk_vregs[0x4/2]);
	tilemap_set_scrollx(tilemap_1, 0, realbrk_vregs[0x6/2]);

#ifdef MAME_DEBUG
if ( code_pressed(KEYCODE_Z) )
{	int msk = 0;
	if (code_pressed(KEYCODE_Q))	msk |= 1;
	if (code_pressed(KEYCODE_W))	msk |= 2;
	if (code_pressed(KEYCODE_E))	msk |= 4;
	if (code_pressed(KEYCODE_A))	msk |= 8;
	if (msk != 0) layers_ctrl &= msk;	}
#endif

	if (disable_video)
	{
		fillbitmap(bitmap,get_black_pen(),cliprect);
		return;
	}
	else
		fillbitmap(bitmap,Machine->pens[realbrk_vregs[0xc/2] & 0x7fff],cliprect);

	if (layers_ctrl & 2)	tilemap_draw(bitmap,cliprect,tilemap_1,0,0);
	if (layers_ctrl & 1)	tilemap_draw(bitmap,cliprect,tilemap_0,0,0);

	if (layers_ctrl & 8)	realbrk_draw_sprites(bitmap,cliprect);

	if (layers_ctrl & 4)	tilemap_draw(bitmap,cliprect,tilemap_2,0,0);

//  usrintf_showmessage("%04x",realbrk_vregs[0x8/2]);
}
