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

Video functions for Bagmanm2 and Bagmanmc.
Written for MisfitMAME by Robbbert, August 2008,
using code derived from MAME.

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

#include "driver.h"
#include "includes/galaxold.h"

static const rectangle _spritevisiblearea =
{
	2*8+1, 32*8-1,
	2*8,   30*8-1
};
static const rectangle _spritevisibleareaflipx =
{
	0*8, 30*8-2,
	2*8, 30*8-1
};

static const rectangle* spritevisiblearea;
static const rectangle* spritevisibleareaflipx;

static rectangle _spritevisibleareamc =
{
	2*8+1, 32*8-1,
	2*8,   30*8-1
};
static rectangle _spritevisibleareaflipxmc =
{
	0*8, 30*8-2,
	2*8, 30*8-1
};

#define STARS_COLOR_BASE 		(memory_region_length(machine, REGION_PROMS))
#define BULLETS_COLOR_BASE		(STARS_COLOR_BASE + 64)
#define BACKGROUND_COLOR_BASE	(BULLETS_COLOR_BASE + 2)


UINT8 *galaxold_videoram;
UINT8 *galaxold_spriteram;
UINT8 *galaxold_spriteram2;
UINT8 *galaxold_attributesram;
UINT8 *galaxold_bulletsram;
size_t galaxold_spriteram_size;
size_t galaxold_spriteram2_size;
size_t galaxold_bulletsram_size;


static TILE_GET_INFO( get_tile_info );
static tilemap *bg_tilemap;
static int spriteram2_present;
static UINT8 gfxbank[5];
static UINT8 flipscreen_x;
static UINT8 flipscreen_y;
static UINT8 color_mask;
static void (*modify_charcode)(UINT16 *code,UINT8 x);		/* function to call to do character banking */
static void (*modify_spritecode)(UINT8 *spriteram,int*,int*,int*,int);	/* function to call to do sprite banking */
static void (*modify_color)(UINT8 *color);	/* function to call to do modify how the color codes map to the PROM */
static void (*modify_ypos)(UINT8*);	/* function to call to do modify how vertical positioning bits are connected */
static void (*tilemap_set_scroll)( tilemap *, int col, int value );

/* background circuit */
static UINT8 background_enable;
static UINT8 background_red, background_green, background_blue;
static void (*draw_background)(bitmap_t *, const rectangle *cliprect);	/* function to call to draw the background */
static void galaxold_draw_background(bitmap_t *bitmap, const rectangle *cliprect);


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

  Convert the color PROMs into a more useable format.

  Galaxian has one 32 bytes palette PROM, connected to the RGB output this way:

  bit 7 -- 220 ohm resistor  -- BLUE
        -- 470 ohm resistor  -- BLUE
        -- 220 ohm resistor  -- GREEN
        -- 470 ohm resistor  -- GREEN
        -- 1  kohm resistor  -- GREEN
        -- 220 ohm resistor  -- RED
        -- 470 ohm resistor  -- RED
  bit 0 -- 1  kohm resistor  -- RED

  The output of the background star generator is connected this way:

  bit 5 -- 100 ohm resistor  -- BLUE
        -- 150 ohm resistor  -- BLUE
        -- 100 ohm resistor  -- GREEN
        -- 150 ohm resistor  -- GREEN
        -- 100 ohm resistor  -- RED
  bit 0 -- 150 ohm resistor  -- RED

  The blue background in Scramble and other games goes through a 390 ohm
  resistor.

  The bullet RGB outputs go through 100 ohm resistors.

  The RGB outputs have a 470 ohm pull-down each.

***************************************************************************/
PALETTE_INIT( galaxold )
{
	int i, len;


	/* first, the character/sprite palette */
	len = memory_region_length(machine, "proms");
	for (i = 0;i < len;i++)
	{
		int bit0,bit1,bit2,r,g,b;

		/* red component */
		bit0 = BIT(*color_prom,0);
		bit1 = BIT(*color_prom,1);
		bit2 = BIT(*color_prom,2);
		r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
		/* green component */
		bit0 = BIT(*color_prom,3);
		bit1 = BIT(*color_prom,4);
		bit2 = BIT(*color_prom,5);
		g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
		/* blue component */
		bit0 = BIT(*color_prom,6);
		bit1 = BIT(*color_prom,7);
		b = 0x4f * bit0 + 0xa8 * bit1;

		palette_set_color_rgb(machine,i,r,g,b);
		color_prom++;
	}
}


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

  Start the video hardware emulation.

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

static void state_save_register(void)
{
	state_save_register_global_array(gfxbank);
	state_save_register_global(flipscreen_x);
	state_save_register_global(flipscreen_y);

	state_save_register_global(background_enable);
	state_save_register_global(background_red);
	state_save_register_global(background_green);
	state_save_register_global(background_blue);
}

static void video_start_common(running_machine *machine, tilemap_mapper_func get_memory_offset)
{
	bg_tilemap = tilemap_create(get_tile_info,get_memory_offset,8,8,32,32);

	tilemap_set_transparent_pen(bg_tilemap,0);


	modify_charcode = 0;
	modify_spritecode = 0;
	modify_color = 0;
	modify_ypos = 0;

	draw_background = galaxold_draw_background;
	background_enable = 0;
	background_blue = 0;
	background_red = 0;
	background_green = 0;

	flipscreen_x = 0;
	flipscreen_y = 0;

	spriteram2_present = 0;

	spritevisiblearea      = &_spritevisiblearea;
	spritevisibleareaflipx = &_spritevisibleareaflipx;

	color_mask = (machine->gfx[0]->color_granularity == 4) ? 7 : 3;

	state_save_register();
}

