/* vidhrdw/spbactn.c - see drivers/spbactn.c for more info */
/* rather similar to galspnbl.c */

#include "driver.h"

extern data16_t *spbactn_bgvideoram, *spbactn_fgvideoram, *spbactn_spvideoram;
static struct mame_bitmap *tile_bitmap_bg, *tile_bitmap_fg;

/* mix & blend the paletted 16-bit tile and sprite bitmaps into an RGB 32-bit bitmap */
static void blendbitmaps(
		struct mame_bitmap *dest,struct mame_bitmap *src1,struct mame_bitmap *src2,
		int sx,int sy,const struct rectangle *clip)
{
	int ox;
	int oy;
	int ex;
	int ey;

	/* check bounds */
	ox = sx;
	oy = sy;

	ex = sx + src1->width - 1;
	if (sx < 0) sx = 0;
	if (sx < clip->min_x) sx = clip->min_x;
	if (ex >= dest->width) ex = dest->width - 1;
	if (ex > clip->max_x) ex = clip->max_x;
	if (sx > ex) return;

	ey = sy + src1->height - 1;
	if (sy < 0) sy = 0;
	if (sy < clip->min_y) sy = clip->min_y;
	if (ey >= dest->height) ey = dest->height - 1;
	if (ey > clip->max_y) ey = clip->max_y;
	if (sy > ey) return;

	{
		pen_t *paldata = Machine->pens;
		UINT32 *end;

		UINT16 *sd1 = ((UINT16 *)src1->line[0]);								/* source data   */
		UINT16 *sd2 = ((UINT16 *)src2->line[0]);

		int sw = ex-sx+1;														/* source width  */
		int sh = ey-sy+1;														/* source height */
		int sm = ((UINT16 *)src1->line[1]) - ((UINT16 *)src1->line[0]);			/* source modulo */

		UINT32 *dd = ((UINT32 *)dest->line[sy]) + sx;							/* dest data     */
		int dm = ((UINT32 *)dest->line[1]) - ((UINT32 *)dest->line[0]);			/* dest modulo   */

		sd1 += (sx-ox);
		sd1 += sm * (sy-oy);
		sd2 += (sx-ox);
		sd2 += sm * (sy-oy);

		sm -= sw;
		dm -= sw;

		while (sh)
		{

#define BLENDPIXEL(x)	if (sd2[x]) {												\
							if (sd2[x] & 0x1000) {									\
								dd[x] = paldata[sd1[x] & 0x07ff] + paldata[sd2[x]];	\
							} else {												\
								dd[x] = paldata[sd2[x]];							\
							}														\
						} else {													\
							dd[x] = paldata[sd1[x]];								\
						}

			end = dd + sw;
			while (dd <= end - 8)
			{
				BLENDPIXEL(0);
				BLENDPIXEL(1);
				BLENDPIXEL(2);
				BLENDPIXEL(3);
				BLENDPIXEL(4);
				BLENDPIXEL(5);
				BLENDPIXEL(6);
				BLENDPIXEL(7);
				dd += 8;
				sd1 += 8;
				sd2 += 8;
			}
			while (dd < end)
			{
				BLENDPIXEL(0);
				dd++;
				sd1++;
				sd2++;
			}
			sd1 += sm;
			sd2 += sm;
			dd += dm;
			sh--;

#undef BLENDPIXEL

		}
	}
}

