#define NEW_DRAWSPRITE 1
/* System 32 Video Hardware */

/* todo:

add linezoom, clipping window effects on bg tilemaps
fix sprite clipping effect? (outside area clip)
fix / improve alphablending
fix alphablending enable, amount etc. (sonic almost certainly shouldn't have it enabled ?)
fix / add row-select, linescroll
fix priorities properly (will need vmixer)
find rad rally title screen background
remaining colour problems (sonic?)
solid flag on tiles? (rad rally..)
background colour
any remaining glitches

*/

#include "driver.h"
#define MAX_COLOURS (16384)

/* Debugging flags and kludges*/
extern int system32_temp_kludge;
int priloop;

extern int multi32;

extern data16_t *sys32_spriteram16;
data8_t  *sys32_spriteram8; /* I maintain this to make drawing ram based sprites easier */
extern data16_t *system32_mixerregs[2];		/* mixer registers*/
data16_t *sys32_videoram;
data32_t *multi32_videoram;
data8_t sys32_ramtile_dirty[0x1000];
extern data16_t sys32_displayenable;
extern data16_t sys32_tilebank_external;
data16_t sys32_old_tilebank_external;

int sys32_tilebank_internal;
int sys32_old_tilebank_internal;

int sys32_paletteshift[4];
int sys32_palettebank[4];
int sys32_old_paletteshift[4];
int sys32_old_palettebank[4];

extern int system32_mixerShift;
int system32_screen_mode;
int system32_screen_old_mode;
int system32_allow_high_resolution;
static int sys32_old_brightness[2][3];
int sys32_brightness[2][3];

data8_t system32_dirty_window[0x100];
data8_t system32_windows[4][4];
data8_t system32_old_windows[4][4];

/* these are the various attributes a sprite can have, will decide which need to be global later, maybe put them in a struct */

static int sys32sprite_indirect_palette;
static int sys32sprite_indirect_interleave;
static int sys32sprite_is_shadow;
static int sys32sprite_rambasedgfx;
static int sys32sprite_8bpp;
static int sys32sprite_draw_colour_f;
static int sys32sprite_yflip;
static int sys32sprite_xflip;
static int sys32sprite_use_yoffset;
static int sys32sprite_use_xoffset;
static int sys32sprite_yalign;
static int sys32sprite_xalign;
static int sys32sprite_rom_height;
static int sys32sprite_rom_width;
static int sys32sprite_rom_bank_low;
static int sys32sprite_unknown_1;
static int sys32sprite_unknown_2;
/*static int sys32sprite_solid;*/
static int sys32sprite_screen_height;
static int sys32sprite_unknown_3;
static int sys32sprite_rom_bank_high;
static int sys32sprite_unknown_4;
static int sys32sprite_unknown_5;
static int sys32sprite_rom_bank_mid;
static int sys32sprite_screen_width;
static int sys32sprite_ypos;
static int sys32sprite_xpos;
static int sys32sprite_rom_offset;
static int sys32sprite_palette;
static int sys32sprite_monitor_select; /* multi32*/
static int sys32sprite_priority;

static data16_t *sys32sprite_table;

static int spritenum; /* used to go through the sprite list */
static int jump_x, jump_y; /* these are set during a jump command and sometimes used by the sprites afterwards */
static data16_t *spritedata_source; /* a pointer into spriteram */

#if !NEW_DRAWSPRITE
static UINT32 sys32sprite_x_zoom;
static UINT32 sys32sprite_y_zoom;
#else
static int sys32mon_old4, sys32mon_old8;
#endif

/*

this actually draws the sprite, and could probably be optimized quite a bit ;-)
currently zooming isn't supported etc.

*/
#if NEW_DRAWSPRITE

