#include "emu.h"
#include "includes/sf.h"

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

  Callbacks for the TileMap code

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

static TILE_GET_INFO( get_bg_tile_info )
{
	UINT8 *base = machine.region("gfx5")->base() + 2 * tile_index;
	int attr = base[0x10000];
	int color = base[0];
	int code = (base[0x10000 + 1] << 8) | base[1];
	SET_TILE_INFO(
			0,
			code,
			color,
			TILE_FLIPYX(attr & 3));
}

static TILE_GET_INFO( get_fg_tile_info )
{
	UINT8 *base = machine.region("gfx5")->base() + 0x20000 + 2 * tile_index;
	int attr = base[0x10000];
	int color = base[0];
	int code = (base[0x10000 + 1] << 8) | base[1];
	SET_TILE_INFO(
			1,
			code,
			color,
			TILE_FLIPYX(attr & 3));
}

static TILE_GET_INFO( get_tx_tile_info )
{
	sf_state *state = machine.driver_data<sf_state>();
	int code = state->m_videoram[tile_index];
	SET_TILE_INFO(
			3,
			code & 0x3ff,
			code>>12,
			TILE_FLIPYX((code & 0xc00)>>10));
}



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

  Start the video hardware emulation.

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

VIDEO_START( sf )
{
	sf_state *state = machine.driver_data<sf_state>();

	state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_cols, 16, 16, 2048, 16);
	state->m_fg_tilemap = tilemap_create(machine, get_fg_tile_info, tilemap_scan_cols, 16, 16, 2048, 16);
	state->m_tx_tilemap = tilemap_create(machine, get_tx_tile_info, tilemap_scan_rows, 8, 8, 64, 32);

	tilemap_set_transparent_pen(state->m_fg_tilemap, 15);
	tilemap_set_transparent_pen(state->m_tx_tilemap, 3);
}



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

  Memory handlers

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

WRITE16_HANDLER( sf_videoram_w )
{
	sf_state *state = space->machine().driver_data<sf_state>();
	COMBINE_DATA(&state->m_videoram[offset]);
	tilemap_mark_tile_dirty(state->m_tx_tilemap, offset);
}

WRITE16_HANDLER( sf_bg_scroll_w )
{
	sf_state *state = space->machine().driver_data<sf_state>();
	COMBINE_DATA(&state->m_bgscroll);
	tilemap_set_scrollx(state->m_bg_tilemap, 0, state->m_bgscroll);
}

WRITE16_HANDLER( sf_fg_scroll_w )
{
	sf_state *state = space->machine().driver_data<sf_state>();
	COMBINE_DATA(&state->m_fgscroll);
	tilemap_set_scrollx(state->m_fg_tilemap, 0, state->m_fgscroll);
}

WRITE16_HANDLER( sf_gfxctrl_w )
{
	/* b0 = reset, or maybe "set anyway" */
	/* b1 = pulsed when control6.b6==0 until it's 1 */
	/* b2 = active when dip 8 (flip) on */
	/* b3 = active character plane */
	/* b4 = unused */
	/* b5 = active background plane */
	/* b6 = active middle plane */
	/* b7 = active sprites */

	sf_state *state = space->machine().driver_data<sf_state>();
	if (ACCESSING_BITS_0_7)
	{
		state->m_sf_active = data & 0xff;
		flip_screen_set(space->machine(), data & 0x04);
		tilemap_set_enable(state->m_tx_tilemap, data & 0x08);
		tilemap_set_enable(state->m_bg_tilemap, data & 0x20);
		tilemap_set_enable(state->m_fg_tilemap, data & 0x40);
	}
}



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

  Display refresh

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

INLINE int sf_invert( int nb )
{
	static const int delta[4] = {0x00, 0x18, 0x18, 0x00};
	return nb ^ delta[(nb >> 3) & 3];
}

static void draw_sprites( running_machine &machine, bitmap_t *bitmap,const rectangle *cliprect )
{
	sf_state *state = machine.driver_data<sf_state>();
	int offs;

	for (offs = 0x1000 - 0x20; offs >= 0; offs -= 0x20)
	{
		int c = state->m_objectram[offs];
		int attr = state->m_objectram[offs + 1];
		int sy = state->m_objectram[offs + 2];
		int sx = state->m_objectram[offs + 3];
		int color = attr & 0x000f;
		int flipx = attr & 0x0100;
		int flipy = attr & 0x0200;

		if (attr & 0x400)	/* large sprite */
		{
			int c1, c2, c3, c4, t;

			if (flip_screen_get(machine))
			{
				sx = 480 - sx;
				sy = 224 - sy;
				flipx = !flipx;
				flipy = !flipy;
			}

			c1 = c;
			c2 = c + 1;
			c3 = c + 16;
			c4 = c + 17;

			if (flipx)
			{
				t = c1; c1 = c2; c2 = t;
				t = c3; c3 = c4; c4 = t;
			}
			if (flipy)
			{
				t = c1; c1 = c3; c3 = t;
				t = c2; c2 = c4; c4 = t;
			}

			drawgfx_transpen(bitmap,
					cliprect, machine.gfx[2],
					sf_invert(c1),
					color,
					flipx,flipy,
					sx,sy, 15);
			drawgfx_transpen(bitmap,
					cliprect, machine.gfx[2],
					sf_invert(c2),
					color,
					flipx,flipy,
					sx+16,sy, 15);
			drawgfx_transpen(bitmap,
					cliprect, machine.gfx[2],
					sf_invert(c3),
					color,
					flipx,flipy,
					sx,sy+16, 15);
			drawgfx_transpen(bitmap,
					cliprect, machine.gfx[2],
					sf_invert(c4),
					color,
					flipx,flipy,
					sx+16,sy+16, 15);
		}
		else
		{
			if (flip_screen_get(machine))
			{
				sx = 496 - sx;
				sy = 240 - sy;
				flipx = !flipx;
				flipy = !flipy;
			}

			drawgfx_transpen(bitmap,
					cliprect, machine.gfx[2],
					sf_invert(c),
					color,
					flipx,flipy,
					sx,sy, 15);
		}
	}
}


SCREEN_UPDATE( sf )
{
	sf_state *state = screen->machine().driver_data<sf_state>();

	if (state->m_sf_active & 0x20)
		tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, 0);
	else
		bitmap_fill(bitmap, cliprect, 0);

	tilemap_draw(bitmap, cliprect, state->m_fg_tilemap, 0, 0);

	if (state->m_sf_active & 0x80)
		draw_sprites(screen->machine(), bitmap, cliprect);

	tilemap_draw(bitmap, cliprect, state->m_tx_tilemap, 0, 0);
	return 0;
}
