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

  vidhrdw.c

  Functions to emulate the video hardware of the machine.

Important!	There are two types of NeoGeo romdump - MVS & MGD2.  They are both
converted to a standard format in the vh_start routines.


Graphics information:

0x00000 - 0xdfff	: Blocks of sprite data, each 0x80 bytes:
	Each 0x80 block is made up of 0x20 double words, their format is:
	Word: Sprite number (16 bits)
	Byte: Palette number (8 bits)
	Byte: Bit 0: X flip
		  Bit 1: Y flip
		  Bit 2: Automatic animation flag (4 tiles?)
		  Bit 3: Automatic animation flag (8 tiles?)
		  Bit 4: MSB of sprite number (confirmed, Karnov_r, Mslug). See note.
		  Bit 5: MSB of sprite number (MSlug2)
		  Bit 6: MSB of sprite number (Kof97)
		  Bit 7: Unknown for now

	Each double word sprite is drawn directly underneath the previous one,
	based on the starting coordinates.

0x0e000 - 0x0ea00	: Front plane fix tiles (8*8), 2 bytes each

0x10000: Control for sprites banks, arranged in words

	Bit 0 to 3 - Y zoom LSB
	Bit 4 to 7 - Y zoom MSB (ie, 1 byte for Y zoom).
	Bit 8 to 11 - X zoom, 0xf is full size (no scale).
	Bit 12 to 15 - Unknown, probably unused

0x10400: Control for sprite banks, arranged in words

	Bit 0 to 5: Number of sprites in this bank (see note below).
	Bit 6 - If set, this bank is placed to right of previous bank (same Y-coord).
	Bit 7 to 15 - Y position for sprite bank.

0x10800: Control for sprite banks, arranged in words
	Bit 0 to 5: Unknown
	Bit 7 to 15 - X position for sprite bank.

Notes:

* If rom set has less than 0x10000 tiles then msb of tile must be ignored
(see Magician Lord).

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

#ifndef SELF_INCLUDE

#include "driver.h"
#include "state.h"
#include "neogeo.h"

#define PALETTE_RGB_DIRECT 0

#define MASK(n) (0xf << n)

#if PALETTE_RGB_DIRECT
#define ARGS    UINT32 *sprite, void **line, UINT32 *paldata, int sx, int sy, int zy, int dy, int l
#else
#define ARGS    UINT32 *sprite, void **line, UINT32 color, int sx, int sy, int zy, int dy, int l
#endif

#define FUNC_START									\
	UINT32 tile, pixel;								\
	DATA_TYPE *bm = &((DATA_TYPE *)line[sy])[sx];	\
													\
	while (zy--)									\
	{												\
		sprite += l_y_skip[l++] * dy;				\

#define FUNC_END									\
		bm += bitmap_pitch;							\
	}												\

#define LOW_TILE \
tile = *sprite;

#define HIGH_TILE \
tile = *(sprite + 1);

#if PALETTE_RGB_DIRECT
#define BLIT(x, shift) \
pixel = (tile & MASK(shift)); if (pixel) bm[x] = paldata[pixel >> shift];
#else
#define BLIT(x, shift) \
pixel = (tile & MASK(shift)); if (pixel) bm[x] = color | (pixel >> shift);
#endif