/** AT050703 new drawsprite (unproven, general testing required)*/
static INLINE void system32_draw_sprite ( struct mame_bitmap *bitmap, const struct rectangle *cliprect )
{
#define FP     20
#define FPONE  (1<<FP)
#define FPHALF (1<<(FP-1))

/* FP entry vaule(FPENT) should normally be 0.5(FPHALF) but it causes sprite gaps occationally.*/
#define FPENT  0

	static UINT32 idp_cache8[256];
	static UINT32 idp_cache4[16];
	static data16_t *idp_base, *idb_old=0;
	static int idi_old=-1;

	/* one-time*/
	int src_fw, src_fh;
	int dst_minx, dst_maxx, dst_miny, dst_maxy;
	int dst_skipx, dst_skipy, dst_x, dst_y, dst_lastx, dst_lasty; /* Buy Warren Spector's Deus Ex2. It's cool.*/
	int flipx, flipy;

	/* inner loop*/
	UINT8 *src_ptr;
	register int edx, eax, ecx;
	int src_fx, src_fdx, transparent_pen;
	UINT32 *pal_base;
	UINT32 *dst_ptr;

	/* outter loop*/
	int src_fby, src_fdy;
	int dst_pitch;
	int src_pitch, src_fbx;
	UINT8 *src_base;
	int dst_w, dst_h;


	/* fill internal data structure with default values*/
	src_base  = memory_region(REGION_GFX2);
	src_pitch = sys32sprite_rom_width;
	src_fw    = sys32sprite_rom_width;
	src_fh    = sys32sprite_rom_height;

	idp_base  = sys32sprite_table;
	pal_base  = Machine->gfx[0]->colortable;

	dst_ptr   = bitmap->base;
	dst_pitch = bitmap->rowpixels;
	dst_minx  = cliprect->min_x;
	dst_maxx  = cliprect->max_x;
	dst_miny  = cliprect->min_y;
	dst_maxy  = cliprect->max_y;
	dst_x     = sys32sprite_xpos;
	dst_y     = sys32sprite_ypos;
	dst_w     = sys32sprite_screen_width;
	dst_h     = sys32sprite_screen_height;

	flipx     = sys32sprite_xflip;
	flipy     = sys32sprite_yflip;
	transparent_pen   = 0;

	/* cull zero dimension and off-screen objects*/
	if (!src_fw || !src_fh || !dst_w || !dst_h) return;
	if (dst_x > dst_maxx || dst_y > dst_maxy) return;
	dst_lastx = dst_x + dst_w - 1;
	if (dst_lastx < dst_minx) return;
	dst_lasty = dst_y + dst_h - 1;
	if (dst_lasty < dst_miny) return;

	/* calculate zoom factors*/
	src_fw <<= FP;
	src_fh <<= FP;
	src_fdx = src_fw / dst_w;
	src_fdy = src_fh / dst_h;

	/* clip destination*/
	dst_skipx = 0;
	eax = dst_minx;  if ((eax -= dst_x) > 0) { dst_skipx = eax;  dst_w -= eax;  dst_x = dst_minx; }
	eax = dst_lastx; if ((eax -= dst_maxx) > 0) dst_w -= eax;
	dst_skipy = 0;
	eax = dst_miny;  if ((eax -= dst_y) > 0) { dst_skipy = eax;  dst_h -= eax;  dst_y = dst_miny; }
	eax = dst_lasty; if ((eax -= dst_maxy) > 0) dst_h -= eax;

	/* clip source (precision loss from MUL after DIV is intentional to maintain pixel consistency)*/
	if (flipx)
	{
		src_fbx = src_fw - FPENT - 1;
		src_fdx = -src_fdx;
	}
	else src_fbx = FPENT;
	src_fbx += dst_skipx * src_fdx;
	if (flipy)
	{
		src_fby = src_fh - FPENT - 1;
		src_fdy = -src_fdy;
	}
	else src_fby = FPENT;
	src_fby += dst_skipy * src_fdy;


	/* modify oddities*/
	/* if the gfx data is coming from RAM instead of ROM change the pointer*/
	if (sys32sprite_rambasedgfx)
	{
		src_base = sys32_spriteram8;
		sys32sprite_rom_offset &= 0x1ffff; /* right mask?*/
	}

	if (sys32sprite_monitor_select)
	{
		pal_base += MAX_COLOURS;
		dst_x += system32_screen_mode ? 52*8 : 40*8;
	}

	if (!sys32sprite_8bpp)
	{
		src_pitch >>= 1;
		if (!sys32sprite_draw_colour_f) transparent_pen = 0x0f;
	}
	else
		if (!sys32sprite_draw_colour_f) transparent_pen = 0xff;

	if (!sys32sprite_is_shadow)
	{
		if (sys32sprite_indirect_palette)
		{
			/* update indirect palette cache if necessary*/
			if (!sys32sprite_8bpp)
			{
				if (idb_old != idp_base || sys32mon_old4 != sys32sprite_monitor_select)
				{
					idb_old = idp_base;
					sys32mon_old4 = sys32sprite_monitor_select;

					for (ecx=0; ecx<0x10; ecx+=2)
					{
						eax = idp_base[ecx];   edx = idp_base[ecx+1];
						eax &= 0x0fff;         edx &= 0x0fff; /* no apparent side-effect observed*/
						eax = pal_base[eax];   edx = pal_base[edx];
						idp_cache4[ecx] = eax; idp_cache4[ecx+1] = edx;
					}
				}
			}
			else
			{
				edx = *idp_base & 0xfff;
				if (idi_old != edx || sys32mon_old8 != sys32sprite_monitor_select)
				{
					idi_old = edx;
					sys32mon_old8 = sys32sprite_monitor_select;
					pal_base += edx;

					for (ecx=0; ecx<0x100; ecx+=2)
					{
						eax = pal_base[ecx];   edx = pal_base[ecx+1];
						idp_cache8[ecx] = eax; idp_cache8[ecx+1] = edx;
					}
				}
			}
		}
		else
			pal_base += sys32sprite_palette<<4;
	}
	else
		sys32sprite_indirect_palette = 0; /* make sure full-shadows and IDP's are mutually exclusive*/


	/* adjust insertion points and pre-entry constants*/
	src_base += sys32sprite_rom_offset;
	dst_ptr += dst_y * dst_pitch + dst_x + dst_w;
	dst_w = -dst_w;

	ecx = src_fby;
	src_fby += src_fdy;
	ecx >>= FP;
	src_ptr = src_base;
	ecx *= src_pitch;
	src_fx = src_fbx;
	edx    = src_fbx;
	src_ptr += ecx;
	ecx = dst_w;

	if (!sys32sprite_8bpp)
	{
		/* 4bpp*/
		edx >>= FP+1;

		if (sys32sprite_indirect_palette)
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					if (src_fx & FPONE) eax &= 0xf; else eax >>= 4;
					edx += src_fdx;
					src_fx += src_fdx;
					edx >>= FP+1;

					if (!eax || eax == transparent_pen) continue;
					if (eax != 0x0e)
						dst_ptr[ecx] = idp_cache4[eax];
					else
					{
						eax = dst_ptr[ecx];
						eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f);
						dst_ptr[ecx] = ((UINT32*)palette_shadow_table)[eax];
					}

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;
				src_ptr = src_base; edx >>= FP+1;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
		else if (!sys32sprite_is_shadow)
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					if (src_fx & FPONE) eax &= 0xf; else eax >>= 4;
					edx += src_fdx;
					src_fx += src_fdx;
					edx >>= (FP+1);

					if (!eax || eax == transparent_pen) continue;
					dst_ptr[ecx] = pal_base[eax];

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;
				src_ptr = src_base; edx >>= FP+1;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
		else
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					if (src_fx & FPONE) eax &= 0xf; else eax >>= 4;
					edx += src_fdx;
					src_fx += src_fdx;
					edx >>= (FP+1);

					if (!eax || eax == transparent_pen) continue;
					eax = dst_ptr[ecx];
					eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f);
					dst_ptr[ecx] = ((UINT32*)palette_shadow_table)[eax];

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;
				src_ptr = src_base; edx >>= FP+1;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
	}
	else
	{
		/* 8bpp*/
		edx >>= FP;
		src_fx += src_fdx;

		if (sys32sprite_indirect_palette)
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					src_fx += src_fdx;
					edx >>= FP;

					if (!eax || eax == 0xe0 || eax == transparent_pen) continue;
					if (eax != 0xf0)
						dst_ptr[ecx] = idp_cache8[eax];
					else
					{
						eax = dst_ptr[ecx];
						eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f);
						dst_ptr[ecx] = ((UINT32*)palette_shadow_table)[eax];
					}

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;      src_fx += src_fdx;
				src_ptr = src_base; edx >>= FP;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
		else if (!sys32sprite_is_shadow)
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					src_fx += src_fdx;
					edx >>= FP;

					if (!eax || eax == transparent_pen) continue;
					dst_ptr[ecx] = pal_base[eax];

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;      src_fx += src_fdx;
				src_ptr = src_base; edx >>= FP;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
		else
		{
			do {
				do {
					eax = src_ptr[edx];
					edx = src_fx;
					src_fx += src_fdx;
					edx >>= FP;

					if (!eax || eax == transparent_pen) continue;
					eax = dst_ptr[ecx];
					eax = (eax>>9&0x7c00) | (eax>>6&0x03e0) | (eax>>3&0x001f);
					dst_ptr[ecx] = ((UINT32*)palette_shadow_table)[eax];

				} while (++ecx);

				ecx = src_fby;      src_fby += src_fdy;
				ecx >>= FP;         dst_ptr += dst_pitch;
				ecx *= src_pitch;   src_fx = src_fbx;
				edx = src_fbx;      src_fx += src_fdx;
				src_ptr = src_base; edx >>= FP;
				src_ptr += ecx;     ecx = dst_w;

			} while (--dst_h);
		}
	}
#undef FP
#undef FPONE
#undef FPHALF
#undef FPENT
}

#else

