// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino
/***************************************************************************

Atari Fire Truck + Super Bug + Monte Carlo video emulation

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

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

static const rectangle playfield_window(0x02a, 0x115, 0x000, 0x0ff);


void firetrk_state::firetrk_palette(palette_device &palette)
{
	static constexpr uint8_t colortable_source[] =
	{
		0, 0, 1, 0,
		2, 0, 3, 0,
		3, 3, 2, 3,
		1, 3, 0, 3,
		0, 0, 1, 0,
		2, 0, 0, 3,
		3, 0, 0, 3
	};
	static constexpr rgb_t palette_source[] =
	{
		rgb_t::black(),
		rgb_t(0x5b, 0x5b, 0x5b),
		rgb_t(0xa4, 0xa4, 0xa4),
		rgb_t::white()
	};

	m_color1_mask = m_color2_mask = 0;

	for (int i = 0; i < std::size(colortable_source); i++)
	{
		uint8_t color = colortable_source[i];

		if (color == 1)
			m_color1_mask |= 1 << i;
		else if (color == 2)
			m_color2_mask |= 1 << i;

		palette.set_pen_color(i, palette_source[color]);
	}
}


void firetrk_state::prom_to_palette(int number, uint8_t val)
{
	m_palette->set_pen_color(number, rgb_t(pal1bit(val >> 2), pal1bit(val >> 1), pal1bit(val >> 0)));
}


void firetrk_state::montecar_palette(palette_device &palette)
{
	const uint8_t *color_prom = memregion("proms")->base();

	static constexpr uint8_t colortable_source[] =
	{
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x02, 0x00, 0x03,
		0x03, 0x03, 0x03, 0x02,
		0x03, 0x01, 0x03, 0x00,
		0x00, 0x00, 0x02, 0x00,
		0x02, 0x01, 0x02, 0x02,
		0x00, 0x10, 0x20, 0x30,
		0x00, 0x04, 0x08, 0x0c,
		0x00, 0x44, 0x48, 0x4c,
		0x00, 0x84, 0x88, 0x8c,
		0x00, 0xc4, 0xc8, 0xcc
	};

	/*
	 * The color PROM is addressed as follows:
	 *
	 *   A0 => PLAYFIELD 1
	 *   A1 => PLAYFIELD 2
	 *   A2 => DRONE 1
	 *   A3 => DRONE 2
	 *   A4 => CAR 1
	 *   A5 => CAR 2
	 *   A6 => DRONE COLOR 1
	 *   A7 => DRONE COLOR 2
	 *   A8 => PLAYFIELD WINDOW
	 *
	 * This driver hard-codes some behavior which actually depends
	 * on the PROM, like priorities, clipping and transparency.
	 *
	 */

	m_color1_mask = m_color2_mask = 0;

	for (int i = 0; i < std::size(colortable_source); i++)
	{
		uint8_t color = colortable_source[i];

		if (color == 1)
			m_color1_mask |= 1 << i;
		else if (color == 2)
			m_color2_mask |= 1 << i;

		prom_to_palette(i, color_prom[0x100 + colortable_source[i]]);
	}

	palette.set_pen_color(std::size(colortable_source) + 0, rgb_t::black());
	palette.set_pen_color(std::size(colortable_source) + 1, rgb_t::white());
}


TILE_GET_INFO_MEMBER(firetrk_state::firetrk_get_tile_info1)
{
	int code = m_playfield_ram[tile_index] & 0x3f;
	int color = (m_playfield_ram[tile_index] >> 6) & 0x03;

	if (*m_blink && (code >= 0x04) && (code <= 0x0b))
		color = 0;

	if (m_flash)
		color = color | 0x04;

	tileinfo.set(1, code, color, 0);
}


TILE_GET_INFO_MEMBER(firetrk_state::superbug_get_tile_info1)
{
	int code = m_playfield_ram[tile_index] & 0x3f;
	int color = (m_playfield_ram[tile_index] >> 6) & 0x03;

	if (*m_blink && (code >= 0x08) && (code <= 0x0f))
		color = 0;

	if (m_flash)
		color = color | 0x04;

	tileinfo.set(1, code, color, 0);
}


TILE_GET_INFO_MEMBER(firetrk_state::montecar_get_tile_info1)
{
	int code = m_playfield_ram[tile_index] & 0x3f;
	int color = (m_playfield_ram[tile_index] >> 6) & 0x03;

	if (m_flash)
		color = color | 0x04;

	tileinfo.set(1, code, color, 0);
}