WRITE8_HANDLER( galaxold_videoram_w )
{
	galaxold_videoram[offset] = data;
	tilemap_mark_tile_dirty(bg_tilemap, offset);
}

READ8_HANDLER( galaxold_videoram_r )
{
	return galaxold_videoram[offset];
}


WRITE8_HANDLER( galaxold_attributesram_w )
{
	if (galaxold_attributesram[offset] != data)
	{
		if (offset & 0x01)
		{
			/* color change */
			int i;

			for (i = offset >> 1; i < 0x0400; i += 32)
				tilemap_mark_tile_dirty(bg_tilemap, i);
		}
		else
		{
			if (modify_ypos)
			{
				modify_ypos(&data);
			}

			tilemap_set_scroll(bg_tilemap, offset >> 1, data);
		}

		galaxold_attributesram[offset] = data;
	}
}


WRITE8_HANDLER( galaxold_flip_screen_x_w )
{
	if (flipscreen_x != (data & 0x01))
	{
		flipscreen_x = data & 0x01;

		tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
	}
}

WRITE8_HANDLER( galaxold_flip_screen_y_w )
{
	if (flipscreen_y != (data & 0x01))
	{
		flipscreen_y = data & 0x01;

		tilemap_set_flip(bg_tilemap, (flipscreen_x ? TILEMAP_FLIPX : 0) | (flipscreen_y ? TILEMAP_FLIPY : 0));
	}
}


WRITE8_HANDLER( galaxold_stars_enable_w )
{
	/* stars code has been removed - not needed */
}


WRITE8_HANDLER( galaxold_gfxbank_w )
{
	if (gfxbank[offset] != data)
	{
		gfxbank[offset] = data;

		tilemap_mark_all_tiles_dirty(bg_tilemap);
	}
}


/* background drawing functions */

static void galaxold_draw_background(bitmap_t *bitmap, const rectangle *cliprect)
{
	/* plain black background */
	fillbitmap(bitmap,0,cliprect);
}


static TILE_GET_INFO( get_tile_info )
{
	UINT8 x = tile_index & 0x1f;

	UINT16 code = galaxold_videoram[tile_index];
	UINT8 color = galaxold_attributesram[(x << 1) | 1] & color_mask;

	if (modify_charcode)
	{
		modify_charcode(&code, x);
	}

	if (modify_color)
	{
		modify_color(&color);
	}

	SET_TILE_INFO(0, code, color, 0);
}


static void draw_sprites(running_machine *machine, bitmap_t *bitmap, UINT8 *spriteram, size_t spriteram_size)
{
	int offs;


	for (offs = spriteram_size - 4;offs >= 0;offs -= 4)
	{
		UINT8 sx,sy,color;
		int flipx,flipy,code;

		sx = spriteram[offs + 3] + 1;
		sy = spriteram[offs];
		flipx = spriteram[offs + 1] & 0x40;
		flipy = spriteram[offs + 1] & 0x80;
		code = spriteram[offs + 1] & 0x3f;
		color = spriteram[offs + 2] & color_mask;

		if (modify_spritecode)
		{
			modify_spritecode(spriteram, &code, &flipx, &flipy, offs);
		}

		if (modify_color)
		{
			modify_color(&color);
		}

		if (modify_ypos)
		{
			modify_ypos(&sy);
		}

		if (flipscreen_x)
		{
			sx = 240 - sx;
			flipx = !flipx;
		}

		if (flipscreen_y)
		{
			flipy = !flipy;
		}
		else
		{
			sy = 240 - sy;
		}

		if (offs < 3*4)  sy++;


		drawgfx(bitmap,machine->gfx[1],
				code,color,
				flipx,flipy,
				sx,sy,
				flipscreen_x ? spritevisibleareaflipx : spritevisiblearea,TRANSPARENCY_PEN,0);
	}
}


VIDEO_UPDATE( galaxold )
{
	draw_background(bitmap, cliprect);

	tilemap_draw(bitmap, 0, bg_tilemap, 0, 0);

	draw_sprites(screen->machine, bitmap, galaxold_spriteram, galaxold_spriteram_size);

	if (spriteram2_present)
	{
		draw_sprites(screen->machine, bitmap, galaxold_spriteram2, galaxold_spriteram2_size);
	}
	return 0;
}


static void pisces_modify_charcode(UINT16 *code,UINT8 x)
{
	*code |= (gfxbank[0] << 8);
}

static void gmgalax_modify_charcode(UINT16 *code,UINT8 x)
{
	*code |= (gfxbank[0] << 9);
}

static void pisces_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
{
	*code |= (gfxbank[0] << 6);
}

static void gmgalax_modify_spritecode(UINT8 *spriteram,int *code,int *flipx,int *flipy,int offs)
{
	*code |= (gfxbank[0] << 7) | 0x40;
}


VIDEO_START( pisces )
{
	video_start_common(machine,tilemap_scan_rows);

	tilemap_set_scroll_cols(bg_tilemap, 32);
	tilemap_set_scroll = tilemap_set_scrolly;

	modify_charcode   = pisces_modify_charcode;
	modify_spritecode = pisces_modify_spritecode;
}

VIDEO_START( bagmanm2 )
{
	video_start_common(machine,tilemap_scan_rows);

	tilemap_set_scroll_cols(bg_tilemap, 32);
	tilemap_set_scroll = tilemap_set_scrolly;

	modify_charcode = gmgalax_modify_charcode;
	modify_spritecode = gmgalax_modify_spritecode;
	spritevisiblearea      = &_spritevisibleareamc;
	spritevisibleareaflipx = &_spritevisibleareaflipxmc;
}