/* old drawsprite (working and proven)*/
void system32_draw_sprite ( struct mame_bitmap *bitmap, const struct rectangle *cliprect ) {
	data8_t *sprite_gfxdata = memory_region ( REGION_GFX2 );
	UINT32 xsrc,ysrc;
	UINT32 xdst,ydst;
	/* um .. probably a better way to do this */
	struct GfxElement *gfx=Machine->gfx[0];
	const pen_t *paldata = &gfx->colortable[0];

	/* if the gfx data is coming from RAM instead of ROM change the pointer */
	if ( sys32sprite_rambasedgfx ) {
		sprite_gfxdata = sys32_spriteram8;
		sys32sprite_rom_offset &= 0x1ffff; /* right mask? */
	}

	ysrc = 0;
	ydst = 0;

	while ( ysrc < (sys32sprite_rom_height<<16) ) {
		int drawypos;
		xsrc = 0;
		xdst = 0;

		if (!sys32sprite_yflip) {
			drawypos = sys32sprite_ypos+ydst; /* no flip*/
			if (drawypos > cliprect->max_y) ysrc = sys32sprite_rom_height<<16; /* quit drawing if we've gone off the right*/
		}
		else {
			drawypos = sys32sprite_ypos+((sys32sprite_screen_height-1)-ydst); /* y flip*/
			if (drawypos < cliprect->min_y) ysrc = sys32sprite_rom_height<<16; /* quit drawing if we've gone off the left on a flipped sprite*/
		}

		if ((drawypos >= cliprect->min_y) && (drawypos <= cliprect->max_y)) {
			UINT32 *destline = (bitmap->line[drawypos]);

			while ( xsrc < (sys32sprite_rom_width<<16) ) {

				int drawxpos;

				if (!sys32sprite_xflip) {
					drawxpos = sys32sprite_xpos+xdst; /* no flip*/
					if (drawxpos > cliprect->max_x) xsrc = sys32sprite_rom_width<<16; /* quit drawing if we've gone off the right*/
				}
				else {
					drawxpos = sys32sprite_xpos+((sys32sprite_screen_width-1)-xdst); /* x flip*/
					if (drawxpos < cliprect->min_x) xsrc = sys32sprite_rom_width<<16; /* quit drawing if we've gone off the left on a flipped sprite*/
				}

				if ((drawxpos >= cliprect->min_x) && (drawxpos <= cliprect->max_x)) {
					int gfxdata;
					int data;
					int r,g,b;

					if (sys32sprite_monitor_select) drawxpos+=system32_screen_mode?52*8:40*8;
					if (!sys32sprite_8bpp) { /* 4bpp*/
						gfxdata = (sprite_gfxdata[sys32sprite_rom_offset+((xsrc>>16)/2)+(ysrc>>16)*(sys32sprite_rom_width/2)]);

						if (xsrc & 0x10000) gfxdata = gfxdata & 0x0f;
						else gfxdata = (gfxdata & 0xf0) >> 4;

						if ( (!sys32sprite_draw_colour_f && gfxdata == 0x0f) ) gfxdata = 0;
						if (sys32sprite_indirect_palette) {
							switch (gfxdata) {
							case 0x00:
								break;

							case 0x0f: /* Transparent*/
								break;

							case 0x0e: /* Shadow*/
								data=destline[drawxpos];

								r = ((data >> 16) & 0xff)*0.5;
								g = ((data >> 8) & 0xff)*0.5;
								b = ((data >> 0) & 0xff)*0.5;

								destline[drawxpos] =  MAKE_RGB(r,g,b);
								break;

							default:
								destline[drawxpos] =  paldata[(sys32sprite_table[gfxdata] & 0xfff)+(sys32sprite_monitor_select*MAX_COLOURS)];
								break;
							}
						}
						else {
							if (sys32sprite_is_shadow) {
								data=destline[drawxpos];

								r = ((data >> 16) & 0xff)*0.5;
								g = ((data >> 8) & 0xff)*0.5;
								b = ((data >> 0) & 0xff)*0.5;

								if (gfxdata) destline[drawxpos] =  MAKE_RGB(r,g,b);
							}
							else {

								switch (gfxdata) {
								case 0x00:
									break;
								default:
									destline[drawxpos] =  paldata[gfxdata + (sys32sprite_palette * 16)+(sys32sprite_monitor_select*MAX_COLOURS)];
									break;
								}

							}
						}
					}
					else { /* 8bpp*/
						gfxdata = (sprite_gfxdata[sys32sprite_rom_offset+(xsrc>>16)+(ysrc>>16)*(sys32sprite_rom_width)]);

						if ( (!sys32sprite_draw_colour_f) && (gfxdata == 0xff) ) gfxdata = 0;

						if (sys32sprite_indirect_palette) {
							switch (gfxdata) {
							case 0x00:
								break;
							case 0xe0: /* Transparent*/
								break;
							case 0xf0: /* Shadow*/
								data=destline[drawxpos];

								r = ((data >> 16) & 0xff)*0.5;
								g = ((data >> 8) & 0xff)*0.5;
								b = ((data >> 0) & 0xff)*0.5;

								destline[drawxpos] =  MAKE_RGB(r,g,b);
								break;
							default:
								destline[drawxpos] =  paldata[gfxdata+(sys32sprite_table[0] & 0xfff)+sys32sprite_monitor_select*MAX_COLOURS];
								break;
							}
						}
						else {
							if (sys32sprite_is_shadow) {
								data=destline[drawxpos];

								r = ((data >> 16) & 0xff)*0.5;
								g = ((data >> 8) & 0xff)*0.5;
								b = ((data >> 0) & 0xff)*0.5;

								if (gfxdata) destline[drawxpos] =  MAKE_RGB(r,g,b);
							}
							else {
								if (gfxdata) destline[drawxpos] =  paldata[gfxdata + (sys32sprite_palette * 16)+sys32sprite_monitor_select*MAX_COLOURS];
							}
						}
					} /* bpp */
				} /* xclipping */
				xsrc+=sys32sprite_x_zoom;
				xdst++;
			}
		}
		ysrc+=sys32sprite_y_zoom;
		ydst++;
	}
}

#endif

/* system32_get_sprite_info

this function is used to get information on the sprite from spriteram and call the
drawing functions

	spriteram Sprite Entry layout

	0:  ffffffff ffffffff  1:  HHHHHHHH WWWWWWWW  2:  hhhhhhhh hhhhhhhh  3:  wwwwwwww wwwwwwww
	4:  yyyyyyyy yyyyyyyy  5:  xxxxxxxx xxxxxxxx  6:  rrrrrrrr rrrrrrrr  7:  pppppppp pppppppp

	f = various flags
		xx------ -------- (0xc000) :  Command (00 for a sprite, other values would mean this isn't a sprite)
		--x----- -------- (0x2000) :  Sprite uses Indirect Palette (TRUSTED)
		---x---- -------- (0x1000) :  Sprite uses Indirect Palette which is Interleaved in Spritelist (GA2?)
		----x--- -------- (0x0800) :  Sprite is a shadow.  Uses upper 16 values of the sprite priority table
		-----x-- -------- (0x0400) :  Sprite GFX data comes from Spriteram, not ROM (TRUSTED)
		------x- -------- (0x0200) :  Sprite is 8bpp not 4bpp (TRUSTED)
		-------x -------- (0x0100) :  If NOT set colour in palette 0x0f is transparent (TRUSTED)
		-------- x------- (0x0080) :  Sprite Y-Flip (TRUSTED)
		-------- -x------ (0x0040) :  Sprite X-Flip (TRUSTED)
		-------- --x----- (0x0020) :  Use Y offset (offset set in last jump) (not trusted)
		-------- ---x---- (0x0010) :  Use X offset (offset set in last jump) (TRUSTED)
		-------- ----xx-- (0x000c) :  Y alignment. 00=Center, 10=Start, 01=End (TRUSTED)
		-------- ------xx (0x0003) :  X alignment. 00=Center, 10=Start, 01=End (TRUSTED)

	H = height of sprite in ROM
	W = width  of sprite in ROM (multiply by 4 to get screen width)

	System32:
	w = width to draw on SCREEN + extra attributes
		x------- -------- (0x8000) :  unknown
		-x------ -------- (0x4000) :  Bit 5 of Sprite ROM Bank (TRUSTED)
		--x----- -------- (0x2000) :  unknown
		---x---- -------- (0x1000) :  unknown
		----x--- -------- (0x0800) :  Bit 4 of Sprite ROM Bank (TRUSTED)
		-----xxx xxxxxxxx (0x07ff) :  Width to draw on screen (TRUSTED)

	Multi32:
	w = width to draw on SCREEN + extra attributes
		x------- -------- (0x8000) :  bit 5 of the sprite bank (TRUSTED)
		-x------ -------- (0x4000) :  unknown
		--x----- -------- (0x2000) :  Bit 4 of the sprite bank (TRUSTED)
		---x---- -------- (0x1000) :  unknown
		----x--- -------- (0x0800) :  Monitor selection for this sprite (TRUSTED)
		-----xxx xxxxxxxx (0x07ff) :  Width to draw on screen (TRUSTED)
	y = y-position (12-bit?, high bit = sign bit?)

	x = x-position (12-bit, high bit = sign bit)

	r = ROM Offset of GFX data (multiply by 4 to get real offset)

	p = Palette & Priority bits, I think these change depending on the mode (Direct or Indirect)
		DIRECT MODE *probably wrong, holoseum needed a kludge to work
		xxxxx--- -------- (0xf800) :  unknown
		-----xxx xxxx---- (0x07f0) :  palette #
		-------- ----xxxx (0x000f) :  unknown

*/