TILE_GET_INFO_MEMBER(firetrk_state::firetrk_get_tile_info2)
{
	uint8_t code = m_playfield_ram[tile_index] & 0x3f;
	int color = 0;

	/* palette 1 for crash and palette 2 for skid */
	if (((code & 0x30) != 0x00) || ((code & 0x0c) == 0x00))
		color = 1;   /* palette 0, 1 */

	if ((code & 0x3c) == 0x0c)
		color = 2;   /* palette 0, 2 */

	tileinfo.set(2, code, color, 0);
}


TILE_GET_INFO_MEMBER(firetrk_state::superbug_get_tile_info2)
{
	uint8_t code = m_playfield_ram[tile_index] & 0x3f;
	int color = 0;

	/* palette 1 for crash and palette 2 for skid */
	if ((code & 0x30) != 0x00)
		color = 1;   /* palette 0, 1 */

	if ((code & 0x38) == 0x00)
		color = 2;   /* palette 0, 2 */

	tileinfo.set(2, code, color, 0);
}


TILE_GET_INFO_MEMBER(firetrk_state::montecar_get_tile_info2)
{
	uint8_t code = m_playfield_ram[tile_index];
	int color = 0;

	/* palette 1 for crash and palette 2 for skid */
	if (((code & 0xc0) == 0x40) || ((code & 0xc0) == 0x80))
		color = 2;   /* palette 2, 1 */

	if ((code & 0xc0) == 0xc0)
		color = 1;   /* palette 2, 0 */

	if ((code & 0xc0) == 0x00)
		color = 3;   /* palette 2, 2 */

	if ((code & 0x30) == 0x30)
		color = 0;   /* palette 0, 0 */

	tileinfo.set(2, code & 0x3f, color, 0);
}


void firetrk_state::video_start()
{
	m_screen->register_screen_bitmap(m_helper1);
	m_screen->register_screen_bitmap(m_helper2);

	m_tilemap1 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::firetrk_get_tile_info1)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
	m_tilemap2 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::firetrk_get_tile_info2)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
}


VIDEO_START_MEMBER(firetrk_state,superbug)
{
	m_screen->register_screen_bitmap(m_helper1);
	m_screen->register_screen_bitmap(m_helper2);

	m_tilemap1 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::superbug_get_tile_info1)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
	m_tilemap2 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::superbug_get_tile_info2)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
}


VIDEO_START_MEMBER(firetrk_state,montecar)
{
	m_screen->register_screen_bitmap(m_helper1);
	m_screen->register_screen_bitmap(m_helper2);

	m_tilemap1 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::montecar_get_tile_info1)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
	m_tilemap2 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(firetrk_state::montecar_get_tile_info2)), TILEMAP_SCAN_ROWS, 16, 16, 16, 16);
}


void firetrk_state::firetrk_draw_car(bitmap_ind16 &bitmap, const rectangle &cliprect, int which, int flash)
{
	int gfx_bank, code, color, flip_x, flip_y, x, y;

	if (which)
	{
		gfx_bank = 5;
		code = *m_drone_rot & 0x07;
		color = flash ? 1 : 0;
		flip_x = *m_drone_rot & 0x08;
		flip_y = *m_drone_rot & 0x10;
		x = (flip_x ? *m_drone_x - 63 : 192 - *m_drone_x) + 36;
		y =  flip_y ? *m_drone_y - 63 : 192 - *m_drone_y;
	}
	else
	{
		gfx_bank = (*m_car_rot & 0x10) ? 4 : 3;
		code = *m_car_rot & 0x03;
		color = flash ? 1 : 0;
		flip_x = *m_car_rot & 0x04;
		flip_y = *m_car_rot & 0x08;
		x = 144;
		y = 104;
	}

		m_gfxdecode->gfx(gfx_bank)->transpen(bitmap,cliprect, code, color, flip_x, flip_y, x, y, 0);
}


void firetrk_state::superbug_draw_car(bitmap_ind16 &bitmap, const rectangle &cliprect, int flash)
{
	int gfx_bank = (*m_car_rot & 0x10) ? 4 : 3;
	int code = ~*m_car_rot & 0x03;
	int color = flash ? 1 : 0;
	int flip_x = *m_car_rot & 0x04;
	int flip_y = *m_car_rot & 0x08;

		m_gfxdecode->gfx(gfx_bank)->transpen(bitmap,cliprect, code, color, flip_x, flip_y, 144, 104, 0);
}


void firetrk_state::montecar_draw_car(bitmap_ind16 &bitmap, const rectangle &cliprect, int which, int is_collision_detection)
{
	int gfx_bank, code, color, flip_x, flip_y, x, y;

	if (which)
	{
		gfx_bank = 4;
		code = *m_drone_rot & 0x07;
		color = is_collision_detection ? 0 : (((*m_car_rot & 0x80) >> 6) | ((*m_drone_rot & 0x80) >> 7));
		flip_x = *m_drone_rot & 0x10;
		flip_y = *m_drone_rot & 0x08;
		x = (flip_x ? *m_drone_x - 31 : 224 - *m_drone_x) + 34;
		y =  flip_y ? *m_drone_y - 31 : 224 - *m_drone_y;
	}
	else
	{
		gfx_bank = 3;
		code = *m_car_rot & 0x07;
		color = 0;
		flip_x = *m_car_rot & 0x10;
		flip_y = *m_car_rot & 0x08;
		x = 144;
		y = 104;
	}

		m_gfxdecode->gfx(gfx_bank)->transpen(bitmap,cliprect, code, color, flip_x, flip_y, x, y, 0);
}


