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

  gba.c

  File to handle emulation of the video hardware of the Game Boy Advance

  By R. Belmont, MooglyGuy, Harmony

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

#include "emu.h"
#include "video/generic.h"
#include "includes/gba.h"

#define VERBOSE_LEVEL	(0)

INLINE void verboselog(running_machine &machine, int n_level, const char *s_fmt, ...)
{
	if( VERBOSE_LEVEL >= n_level )
	{
		va_list v;
		char buf[ 32768 ];
		va_start( v, s_fmt );
		vsprintf( buf, s_fmt, v );
		va_end( v );
		logerror( "%08x: %s", cpu_get_pc(machine.device("maincpu")), buf );
	}
}

static const int coeff[32] = {
	0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
	16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};

/* Drawing functions */
static void draw_roz_bitmap_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed, int depth);
static void draw_roz_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed);
static void draw_bg_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, UINT32 hofs, UINT32 vofs);
static void draw_gba_oam_window(gba_state *state, running_machine &machine, UINT32 *scanline, int y);
static void draw_gba_oam(gba_state *state, running_machine &machine, UINT32 *scanline, int y);
static void invalid_gba_draw_function(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux);

/* Utility functions */
INLINE int is_in_window(gba_state *state, int x, int window);
INLINE UINT32 alpha_blend_pixel(UINT32 color0, UINT32 color1, int ca, int cb);
INLINE UINT32 increase_brightness(UINT32 color, int coeff_);
INLINE UINT32 decrease_brightness(UINT32 color, int coeff_);

#include "gbamode0.c"
#include "gbamode1.c"
#include "gbamode2.c"
#include "gbam345.c"

static void (*const gba_draw_scanline_modes[8][3])(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux) =
{
	/* All modes have three sub-modes: No effects, effects, and windowed effects. */
	{	/* Mode 0: 4 non-rotatable tilemaps and 1 OAM layer */
		&draw_mode0_scanline,
		&draw_mode0_scanline_nowindow,
		&draw_mode0_scanline_all
	},
	{	/* Mode 1: 2 non-rotatable tilemaps, 1 rotozoomable tilemap, and 1 OAM layer */
		&draw_mode1_scanline,
		&draw_mode1_scanline_nowindow,
		&draw_mode1_scanline_all
	},
	{	/* Mode 2: 2 rotozoomable tilemaps, and 1 OAM layer */
		&draw_mode2_scanline,
		&draw_mode2_scanline_nowindow,
		&draw_mode2_scanline_all
	},
	{	/* Mode 3: 1 rotatable 8bpp bitmap and one OAM layer */
		&draw_roz_bitmap_mode_scanline,
		&draw_roz_bitmap_mode_scanline_nowindow,
		&draw_roz_bitmap_mode_scanline_all
	},
	{	/* Mode 4: 1 rotatable 16bpp bitmap and one OAM layer */
		&draw_roz_bitmap_mode_scanline,
		&draw_roz_bitmap_mode_scanline_nowindow,
		&draw_roz_bitmap_mode_scanline_all
	},
	{	/* Mode 5: 1 rotatable 4bpp bitmap and one OAM layer */
		&draw_roz_bitmap_mode_scanline,
		&draw_roz_bitmap_mode_scanline_nowindow,
		&draw_roz_bitmap_mode_scanline_all
	},
	{
		&invalid_gba_draw_function,
		&invalid_gba_draw_function,
		&invalid_gba_draw_function,
	},
	{
		&invalid_gba_draw_function,
		&invalid_gba_draw_function,
		&invalid_gba_draw_function,
	},
};

static void invalid_gba_draw_function(running_machine &machine, gba_state *state, int y, UINT32* line0, UINT32* line1, UINT32* line2, UINT32* line3, UINT32* lineOBJ, UINT32* lineOBJWin, UINT32* lineMix, int aux)
{
	fatalerror( "Invalid screen mode (6 or 7)!" );
}

static void draw_roz_bitmap_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed, int depth)
{
	UINT8 *src8 = (UINT8 *)state->m_gba_vram;
	UINT16 *src16 = (UINT16 *)state->m_gba_vram;
	UINT16 *palette = (UINT16 *)state->m_gba_pram;
	INT32 sx = (depth == 4) ? 160 : 240;
	INT32 sy = (depth == 4) ? 128 : 160;
	UINT32 prio = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;
	INT32 dx, dmx, dy, dmy, startx, starty;
	INT32 rx, ry, pixx, pixy, x;

	if ((depth == 8) && (state->m_DISPCNT & DISPCNT_FRAMESEL))
		src8 += 0xa000;

	if ((depth == 4) && (state->m_DISPCNT & DISPCNT_FRAMESEL))
		src16 += 0xa000/2;

	// sign extend roz parameters
	if (X & 0x08000000) X |= 0xf0000000;
	if (Y & 0x08000000) Y |= 0xf0000000;
	if (PA & 0x8000) PA |= 0xffff0000;
	if (PB & 0x8000) PB |= 0xffff0000;
	if (PC & 0x8000) PC |= 0xffff0000;
	if (PD & 0x8000) PD |= 0xffff0000;

	// re-assign parameters for convenience's sake
	dx = PA;
	dmx = PB;
	dy = PC;
	dmy = PD;
	startx = X;
	starty = Y;

	if(ypos == 0)
		changed = 3;

	if(changed & 1)
		*currentx = startx;
	else
		*currentx += dmx;

	if(changed & 2)
		*currenty = starty;
	else
		*currenty += dmy;

	rx = *currentx;
	ry = *currenty;

	if(ctrl & BGCNT_MOSAIC)
	{
		INT32 mosaic_line = ((state->m_MOSAIC & 0x00f0) >> 4) + 1;
		INT32 tempy = (ypos / mosaic_line) * mosaic_line;
		rx = startx + tempy*dmx;
		ry = starty + tempy*dmy;
	}

	pixx = rx >> 8;
	pixy = ry >> 8;

	for(x = 0; x < 240; x++)
	{
		if(pixx < 0 || pixy < 0 || pixx >= sx || pixy >= sy)
		{
			scanline[x] = 0x80000000;
		}
		else
		{
			if (depth == 8)
			{
				UINT8 color = src8[pixy*sx + pixx];
				scanline[x] = color ? (palette[color] | prio) : 0x80000000;
			}
			else
			{
				scanline[x] = src16[pixy*sx + pixx] | prio;
			}
		}

		rx += dx;
		ry += dy;

		pixx = rx >> 8;
		pixy = ry >> 8;
	}

	if(ctrl & BGCNT_MOSAIC)
	{
		INT32 mosaicx = (state->m_MOSAIC & 0x0f) + 1;
		if(mosaicx > 1)
		{
			INT32 m = 1;
			for(x = 0; x < 239; x++)
			{
				scanline[x+1] = scanline[x];
				m++;
				if(m == mosaicx)
				{
					m = 1;
					x++;
				}
			}
		}
	}
}