/** AT050703: minor clean-up's*/
static INLINE void system32_get_sprite_info ( struct mame_bitmap *bitmap, const struct rectangle *cliprect ) {
	/* get attributes */
	int mixerinput, sprite_palette_mask, sprite_priority_levels, sys32sprite_priority_lookup;

	sys32sprite_indirect_palette		= (spritedata_source[0]&0x2000) >> 13;
	sys32sprite_indirect_interleave		= (spritedata_source[0]&0x1000) >> 12;
	sys32sprite_is_shadow				= (spritedata_source[0]&0x0800) >> 11;
	sys32sprite_rambasedgfx				= (spritedata_source[0]&0x0400) >> 10;
	sys32sprite_8bpp					= (spritedata_source[0]&0x0200) >> 9;
	sys32sprite_draw_colour_f			= (spritedata_source[0]&0x0100) >> 8;
	sys32sprite_yflip					= (spritedata_source[0]&0x0080) >> 7;
	sys32sprite_xflip					= (spritedata_source[0]&0x0040) >> 6;
	sys32sprite_use_yoffset				= (spritedata_source[0]&0x0020) >> 5;
	sys32sprite_use_xoffset				= (spritedata_source[0]&0x0010) >> 4;
	sys32sprite_yalign					= (spritedata_source[0]&0x000c) >> 2;
	sys32sprite_xalign					= (spritedata_source[0]&0x0003) >> 0;

	sys32sprite_rom_height				= (spritedata_source[1]&0xff00) >> 8;
	sys32sprite_rom_width				= (spritedata_source[1]&0x00ff) >> 0;

	sys32sprite_rom_bank_low			= (spritedata_source[2]&0xf000) >> 12;
	sys32sprite_unknown_1				= (spritedata_source[2]&0x0800) >> 11;
	sys32sprite_unknown_2				= (spritedata_source[2]&0x0400) >> 10;
	sys32sprite_screen_height			= (spritedata_source[2]&0x03ff) >> 0;

	if (multi32) {
		sys32sprite_rom_bank_high			= (spritedata_source[3]&0x8000) >> 15;
		sys32sprite_unknown_3				= (spritedata_source[3]&0x4000) >> 14;
		sys32sprite_rom_bank_mid			= (spritedata_source[3]&0x2000) >> 13;
		sys32sprite_unknown_4				= (spritedata_source[3]&0x1000) >> 12;
		sys32sprite_monitor_select			= (spritedata_source[3]&0x0800) >> 11;
	}
	else {
		sys32sprite_unknown_3				= (spritedata_source[3]&0x8000) >> 15;
		sys32sprite_rom_bank_high			= (spritedata_source[3]&0x4000) >> 14;
		sys32sprite_unknown_4				= (spritedata_source[3]&0x2000) >> 13;
		sys32sprite_unknown_5				= (spritedata_source[3]&0x1000) >> 12;
		sys32sprite_rom_bank_mid			= (spritedata_source[3]&0x0800) >> 11;
		sys32sprite_monitor_select			= 0;
	}
	sys32sprite_screen_width			= (spritedata_source[3]&0x07ff) >> 0;

	sys32sprite_ypos					= (spritedata_source[4]&0xffff) >> 0;

	sys32sprite_xpos					= (spritedata_source[5]&0xffff) >> 0;

	sys32sprite_rom_offset				= (spritedata_source[6]&0xffff) >> 0;

	sprite_palette_mask=(1<<(system32_mixerShift+4))-1;
	sprite_priority_levels=system32_mixerregs[sys32sprite_monitor_select][0x4d/2]&2?15:3;
	mixerinput = (spritedata_source[7] >> (system32_mixerShift + 8)) & 0xf;
	sys32sprite_palette = (spritedata_source[7] >> 4) & sprite_palette_mask;
	sys32sprite_palette += (system32_mixerregs[sys32sprite_monitor_select][mixerinput] & 0x30)<<2;

	/* process attributes */

	sys32sprite_rom_width = sys32sprite_rom_width << 2;
	sys32sprite_rom_offset = sys32sprite_rom_offset | (sys32sprite_rom_bank_low << 16) | (sys32sprite_rom_bank_mid << 20) | (sys32sprite_rom_bank_high << 21);
	sys32sprite_rom_offset = sys32sprite_rom_offset << 2;

	/* Determine the sprites palette and priority.  The actual priority of the sprite is found by looking up
	   the sprite priority table in the mixer registers.  The lookup value is found by reading the first colour
	   in the sprites palette in the case of indirect sprites.  For direct sprites, the lookup value is found by
	   reading the sprite priority data.
	*/
	if (sys32sprite_indirect_palette) {
		if (sys32sprite_indirect_interleave) /* indirect mode where the table is included in the display list */
		{
			sys32sprite_table = spritedata_source+8;
			spritenum+=2;
		}
		else /* indirect mode where the display list contains an offset to the table */
		{
			sys32sprite_table = sys32_spriteram16 + ((spritedata_source[7] & ((1<<(8+system32_mixerShift))-1))*8);
		}
		if (sys32sprite_table[0]==0xffff) sys32sprite_priority_lookup=1;
		else sys32sprite_priority_lookup = (sys32sprite_table[0]>>(8+system32_mixerShift))&0xf;
	}
	else {
		/* If all of the palette bits are set, the sprite is a shadow.  This is a secondary
		   method to define sprite shadows alongside the sys32sprite_is_shadow bit.
		   Direct palette shadow sprites use the upper 16 values in the sprite priority lookup table. */
		if (sprite_palette_mask==((spritedata_source[7]>>4)&sprite_palette_mask)) sys32sprite_is_shadow=1;
		sys32sprite_priority_lookup = (spritedata_source[7]>>(system32_mixerShift+8))&0xf;
	}

	sys32sprite_priority = system32_mixerregs[sys32sprite_monitor_select][sys32sprite_priority_lookup&sprite_priority_levels]&0xf;
	if (sys32sprite_is_shadow && ((!strcmp(Machine->gamedrv->name,"f1en")) || (!strcmp(Machine->gamedrv->name,"f1lap")))) sys32sprite_is_shadow=0;  /* f1en turns this flag on the car sprites?*/

	if (sys32sprite_use_yoffset) sys32sprite_ypos += jump_y;
	if (sys32sprite_use_xoffset) sys32sprite_xpos += jump_x;

	/* adjust positions according to offsets if used (radm, radr, alien3, darkedge etc.) */

	/* adjust sprite positions based on alignment, pretty much straight from modeler */
	switch (sys32sprite_xalign) {
	case 0: /* centerX*/
	case 3:
		sys32sprite_xpos -= (sys32sprite_screen_width-1) / 2; /* this is trusted again spiderman truck door*/
		break;
	case 1: /* rightX*/
		sys32sprite_xpos -= sys32sprite_screen_width - 1;
		break;
	case 2: /* leftX*/
		break;
	}

	switch (sys32sprite_yalign) {
	case 0: /* centerY*/
	case 3:
		sys32sprite_ypos -= (sys32sprite_screen_height-1) / 2; /* this is trusted against alien3 energy bars*/
		break;
	case 1: /* bottomY*/
		sys32sprite_ypos -= sys32sprite_screen_height - 1;
		break;
	case 2: /* topY*/
		break;
	}

	sys32sprite_xpos &= 0x0fff;
	sys32sprite_ypos &= 0x0fff;

	/* sprite positions are signed */
	if (sys32sprite_ypos & 0x0800) sys32sprite_ypos -= 0x1000;
	if (sys32sprite_xpos & 0x0800) sys32sprite_xpos -= 0x1000;

	/* Inefficient sprite priority hack to get things working for now.  Will change to arrays later.
		Currently, draw_sprite is a lot more processor intensive and has a greater need for optimisation. */
	if (priloop==sys32sprite_priority)
		if (!multi32 || (multi32 && (readinputport(0xf)&(sys32sprite_monitor_select+1))>>sys32sprite_monitor_select))
			system32_draw_sprite ( bitmap, cliprect );
}