void firetrk_state::draw_text(bitmap_ind16 &bitmap, const rectangle &cliprect, uint8_t *alpha_ram,
						int x, int count, int height)
{
	int i;

	for (i = 0; i < count; i++)
			m_gfxdecode->gfx(0)->opaque(bitmap,cliprect, alpha_ram[i], 0, 0, 0, x, i * height);
}


void firetrk_state::check_collision(int which)
{
	for (int y = playfield_window.top(); y <= playfield_window.bottom(); y++)
		for (int x = playfield_window.left(); x <= playfield_window.right(); x++)
		{
			pen_t const a = m_helper1.pix(y, x);
			pen_t const b = m_helper2.pix(y, x);

			if (b != 0xff && (m_color1_mask >> a) & 1)
				m_crash[which] = 1;

			if (b != 0xff && (m_color2_mask >> a) & 1)
				m_skid[which] = 1;
		}
}


uint32_t firetrk_state::screen_update_firetrk(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	machine().tilemap().mark_all_dirty();
	m_tilemap1->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap2->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap1->set_scrolly(0, *m_scroll_y);
	m_tilemap2->set_scrolly(0, *m_scroll_y);

	bitmap.fill(0, cliprect);
	m_tilemap1->draw(screen, bitmap, playfield_window, 0, 0);
	firetrk_draw_car(bitmap, playfield_window, 0, m_flash);
	firetrk_draw_car(bitmap, playfield_window, 1, m_flash);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x00, 296, 0x10, 0x10);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x10,   8, 0x10, 0x10);

	if (cliprect.bottom() == screen.visible_area().bottom())
	{
		m_tilemap2->draw(screen, m_helper1, playfield_window, 0, 0);

		m_helper2.fill(0xff, playfield_window);
		firetrk_draw_car(m_helper2, playfield_window, 0, false);
		check_collision(0);

		m_helper2.fill(0xff, playfield_window);
		firetrk_draw_car(m_helper2, playfield_window, 1, false);
		check_collision(1);

		*m_blink = false;
	}

	return 0;
}


uint32_t firetrk_state::screen_update_superbug(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	machine().tilemap().mark_all_dirty();
	m_tilemap1->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap2->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap1->set_scrolly(0, *m_scroll_y);
	m_tilemap2->set_scrolly(0, *m_scroll_y);

	bitmap.fill(0, cliprect);
	m_tilemap1->draw(screen, bitmap, playfield_window, 0, 0);
	superbug_draw_car(bitmap, playfield_window, m_flash);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x00, 296, 0x10, 0x10);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x10,   8, 0x10, 0x10);

	if (cliprect.bottom() == screen.visible_area().bottom())
	{
		m_tilemap2->draw(screen, m_helper1, playfield_window, 0, 0);

		m_helper2.fill(0xff, playfield_window);
		superbug_draw_car(m_helper2, playfield_window, false);
		check_collision(0);

		*m_blink = false;
	}

	return 0;
}


uint32_t firetrk_state::screen_update_montecar(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	machine().tilemap().mark_all_dirty();
	m_tilemap1->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap2->set_scrollx(0, *m_scroll_x - 37);
	m_tilemap1->set_scrolly(0, *m_scroll_y);
	m_tilemap2->set_scrolly(0, *m_scroll_y);

	bitmap.fill(0x2c, cliprect);
	m_tilemap1->draw(screen, bitmap, playfield_window, 0, 0);
	montecar_draw_car(bitmap, playfield_window, 0, false);
	montecar_draw_car(bitmap, playfield_window, 1, false);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x00, 24, 0x20, 0x08);
	draw_text(bitmap, cliprect, m_alpha_num_ram + 0x20, 16, 0x20, 0x08);

	if (cliprect.bottom() == screen.visible_area().bottom())
	{
		m_tilemap2->draw(screen, m_helper1, playfield_window, 0, 0);

		m_helper2.fill(0xff, playfield_window);
		montecar_draw_car(m_helper2, playfield_window, 0, true);
		check_collision(0);

		m_helper2.fill(0xff, playfield_window);
		montecar_draw_car(m_helper2, playfield_window, 1, true);
		check_collision(1);
	}

	return 0;
}