#define sprite_func(depth)										\
void (*neo_draw_sprite##depth##[2][16])(ARGS) =					\
{																\
	{															\
		draw_sprite##depth##_1_0,  draw_sprite##depth##_2_0,	\
		draw_sprite##depth##_3_0,  draw_sprite##depth##_4_0,	\
		draw_sprite##depth##_5_0,  draw_sprite##depth##_6_0,	\
		draw_sprite##depth##_7_0,  draw_sprite##depth##_8_0,	\
		draw_sprite##depth##_9_0,  draw_sprite##depth##_10_0,	\
		draw_sprite##depth##_11_0, draw_sprite##depth##_12_0,	\
		draw_sprite##depth##_13_0, draw_sprite##depth##_14_0,	\
		draw_sprite##depth##_15_0, draw_sprite##depth##_16_0	\
	},															\
	{															\
		draw_sprite##depth##_1_1,  draw_sprite##depth##_2_1,	\
		draw_sprite##depth##_3_1,  draw_sprite##depth##_4_1,	\
		draw_sprite##depth##_5_1,  draw_sprite##depth##_6_1,	\
		draw_sprite##depth##_7_1,  draw_sprite##depth##_8_1,	\
		draw_sprite##depth##_9_1,  draw_sprite##depth##_10_1,	\
		draw_sprite##depth##_11_1, draw_sprite##depth##_12_1,	\
		draw_sprite##depth##_13_1, draw_sprite##depth##_14_1,	\
		draw_sprite##depth##_15_1, draw_sprite##depth##_16_1	\
	}															\
};

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

static data16_t *neogeo_vidram16;
static data16_t *neogeo_paletteram16;	/* pointer to 1 of the 2 palette banks */
static data16_t *neogeo_palettebank[2]; /* 0x100*16 2 byte palette entries */
static int neogeo_palette_index;
static data16_t neogeo_vidram16_modulo;
static data16_t neogeo_vidram16_offset;
static int high_tile;
static int no_of_tiles;
static int palette_swap_pending;
static int fix_bank;

static UINT32 *l_y_skip;
static UINT32 dda_y_skip[0x100][0x21][17];
static UINT8 yskip[0x100][0x21];
static UINT8 my_tbl[0x100][0x10];

static int bitmap_pitch = 0;
static int bitmap_depth = 0;
static void (*neo_draw_sprite[2][16])(ARGS);

static int next_update_first_line;

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

extern data16_t *neogeo_ram16;
extern UINT32 neogeo_frame_counter;
extern int neogeo_raster_enable;

#ifdef MAME32JP
extern int neogeo_machine_country;
extern int gururin_fix;
extern int sdodgeb_fix;
#endif

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

#define SELF_INCLUDE

#define DATA_TYPE UINT16
#define function draw_sprite16
#define DRAW_SPRITE(flip, zx) static void draw_sprite16_##zx##_##flip(ARGS)
#include "vidhrdw/neogeo.c"
#undef DRAW_SPRITE
#undef DATA_TYPE
sprite_func(16)

#ifdef SUPPORT_32BPP
#define DATA_TYPE UINT32
#define DRAW_SPRITE(flip, zx) static void draw_sprite32_##zx##_##flip(ARGS)
#include "vidhrdw/neogeo.c"
#undef DRAW_SPRITE
#undef DATA_TYPE
sprite_func(32)
#endif

#undef SELF_INCLUDE

void neogeo_init_sprite(void)
{
	int i, j;

	switch (Machine->scrbitmap->depth)
	{
	case 15:
	case 16:
		bitmap_depth = 16/8;
		bitmap_pitch = (UINT16 *)Machine->scrbitmap->line[1] - (UINT16 *)Machine->scrbitmap->line[0];
		for (i = 0; i < 2; i++)
			for (j = 0; j < 16; j++)
				neo_draw_sprite[i][j] = neo_draw_sprite16[i][j];
		break;

#ifdef SUPPORT_32BPP
	case 32:
		bitmap_depth = 32/8;
		bitmap_pitch = (UINT32 *)Machine->scrbitmap->line[1] - (UINT32 *)Machine->scrbitmap->line[0];
		for (i = 0; i < 2; i++)
			for (j = 0; j < 16; j++)
				neo_draw_sprite[i][j] = neo_draw_sprite32[i][j];
		break;
#endif
	}
}

static void build_zoom_table(void)
{
	int i, y, my, zy, dday;

	for (zy = 0; zy <= 0xff; zy++)
	{
		dday = 0;

		for (y = 0; y < 0x21; y++)
		{
			if (zy != 0xff)
			{
				yskip[zy][y] = 0;
				dda_y_skip[zy][y][0] = 0;

				for(i = 0; i < 16; i++)
				{
					dda_y_skip[zy][y][i + 1] = 0;
					dday -= zy + 1;
					if (dday <= 0)
					{
						dday += 256;
						yskip[zy][y]++;
					}
					dda_y_skip[zy][y][yskip[zy][y]]++;
				}
			}
			else
			{
				dda_y_skip[zy][y][0] = 0;

				for(i = 1; i < 16; i++)
					dda_y_skip[zy][y][i] = 1;

				yskip[zy][y] = 16;
			}
		}

		for (my = 0; my < 0x10; my++)
		{
			my_tbl[zy][my] = ((my * 16 * 256) / (zy + 1) + 15) / 16;
			if (my_tbl[zy][my] > 0x10)
				my_tbl[zy][my] = 0x10;
		}
	}
}

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

static void set_palettebank_on_postload(void)
{
	int i;

	neogeo_paletteram16 = neogeo_palettebank[neogeo_palette_index];

	for (i = 0; i < 0x2000 >> 1; i++)
	{
		data16_t newword = neogeo_paletteram16[i];
		int r,g,b;

		r = ((newword >> 7) & 0x1e) | ((newword >> 14) & 0x01);
		g = ((newword >> 3) & 0x1e) | ((newword >> 13) & 0x01);
		b = ((newword << 1) & 0x1e) | ((newword >> 12) & 0x01);

		r = (r << 3) | (r >> 2);
		g = (g << 3) | (g >> 2);
		b = (b << 3) | (b >> 2);

		palette_set_color(i, r, g, b);
	}
}

static void register_savestate(void)
{
	const char *statename = "NEOGEO";

	state_save_register_UINT16(statename, 0, "neogeo_vidram16",        neogeo_vidram16,         0x10c00>>1);
	state_save_register_UINT16(statename, 0, "neogeo_palettebank[0]",  neogeo_palettebank[0],   0x2000>>1);
	state_save_register_UINT16(statename, 0, "neogeo_palettebank[1]",  neogeo_palettebank[1],   0x2000>>1);
	state_save_register_int   (statename, 0, "neogeo_palette_index",   &neogeo_palette_index);
	state_save_register_UINT16(statename, 0, "neogeo_vidram16_modulo", &neogeo_vidram16_modulo, 1);
	state_save_register_UINT16(statename, 0, "neogeo_vidram16_offset", &neogeo_vidram16_offset, 1);
	state_save_register_int   (statename, 0, "palette_swap_pending",   &palette_swap_pending);
	state_save_register_int   (statename, 0, "fix_bank",               &fix_bank);

	state_save_register_func_postload(set_palettebank_on_postload);
}

static void decodetile(int tileno)
{
	unsigned char swap[128];
	UINT32 *gfxdata;
	int x,y;
	unsigned int pen;


	gfxdata = (UINT32 *)&memory_region(REGION_GFX3)[128 * tileno];

	memcpy(swap,gfxdata,128);

	for (y = 0; y < 16; y++)
	{
		UINT32 dw;

		dw = 0;
		for (x = 0; x < 8; x++)
		{
			pen  = ((swap[64 + 4*y + 3] >> x) & 1) << 3;
			pen |= ((swap[64 + 4*y + 1] >> x) & 1) << 2;
			pen |= ((swap[64 + 4*y + 2] >> x) & 1) << 1;
			pen |=  (swap[64 + 4*y    ] >> x) & 1;
			dw |= pen << 4*x;
			Machine->gfx[2]->pen_usage[tileno] |= (1 << pen);
		}
		*(gfxdata++) = dw;

		dw = 0;
		for (x = 0; x < 8; x++)
		{
			pen  = ((swap[4*y + 3] >> x) & 1) << 3;
			pen |= ((swap[4*y + 1] >> x) & 1) << 2;
			pen |= ((swap[4*y + 2] >> x) & 1) << 1;
			pen |=  (swap[4*y    ] >> x) & 1;
			dw |= pen << 4*x;
			Machine->gfx[2]->pen_usage[tileno] |= (1 << pen);
		}
		*(gfxdata++) = dw;
	}
}

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

VIDEO_START( neogeo_mvs )
{
    no_of_tiles = memory_region_length(REGION_GFX3) / 128;

	high_tile = 0;
	if (no_of_tiles > 0x10000) high_tile += 0x10;
	if (no_of_tiles > 0x20000) high_tile += 0x20;
	if (no_of_tiles > 0x40000) high_tile += 0x40;

	Machine->gfx[2]->total_elements = no_of_tiles;
	Machine->gfx[2]->pen_usage = calloc(no_of_tiles * sizeof(int), 1);

	neogeo_palettebank[0] = NULL;
	neogeo_palettebank[1] = NULL;
	neogeo_vidram16 = NULL;

	neogeo_palettebank[0] = auto_malloc(0x2000);
	if (!neogeo_palettebank[0])
		return 1;

	neogeo_palettebank[1] = auto_malloc(0x2000);
	if (!neogeo_palettebank[1])
		return 1;

	/* 0x20000 bytes even though only 0x10c00 is used */
	neogeo_vidram16 = auto_malloc(0x20000);
	if (!neogeo_vidram16)
		return 1;
	memset(neogeo_vidram16,0,0x20000);

	neogeo_paletteram16 = neogeo_palettebank[0];
	neogeo_palette_index = 0;
	neogeo_vidram16_modulo = 1;
	neogeo_vidram16_offset = 0;
	fix_bank = 0;
	palette_swap_pending = 0;
	next_update_first_line = 0;
	build_zoom_table();
	neogeo_init_sprite();
	register_savestate();

	return 0;
}

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

static void swap_palettes(void)
{
	int i;

	for (i = 0; i < 0x2000 >> 1; i++)
	{
		data16_t newword = neogeo_paletteram16[i];
		int r,g,b;

		r = ((newword >> 7) & 0x1e) | ((newword >> 14) & 0x01);
		g = ((newword >> 3) & 0x1e) | ((newword >> 13) & 0x01);
		b = ((newword << 1) & 0x1e) | ((newword >> 12) & 0x01);

		r = (r << 3) | (r >> 2);
		g = (g << 3) | (g >> 2);
		b = (b << 3) | (b >> 2);

		palette_set_color(i, r, g, b);
	}

	palette_swap_pending = 0;
}

static void neogeo_setpalbank(int n)
{
	if (neogeo_palette_index != n)
	{
		neogeo_palette_index = n;
		neogeo_paletteram16 = neogeo_palettebank[n];
		palette_swap_pending = 1;
	}
}

WRITE16_HANDLER( neogeo_setpalbank0_16_w )
{
	neogeo_setpalbank(0);
}

WRITE16_HANDLER( neogeo_setpalbank1_16_w )
{
	neogeo_setpalbank(1);
}

READ16_HANDLER( neogeo_paletteram16_r )
{
	return neogeo_paletteram16[offset];
}

WRITE16_HANDLER( neogeo_paletteram16_w )
{
	data16_t oldword, newword;
	int r,g,b;

	oldword = newword = neogeo_paletteram16[offset];
	COMBINE_DATA(&newword);

	if (oldword == newword)
		return;

	neogeo_paletteram16[offset] = newword;

	r = ((newword >> 7) & 0x1e) | ((newword >> 14) & 0x01);
	g = ((newword >> 3) & 0x1e) | ((newword >> 13) & 0x01) ;
	b = ((newword << 1) & 0x1e) | ((newword >> 12) & 0x01) ;

	r = (r << 3) | (r >> 2);
	g = (g << 3) | (g >> 2);
	b = (b << 3) | (b >> 2);

	palette_set_color(offset, r, g, b);
}

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

WRITE16_HANDLER( neogeo_vidram16_offset_w )
{
	COMBINE_DATA(&neogeo_vidram16_offset);
}

READ16_HANDLER( neogeo_vidram16_data_r )
{
	return neogeo_vidram16[neogeo_vidram16_offset];
}

WRITE16_HANDLER( neogeo_vidram16_data_w )
{
	COMBINE_DATA(&neogeo_vidram16[neogeo_vidram16_offset]);
	neogeo_vidram16_offset = (neogeo_vidram16_offset & 0x8000)	/* gururin fix */
			| ((neogeo_vidram16_offset + neogeo_vidram16_modulo) & 0x7fff);
}

/* Modulo can become negative , Puzzle Bobble Super Sidekicks and a lot */
/* of other games use this */
WRITE16_HANDLER( neogeo_vidram16_modulo_w )
{
	COMBINE_DATA(&neogeo_vidram16_modulo);
}

READ16_HANDLER( neogeo_vidram16_modulo_r )
{
	return neogeo_vidram16_modulo;
}


WRITE16_HANDLER( neo_board_fix_16_w )
{
	fix_bank = 1;
}

WRITE16_HANDLER( neo_game_fix_16_w )
{
	fix_bank = 0;
}

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

#if PALETTE_RGB_DIRECT
INLINE void neo_draw_gfx(void **line, UINT32 *paldata,
#else
INLINE void neo_draw_gfx(void **line, UINT32 color,
#endif
		unsigned int code, int flipx, int flipy, int sx, int sy, int zx, int zy,
		const struct rectangle *clip)
{
	int oy, ey, dy, skip, l = 0;
	UINT32 *fspr;

	oy = sy;
	ey = sy + zy -1;

	if (sy < clip->min_y) sy = clip->min_y;
	if (ey >= clip->max_y) ey = clip->max_y;

	skip = sy - oy;

	zy  -= skip;
	if (zy <= 0) return;

	fspr = (UINT32 *)memory_region(REGION_GFX3);

	if (!flipy) /* normal */
	{
		dy = 2;
		fspr += code * 32;
	}
	else /* Y flip */
	{
		dy = -2;
		fspr += (code + 1) * 32 - 2;
	}

	if (skip)
	{
		while (skip--)
			fspr += l_y_skip[l++] * dy;
	}

#if PALETTE_RGB_DIRECT
	(*neo_draw_sprite[flipx][zx - 1])(fspr, line, paldata, sx, sy, zy, dy, l);
#else
	(*neo_draw_sprite[flipx][zx - 1])(fspr, line, color, sx, sy, zy, dy, l);
#endif
}


void NeoMVSDrawGfx(void **line,const struct GfxElement *gfx,
		unsigned int code,unsigned int color,int flipx,int flipy,int sx,int sy,
		int zx,int zy,const struct rectangle *clip)
{
	/* Safety feature */
	code = code % no_of_tiles;

	if (!gfx->pen_usage[code])	/* decode tile if it hasn't been yet */
        {
                        decodetile(code);
	}

	/* Check for total transparency, no need to draw */
	if (gfx->pen_usage[code] & ~1)
	{
		neo_draw_gfx(line,
#if PALETTE_RGB_DIRECT
			&gfx->colortable[color << 4],
#else
			color << 4,
#endif
			code,
			flipx, flipy,
			sx,sy,zx,zy,
			clip
		);
	}
}


#ifdef MAME32JP
INLINE int convert_jfont(int code)
{
	if (sdodgeb_fix)
	{
		switch (code)
		{
		case 0x016e:
		case 0x0166:
		case 0x0173:
			code -= 0xc0;
			break;

		case 0x026e:
		case 0x0273:
		case 0x0266:
			code -= 0x180;
			break;

		case 0x010d:
			code = 0x008d;
			break;
		case 0x020d:
			code = 0x00cd;
			break;
		}
	}

	if (code >= 0x100 && code <= 0x2ff)
		code += 0x200;

	return code;
}
#endif


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

static void draw_sprites(struct mame_bitmap *bitmap, const struct rectangle *clip)
{
	int sx = 0, sy = 0, oy = 0, my = 0, zx = 0, zy = 0;
	int offs, count, y;
	int t1, t3;
	char fullmode = 0;
	void **line = bitmap->line;
	struct GfxElement *gfx = Machine->gfx[2]; /* Save constant struct dereference */
	int skip_draw = 1;
	int first_draw = 1;

	/* Draw sprites */
	for (count = 0; count < (0x300 >> 1); count++)
	{
		t1 = neogeo_vidram16[(0x10400 >> 1) + count];
		t3 = neogeo_vidram16[(0x10000 >> 1) + count];

		/* If this bit is set this new column is placed next to last one */
		if (t1 & 0x40)
		{
			if (!first_draw && skip_draw)
			{
				skip_draw = 0;
				my = 0;
			}

			/* No point doing anything if tile strip is 0 */
			if (my == 0) continue;

			sx += zx;
			sy = oy;
		}
		else /* nope it is a new block */
		{
			/* Number of tiles in this strip */
			my = t1 & 0x3f;
			if (my == 0)
				continue; /* No point doing anything if tile strip is 0 */
			else if (my == 0x20)
				fullmode = 1;
			else if (my >= 0x21)
				fullmode = 2;	/* most games use 0x21, but  Alpha Mission II uses 0x3f */
			else
				fullmode = 0;

			/* Sprite scaling */
			zy = t3 & 0xff;
			if (gururin_fix && (t3 == 0 || t3 == 0x147f))
			{
				zy = 0xff;
			}
			else if (zy == 0)
			{
				/* No point doing anything if tile Y zoom is 0 */
				my = 0;
				continue;
			}

			if (zy < 0xff && my < 0x10)
			{
				my = my_tbl[zy][my];
				if (my == 0)
					continue; /* No point doing anything if tile strip is 0 */
			}
			else if (my > 0x20)
				my = 0x20;

			sy = 0x200 - (t1 >> 7);

			if (clip->max_y - clip->min_y > 8 ||	/* kludge to improve the ssideki games */
				clip->min_y == Machine->visible_area.min_y)
			{
				if (sy > 0x110) sy -= 0x200;
				if (fullmode == 2 || (fullmode == 1 && zy == 0xff))
				{
					while (sy < 0) sy += 2 * (zy + 1);
				}
			}
			oy = sy;

			sx = (neogeo_vidram16[(0x10800 >> 1) + count] >> 7);

			skip_draw = 1;
			first_draw = 1;
		}

		/* Get new zoom for this column */
		zx = (t3 >> 8) & 0x0f;
		if (gururin_fix && (t3 == 0 || t3 == 0x147f))
			zx = 0x0f;
		zx++;

		if (sx >= 312)    /* clip->max_y */
			sx -= 0x200;

		if (sx + zx <= 8) /* clip->min_y */
			continue;

		first_draw = 0;

		offs = count << 6;

		/* my holds the number of tiles in each vertical multisprite block */
		for (y = 0; y < my ; y++)
		{
			int zy2 = yskip[zy][y];

			if (fullmode == 2 || (fullmode == 1 && zy == 0xff))
			{
				if (sy >= 248) sy -= 2 * (zy + 1);
			}
			else if (fullmode == 1)
			{
				if (y == 0x10) sy -= 2 * (zy + 1);
			}
			else if (sy > 0x110)
			{
				sy -= 0x200;	/* NS990105 mslug2 fix */
			}

			if (sy + zy2 > clip->min_y && sy <= clip->max_y)
			{
				int tileno  = neogeo_vidram16[offs++];
				int tileatr = neogeo_vidram16[offs++];

				tileno += (tileatr & high_tile) << 12;

				if (tileatr & 0x8)
					tileno = (tileno & ~7) + (neogeo_frame_counter & 7);
				else
				if (tileatr & 0x4)
					tileno = (tileno & ~3) + (neogeo_frame_counter & 3);

				skip_draw = 0;

				/* Safety feature */
				tileno = tileno % no_of_tiles;

				if (!gfx->pen_usage[tileno])	/* decode tile if it hasn't been yet */
				{
                                                decodetile(tileno);
                                }

				/* Check for total transparency, no need to draw */
				if (gfx->pen_usage[tileno] & ~1)
				{
					int color = tileatr >> 8;

					l_y_skip = dda_y_skip[zy][y];

					neo_draw_gfx(line,
#if PALETTE_RGB_DIRECT
						&gfx->colortable[color << 4],
#else
						color << 4,
#endif
						tileno,
						tileatr & 0x01,
						tileatr & 0x02,
						sx, sy,
						zx, zy2,
						clip
					);
				}
			}
			else
			{
				offs += 2;
			}

			sy += zy2;
		}  /* for y */
	}  /* for count */
}

static void draw_foreground(struct mame_bitmap *bitmap)
{
 	/* Character foreground */
	/* thanks to Mr K for the garou & kof2000 banking info */
	int y,x;
	unsigned int *pen_usage;
	struct GfxElement *gfx;
	int banked;
	int garouoffsets[32];

		banked = (fix_bank == 0 && Machine->gfx[0]->total_elements > 0x1000) ? 1 : 0;

		/* Build line banking table for Garou & MS3 before starting render */
		if (banked && neogeo_fix_bank_type == 1)
		{
			int garoubank = 0;
			int k = 0;
			y = 0;
			while (y < 32)
			{
				if (neogeo_vidram16[(0xea00>>1)+k] == 0x0200 && (neogeo_vidram16[(0xeb00>>1)+k] & 0xff00) == 0xff00)
				{
					garoubank = neogeo_vidram16[(0xeb00>>1)+k] & 3;
					garouoffsets[y++] = garoubank;
				}
				garouoffsets[y++] = garoubank;
				k += 2;
			}
		}

	/* Save some struct de-refs */
	gfx = Machine->gfx[fix_bank];
	pen_usage = gfx->pen_usage;

	for (y = 2; y < 30; y++)
	{
		for (x = 1; x < 40; x++)
		{

			int byte1 = neogeo_vidram16[(0xe000 >> 1) + y + 32 * x];
			int byte2 = byte1 >> 12;
			byte1 = byte1 & 0xfff;

				if (banked)
				{
					switch (neogeo_fix_bank_type)
					{
						case 1:
							/* Garou, MSlug 3 */
							byte1 += 0x1000 * (garouoffsets[(y-2)&31] ^ 3);
							break;
						case 2:
							byte1 += 0x1000 * (((neogeo_vidram16[(0xea00 >> 1) + ((y-1)&31) + 32 * (x/6)] >> (5-(x%6))*2) & 3) ^ 3);
							break;
					}
				}

#ifdef MAME32JP
			if (fix_bank && !neogeo_machine_country)
				byte1 = convert_jfont(byte1);
#endif

			if (!(pen_usage[byte1] & ~1)) continue;

                        drawgfx(bitmap, gfx,
					byte1,
					byte2,
					0, 0,
                                        x * 8, y * 8,
                                        NULL, TRANSPARENCY_PEN, 0);
                }
        }
}

VIDEO_UPDATE( neogeo )
{
	/* Palette swap occured after last frame but before this one */
	if (palette_swap_pending) swap_palettes();

#if PALETTE_RGB_DIRECT
	fillbitmap(bitmap, Machine->pens[4095], cliprect);
#else
	fillbitmap(bitmap, 4095, cliprect);
#endif

	draw_sprites(bitmap,cliprect);
	draw_foreground(bitmap);
}


void neogeo_vh_raster_partial_refresh(struct mame_bitmap *bitmap,int current_line)
{
	struct rectangle clip;

	if (current_line < next_update_first_line)
	{
		/* Palette swap occured after last frame but before this one */
		if (palette_swap_pending) swap_palettes();

#if PALETTE_RGB_DIRECT
		fillbitmap(bitmap, Machine->pens[4095], &Machine->visible_area);
#else
		fillbitmap(bitmap, 4095, &Machine->visible_area);
#endif

		next_update_first_line = 0;
	}

	clip.min_x = Machine->visible_area.min_x;
	clip.max_x = Machine->visible_area.max_x;
	clip.min_y = next_update_first_line;
	clip.max_y = current_line;
	if (clip.min_y < Machine->visible_area.min_y)
		clip.min_y = Machine->visible_area.min_y;
	if (clip.max_y > Machine->visible_area.max_y)
		clip.max_y = Machine->visible_area.max_y;

	if (clip.max_y >= clip.min_y)
	{
//logerror("refresh %d-%d\n",clip.min_y,clip.max_y);
		draw_sprites(bitmap, &clip);

		if (neogeo_raster_enable == 2)
		{
			int x, draw = clip.max_y & 1;

			for (x = 8; x < 312; x++)
			{
				if ((x & 1) == draw)
					plot_pixel(bitmap, x, clip.max_y, Machine->uifont->colortable[1]);
			}
		}
	}

	next_update_first_line = current_line + 1;
}

VIDEO_UPDATE( neogeo_raster )
{
	draw_foreground(bitmap);
}

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

#else	/* SELF_INCLUDE */

DRAW_SPRITE(0, 16)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  4) BLIT( 2,  8) BLIT( 3, 12)
	BLIT( 4, 16) BLIT( 5, 20) BLIT( 6, 24) BLIT( 7, 28)
	HIGH_TILE
	BLIT( 8,  0) BLIT( 9,  4) BLIT(10,  8) BLIT(11, 12)
	BLIT(12, 16) BLIT(13, 20) BLIT(14, 24) BLIT(15, 28)
	FUNC_END
}