/* from gals pinball (which was in turn from ninja gaiden) */
static int draw_sprites(struct mame_bitmap *bitmap, int priority)
{
	const UINT8 layout[8][8] =
	{
		{ 0, 1, 4, 5,16,17,20,21},
		{ 2, 3, 6, 7,18,19,22,23},
		{ 8, 9,12,13,24,25,28,29},
		{10,11,14,15,26,27,30,31},
		{32,33,36,37,48,49,52,53},
		{34,35,38,39,50,51,54,55},
		{40,41,44,45,56,57,60,61},
		{42,43,46,47,58,59,62,63}
	};

	int count = 0;

	int offs;

	for (offs = (0x1000 - 16) / 2; offs >= 0; offs -= 8)
	{
		int sx, sy, code, color, size, attr, flipx, flipy;
		int col, row;

		attr = spbactn_spvideoram[offs];
		if ((attr & 0x0004) &&
			((attr & 0x0030) >> 4) == priority)
		{
			flipx = attr & 0x0001;
			flipy = attr & 0x0002;

			code = spbactn_spvideoram[offs + 1];

			color = spbactn_spvideoram[offs + 2];
			size = 1 << (color & 0x0003);				/* 1,2,4,8 */
			color = (color & 0x00f0) >> 4;

			sx = spbactn_spvideoram[offs + 4];
			sy = spbactn_spvideoram[offs + 3];

			attr &= ~0x0040;							/* !!! */

			if (attr & 0x0040)
				color |= 0x0180;
			else
				color |= 0x0080;


			for (row = 0; row < size; row++)
			{
				for (col = 0; col < size; col++)
				{
					int x = sx + 8 * (flipx ? (size - 1 - col) : col);
					int y = sy + 8 * (flipy ? (size - 1 - row) : row);

					drawgfx(bitmap, Machine->gfx[2],
						code + layout[row][col],
						color,
						flipx, flipy,
						x, y,
						&Machine->visible_area, TRANSPARENCY_PEN, 0);
				}
			}

			count++;
		}
	}

	return count;
}


VIDEO_START( spbactn )
{
	/* allocate bitmaps */
	tile_bitmap_bg = auto_bitmap_alloc_depth(Machine->drv->screen_width, Machine->drv->screen_height, 16);
	tile_bitmap_fg = auto_bitmap_alloc_depth(Machine->drv->screen_width, Machine->drv->screen_height, 16);

	if (!tile_bitmap_bg || !tile_bitmap_fg)
		return 1;

	return 0;
}

VIDEO_UPDATE( spbactn )
{
	int offs, sx, sy;

	fillbitmap(tile_bitmap_fg,      0, cliprect);

	/* draw table bg gfx */
	for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
	{
		int attr, code, colour;

		code = spbactn_bgvideoram[offs + 0x4000 / 2];
		attr = spbactn_bgvideoram[offs + 0x0000 / 2];

		colour = ((attr & 0x00f0) >> 4) | 0x80;

		drawgfx(tile_bitmap_bg, Machine->gfx[1],
					code,
					colour,
					0, 0,
					16 * sx, 8 * sy,
					&Machine->visible_area, TRANSPARENCY_NONE, 0);

		sx++;
		if (sx > 63)
		{
			sy++;
			sx = 0;
		}
	}

	if (draw_sprites(tile_bitmap_bg, 0))
	{
		/* kludge: draw table bg gfx again if priority 0 sprites are enabled */
		for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
		{
			int attr, code, colour;

			code = spbactn_bgvideoram[offs + 0x4000 / 2];
			attr = spbactn_bgvideoram[offs + 0x0000 / 2];

			colour = ((attr & 0x00f0) >> 4) | 0x80;

			drawgfx(tile_bitmap_bg, Machine->gfx[1],
					code,
					colour,
					0, 0,
					16 * sx, 8 * sy,
					&Machine->visible_area, TRANSPARENCY_PEN, 0);

			sx++;
			if (sx > 63)
			{
				sy++;
				sx = 0;
			}
		}
	}

	draw_sprites(tile_bitmap_bg, 1);

	/* draw table fg gfx */
	for (sx = sy = offs = 0; offs < 0x4000 / 2; offs++)
	{
		int attr, code, colour;

		code = spbactn_fgvideoram[offs + 0x4000 / 2];
		attr = spbactn_fgvideoram[offs + 0x0000 / 2];

		colour = ((attr & 0x00f0) >> 4);

		/* blending */
		if (attr & 0x0008)
			colour += 0x00f0;
		else
			colour |= 0x0080;

		drawgfx(tile_bitmap_fg, Machine->gfx[0],
					code,
					colour,
					0, 0,
					16 * sx, 8 * sy,
					&Machine->visible_area,TRANSPARENCY_PEN, 0);

		sx++;
		if (sx > 63)
		{
			sy++;
			sx = 0;
		}
	}
	draw_sprites(tile_bitmap_fg, 2);
	draw_sprites(tile_bitmap_fg, 3);

	/* mix & blend the tilemaps and sprites into a 32-bit bitmap */
	blendbitmaps(bitmap, tile_bitmap_bg, tile_bitmap_fg, 0, 0, cliprect);
}