/* Sprite RAM

each entry in the sprite list is 16 bytes (8 words)
the sprite list itself consists of 4 main different types of entry
 a normal sprite

	0:  00------ --------  1:  -------- --------  2:  -------- --------  3:  -------- --------
	4:  -------- --------  5:  -------- --------  6:  -------- --------  7:  -------- --------

		(See Above for bit usage)

 a command to set the clipping area

	0:  01------ --------  1:  -------- --------  2:  -------- --------  3:  -------- --------
	4:  -------- --------  5:  -------- --------  6:  -------- --------  7:  -------- --------

		(to be filled in later)

 a jump command

	0:  10ujjjjj jjjjjjjj  1:  yyyyyyyy yyyyyyyy  2:  xxxxxxxx xxxxxxxx  3:  -------- --------
	4:  -------- --------  5:  -------- --------  6:  -------- --------  7:  -------- --------

		u = set sprite offset positions with this jump (alien3 proves this test is needed)
		j = sprite number to jump to
		y = sprite y offset to use (? bits) (only set if u = 1)
		x = sprite x offset to use (? bits) (only set if u = 1)

		other bits unused / unknown

 a terminate list command

	0:  11------ --------  1:  -------- --------  2:  -------- --------  3:  -------- --------
	4:  -------- --------  5:  -------- --------  6:  -------- --------  7:  -------- --------

		(other bits unused, list is terminated)

sprite ram can also contain palette look up data for the special indirect
palette modes, as well as sprite gfx data which is used instead of the gfx
in the roms if a bit in the sprite entry is set.

*/

void system32_process_spritelist ( struct mame_bitmap *bitmap, const struct rectangle *cliprect ) {
	int processed;
	int command;
	struct rectangle clip;

	/* set clipping defaults */
	clip.min_x = Machine->visible_area.min_x;
	clip.max_x = Machine->visible_area.max_x;
	clip.min_y = Machine->visible_area.min_y;
	clip.max_y = Machine->visible_area.max_y;

	processed = 0;
	spritenum = 0;

	while (spritenum < 0x20000/16) {
		spritedata_source = sys32_spriteram16 + 8 * spritenum;

		command = (spritedata_source[0] & 0xc000) >> 14;

		switch (command) {
		case 0x3: /* end of sprite list */
			/*				logerror ("SPRITELIST: terminated at sprite %06x\n", spritenum*16);*/
			spritenum = 60000; /* just set a high sprite number so we stop processing */
			break;
		case 0x2: /* jump to position in sprite list*/
			/*				logerror ("SPRITELIST: jump at sprite %06x to %06x extra data 0 %04x 1 %04x, 2 %04x 3 %04x 4 %04x 5 %04x 6 %04x 7 %04x\n", spritenum*16, (spritedata_source[0] & 0x1fff)*16, spritedata_source[0] & 0x2000, spritedata_source[1], spritedata_source[2], spritedata_source[3] , spritedata_source[4] , spritedata_source[5] ,spritedata_source[6] , spritedata_source[7] );*/
			spritenum = spritedata_source[0] & 0x1fff;
			if (spritedata_source[0] & 0x2000) {
				jump_y = spritedata_source[1];
				jump_x = spritedata_source[2];
			}
			break;
		case 0x1: /* set clipping registers */
			/*				logerror ("SPRITELIST: set clip regs at %06x extra data 0 %04x 1 %04x 2 %04x 3 %04x 4 %04x 5 %04x 6 %04x 7 %04x\n", spritenum*16, spritedata_source[0], spritedata_source[1],spritedata_source[2],spritedata_source[3],spritedata_source[4],spritedata_source[5],spritedata_source[6],spritedata_source[7]  );*/
			{

				if (spritedata_source[0] & 0x3000) /* alien 3 needs something like this ... */
				{
					clip.min_y = spritedata_source[0]& 0x0fff;
					clip.max_y = spritedata_source[1]& 0x0fff;
					clip.min_x = spritedata_source[2]& 0x0fff;
					clip.max_x = spritedata_source[3]& 0x0fff;

					if  (clip.max_y > Machine->visible_area.max_y) clip.max_y = Machine->visible_area.max_y;
					if  (clip.max_x > Machine->visible_area.max_x) clip.max_x = Machine->visible_area.max_x;
				}
				else {
					clip.min_x = Machine->visible_area.min_x;
					clip.max_x = Machine->visible_area.max_x;
					clip.min_y = Machine->visible_area.min_y;
					clip.max_y = Machine->visible_area.max_y;
				}

			}

			spritenum ++;
			break;
		case 0x0: /* draw sprite */
			/*				logerror ("SPRITELIST: draw sprite at %06x\n", spritenum*16 );*/
			system32_get_sprite_info (bitmap, &clip);
			spritenum ++;
			break;
		}

		processed++;
		if (processed > 0x20000/16) /* its dead ;-) */
		{
			/*			logerror ("SPRITELIST: terminated due to infinite loop\n");*/
			spritenum = 16384;
		};
	}
}

/* 0x31ff00 - 0x31ffff are video registers

tile banking is controlled by a register in here as well as a register external to the tilemap chip
which is mapped at 0xc0000e

	00 | rR-- -b--  ---- ----    |  b = tile bank low bit ( | 0x2000 ), not multi-32  r = screen resolution R also resolution?
	02 | ---- ----  ---- dddd    |  d = tilemap disable registers
	04 | bbbb bbbb  ???? SsRr       S = layer 3 rowselect enable
									s = layer 2 rowselect enable
									R = layer 3 rowscroll enable
									r = layer 2 rowscroll enable
									b = table bases
									jpark sets one of the ?
	06 |
	08 |
	0a |
	0c |
	0e |
	10 |
	12 | scroll x for tilemap 0
	14 |
	16 | scroll y for tilemap 0
	18 |
	1a | scroll x for tilemap 1
	1c |
	1e | scroll y for tilemap 1
	20 |
	22 | scroll x for tilemap 2
	24 |
	26 | scroll y for tilemap 2
	28 |
	2a | scroll x for tilemap 3
	2c |
	2e | scroll y for tilemap 3
	30 | scroll x offset tilemap 0
	32 | scroll y offset tilemap 0
	34 | scroll x offset tilemap 1
	36 | scroll y offset tilemap 1
	38 | scroll x offset tilemap 2
	3a | scroll y offset tilemap 2
	3c | scroll x offset tilemap 3
	3e | scroll y offset tilemap 3
	40 | pages 0 + 1 of tilemap 0
	42 | pages 2 + 3 of tilemap 0
	44 | pages 0 + 1 of tilemap 1
	46 | pages 2 + 3 of tilemap 1
	48 | pages 0 + 1 of tilemap 2
	4a | pages 2 + 3 of tilemap 2
	4c | pages 0 + 1 of tilemap 3
	4e | pages 2 + 3 of tilemap 4
	50 |
	52 |
	54 |
	56 |
	58 |
	5a |
	5c |
	5e |
	60 |
	62 |
	64 |
	66 |
	.... etc.. fill the rest in later

*/


/* Mixer Registers

00 ---- ---- ---- pppp  p = Sprite Priority Table
02 ---- ---- ---- pppp  p = Sprite Priority Table
04 ---- ---- ---- pppp  p = Sprite Priority Table
06 ---- ---- ---- pppp  p = Sprite Priority Table
08 ---- ---- ---- pppp  p = Sprite Priority Table
0a ---- ---- ---- pppp  p = Sprite Priority Table
0c ---- ---- ---- pppp  p = Sprite Priority Table
0e ---- ---- ---- pppp  p = Sprite Priority Table
10 ---- ---- ---- pppp  p = Sprite shadow? Priority Table
12 ---- ---- ---- pppp  p = Sprite shadow? Priority Table
14 ---- ---- ---- pppp  p = Sprite shadow? Priority Table
16 ---- ---- ---- pppp  p = Sprite shadow? Priority Table
18 ---- ---- ---- pppp  p = Sprite shadow? Priority Table
1a ---- ---- ---- pppp  p = Sprite shadow? Priority Table
1c ---- ---- ---- pppp  p = Sprite shadow? Priority Table
1e ---- ---- ---- pppp  p = Sprite shadow? Priority Table
20 ---- ---- ssss ssss  s = Mixershift?
22 ---- ssss bbbb pppp  Tilemap Palette Base + Shifting, b = bank, s = shift p = priority 0
24 ---- ssss bbbb pppp  p = priority 1
26 ---- ssss bbbb pppp  p = priority 2
28 ---- ssss bbbb pppp  p = priority 3
2a ---- ---- ---- f---  f = tilemap flip x 0
2c ---- ---- ---- f---  f = tilemap flip x 1
2e ---- ---- ---- f---  f = tilemap flip x 2
30 ---- ---- ---- f---  f = tilemap flip x 3
32 ---e ---- ---e ----  e = alpha enable 0
34 ---e ---- ---e ----  e = alpha enable 1
36 ---e ---- ---e ----  e = alpha enable 2
38 ---e ---- ---e ----  e = alpha enable 3
3a
3c
3e ---- ---- ---- ---w  w = tilemap wrap disable?
40 bbbb bbbb bbbb bbbb  b = brightness (red)
42 bbbb bbbb bbbb bbbb  b = brightness (green)
44 bbbb bbbb bbbb bbbb  b = brightness (blue)
46 bbbb bbbb bbbb bbbb  b = brightness? (layer?) 2?     or r ? (jpark)
48 bbbb bbbb bbbb bbbb  b = brightness? (layer?) 3?     or g ? (jpark)
4a bbbb bbbb bbbb bbbb  b = brightness? (layer?)        or b ? (jpark)
4c ---- ---- ---- --l-   l = number of sprite layers?16:4
4e bbbb bbbb ---- ----   b = alpha blend amount?

*/