DRAW_SPRITE(0, 15)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  4) BLIT( 2,  8) BLIT( 3, 12)
	BLIT( 4, 16) BLIT( 5, 20) BLIT( 6, 24)
	HIGH_TILE
	BLIT( 7,  0) BLIT( 8,  4) BLIT( 9,  8) BLIT(10, 12)
	BLIT(11, 16) BLIT(12, 20) BLIT(13, 24) BLIT(14, 28)
	FUNC_END
}

DRAW_SPRITE(0, 14)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  4) BLIT( 2,  8) BLIT( 3, 12)
	BLIT( 4, 16) BLIT( 5, 20) BLIT( 6, 24)
	HIGH_TILE
	BLIT( 7,  0) BLIT( 8,  4) BLIT( 9,  8) BLIT(10, 12)
	BLIT(11, 16) BLIT(12, 20) BLIT(13, 24)
	FUNC_END
}

DRAW_SPRITE(0, 13)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  4) BLIT( 2, 12) BLIT( 3, 16)
	BLIT( 4, 20) BLIT( 5, 24)
	HIGH_TILE
	BLIT( 6,  0) BLIT( 7,  4) BLIT( 8,  8) BLIT( 9, 12)
	BLIT(10, 20) BLIT(11, 24) BLIT(12, 28)
	FUNC_END
}

