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

                              -= Paradise / Target Ball / Torus =-

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


Note:   if MAME_DEBUG is defined, pressing Z with:

        Q       shows the background layer
        W       shows the midground layer
        E       shows the foreground layer
        R       shows the pixmap layer
        A       shows sprites

        There are 4 Fixed 256 x 256 Layers.

        Background tiles are 8x8x4 with a register selecting which
        color code to use.

        midground and foreground tiles are 8x8x8 with no color code.
        Then there's a 16 color pixel layer.

        Bog standard 16x16x8 sprites, apparently with no color code nor flipping.

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

#include "driver.h"
#include "paradise.h"

/* Variables that driver has access to: */

UINT8 *paradise_vram_0,*paradise_vram_1,*paradise_vram_2;
int paradise_sprite_inc;

/* Variables only used here */

static UINT8 paradise_palbank, paradise_priority;

WRITE8_HANDLER( paradise_flipscreen_w )
{
	flip_screen_set(data ? 0 : 1);
}

WRITE8_HANDLER( tgtball_flipscreen_w )
{
	flip_screen_set(data ? 1 : 0);
}


/* 800 bytes for red, followed by 800 bytes for green & 800 bytes for blue */
WRITE8_HANDLER( paradise_palette_w )
{
	paletteram[offset] = data;
	offset %= 0x800;
	palette_set_color_rgb(Machine,offset,	paletteram[offset + 0x800 * 0],
											paletteram[offset + 0x800 * 1],
											paletteram[offset + 0x800 * 2]	);
}

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

                                    Tilemaps

    Offset:

    $000.b      Code (Low  Bits)
    $400.b      Code (High Bits)

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

static tilemap *tilemap_0,*tilemap_1,*tilemap_2;

/* Background */
WRITE8_HANDLER( paradise_vram_0_w )
{
	paradise_vram_0[offset] = data;
	tilemap_mark_tile_dirty(tilemap_0, offset % 0x400);
}

/* 16 color tiles with paradise_palbank as color code */
WRITE8_HANDLER( paradise_palbank_w )
{
	int i;
	int bank1 = (data & 0x0e) | 1;
	int bank2 = (data & 0xf0);

	for (i = 0; i < 15; i++)
		palette_set_color_rgb(Machine,0x800+i,	paletteram[0x200 + bank2 + i + 0x800 * 0],
												paletteram[0x200 + bank2 + i + 0x800 * 1],
												paletteram[0x200 + bank2 + i + 0x800 * 2]	);
	if (paradise_palbank != bank1)
	{
		paradise_palbank = bank1;
		tilemap_mark_all_tiles_dirty(tilemap_0);
	}
}

static TILE_GET_INFO( get_tile_info_0 )
{
	int code = paradise_vram_0[tile_index] + (paradise_vram_0[tile_index + 0x400] << 8);
	SET_TILE_INFO(1, code, paradise_palbank, 0);
}


/* Midground */
WRITE8_HANDLER( paradise_vram_1_w )
{
	paradise_vram_1[offset] = data;
	tilemap_mark_tile_dirty(tilemap_1, offset % 0x400);
}

static TILE_GET_INFO( get_tile_info_1 )
{
	int code = paradise_vram_1[tile_index] + (paradise_vram_1[tile_index + 0x400] << 8);
	SET_TILE_INFO(2, code, 0, 0);
}


/* Foreground */
WRITE8_HANDLER( paradise_vram_2_w )
{
	paradise_vram_2[offset] = data;
	tilemap_mark_tile_dirty(tilemap_2, offset % 0x400);
}

static TILE_GET_INFO( get_tile_info_2 )
{
	int code = paradise_vram_2[tile_index] + (paradise_vram_2[tile_index + 0x400] << 8);
	SET_TILE_INFO(3, code, 0, 0);
}

/* 256 x 256 bitmap. 4 bits per pixel so every byte encodes 2 pixels */

WRITE8_HANDLER( paradise_pixmap_w )
{
	int x,y;

	videoram[offset] = data;

	x = (offset & 0x7f) << 1;
	y = (offset >> 7);

	*BITMAP_ADDR16(tmpbitmap, y, x+0) = 0x80f - (data >> 4);
	*BITMAP_ADDR16(tmpbitmap, y, x+1) = 0x80f - (data & 0x0f);
}


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

                            Vide Hardware Init

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