/** AT050703: minor code shufflings*/
void system32_draw_text_layer ( struct mame_bitmap *bitmap, const struct rectangle *cliprect ) /* using this for now to save me tilemap system related headaches */
{
	int x,y;
	int textbank = sys32_videoram[0x01ff5c/2] & 0x0007;
	int tmaddress = (sys32_videoram[0x01ff5c/2] & 0x00f0) >> 4;

	int monitor_select, monitor_offset;
	struct GfxElement *gfx = Machine->gfx[1];
	struct GfxLayout *gfxlayout = Machine->drv->gfxdecodeinfo[1].gfxlayout;
	data8_t *txtile_gfxregion = memory_region(REGION_GFX3);
	data16_t* tx_tilemapbase = sys32_videoram + ((0x10000+tmaddress*0x1000) /2);

	if (multi32)
	{
		monitor_select = readinputport(0xf) & 3;
		monitor_offset = system32_screen_mode ? 52*8 : 40*8;
	}
	else
	{
		monitor_select = 1;
		monitor_offset = 0;
	}

	/* this register is like this

	 ---- ----  tttt -bbb

	 t = address of tilemap data (used by dbzvrvs)
	 b = address of tile gfx data (used by radmobile / radrally ingame, jpark)

	 */

	for (y = 0; y < 32 ; y++) {
		for (x = 0; x < 64 ; x++) {
			int data=tx_tilemapbase[x+y*64];
			int code = data & 0x01ff;
			int pal = (data>>9) & 0x7f;
			int drawypos, flip;

			pal += (((system32_mixerregs[0][0x10] & 0xf0) >> 4) * 0x40);

			code += textbank * 0x200;

			if (sys32_ramtile_dirty[code]) {
				decodechar(gfx, code, (data8_t*)txtile_gfxregion, gfxlayout);
				sys32_ramtile_dirty[code] = 0;
			}

			if (system32_temp_kludge != 1) {
				drawypos = y*8;
				flip = 0;
			}
			else /* holoseum, actually probably requires the sprites to be globally flipped + game ROT180 not the tilemap */
			{
				drawypos = 215-y*8;
				flip = 1;
			}

			if (monitor_select & 1)
				drawgfx(bitmap,gfx,code,pal,0,flip,(x<<3),drawypos,cliprect,TRANSPARENCY_PEN,0);

			/* Multi32: Draw the same text on Monitor B*/
			if (monitor_select & 2)
				drawgfx(bitmap,gfx,code,pal,0,flip,(x<<3)+monitor_offset,drawypos,cliprect,TRANSPARENCY_PEN,0);
		}
	}
}

READ16_HANDLER ( sys32_videoram_r ) {
	return sys32_videoram[offset];
}

WRITE16_HANDLER ( sys32_videoram_w ) {
	data8_t *txtile_gfxregion = memory_region(REGION_GFX3);

	COMBINE_DATA(&sys32_videoram[offset]);


	/* also write it to another region so its easier (imo) to work with the ram based tiles */
	if (ACCESSING_MSB)
		txtile_gfxregion[offset*2+1] = (data & 0xff00) >> 8;

	if (ACCESSING_LSB)
		txtile_gfxregion[offset*2] = (data & 0x00ff );

	/* each tile is 0x10 words */
	sys32_ramtile_dirty[offset / 0x10] = 1;

	system32_dirty_window[offset>>9]=1;

}

WRITE16_HANDLER ( sys32_spriteram_w ) {

	COMBINE_DATA(&sys32_spriteram16[offset]);

	/* also write it to another region so its easier to work with when drawing sprites with RAM based gfx */
	if (ACCESSING_MSB)
		sys32_spriteram8[offset*2+1] = (data & 0xff00) >> 8;

	if (ACCESSING_LSB)
		sys32_spriteram8[offset*2] = (data & 0x00ff );
}

/*

Tilemaps are made of 4 windows

each window is 32x16 in size

*/

UINT32 sys32_bg_map( UINT32 col, UINT32 row, UINT32 num_cols, UINT32 num_rows ) {
	int page = 0;
	if( row<16 ) { /* top */
		if( col<32 ) page = 0; else page = 1;
	}
	else { /* bottom */
		if( col<32 ) page = 2; else page = 3;
	}

	return ((col & 31) + (row & 15) * 32) + page * 0x200;

}


static struct tilemap *system32_layer_tilemap[4];

static void get_system32_tile_info ( int tile_index, int layer ) {
	int tileno, s32palette;
	int page;
	int yxflip;
	int monitor=multi32?layer%2:0;

	page = tile_index >> 9;

	tileno = sys32_videoram[(tile_index&0x1ff)+system32_windows[layer][page]*0x200];
	s32palette = ((tileno & 0x1ff0) >> (sys32_paletteshift[layer]+4));
	yxflip = (tileno & 0xc000)>>14;

	tileno &= 0x1fff;

	if (multi32) {

		/*
		External tilebank register (0xc0000e)

		-------- x-------  Tilemap Layer 3 bank += 0x4000
		-------- -x------  Tilemap Layer 3 bank += 0x2000
		-------- --x-----  Tilemap Layer 2 bank += 0x4000
		-------- ---x----  Tilemap Layer 2 bank += 0x2000
		-------- ----x---  Tilemap Layer 1 bank += 0x4000
		-------- -----x--  Tilemap Layer 1 bank += 0x2000
		-------- ------x-  Tilemap Layer 0 bank += 0x4000
		-------- -------x  Tilemap Layer 0 bank += 0x2000
		*/

		tileno|=(sys32_tilebank_external>>(layer*2)&3)*0x2000;
	}
	else {
		if (sys32_tilebank_internal) tileno |= 0x2000;
		if (sys32_tilebank_external&1) tileno |= 0x4000;
	}

	/* Multi32: use palette_b for monitor 2*/
	SET_TILE_INFO(0,tileno,sys32_palettebank[layer]+s32palette+(monitor*MAX_COLOURS/0x10),TILE_FLIPYX(yxflip))
}

static void get_system32_layer0_tile_info(int tile_index) {
	get_system32_tile_info(tile_index,0);
}
static void get_system32_layer1_tile_info(int tile_index) {
	get_system32_tile_info(tile_index,1);
}
static void get_system32_layer2_tile_info(int tile_index) {
	get_system32_tile_info(tile_index,2);
}
static void get_system32_layer3_tile_info(int tile_index) {
	get_system32_tile_info(tile_index,3);
}