DRAW_SPRITE(0, 12)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  4) BLIT( 2,  8) BLIT( 3, 16)
	BLIT( 4, 20) BLIT( 5, 24)
	HIGH_TILE
	BLIT( 6,  0) BLIT( 7,  4) BLIT( 8,  8) BLIT( 9, 16)
	BLIT(10, 20) BLIT(11, 24)
	FUNC_END
}

DRAW_SPRITE(0, 11)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  4) BLIT( 1,  8) BLIT( 2, 16) BLIT( 3, 20)
	BLIT( 4, 28)
	HIGH_TILE
	BLIT( 5,  0) BLIT( 6,  4) BLIT( 7, 12) BLIT( 8, 16)
	BLIT( 9, 24) BLIT(10, 28)
	FUNC_END
}

DRAW_SPRITE(0, 10)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  8) BLIT( 2, 16) BLIT( 3, 24)
	BLIT( 4, 28)
	HIGH_TILE
	BLIT( 5,  0) BLIT( 6,  8) BLIT( 7, 16) BLIT( 8, 24)
	BLIT( 9, 28)
	FUNC_END
}

DRAW_SPRITE(0, 9)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  8) BLIT( 2, 16) BLIT( 3, 24)
	HIGH_TILE
	BLIT( 4,  0) BLIT( 5,  8) BLIT( 6, 16) BLIT( 7, 24)
	BLIT( 8, 28)
	FUNC_END
}