static void draw_roz_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, INT32 X, INT32 Y, INT32 PA, INT32 PB, INT32 PC, INT32 PD, INT32 *currentx, INT32 *currenty, int changed)
{
	UINT32 base, mapbase, size;
	static const INT32 sizes[4] = { 128, 256, 512, 1024 };
	INT32 cx, cy, x, pixx, pixy;
	UINT8 *mgba_vram = (UINT8 *)state->m_gba_vram;
	UINT32 tile;
	UINT16 *pgba_pram = (UINT16 *)state->m_gba_pram;
	UINT16 pixel;
	UINT32 prio = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;

	for(x = 0; x < 240; x++)
	{
		scanline[x] = 0x80000000;
	}

	if (state->m_DISPCNT & enablemask)
	{
		base = ((ctrl & BGCNT_CHARBASE) >> BGCNT_CHARBASE_SHIFT) * 0x4000;			// VRAM base of tiles
		mapbase = ((ctrl & BGCNT_SCREENBASE) >> BGCNT_SCREENBASE_SHIFT) * 0x800;	// VRAM base of map
		size = (ctrl & BGCNT_SCREENSIZE) >> BGCNT_SCREENSIZE_SHIFT;					// size of map in submaps

		// sign extend roz parameters
		if (X & 0x08000000) X |= 0xf0000000;
		if (Y & 0x08000000) Y |= 0xf0000000;
		if (PA & 0x8000) PA |= 0xffff0000;
		if (PB & 0x8000) PB |= 0xffff0000;
		if (PC & 0x8000) PC |= 0xffff0000;
		if (PD & 0x8000) PD |= 0xffff0000;

		if(ypos == 0)
		{
			changed = 3;
		}

		if(changed & 1)
		{
			*currentx = X;
		}
		else
		{
			*currentx += PB;
		}

		if(changed & 2)
		{
			*currenty = Y;
		}
		else
		{
			*currenty += PD;
		}

		cx = *currentx;
		cy = *currenty;

		if(ctrl & BGCNT_MOSAIC)
		{
			int mosaicy = ((state->m_MOSAIC & 0xf0) >> 4) + 1;
			int y = ypos % mosaicy;
			cx -= y*PB;
			cy -= y*PD;
		}

		pixx = cx >> 8;
		pixy = cy >> 8;

		if(ctrl & BGCNT_PALETTESET_WRAP)
		{
			pixx %= sizes[size];
			pixy %= sizes[size];
			if(pixx < 0)
			{
				pixx += sizes[size];
			}
			if(pixy < 0)
			{
				pixy += sizes[size];
			}
		}

		if(ctrl & BGCNT_PALETTE256)
		{
			for(x = 0; x < 240; x++)
			{
				if(pixx < 0 || pixy < 0 || pixx >= sizes[size] || pixy >= sizes[size])
				{
					scanline[x] = 0x80000000;
				}
				else
				{
					int tilex = pixx & 7;
					int tiley = pixy & 7;

					tile = mgba_vram[mapbase + (pixx >> 3) + (pixy >> 3) * (sizes[size] >> 3)];
					pixel = mgba_vram[base + (tile << 6) + (tiley << 3) + tilex];

					// plot it
					scanline[x] = pixel ? (pgba_pram[pixel] | prio) : 0x80000000;
				}

				cx += PA;
				cy += PC;

				pixx = cx >> 8;
				pixy = cy >> 8;

				if(ctrl & BGCNT_PALETTESET_WRAP)
				{
					pixx %= sizes[size];
					pixy %= sizes[size];
					if(pixx < 0)
					{
						pixx += sizes[size];
					}
					if(pixy < 0)
					{
						pixy += sizes[size];
					}
				}
			}
		}
		else
		{
			for(x = 0; x < 240; x++)
			{
				if(pixx < 0 || pixy < 0 || pixx >= sizes[size] || pixy >= sizes[size])
				{
					scanline[x] = 0x80000000;
				}
				else
				{
					int tilex = pixx & 7;
					int tiley = pixy & 7;

					tile = mgba_vram[mapbase + (pixx >> 3) + (pixy >> 3) * (sizes[size] >> 3)];
					pixel = mgba_vram[base + (tile << 6) + (tiley << 3) + tilex];

					// plot it
					scanline[x] = pixel ? (pgba_pram[pixel] | prio) : 0x80000000;
				}

				cx += PA;
				cy += PC;

				pixx = cx >> 8;
				pixy = cy >> 8;

				if(ctrl & BGCNT_PALETTESET_WRAP)
				{
					pixx %= sizes[size];
					pixy %= sizes[size];
					if(pixx < 0)
					{
						pixx += sizes[size];
					}
					if(pixy < 0)
					{
						pixy += sizes[size];
					}
				}
			}
		}

		if(ctrl & BGCNT_MOSAIC)
		{
			int mosaicx = (state->m_MOSAIC & 0x0f) + 1;
			if(mosaicx > 1)
			{
				int m = 1;
				for(x = 0; x < 239; x++)
				{
					scanline[x+1] = scanline[x];
					m++;
					if(m == mosaicx)
					{
						m = 1;
						x++;
					}
				}
			}
		}
	}
}