VIDEO_START( system32 ) {
	int i;

	system32_layer_tilemap[0] = tilemap_create(get_system32_layer0_tile_info,sys32_bg_map,TILEMAP_TRANSPARENT, 16, 16,64,32);
	tilemap_set_transparent_pen(system32_layer_tilemap[0],0);
	system32_layer_tilemap[1] = tilemap_create(get_system32_layer1_tile_info,sys32_bg_map,TILEMAP_TRANSPARENT, 16, 16,64,32);
	tilemap_set_transparent_pen(system32_layer_tilemap[1],0);
	system32_layer_tilemap[2] = tilemap_create(get_system32_layer2_tile_info,sys32_bg_map,TILEMAP_TRANSPARENT, 16, 16,64,32);
	tilemap_set_transparent_pen(system32_layer_tilemap[2],0);
	system32_layer_tilemap[3] = tilemap_create(get_system32_layer3_tile_info,sys32_bg_map,TILEMAP_TRANSPARENT, 16, 16,64,32);
	tilemap_set_transparent_pen(system32_layer_tilemap[3],0);

	sys32_spriteram8 = auto_malloc ( 0x20000 ); /* for ram sprites*/
	sys32_videoram = auto_malloc ( 0x20000 );

	for (i=0; i <= multi32; i++) {
		sys32_old_brightness[i][0] = 0;
		sys32_old_brightness[i][1] = 0;
		sys32_old_brightness[i][2] = 0;
		sys32_brightness[i][0] = 0xff;
		sys32_brightness[i][1] = 0xff;
		sys32_brightness[i][2] = 0xff;
	}

	for (i = 0; i < 0x100; i++)
		system32_dirty_window[i] = 1;

	return 0;
}

void system32_set_colour (int offset);
void multi32_set_colour (int offset, int monitor);

static void system32_recalc_palette( int monitor ) {
	int i;
	for (i = 0; i < MAX_COLOURS; i++) {
		if (multi32) multi32_set_colour (i,monitor);
		else system32_set_colour(i);
	}
}

void system32_draw_bg_layer ( struct mame_bitmap *bitmap, const struct rectangle *cliprect, int layer ) {
	int trans = 0;
	int alphaamount = 0;
	int rowscroll=0, rowselect=0;
	int monitor = multi32?layer%2:0;
	int monitor_res = 0;
	struct rectangle clip;

	if ((system32_mixerregs[monitor][(0x32+2*layer)/2] & 0x1010) == 0x1010) {
		trans = TILEMAP_ALPHA;
		alphaamount = 255-((((system32_mixerregs[monitor][0x4e/2])>>8) & 7) <<5); /*umm this is almost certainly wrong*/
		alpha_set_level(alphaamount);
	}

	/* rowselect / rowscroll

	outrunners road - works ok
	svf pitch - works ok with tilemap flip / clipping hack
	brival floor - seems ok
	arabfgt floor - seems ok, bit shakey
	rad rally mirror - reasonable but doesn't scroll smoothly
	rad mobile backgrounds - wrong?
	sonic title screen background - ok

	what effect does alien3 use? zooming instead?
	jurassic park enables rowscroll on one of the levels in the attract but its hard to see what for

	*/

	if (layer == 2) {
		rowscroll = (sys32_videoram[0x01FF04/2] & 0x0001);
		rowselect = (sys32_videoram[0x01FF04/2] & 0x0004)>>2;
	}

	if (layer == 3) {
		rowscroll = (sys32_videoram[0x01FF04/2] & 0x0002)>>1;
		rowselect = (sys32_videoram[0x01FF04/2] & 0x0008)>>3;
	}

	/* Switch to Machine->visible_area.max_x later*/
	monitor_res=system32_screen_mode?52*8:40*8;

	if (multi32) {
		/*			clip.min_x = Machine->visible_area.min_x;*/
		/*			clip.max_x = Machine->visible_area.max_x;*/
		clip.min_x = (layer%2)*monitor_res;
		clip.max_x = (layer%2+1)*monitor_res;
		clip.min_y = 0;
		clip.max_y = 28*8;
	}
	else {
		clip.min_x = Machine->visible_area.min_x;
		clip.max_x = Machine->visible_area.max_x;
		clip.min_y = Machine->visible_area.min_y;
		clip.max_y = Machine->visible_area.max_y;
	}

	if (rowscroll || rowselect) {
		int line;

		int tableaddress = sys32_videoram[0x01FF04/2]>>8;

		tableaddress = (tableaddress * 0x200);

		if ((system32_mixerregs[monitor][(0x32+layer*2)/2]&8)>>3) {
			if (layer==2) tilemap_set_flip(system32_layer_tilemap[layer], TILEMAP_FLIPX);
		}

		for (line = 0; line < 224;line++) {
			int xscroll = (sys32_videoram[(0x01FF12+8*layer)/2]);
			int yscroll = (sys32_videoram[(0x01FF16+8*layer)/2]);

			clip.min_y = clip.max_y = line;

			if (rowscroll) xscroll+=(sys32_videoram[((tableaddress+(layer-2)*0x200)/2)+line]);
			if (rowselect) yscroll+=(sys32_videoram[((tableaddress+0x400+(layer-2)*0x200)/2)+line])-line;


			if ((system32_mixerregs[monitor][(0x32+layer*2)/2]&8)>>3) {
				/* disable wrap on this tilemap, should be done on the other too but its less important
				   this is a bit messy because mame has no core functionality for this without resorting
				   to tilemap_draw_roz which I can't do because of RGB_DIRECT, it might be wrong anyway,
				   maybe its using the system32 clipping windows somehow */
				if (layer == 3) {
					int x2;
					x2 =xscroll&0x7ff;
					x2 = 0x7ff-x2;
					if (x2 > 0x3ff) clip.min_x = 0;
					else clip.min_x = x2;
					clip.max_x = 320-1;
				}
			}
			/* Multi32: Shift layer 3's rowscroll left one screen so that it lines up*/
			tilemap_set_scrollx(system32_layer_tilemap[layer],0, (xscroll & 0x3ff));
			tilemap_set_scrolly(system32_layer_tilemap[layer],0, (yscroll & 0x1ff));
			tilemap_set_scrolldx(system32_layer_tilemap[layer], (sys32_videoram[(0x01FF30+layer*4)/2]&0x00ff)+monitor*monitor_res, -(sys32_videoram[(0x01FF30+layer*4)/2]&0x00ff)-monitor*monitor_res);
			tilemap_set_scrolldy(system32_layer_tilemap[layer], sys32_videoram[(0x01FF32+layer*4)/2]&0x00ff, -sys32_videoram[(0x01FF32+layer*4)/2]&0x00ff);
			tilemap_draw(bitmap,&clip,system32_layer_tilemap[layer],trans,0);
		}
	}
	else {
		/* Multi32: Shift layer 3's rowscroll left one screen so that it lines up*/
		tilemap_set_scrollx(system32_layer_tilemap[layer],0,((sys32_videoram[(0x01FF12+8*layer)/2]) & 0x3ff));
		tilemap_set_scrolly(system32_layer_tilemap[layer],0,((sys32_videoram[(0x01FF16+8*layer)/2]) & 0x1ff));
		tilemap_set_scrolldx(system32_layer_tilemap[layer], (sys32_videoram[(0x01FF30+layer*4)/2]&0x00ff)+monitor*monitor_res, -(sys32_videoram[(0x01FF30+layer*4)/2]&0x00ff)-monitor*monitor_res);
		tilemap_set_scrolldy(system32_layer_tilemap[layer], sys32_videoram[(0x01FF32+layer*4)/2]&0x00ff, -sys32_videoram[(0x01FF32+layer*4)/2]&0x00ff);
		tilemap_draw(bitmap,&clip,system32_layer_tilemap[layer],trans,0);
	}
}