DRAW_SPRITE(0, 8)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1,  8) BLIT( 2, 16) BLIT( 3, 24)
	HIGH_TILE
	BLIT( 4,  0) BLIT( 5,  8) BLIT( 6, 16) BLIT( 7, 24)
	FUNC_END
}

DRAW_SPRITE(0, 7)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  4) BLIT( 1, 12) BLIT( 2, 20)
	HIGH_TILE
	BLIT( 3,  0) BLIT( 4,  8) BLIT( 5, 16) BLIT( 6, 24)
	FUNC_END
}

DRAW_SPRITE(0, 6)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  4) BLIT( 1, 16) BLIT( 2, 28)
	HIGH_TILE
	BLIT( 3,  0) BLIT( 4, 12) BLIT( 5, 24)
	FUNC_END
}

DRAW_SPRITE(0, 5)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  8) BLIT( 1, 20)
	HIGH_TILE
	BLIT( 2,  0) BLIT( 3, 12) BLIT( 4, 24)
	FUNC_END
}

DRAW_SPRITE(0, 4)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0) BLIT( 1, 16)
	HIGH_TILE
	BLIT( 2,  0) BLIT( 3, 16)
	FUNC_END
}

DRAW_SPRITE(0, 3)
{
	FUNC_START
	LOW_TILE
	BLIT( 0, 12)
	HIGH_TILE
	BLIT( 1,  0) BLIT( 2, 20)
	FUNC_END
}