static void draw_bg_scanline(gba_state *state, UINT32 *scanline, int ypos, UINT32 enablemask, UINT32 ctrl, UINT32 hofs, UINT32 vofs)
{
	UINT8 *vram = (UINT8*)state->m_gba_vram;
	UINT16 *palette = (UINT16*)state->m_gba_pram;
	UINT8 *chardata = &vram[((ctrl & BGCNT_CHARBASE) >> BGCNT_CHARBASE_SHIFT) * 0x4000];
	UINT16 *screendata = (UINT16*)&vram[((ctrl & BGCNT_SCREENBASE) >> BGCNT_SCREENBASE_SHIFT) * 0x800];
	UINT32 priority = ((ctrl & BGCNT_PRIORITY) << 25) + 0x1000000;
	INT32 width = 256;
	INT32 height = 256;
	INT32 maskx, masky, pixx, pixy;
	UINT8 use_mosaic = (ctrl & BGCNT_MOSAIC) ? 1 : 0;
	INT32 mosaicx = (state->m_MOSAIC & 0x000f) + 1;
	INT32 mosaicy = ((state->m_MOSAIC & 0x00f0) >> 4) + 1;
	INT32 stride;
	INT32 x;

	if(!(state->m_DISPCNT & enablemask))
	{
		for(x = 0; x < 240; x++)
		{
			scanline[x] = 0x80000000;
		}

		return;
	}

	switch((ctrl & BGCNT_SCREENSIZE) >> BGCNT_SCREENSIZE_SHIFT)
	{
		case 1:
			width = 512;
			break;
		case 2:
			height = 512;
			break;
		case 3:
			width = 512;
			height = 512;
			break;
	}

	maskx = width - 1;
	masky = height - 1;

	pixx = hofs & maskx;
	pixy = (vofs + ypos) & masky;

	if(use_mosaic)
	{
		if((ypos % mosaicy) != 0)
		{
			mosaicy = (ypos / mosaicy) * mosaicy;
			pixy = (vofs + mosaicy) & masky;
		}
	}

	if(pixy > 255 && height > 256)
	{
		pixy &= 0x000000ff;
		screendata += 0x400;
		if(width > 256)
		{
			screendata += 0x400;
		}
	}

	stride = (pixy >> 3) << 5;

	if(ctrl & BGCNT_PALETTE256)
	{
		UINT16 *src = screendata + 0x400 * (pixx >> 8) + ((pixx & 255) >> 3) + stride;
		for(x = 0; x < 240; x++)
		{
			UINT16 data = *src;
			INT32 tile = data & TILEOBJ_TILE;
			INT32 tilex = pixx & 7;
			INT32 tiley = pixy & 7;
			UINT8 color;

			if(data & TILEOBJ_HFLIP)
			{
				tilex = 7 - tilex;
			}
			if(data & TILEOBJ_VFLIP)
			{
				tiley = 7 - tiley;
			}

			color = chardata[(tile << 6) + (tiley << 3) + tilex];

			if(color)
			{
				scanline[x] = palette[color] | priority;
			}
			else
			{
				scanline[x] = 0x80000000;
			}

			if(data & TILEOBJ_HFLIP)
			{
				if(tilex == 0)
				{
					src++;
				}
			}
			else if(tilex == 7)
			{
				src++;
			}

			pixx++;
			if(pixx == 256)
			{
				if(width > 256)
				{
					src = screendata + 0x400 + stride;
				}
				else
				{
					src = screendata + stride;
					pixx = 0;
				}
			}
			else if(pixx >= width)
			{
				pixx = 0;
				src = screendata + stride;
			}
		}
	}
	else
	{
		UINT16 *src = screendata + 0x400 * (pixx >> 8) + ((pixx & 255) >> 3) + stride;
		for(x = 0; x < 240; x++)
		{
			UINT16 data = *src;
			INT32 tile = data & TILEOBJ_TILE;
			INT32 tilex = pixx & 7;
			INT32 tiley = pixy & 7;
			UINT8 color;
			UINT8 palindex;

			if(data & TILEOBJ_HFLIP)
			{
				tilex = 7 - tilex;
			}
			if(data & TILEOBJ_VFLIP)
			{
				tiley = 7 - tiley;
			}

			color = chardata[(tile << 5) + (tiley << 2) + (tilex >> 1)];

			if(tilex & 1)
			{
				color >>= 4;
			}
			else
			{
				color &= 0x0f;
			}

			palindex = (data >> 8) & 0x00f0;
			if(color)
			{
				scanline[x] = palette[palindex + color] | priority;
			}
			else
			{
				scanline[x] = 0x80000000;
			}

			if(data & TILEOBJ_HFLIP)
			{
				if(tilex == 0)
				{
					src++;
				}
			}
			else if(tilex == 7)
			{
				src++;
			}

			pixx++;
			if(pixx == 256)
			{
				if(width > 256)
				{
					src = screendata + 0x400 + stride;
				}
				else
				{
					src = screendata + stride;
					pixx = 0;
				}
			}
			else if(pixx >= width)
			{
				pixx = 0;
				src = screendata + stride;
			}
		}
	}

	if(use_mosaic)
	{
		if(mosaicx > 1)
		{
			INT32 m = 1;
			for(x = 0; x < 239; x++)
			{
				scanline[x+1] = scanline[x];
				m++;
				if(m == mosaicx)
				{
					m = 1;
					x++;
				}
			}
		}
	}
}