VIDEO_UPDATE( system32 ) {
	int i;

	int monitor_setting;
	int monitor_display_start;
	int monitor_display_width;
	int monitor_vertical_offset;

	int sys32_tmap_disabled = sys32_videoram[0x1FF02/2] & 0x000f;

	int priority0 = (system32_mixerregs[0][0x22/2] & 0x000f);
	int priority1 = (system32_mixerregs[multi32][0x24/2] & 0x000f);
	int priority2 = (system32_mixerregs[0][0x26/2] & 0x000f);
	int priority3 = (system32_mixerregs[multi32][0x28/2] & 0x000f);
	int sys32_palette_dirty[2] = {0, 0};

	/* -------------------------------------- experimental wip code --------------------------------*/
	int tm,ii;

	#if NEW_DRAWSPRITE
		/** force IDP recache*/
		sys32mon_old8 = sys32mon_old4 = -1;
	#endif

	/* if the windows number used by a tilemap use change then that window of the tilemap needs to be considered dirty*/
	for (tm = 0; tm < 4; tm++) {
		system32_windows[tm][0] = (sys32_videoram[(0x01FF40+4*tm)/2] & 0x007f);
		system32_windows[tm][1] = (sys32_videoram[(0x01FF40+4*tm)/2] & 0x7f00)>>8;
		system32_windows[tm][2] = (sys32_videoram[(0x01FF42+4*tm)/2] & 0x007f);
		system32_windows[tm][3] = (sys32_videoram[(0x01FF42+4*tm)/2] & 0x7f00)>>8;

		if (system32_windows[tm][0] != system32_old_windows[tm][0]) {
			for (ii = 0x000 ; ii < 0x200 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_windows[tm][1] != system32_old_windows[tm][1]) {
			for (ii = 0x200 ; ii < 0x400 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_windows[tm][2] != system32_old_windows[tm][2]) {
			for (ii = 0x400 ; ii < 0x600 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_windows[tm][3] != system32_old_windows[tm][3]) {
			for (ii = 0x600 ; ii < 0x800 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}

		/* if the actual windows are dirty we also need to mark them dirty in the tilemap*/
		if (system32_dirty_window [ system32_windows[tm][0] ]) {
			for (ii = 0x000 ; ii < 0x200 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_dirty_window [ system32_windows[tm][1] ]) {
			for (ii = 0x200 ; ii < 0x400 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_dirty_window [ system32_windows[tm][2] ]) {
			for (ii = 0x400 ; ii < 0x600 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}
		if (system32_dirty_window [ system32_windows[tm][3] ]) {
			for (ii = 0x600 ; ii < 0x800 ; ii++) tilemap_mark_tile_dirty(system32_layer_tilemap[tm],ii);
		}

		system32_old_windows[tm][0] = system32_windows[tm][0];
		system32_old_windows[tm][1] = system32_windows[tm][1];
		system32_old_windows[tm][2] = system32_windows[tm][2];
		system32_old_windows[tm][3] = system32_windows[tm][3];
	}

	/* we can clean the dirty window markers now*/
	for (ii = 0; ii < 0x100; ii++)
		system32_dirty_window[ii] = 0;

	/* if the internal tilebank changed everything is dirty*/
	sys32_tilebank_internal = sys32_videoram[0x01FF00/2] & 0x0400;
	if (sys32_tilebank_internal != sys32_old_tilebank_internal) {
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[0]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[1]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[2]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[3]);
	}
	sys32_old_tilebank_internal = sys32_tilebank_internal;

	/* if the external tilebank changed everything is dirty*/

	if  ( (sys32_tilebank_external) != sys32_old_tilebank_external ) {
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[0]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[1]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[2]);
		tilemap_mark_all_tiles_dirty(system32_layer_tilemap[3]);
	}
	sys32_old_tilebank_external = sys32_tilebank_external;

	/* if the palette shift /bank registers changed the tilemap is dirty, not sure these are regs 100% correct some odd colours in sonic / jpark*/
	for (tm = 0; tm < 4; tm++) {
		int monitor=multi32?tm%2:0;
		sys32_paletteshift[tm] = (system32_mixerregs[monitor][(0x22+tm*2)/2] & 0x0f00)>>8;
		if (sys32_paletteshift[tm] != sys32_old_paletteshift[tm]) {
			tilemap_mark_all_tiles_dirty(system32_layer_tilemap[tm]);
			sys32_old_paletteshift[tm] = sys32_paletteshift[tm];
		}

		sys32_palettebank[tm] = ((system32_mixerregs[monitor][(0x22+tm*2)/2] & 0x00f0)>>4)*0x40;
		if (sys32_palettebank[tm] != sys32_old_palettebank[tm]) {
			tilemap_mark_all_tiles_dirty(system32_layer_tilemap[tm]);
			sys32_old_palettebank[tm] = sys32_palettebank[tm];
		}
	}
	/*---------------------------------------- end wip code -----------------------------------------------*/

	/* palette dirty check */

	for (i=0; i <= multi32; i++) {
		sys32_brightness[i][0] = (system32_mixerregs[i][0x40/2]);
		sys32_brightness[i][1] = (system32_mixerregs[i][0x42/2]);
		sys32_brightness[i][2] = (system32_mixerregs[i][0x44/2]);

		if (sys32_brightness[i][0] != sys32_old_brightness[i][0]) {
			sys32_old_brightness[i][0] = sys32_brightness[i][0]; sys32_palette_dirty[i] = 1;
		}
		if (sys32_brightness[i][1] != sys32_old_brightness[i][1]) {
			sys32_old_brightness[i][1] = sys32_brightness[i][1]; sys32_palette_dirty[i] = 1;
		}
		if (sys32_brightness[i][2] != sys32_old_brightness[i][2]) {
			sys32_old_brightness[i][2] = sys32_brightness[i][2]; sys32_palette_dirty[i] = 1;
		}

		if (sys32_palette_dirty[i]) {
			sys32_palette_dirty[i] = 0;
			system32_recalc_palette(i);
		}
	}

	/* end palette dirty*/

	system32_screen_mode = sys32_videoram[0x01FF00/2] & 0xc000;  /* this should be 0x8000 according to modeler but then brival is broken?  this way alien3 and arabfgt try to change when they shouldn't .. wrong register?*/

	if (multi32) {
		monitor_setting=readinputport(0xf);
		monitor_vertical_offset=1;
		monitor_display_start=0;
		if (monitor_setting==2) monitor_display_start=1;
		if (monitor_setting==3) {
			monitor_vertical_offset=2;
			monitor_display_width=2;
		}
		else
			monitor_display_width=1+monitor_display_start;
	}
	else {
		monitor_display_start=0;
		monitor_display_width=1;
		monitor_vertical_offset=1;
	}

	fillbitmap(bitmap, 0, 0);

	if (system32_screen_mode && system32_allow_high_resolution) {
		set_visible_area(52*monitor_display_start*8, 52*8*monitor_display_width-1, 0, 28*8*monitor_vertical_offset-1);
	}
	else {
		set_visible_area(40*monitor_display_start*8, 40*8*monitor_display_width-1, 0, 28*8*monitor_vertical_offset-1);
	}

	fillbitmap(bitmap, 0, 0);

	/* Priority loop.  Draw layers 1 and 3 on Multi32's Monitor B*/
	if (sys32_displayenable & 0x0002) {
		for (priloop=0; priloop < 0x10; priloop++) {
			if (priloop == priority0 && (!multi32 || (multi32 && (readinputport(0xf)&1)))) {
				if (!(sys32_tmap_disabled & 0x1)) system32_draw_bg_layer (bitmap,cliprect,0);
			}
			if (priloop == priority1 && (!multi32 || (multi32 && (readinputport(0xf)&2)>>1))) {
				if (!(sys32_tmap_disabled & 0x2)) system32_draw_bg_layer (bitmap,cliprect,1);
			}
			if (priloop == priority2 && (!multi32 || (multi32 && (readinputport(0xf)&1)))) {
				if (!(sys32_tmap_disabled & 0x4)) system32_draw_bg_layer (bitmap,cliprect,2);
			}
			if (priloop == priority3 && (!multi32 || (multi32 && (readinputport(0xf)&2)>>1))) {
				if (!(sys32_tmap_disabled & 0x8)) system32_draw_bg_layer (bitmap,cliprect,3);
			}
			system32_process_spritelist (bitmap, cliprect);
		}
	}
	system32_draw_text_layer (bitmap, cliprect);
}