DRAW_SPRITE(0, 2)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0)
	HIGH_TILE
	BLIT( 1,  0)
	FUNC_END
}

DRAW_SPRITE(0, 1)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0)
	FUNC_END
}

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

DRAW_SPRITE(1, 16)
{
	FUNC_START
	LOW_TILE
	BLIT(15,  0) BLIT(14,  4) BLIT(13,  8) BLIT(12, 12)
	BLIT(11, 16) BLIT(10, 20) BLIT( 9, 24) BLIT( 8, 28)
	HIGH_TILE
	BLIT( 7,  0) BLIT( 6,  4) BLIT( 5,  8) BLIT( 4, 12)
	BLIT( 3, 16) BLIT( 2, 20) BLIT( 1, 24) BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 15)
{
	FUNC_START
	LOW_TILE
	BLIT(14,  0) BLIT(13,  4) BLIT(12,  8) BLIT(11, 12)
	BLIT(10, 16) BLIT( 9, 20) BLIT( 8, 24)
	HIGH_TILE
	BLIT( 7,  0) BLIT( 6,  4) BLIT( 5,  8) BLIT( 4, 12)
	BLIT( 3, 16) BLIT( 2, 20) BLIT( 1, 24) BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 14)
{
	FUNC_START
	LOW_TILE
	BLIT(13,  0) BLIT(12,  4) BLIT(11,  8) BLIT(10, 12)
	BLIT( 9, 16) BLIT( 8, 20) BLIT( 7, 24)
	HIGH_TILE
	BLIT( 6,  0) BLIT( 5,  4) BLIT( 4,  8) BLIT( 3, 12)
	BLIT( 2, 16) BLIT( 1, 20) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 13)
{
	FUNC_START
	LOW_TILE
	BLIT(12,  0) BLIT(11,  4) BLIT(10, 12) BLIT( 9, 16)
	BLIT( 8, 20) BLIT( 7, 24)
	HIGH_TILE
	BLIT( 6,  0) BLIT( 5,  4) BLIT( 4,  8) BLIT( 3, 12)
	BLIT( 2, 20) BLIT( 1, 24) BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 12)
{
	FUNC_START
	LOW_TILE
	BLIT(11,  0) BLIT(10,  4) BLIT( 9,  8) BLIT( 8, 16)
	BLIT( 7, 20) BLIT( 6, 24)
	HIGH_TILE
	BLIT( 5,  0) BLIT( 4,  4) BLIT( 3,  8) BLIT( 2, 16)
	BLIT( 1, 20) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 11)
{
	FUNC_START
	LOW_TILE
	BLIT(10,  4) BLIT( 9,  8) BLIT( 8, 16) BLIT( 7, 20)
	BLIT( 6, 28)
	HIGH_TILE
	BLIT( 5,  0) BLIT( 4,  4) BLIT( 3, 12) BLIT( 2, 16)
	BLIT( 1, 24) BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 10)
{
	FUNC_START
	LOW_TILE
	BLIT( 9,  0) BLIT( 8,  8) BLIT( 7, 16) BLIT( 6, 24)
	BLIT( 5, 28)
	HIGH_TILE
	BLIT( 4,  0) BLIT( 3,  8) BLIT( 2, 16) BLIT( 1, 24)
	BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 9)
{
	FUNC_START
	LOW_TILE
	BLIT( 8,  0) BLIT( 7,  8) BLIT( 6, 16) BLIT( 5, 24)
	HIGH_TILE
	BLIT( 4,  0) BLIT( 3,  8) BLIT( 2, 16) BLIT( 1, 24)
	BLIT( 0, 28)
	FUNC_END
}