VIDEO_START( paradise )
{
	tilemap_0 = tilemap_create(	get_tile_info_0, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 8,8, 0x20,0x20 );

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

	tilemap_2 = tilemap_create(	get_tile_info_2, tilemap_scan_rows,
								TILEMAP_TRANSPARENT, 8,8, 0x20,0x20 );

	/* pixmap */
	tmpbitmap = auto_bitmap_alloc(machine->screen[0].width,machine->screen[0].height,machine->screen[0].format);

	/* paletteram and videoram (pixmap) are accessed through CPU ports, that don't
       get memory automatically allocated for them */
	paletteram	=	auto_malloc(0x1800);
	videoram	=	auto_malloc(0x8000);

	tilemap_set_transparent_pen(tilemap_0,0x0f);
	tilemap_set_transparent_pen(tilemap_1,0xff);
	tilemap_set_transparent_pen(tilemap_2,0xff);
}


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

                            Sprites Drawing

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

/* Sprites / Layers priority */
WRITE8_HANDLER( paradise_priority_w )
{
	paradise_priority = data;
}

static void draw_sprites(running_machine *machine, mame_bitmap *bitmap,const rectangle *cliprect)
{
	int i;
	for (i = 0; i < spriteram_size ; i += paradise_sprite_inc)
	{
		int code	=	spriteram[i+0];
		int x		=	spriteram[i+1];
		int y		=	spriteram[i+2] - 2;
		int attr	=	spriteram[i+3];

		int flipx	=	0;	// ?
		int flipy	=	0;

		if (flip_screen)	{	x = 0xf0 - x;	flipx = !flipx;
								y = 0xf0 - y;	flipy = !flipy;	}

		drawgfx(bitmap,machine->gfx[0],
				code + (attr << 8),
				0,
				flipx, flipy,
				x,y,
				cliprect,TRANSPARENCY_PEN, 0xff );

		/* wrap around x */
		drawgfx(bitmap,machine->gfx[0],
				code + (attr << 8),
				0,
				flipx, flipy,
				x - 256,y,
				cliprect,TRANSPARENCY_PEN, 0xff );

		drawgfx(bitmap,machine->gfx[0],
				code + (attr << 8),
				0,
				flipx, flipy,
				x + 256,y,
				cliprect,TRANSPARENCY_PEN, 0xff );
	}
}


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

                                Screen Drawing

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

VIDEO_UPDATE( paradise )
{
	int layers_ctrl = -1;

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

	fillbitmap(bitmap,get_black_pen(machine),cliprect);

	if (!(paradise_priority & 4))	/* Screen blanking */
		return 0;

	if (paradise_priority & 1)
		if (layers_ctrl&16)	draw_sprites(machine,bitmap,cliprect);

	if (layers_ctrl&1)	tilemap_draw(bitmap,cliprect, tilemap_0, 0,0);
	if (layers_ctrl&2)	tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
	if (layers_ctrl&4)	copybitmap(bitmap,tmpbitmap,flip_screen,flip_screen,0,0,cliprect,TRANSPARENCY_PEN, 0x80f);

	if (paradise_priority & 2)
	{
		if (!(paradise_priority & 1))
			if (layers_ctrl&16)	draw_sprites(machine, bitmap,cliprect);
		if (layers_ctrl&8)	tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
	}
	else
	{
		if (layers_ctrl&8)	tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
		if (!(paradise_priority & 1))
			if (layers_ctrl&16)	draw_sprites(machine, bitmap,cliprect);
	}
	return 0;
}

/* no pix layer, no tilemap_0, different priority bits */
VIDEO_UPDATE( torus )
{
	fillbitmap(bitmap,get_black_pen(machine),cliprect);

	if (!(paradise_priority & 2))	/* Screen blanking */
		return 0;

	if (paradise_priority & 1)
		draw_sprites(machine, bitmap,cliprect);

	tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);

	if(paradise_priority & 4)
	{
		if (!(paradise_priority & 1))
			draw_sprites(machine, bitmap,cliprect);

		tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
	}
	else
	{
		tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);

		if (!(paradise_priority & 1))
			draw_sprites(machine, bitmap,cliprect);
	}
	return 0;
}

/* I don't know how the priority bits work on this one */
VIDEO_UPDATE( madball )
{
	fillbitmap(bitmap,get_black_pen(machine),cliprect);
	tilemap_draw(bitmap,cliprect, tilemap_0, 0,0);
	tilemap_draw(bitmap,cliprect, tilemap_1, 0,0);
	tilemap_draw(bitmap,cliprect, tilemap_2, 0,0);
	draw_sprites(machine, bitmap,cliprect);
	return 0;
}