static void draw_gba_oam_window(gba_state *state, running_machine &machine, UINT32 *scanline, int y)
{
	INT16 gba_oamindex;
	UINT32 tilebytebase, tileindex, tiledrawindex;
	UINT32 width, height;
	UINT16 *pgba_oam = (UINT16 *)state->m_gba_oam;
	int x = 0;
	UINT8 *src = (UINT8*)state->m_gba_vram;

	for(x = 0; x < 240; x++)
	{
		scanline[x] = 0x80000000;
	}

	if( state->m_DISPCNT & DISPCNT_OBJWIN_EN )
	{
		for( gba_oamindex = 127; gba_oamindex >= 0; gba_oamindex-- )
		{
			INT32 sx, sy;
			UINT16 attr0, attr1, attr2;
			INT32 cury;

			attr0 = pgba_oam[(4*gba_oamindex)+0];
			attr1 = pgba_oam[(4*gba_oamindex)+1];
			attr2 = pgba_oam[(4*gba_oamindex)+2];

			sx = (attr1 & OBJ_X_COORD);
			sy = (attr0 & OBJ_Y_COORD);

			if(sy > 160)
			{
				sy -= 256;
			}

			if ((attr0 & OBJ_MODE) != OBJ_MODE_WINDOW)
			{
				continue;
			}
			else
			{
				width = 0;
				height = 0;
				switch (attr0 & OBJ_SHAPE )
				{
					case OBJ_SHAPE_SQR:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 1;
								height = 1;
								break;
							case OBJ_SIZE_16:
								width = 2;
								height = 2;
								break;
							case OBJ_SIZE_32:
								width = 4;
								height = 4;
								break;
							case OBJ_SIZE_64:
								width = 8;
								height = 8;
								break;
						}
						break;
					case OBJ_SHAPE_HORIZ:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 2;
								height = 1;
								break;
							case OBJ_SIZE_16:
								width = 4;
								height = 1;
								break;
							case OBJ_SIZE_32:
								width = 4;
								height = 2;
								break;
							case OBJ_SIZE_64:
								width = 8;
								height = 4;
								break;
						}
						break;
					case OBJ_SHAPE_VERT:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 1;
								height = 2;
								break;
							case OBJ_SIZE_16:
								width = 1;
								height = 4;
								break;
							case OBJ_SIZE_32:
								width = 2;
								height = 4;
								break;
							case OBJ_SIZE_64:
								width = 4;
								height = 8;
								break;
						}
						break;
					default:
						width = 0;
						height = 0;
						verboselog(machine, 0, "OAM error: Trying to draw OBJ with OBJ_SHAPE = 3!\n" );
						break;
				}

				tiledrawindex = tileindex = (attr2 & OBJ_TILENUM);
				tilebytebase = 0x10000;	// the index doesn't change in the higher modes, we just ignore sprites that are out of range

				if (attr0 & OBJ_ROZMODE_ROZ)
				{
					INT32 fx, fy, ax, ay, rx, ry;
					INT16 dx, dy, dmx, dmy;
					UINT8 color;

					width *= 8;
					height *= 8;

					if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
					{
						continue;
					}

					fx = width;
					fy = height;

					if((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DBLROZ)
					{
						fx *= 2;
						fy *= 2;
					}

					cury = y - sy;

					if(cury >= 0 && cury < fy)
					{
						if(sx < 240 || ((sx + fx) & 0x1ff) < 240)
						{
							int rot = (attr1 & OBJ_SCALE_PARAM) >> OBJ_SCALE_PARAM_SHIFT;
							dx  = (INT16)pgba_oam[(rot << 4)+3];
							dmx = (INT16)pgba_oam[(rot << 4)+7];
							dy  = (INT16)pgba_oam[(rot << 4)+11];
							dmy = (INT16)pgba_oam[(rot << 4)+15];

							rx = (width << 7) - (fx >> 1)*dx - (fy >> 1)*dmx + cury * dmx;
							ry = (height << 7) - (fx >> 1)*dy - (fy >> 1)*dmy + cury * dmy;

							if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
							{
								int inc = 32;
								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}
								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = sx >> 2;
								}
								else
								{
									tiledrawindex &= 0x3fe;
								}
								for(x = 0; x < fx; x++)
								{
									ax = rx >> 8;
									ay = ry >> 8;

									if(ax < 0 || ax >= sx || ay < 0 || ay >= sy)
									{
									}
									else
									{
										color = src[tilebytebase + ((((tiledrawindex + (ay >> 3) * inc) << 5) + ((ay & 0x07) << 3) + ((ax >> 3) << 6) + (ax & 0x07)) & 0x7fff)];

										if(color)
										{
											scanline[sx] = 1;
										}
									}

									sx = (sx + 1) & 0x1ff;

									rx += dx;
									ry += dy;
								}
							}
							else
							{
								int inc = 32;
								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}
								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = sx >> 3;
								}
								for(x = 0; x < fx; x++)
								{
									ax = rx >> 8;
									ay = ry >> 8;

									if(ax < 0 || ax >= sx || ay < 0 || ay >= sy)
									{
									}
									else
									{
										color = src[tilebytebase + ((((tiledrawindex + (ay >> 3) * inc) << 5) + ((ay & 0x07) << 2) + ((ax >> 3) << 5) + ((ax & 0x07) >> 1)) & 0x7fff)];

										if(ax & 1)
										{
											color >>= 4;
										}
										else
										{
											color &= 0x0f;
										}

										if(color)
										{
											scanline[sx] = 1;
										}
									}

									sx = (sx + 1) & 0x1ff;

									rx += dx;
									ry += dy;
								}
							}
						}
					}
				}
				else
				{
					INT32 ax;
					int cury_ = y - sy;

					width *= 8;
					height *= 8;

					if(cury_ >= 0 && cury_ < height)
					{
						if( ( (sx < 240) || ( ( (sx + width) & 0x1ff ) < 240 ) ) && (attr0 & OBJ_ROZMODE_DISABLE) == 0)
						{
							if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
							{
								int inc = 32;
								int address = 0;
								if(attr1 & OBJ_VFLIP)
								{
									cury_ = height - cury_ - 1;
								}
								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 2;
								}
								else
								{
									tiledrawindex &= 0x3fe;
								}

								ax = 0;
								if(attr1 & OBJ_HFLIP)
								{
									ax = width - 1;
								}

								address = 0x10000 + ((((tiledrawindex + (cury_ >> 3) * inc) << 5) + ((cury_ & 7) << 3) + ((ax >> 3) << 6) + (ax & 7)) & 0x7fff);

								if(attr1 & OBJ_HFLIP)
								{
									ax = 7;
								}

								for(x = 0; x < width; x++)
								{
									if(sx < 240)
									{
										UINT8 color = src[address];

										if(color)
										{
											scanline[sx] = 1;
										}
									}

									sx = (sx + 1) & 0x1ff;

									if(attr1 & OBJ_HFLIP)
									{
										ax--;
										address--;
										if(ax == -1)
										{
											address -= 56;
											ax = 7;
										}
										if(address < 0x10000)
										{
											address += 0x8000;
										}
									}
									else
									{
										ax++;
										address++;
										if(ax == 8)
										{
											address += 56;
											ax = 0;
										}
										if(address > 0x17fff)
										{
											address -= 0x8000;
										}
									}
								}
							}
							else
							{
								int inc = 32;
								UINT32 address;
								if(attr1 & OBJ_VFLIP)
								{
									cury_ = height - cury_ - 1;
								}
								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 3;
								}

								ax = 0;
								if(attr1 & OBJ_HFLIP)
								{
									ax = width - 1;
								}

								address = 0x10000 + ((((tiledrawindex + (cury_ >> 3) * inc) << 5) + ((cury_ & 0x07) << 2) + ((ax >> 3) << 5) + ((ax & 0x07) >> 1)) & 0x7fff);
								if(attr1 & OBJ_HFLIP)
								{
									ax = 7;
									for(x = width - 1; x >= 0; x--)
									{
										if(sx < 240)
										{
											UINT8 color = src[address];
											if(x & 1)
											{
												color >>= 4;
											}
											else
											{
												color &= 0x0f;
											}

											if(color)
											{
												scanline[sx] = 1;
											}
										}

										sx = (sx + 1) & 0x1ff;
										ax--;
										if((x & 1) == 0)
										{
											address--;
										}
										if(ax == -1)
										{
											ax = 7;
											address -= 28;
										}
										if(address < 0x10000)
										{
											address += 0x8000;
										}
									}
								}
								else
								{
									for(x = 0; x < width; x++)
									{
										if(sx < 240)
										{
											UINT8 color = src[address];

											if(x & 1)
											{
												color >>= 4;
											}
											else
											{
												color &= 0x0f;
											}

											if(color)
											{
												scanline[sx] = 1;
											}
										}

										sx = (sx + 1) & 0x1ff;
										ax++;
										if(x & 1)
										{
											address++;
										}
										if(ax == 8)
										{
											address += 28;
											ax = 0;
										}
										if(address > 0x17fff)
										{
											address -= 0x8000;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

static void draw_gba_oam(gba_state *state, running_machine &machine, UINT32 *scanline, int y)
{
	INT16 gba_oamindex;
	INT32 mosaiccnt = 0;
	INT32 mosaicy = ((state->m_MOSAIC & 0xf000) >> 12) + 1;
	INT32 mosaicx = ((state->m_MOSAIC & 0x0f00) >>  8) + 1;
	UINT32 tileindex, tiledrawindex; //, tilebytebase
	UINT8 width, height;
	UINT16 *pgba_oam = (UINT16 *)state->m_gba_oam;
	UINT8 *src = (UINT8 *)state->m_gba_vram;
	UINT16 *palette = (UINT16*)state->m_gba_pram;
	int x = 0;

	for(x = 0; x < 240; x++)
	{
		scanline[x] = 0x80000000;
	}

	if( state->m_DISPCNT & DISPCNT_OBJ_EN )
	{
		for( gba_oamindex = 0; gba_oamindex < 128; gba_oamindex++ )
		{
			UINT16 attr0, attr1, attr2;
			INT32 cury;
			UINT32 prio;
			UINT32 priority;

			attr0 = pgba_oam[(4*gba_oamindex)+0];
			attr1 = pgba_oam[(4*gba_oamindex)+1];
			attr2 = pgba_oam[(4*gba_oamindex)+2];
			priority = (attr2 & OBJ_PRIORITY) >> OBJ_PRIORITY_SHIFT;
			prio = (priority << 25) | ((attr0 & OBJ_MODE) << 6);

			if ((attr0 & OBJ_MODE) != OBJ_MODE_WINDOW)
			{
				width = 0;
				height = 0;
				switch (attr0 & OBJ_SHAPE)
				{
					case OBJ_SHAPE_SQR:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 1;
								height = 1;
								break;
							case OBJ_SIZE_16:
								width = 2;
								height = 2;
								break;
							case OBJ_SIZE_32:
								width = 4;
								height = 4;
								break;
							case OBJ_SIZE_64:
								width = 8;
								height = 8;
								break;
						}
						break;
					case OBJ_SHAPE_HORIZ:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 2;
								height = 1;
								break;
							case OBJ_SIZE_16:
								width = 4;
								height = 1;
								break;
							case OBJ_SIZE_32:
								width = 4;
								height = 2;
								break;
							case OBJ_SIZE_64:
								width = 8;
								height = 4;
								break;
						}
						break;
					case OBJ_SHAPE_VERT:
						switch(attr1 & OBJ_SIZE )
						{
							case OBJ_SIZE_8:
								width = 1;
								height = 2;
								break;
							case OBJ_SIZE_16:
								width = 1;
								height = 4;
								break;
							case OBJ_SIZE_32:
								width = 2;
								height = 4;
								break;
							case OBJ_SIZE_64:
								width = 4;
								height = 8;
								break;
						}
						break;
					default:
						width = 0;
						height = 0;
						verboselog(machine, 0, "OAM error: Trying to draw OBJ with OBJ_SHAPE = 3!\n" );
						break;
				}

				tiledrawindex = tileindex = (attr2 & OBJ_TILENUM);
//              tilebytebase = 0x10000; // the index doesn't change in the higher modes, we just ignore sprites that are out of range

				if (attr0 & OBJ_ROZMODE_ROZ)
				{
					INT32 sx, sy;
					INT32 fx, fy, rx, ry;
					INT16 dx, dy, dmx, dmy;

					width *= 8;
					height *= 8;

					if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
					{
						continue;
					}

					sx = (attr1 & OBJ_X_COORD);
					sy = (attr0 & OBJ_Y_COORD);

					if(sy > 160)
					{
						sy -= 256;
					}

					fx = width;
					fy = height;

					if((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DBLROZ)
					{
						fx *= 2;
						fy *= 2;
					}

					cury = y - sy;

					if(cury >= 0 && cury < fy)
					{
						if(sx < 240 || ((sx + fx) & 0x1ff) < 240)
						{
							INT32 oamparam = (attr1 & OBJ_SCALE_PARAM) >> OBJ_SCALE_PARAM_SHIFT;

							dx  = (INT16)pgba_oam[(oamparam << 4)+3];
							dmx = (INT16)pgba_oam[(oamparam << 4)+7];
							dy  = (INT16)pgba_oam[(oamparam << 4)+11];
							dmy = (INT16)pgba_oam[(oamparam << 4)+15];

							if(attr0 & OBJ_MOSAIC)
							{
								cury -= (cury % mosaicy);
							}

							rx = (width << 7) - (fx >> 1)*dx - (fy >> 1)*dmx + cury*dmx;
							ry = (height << 7) - (fx >> 1)*dy - (fy >> 1)*dmy + cury*dmy;

							if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
							{
								INT32 inc = 32;

								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 2;
								}
								else
								{
									tiledrawindex &= 0x3fe;
								}

								for(x = 0; x < fx; x++)
								{
									INT32 pixx = rx >> 8;
									INT32 pixy = ry >> 8;

									if(!(pixx < 0 || pixx >= width || pixy < 0 || pixy >= height || sx >= 240))
									{
										UINT8 color = src[0x10000 + ((((tiledrawindex + (pixy >> 3) * inc) << 5) + ((pixy & 7) << 3) + ((pixx >> 3) << 6) + (pixx & 7)) & 0x7fff)];
										if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
										{
											scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}
										else if(color != 0 && prio < (scanline[sx] & 0xff000000))
										{
											scanline[sx] = palette[256 + color] | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}

										if(attr0 & OBJ_MOSAIC)
										{
											mosaiccnt++;
											if(mosaiccnt == mosaicx)
											{
												mosaiccnt = 0;
											}
										}
									}

									sx++;
									sx &= 0x1ff;

									rx += dx;
									ry += dy;
								}
							}
							else
							{
								INT32 inc = 32;
								INT32 palentry = (attr2 >> 8) & 0xf0;

								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 3;
								}

								for(x = 0; x < fx; x++)
								{
									INT32 pixx = rx >> 8;
									INT32 pixy = ry >> 8;

									if(!(pixx < 0 || pixx >= width || pixy < 0 || pixy >= height || sx >= 240))
									{
										UINT8 color = src[0x10000 + ((((tiledrawindex + (pixy >> 3) * inc) << 5) + ((pixy & 7) << 2) + ((pixx >> 3) << 5) + ((pixx & 7) >> 1)) & 0x7fff)];

										if(pixx & 1)
										{
											color >>= 4;
										}
										else
										{
											color &= 0x0f;
										}

										if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
										{
											scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}
										else if(color != 0 && prio < (scanline[sx] & 0xff000000))
										{
											scanline[sx] = palette[256 + palentry + color] | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}
									}

									if(attr0 & OBJ_MOSAIC)
									{
										mosaiccnt++;
										if(mosaiccnt == mosaicx)
										{
											mosaiccnt = 0;
										}
									}

									sx++;

									sx &= 0x1ff;

									rx += dx;
									ry += dy;
								}
							}
						}
					}
				}
				else
				{
					INT32 sx, sy;
					INT32 vflip = (attr1 & OBJ_VFLIP) ? 1 : 0;
					INT32 hflip = (attr1 & OBJ_HFLIP) ? 1 : 0;

					width *= 8;
					height *= 8;

					if ((attr0 & OBJ_ROZMODE) == OBJ_ROZMODE_DISABLE)
					{
						continue;
					}

					sx = (attr1 & OBJ_X_COORD);
					sy = (attr0 & OBJ_Y_COORD);

					if(sy > 160)
					{
						sy -= 256;
					}

					cury = y - sy;
					if(cury >= 0 && cury < height)
					{
						if(sx < 240 || ((sx + width) & 0x1ff) < 240)
						{
							if((attr0 & OBJ_PALMODE) == OBJ_PALMODE_256)
							{
								INT32 pixx;
								INT32 inc = 32;
								INT32 address = 0;

								if(vflip)
								{
									cury = height - cury - 1;
								}

								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 2;
								}
								else
								{
									tiledrawindex &= 0x3fe;
								}

								pixx = 0;
								if(hflip)
								{
									pixx = width - 1;
								}

								if(attr0 & OBJ_MOSAIC)
								{
									cury -= (cury % mosaicy);
								}

								address = 0x10000 + ((((tiledrawindex + (cury >> 3) * inc) << 5) + ((cury & 7) << 3) + ((pixx >> 3) << 6) + (pixx & 7)) & 0x7fff);

								if(hflip)
								{
									pixx = 7;
								}

								for(x = 0; x < width; x++)
								{
									if(sx < 240)
									{
										UINT8 color = src[address];
										if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
										{
											scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}
										else if(color != 0 && prio < (scanline[sx] & 0xff000000))
										{
											scanline[sx] = palette[256 + color] | prio;
											if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
											{
												scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
											}
										}
									}

									if(attr0 & OBJ_MOSAIC)
									{
										mosaiccnt++;
										if(mosaiccnt == mosaicx)
										{
											mosaiccnt = 0;
										}
									}

									sx++;
									sx &= 0x1ff;

									if(hflip)
									{
										pixx--;
										address--;
										if(pixx == -1)
										{
											address -= 56;
											pixx = 7;
										}
										if(address < 0x10000)
										{
											address += 0x8000;
										}
									}
									else
									{
										pixx++;
										address++;
										if(pixx == 8)
										{
											address += 56;
											pixx = 0;
										}
										if(address > 0x17fff)
										{
											address -= 0x8000;
										}
									}
								}
							}
							else
							{
								INT32 pixx;
								INT32 inc = 32;
								UINT32 address = 0;

								if(vflip)
								{
									cury = height - cury - 1;
								}

								if((state->m_DISPCNT & DISPCNT_MODE) > 2 && tiledrawindex < 0x200)
								{
									continue;
								}

								if((state->m_DISPCNT & DISPCNT_VRAM_MAP) == DISPCNT_VRAM_MAP_1D)
								{
									inc = width >> 3;
								}

								pixx = 0;
								if(hflip)
								{
									pixx = width - 1;
								}

								if(attr0 & OBJ_MOSAIC)
								{
									cury -= (cury % mosaicy);
								}

								address = 0x10000 + ((((tiledrawindex + (cury >> 3) * inc) << 5) + ((cury & 7) << 2) + ((pixx >> 3) << 5) + ((pixx & 7) >> 1)) & 0x7fff);

								if(hflip)
								{
									pixx = 7;
									for(x = width - 1; x >= 0; x--)
									{
										if(sx < 240)
										{
											UINT8 color = src[address];
											UINT8 palentry = (attr2 >> 8) & 0xf0;

											if(x & 1)
											{
												color >>= 4;
											}
											else
											{
												color &= 0x0f;
											}

											if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
											{
												scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
												if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
												{
													scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
												}
											}
											else if(color != 0 && prio < (scanline[sx] & 0xff000000))
											{
												scanline[sx] = palette[256 + palentry + color] | prio;
												if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
												{
													scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
												}
											}
										}

										sx++;
										sx &= 0x1ff;

										pixx--;
										if(!(x & 1))
										{
											address--;
										}
										if(pixx == -1)
										{
											address -= 28;
											pixx = 7;
										}
										if(address < 0x10000)
										{
											address += 0x8000;
										}
									}
								}
								else
								{
									for(x = 0; x < width; x++)
									{
										if(sx < 240)
										{
											UINT8 color = src[address];
											UINT8 palentry = (attr2 >> 8) & 0xf0;

											if(x & 1)
											{
												color >>= 4;
											}
											else
											{
												color &= 0x0f;
											}

											if(color == 0 && priority < ((scanline[sx] >> 25) & 3))
											{
												scanline[sx] = (scanline[sx] & 0xf9ffffff) | prio;
												if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
												{
													scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
												}
											}
											else if(color != 0 && prio < (scanline[sx] & 0xff000000))
											{
												scanline[sx] = palette[256 + palentry + color] | prio;
												if((attr0 & OBJ_MOSAIC) != 0 && mosaiccnt != 0)
												{
													scanline[sx] = (scanline[sx - 1] & 0xf9ffffff) | prio;
												}
											}
										}

										if(attr0 & OBJ_MOSAIC)
										{
											mosaiccnt++;
											if(mosaiccnt == mosaicx)
											{
												mosaiccnt = 0;
											}
										}

										sx++;
										sx &= 0x1ff;

										pixx++;
										if(x & 1)
										{
											address++;
										}
										if(pixx == 8)
										{
											address += 28;
											pixx = 0;
										}
										if(address > 0x17fff)
										{
											address -= 0x8000;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

INLINE int is_in_window(gba_state *state, int x, int window)
{
	int x0 = state->m_WIN0H >> 8;
	int x1 = state->m_WIN0H & 0x00ff;

	if(window == 1)
	{
		x0 = state->m_WIN1H >> 8;
		x1 = state->m_WIN1H & 0x00ff;
	}

	if(x0 <= x1)
	{
		if(x >= x0 && x < x1)
		{
			return 1;
		}
	}
	else
	{
		if(x >= x0 || x < x1)
		{
			return 1;
		}
	}

	return 0;
}

INLINE UINT32 alpha_blend_pixel(UINT32 color0, UINT32 color1, int ca, int cb)
{
	if(color0 < 0x80000000)
	{
		int r0 = (color0 >>  0) & 0x1f;
		int g0 = (color0 >>  5) & 0x1f;
		int b0 = (color0 >> 10) & 0x1f;
		int r1 = (color1 >>  0) & 0x1f;
		int g1 = (color1 >>  5) & 0x1f;
		int b1 = (color1 >> 10) & 0x1f;
		int r = ((r0 * ca) >> 4) + ((r1 * cb) >> 4);
		int g = ((g0 * ca) >> 4) + ((g1 * cb) >> 4);
		int b = ((b0 * ca) >> 4) + ((b1 * cb) >> 4);

		if(r > 0x1f) r = 0x1f;
		if(g > 0x1f) g = 0x1f;
		if(b > 0x1f) b = 0x1f;

		return (color0 & 0xffff0000) | (b << 10) | (g << 5) | r;
	}
	return color0;
}

INLINE UINT32 increase_brightness(UINT32 color, int coeff_)
{
	int r = (color >>  0) & 0x1f;
	int g = (color >>  5) & 0x1f;
	int b = (color >> 10) & 0x1f;

	r += ((0x1f - r) * coeff_) >> 4;
	g += ((0x1f - g) * coeff_) >> 4;
	b += ((0x1f - b) * coeff_) >> 4;

	if(r > 0x1f) r = 0x1f;
	if(g > 0x1f) g = 0x1f;
	if(b > 0x1f) b = 0x1f;

	return (color & 0xffff0000) | (b << 10) | (g << 5) | r;
}

INLINE UINT32 decrease_brightness(UINT32 color, int coeff_)
{
	int r = (color >>  0) & 0x1f;
	int g = (color >>  5) & 0x1f;
	int b = (color >> 10) & 0x1f;

	r -= (r * coeff_) >> 4;
	g -= (g * coeff_) >> 4;
	b -= (b * coeff_) >> 4;

	if(r < 0) r = 0;
	if(g < 0) g = 0;
	if(b < 0) b = 0;

	return (color & 0xffff0000) | (b << 10) | (g << 5) | r;
}

void gba_draw_scanline(running_machine &machine, int y)
{
	bitmap_t *bitmap = machine.generic.tmpbitmap;
	UINT16 *scanline = BITMAP_ADDR16(bitmap, y, 0);
	int i, x;
	gba_state *state = machine.driver_data<gba_state>();
	UINT8 submode = 0;
	int bpp = 0;

	// forced blank
	if (state->m_DISPCNT & DISPCNT_BLANK)
	{
		// forced blank is white
		for (i = 0; i < 240; i++)
		{
			scanline[i] = 0x7fff;
		}
		return;
	}

	if(!state->m_fxOn && !state->m_windowOn && !(state->m_DISPCNT & DISPCNT_OBJWIN_EN))
	{
		submode = 0;
	}
	else if(state->m_fxOn && !state->m_windowOn && !(state->m_DISPCNT & DISPCNT_OBJWIN_EN))
	{
		submode = 1;
	}
	else
	{
		submode = 2;
	}

	//printf( "mode = %d, %d\n", state->m_DISPCNT & 7, submode );

	switch(state->m_DISPCNT & 7)
	{
		case 3:
			bpp = 16;
			break;
		case 4:
			bpp = 8;
			break;
		case 5:
			bpp = 4;
			break;
	}

	gba_draw_scanline_modes[state->m_DISPCNT & 7][submode](machine, state, y, &state->m_xferscan[0][1024], &state->m_xferscan[1][1024], &state->m_xferscan[2][1024], &state->m_xferscan[3][1024], &state->m_xferscan[4][1024], &state->m_xferscan[5][1024], &state->m_xferscan[6][1024], bpp);

	for(x = 0; x < 240; x++)
	{
		scanline[x] = state->m_xferscan[6][1024 + x] & 0x7fff;
	}

	return;
}

void gba_video_start(running_machine &machine)
{
}