DRAW_SPRITE(1, 8)
{
	FUNC_START
	LOW_TILE
	BLIT( 7,  0) BLIT( 6,  8) BLIT( 5, 16) BLIT( 4, 24)
	HIGH_TILE
	BLIT( 3,  0) BLIT( 2,  8) BLIT( 1, 16) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 7)
{
	FUNC_START
	LOW_TILE
	BLIT( 6,  4) BLIT( 5, 12) BLIT( 4, 20)
	HIGH_TILE
	BLIT( 3,  0) BLIT( 2,  8) BLIT( 1, 16) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 6)
{
	FUNC_START
	LOW_TILE
	BLIT( 5,  4) BLIT( 4, 16) BLIT( 3, 28)
	HIGH_TILE
	BLIT( 2,  0) BLIT( 1, 12) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 5)
{
	FUNC_START
	LOW_TILE
	BLIT( 4,  8) BLIT( 3, 20)
	HIGH_TILE
	BLIT( 2,  0) BLIT( 1, 12) BLIT( 0, 24)
	FUNC_END
}

DRAW_SPRITE(1, 4)
{
	FUNC_START
	LOW_TILE
	BLIT( 3,  0) BLIT( 2, 16)
	HIGH_TILE
	BLIT( 1,  0) BLIT( 0, 16)
	FUNC_END
}

DRAW_SPRITE(1, 3)
{
	FUNC_START
	LOW_TILE
	BLIT( 2, 12)
	HIGH_TILE
	BLIT( 1,  0) BLIT( 0, 20)
	FUNC_END
}

DRAW_SPRITE(1, 2)
{
	FUNC_START
	LOW_TILE
	BLIT( 0,  0)
	HIGH_TILE
	BLIT( 1,  0)
	FUNC_END
}

DRAW_SPRITE(1, 1)
{
	FUNC_START
	HIGH_TILE
	BLIT( 0,  0)
	FUNC_END
}

#endif /* SELF_INCLUDE */
