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

Knuckle Joe - (c) 1985 Taito Corporation

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

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


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

  Convert the color PROMs into a more useable format.

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

PALETTE_INIT( kncljoe )
{
	int i;

	/* allocate the colortable */
	machine.colortable = colortable_alloc(machine, 0x90);

	/* create a lookup table for the palette */
	for (i = 0; i < 0x80; i++)
	{
		int r = pal4bit(color_prom[i + 0x000]);
		int g = pal4bit(color_prom[i + 0x100]);
		int b = pal4bit(color_prom[i + 0x200]);

		colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
	}

	for (i = 0x80; i < 0x90; i++)
	{
		int bit0, bit1, bit2;
		int r, g, b;

		/* red component */
		bit0 = 0;
		bit1 = (color_prom[(i - 0x80) + 0x300] >> 6) & 0x01;
		bit2 = (color_prom[(i - 0x80) + 0x300] >> 7) & 0x01;
		r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;

		/* green component */
		bit0 = (color_prom[(i - 0x80) + 0x300] >> 3) & 0x01;
		bit1 = (color_prom[(i - 0x80) + 0x300] >> 4) & 0x01;
		bit2 = (color_prom[(i - 0x80) + 0x300] >> 5) & 0x01;
		g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;

		/* blue component */
		bit0 = (color_prom[(i - 0x80) + 0x300] >> 0) & 0x01;
		bit1 = (color_prom[(i - 0x80) + 0x300] >> 1) & 0x01;
		bit2 = (color_prom[(i - 0x80) + 0x300] >> 2) & 0x01;
		b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;

		colortable_palette_set_color(machine.colortable, i, MAKE_RGB(r, g, b));
	}

	/* color_prom now points to the beginning of the lookup table */
	color_prom += 0x320;

	/* chars */
	for (i = 0; i < 0x80; i++)
		colortable_entry_set_value(machine.colortable, i, i);

	/* sprite lookup table */
	for (i = 0x80; i < 0x100; i++)
	{
		UINT8 ctabentry = (color_prom[i - 0x80] & 0x0f) | 0x80;
		colortable_entry_set_value(machine.colortable, i, ctabentry);
	}
}



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

  Callbacks for the TileMap code

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

static TILE_GET_INFO( get_bg_tile_info )
{
	kncljoe_state *state = machine.driver_data<kncljoe_state>();
	int attr = state->m_videoram[2 * tile_index + 1];
	int code = state->m_videoram[2 * tile_index] + ((attr & 0xc0) << 2) + (state->m_tile_bank << 10);

	SET_TILE_INFO(
			0,
			code,
			attr & 0xf,
			TILE_FLIPXY((attr & 0x30) >> 4));
}



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

  Start the video hardware emulation.

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

VIDEO_START( kncljoe )
{
	kncljoe_state *state = machine.driver_data<kncljoe_state>();
	state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows, 8, 8, 64, 32);

	tilemap_set_scroll_rows(state->m_bg_tilemap, 4);
}



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

  Memory handlers

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

WRITE8_HANDLER( kncljoe_videoram_w )
{
	kncljoe_state *state = space->machine().driver_data<kncljoe_state>();
	state->m_videoram[offset] = data;
	tilemap_mark_tile_dirty(state->m_bg_tilemap, offset / 2);
}

WRITE8_HANDLER( kncljoe_control_w )
{
	kncljoe_state *state = space->machine().driver_data<kncljoe_state>();
	int i;
	/*
            0x01    screen flip
            0x02    coin counter#1
            0x04    sprite bank
            0x10    character bank
            0x20    coin counter#2

            reset when IN0 - Coin 1 goes low (active)
            set after IN0 - Coin 1 goes high AND the credit has been added
   */
	state->m_flipscreen = data & 0x01;
	tilemap_set_flip_all(space->machine(), state->m_flipscreen ? TILEMAP_FLIPX : TILEMAP_FLIPY);

	coin_counter_w(space->machine(), 0, data & 0x02);
	coin_counter_w(space->machine(), 1, data & 0x20);

	i = (data & 0x10) >> 4;
	if (state->m_tile_bank != i)
	{
		state->m_tile_bank = i;
		tilemap_mark_all_tiles_dirty(state->m_bg_tilemap);
	}

	i = (data & 0x04) >> 2;
	if (state->m_sprite_bank != i)
	{
		state->m_sprite_bank = i;
		memset(space->machine().region("maincpu")->base() + 0xf100, 0, 0x180);
	}
}

WRITE8_HANDLER( kncljoe_scroll_w )
{
	kncljoe_state *state = space->machine().driver_data<kncljoe_state>();
	int scrollx;

	state->m_scrollregs[offset] = data;
	scrollx = state->m_scrollregs[0] | state->m_scrollregs[1] << 8;
	tilemap_set_scrollx(state->m_bg_tilemap, 0, scrollx);
	tilemap_set_scrollx(state->m_bg_tilemap, 1, scrollx);
	tilemap_set_scrollx(state->m_bg_tilemap, 2, scrollx);
	tilemap_set_scrollx(state->m_bg_tilemap, 3, 0);
}



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

  Display refresh

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

static void draw_sprites( running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect )
{
	kncljoe_state *state = machine.driver_data<kncljoe_state>();
	UINT8 *spriteram = state->m_spriteram;
	rectangle clip = *cliprect;
	const gfx_element *gfx = machine.gfx[1 + state->m_sprite_bank];
	int i, j;
	static const int pribase[4]={0x0180, 0x0080, 0x0100, 0x0000};
	const rectangle &visarea = machine.primary_screen->visible_area();

	/* score covers sprites */
	if (state->m_flipscreen)
	{
		if (clip.max_y > visarea.max_y - 64)
			clip.max_y = visarea.max_y - 64;
	}
	else
	{
		if (clip.min_y < visarea.min_y + 64)
			clip.min_y = visarea.min_y + 64;
	}

	for (i = 0; i < 4; i++)
		for (j = 0x7c; j >= 0; j -= 4)
		{
			int offs = pribase[i] + j;
			int sy = spriteram[offs];
			int sx = spriteram[offs + 3];
			int code = spriteram[offs + 2];
			int attr = spriteram[offs + 1];
			int flipx = attr & 0x40;
			int flipy = !(attr & 0x80);
			int color = attr & 0x0f;

			if (attr & 0x10)
				code += 512;
			if (attr & 0x20)
				code += 256;

			if (state->m_flipscreen)
			{
				flipx = !flipx;
				flipy = !flipy;
				sx = 240 - sx;
				sy = 240 - sy;
			}

			if (sx >= 256-8)
				sx -= 256;

			drawgfx_transpen(bitmap,&clip,gfx,
				code,
				color,
				flipx,flipy,
				sx,sy,0);
		}
}

SCREEN_UPDATE( kncljoe )
{
	kncljoe_state *state = screen->machine().driver_data<kncljoe_state>();

	tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, 0);
	draw_sprites(screen->machine(), bitmap, cliprect);
	return 0;
}
