text: /*******************************************************************
  
  Namco System 86 Video Hardware
  
  *******************************************************************/
  
  #include "driver.h"
  
  
  UINT8 *rthunder_videoram1, *rthunder_videoram2, *rthunder_spriteram;
  
  static int tilebank;
  static int xscroll[4], yscroll[4];	/* scroll + priority */
  
  static tilemap *bg_tilemap[4];
  
  static int backcolor;
  static const UINT8 *tile_address_prom;
  
  
  /***************************************************************************
  
    Convert the color PROMs into a more useable format.
  
    Rolling Thunder has two palette PROMs (512x8 and 512x4) and two 2048x8
    lookup table PROMs.
    The palette PROMs are connected to the RGB output this way:
  
    bit 3 -- 220 ohm resistor  -- BLUE
          -- 470 ohm resistor  -- BLUE
          -- 1  kohm resistor  -- BLUE
    bit 0 -- 2.2kohm resistor  -- BLUE
  
    bit 7 -- 220 ohm resistor  -- GREEN
          -- 470 ohm resistor  -- GREEN
          -- 1  kohm resistor  -- GREEN
          -- 2.2kohm resistor  -- GREEN
          -- 220 ohm resistor  -- RED
          -- 470 ohm resistor  -- RED
          -- 1  kohm resistor  -- RED
    bit 0 -- 2.2kohm resistor  -- RED
  
  ***************************************************************************/
  
  PALETTE_INIT( namcos86 )
  {
  	int i;
  	rgb_t palette[512];
  
  	for (i = 0;i < 512;i++)
  	{
  		int bit0,bit1,bit2,bit3,r,g,b;
  
  		bit0 = (color_prom[0] >> 0) & 0x01;
  		bit1 = (color_prom[0] >> 1) & 0x01;
  		bit2 = (color_prom[0] >> 2) & 0x01;
  		bit3 = (color_prom[0] >> 3) & 0x01;
  		r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
  		bit0 = (color_prom[0] >> 4) & 0x01;
  		bit1 = (color_prom[0] >> 5) & 0x01;
  		bit2 = (color_prom[0] >> 6) & 0x01;
  		bit3 = (color_prom[0] >> 7) & 0x01;
  		g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
  		bit0 = (color_prom[512] >> 0) & 0x01;
  		bit1 = (color_prom[512] >> 1) & 0x01;
  		bit2 = (color_prom[512] >> 2) & 0x01;
  		bit3 = (color_prom[512] >> 3) & 0x01;
  		b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
  
  		palette[i] = MAKE_RGB(r,g,b);
  		color_prom++;
  	}
  
  	color_prom += 512;
  	/* color_prom now points to the beginning of the lookup table */
  
  	/* tiles lookup table */
  	for (i = 0;i < 2048;i++)
  		palette_set_color(machine, i, palette[*color_prom++]);
  
  	/* sprites lookup table */
  	for (i = 0;i < 2048;i++)
  		palette_set_color(machine, 2048 + i, palette[256 + *color_prom++]);
  
  	/* color_prom now points to the beginning of the tile address decode PROM */
  
  	tile_address_prom = color_prom;	/* we'll need this at run time */
  }
  
  
  
  
  /***************************************************************************
  
    Callbacks for the TileMap code
  
  ***************************************************************************/
  
  INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,int layer,UINT8 *vram)
  {
  	int attr = vram[2*tile_index + 1];
  	int tile_offs;
  	if (layer & 2)
  		tile_offs = ((tile_address_prom[((layer & 1) << 4) + (attr & 0x03)] & 0xe0) >> 5) * 0x100;
  	else
  		tile_offs = ((tile_address_prom[((layer & 1) << 4) + ((attr & 0x03) << 2)] & 0x0e) >> 1) * 0x100 + tilebank * 0x800;
  
  	SET_TILE_INFO(
  			(layer & 2) ? 1 : 0,
  			vram[2*tile_index] + tile_offs,
  			attr,
  			0);
  }
  
  static TILE_GET_INFO( get_tile_info0 ) { get_tile_info(machine,tileinfo,tile_index,0,&rthunder_videoram1[0x0000]); }
  static TILE_GET_INFO( get_tile_info1 ) { get_tile_info(machine,tileinfo,tile_index,1,&rthunder_videoram1[0x1000]); }
  static TILE_GET_INFO( get_tile_info2 ) { get_tile_info(machine,tileinfo,tile_index,2,&rthunder_videoram2[0x0000]); }
  static TILE_GET_INFO( get_tile_info3 ) { get_tile_info(machine,tileinfo,tile_index,3,&rthunder_videoram2[0x1000]); }
  
  
  /***************************************************************************
  
    Start the video hardware emulation.
  
  ***************************************************************************/
  
  VIDEO_START( namcos86 )
  {
  	bg_tilemap[0] = tilemap_create(machine, get_tile_info0,tilemap_scan_rows,8,8,64,32);
  	bg_tilemap[1] = tilemap_create(machine, get_tile_info1,tilemap_scan_rows,8,8,64,32);
  	bg_tilemap[2] = tilemap_create(machine, get_tile_info2,tilemap_scan_rows,8,8,64,32);
  	bg_tilemap[3] = tilemap_create(machine, get_tile_info3,tilemap_scan_rows,8,8,64,32);
  
  	tilemap_set_transparent_pen(bg_tilemap[0],7);
  	tilemap_set_transparent_pen(bg_tilemap[1],7);
  	tilemap_set_transparent_pen(bg_tilemap[2],7);
  	tilemap_set_transparent_pen(bg_tilemap[3],7);
  
  	spriteram = rthunder_spriteram + 0x1800;
  }
  
  
  
  /***************************************************************************
  
    Memory handlers
  
  ***************************************************************************/
  
  READ8_HANDLER( rthunder_videoram1_r )
  {
  	return rthunder_videoram1[offset];
  }
  
  WRITE8_HANDLER( rthunder_videoram1_w )
  {
  	rthunder_videoram1[offset] = data;
  	tilemap_mark_tile_dirty(bg_tilemap[offset/0x1000],(offset & 0xfff)/2);
  }
  
  READ8_HANDLER( rthunder_videoram2_r )
  {
  	return rthunder_videoram2[offset];
  }
  
  WRITE8_HANDLER( rthunder_videoram2_w )
  {
  	rthunder_videoram2[offset] = data;
  	tilemap_mark_tile_dirty(bg_tilemap[2+offset/0x1000],(offset & 0xfff)/2);
  }
  
  WRITE8_HANDLER( rthunder_tilebank_select_w )
  {
  	int bit = BIT(offset,10);
  	if (tilebank != bit)
  	{
  		tilebank = bit;
  		tilemap_mark_all_tiles_dirty(bg_tilemap[0]);
  		tilemap_mark_all_tiles_dirty(bg_tilemap[1]);
  	}
  }
  
  static void scroll_w(int layer,int offset,int data)
  {
  	switch (offset)
  	{
  		case 0:
  			xscroll[layer] = (xscroll[layer]&0xff)|(data<<8);
  			break;
  		case 1:
  			xscroll[layer] = (xscroll[layer]&0xff00)|data;
  			break;
  		case 2:
  			yscroll[layer] = data;
  			break;
  	}
  }
  
  WRITE8_HANDLER( rthunder_scroll0_w )
  {
  	scroll_w(0,offset,data);
  }
  WRITE8_HANDLER( rthunder_scroll1_w )
  {
  	scroll_w(1,offset,data);
  }
  WRITE8_HANDLER( rthunder_scroll2_w )
  {
  	scroll_w(2,offset,data);
  }
  WRITE8_HANDLER( rthunder_scroll3_w )
  {
  	scroll_w(3,offset,data);
  }
  
  WRITE8_HANDLER( rthunder_backcolor_w )
  {
  	backcolor = data;
  }
  
  
  static int copy_sprites;
  
  READ8_HANDLER( rthunder_spriteram_r )
  {
  	return rthunder_spriteram[offset];
  }
  
  WRITE8_HANDLER( rthunder_spriteram_w )
  {
  	rthunder_spriteram[offset] = data;
  
  	/* a write to this offset tells the sprite chip to buffer the sprite list */
  	if (offset == 0x1ff2)
  		copy_sprites = 1;
  }
  
  
  /***************************************************************************
  
    Display refresh
  
  ***************************************************************************/
  
  /*
  sprite format:
  
  0-3  scratchpad RAM
  4-9  CPU writes here, hardware copies from here to 10-15
  10   xx------  X size (16, 8, 32, 4)
  10   --x-----  X flip
  10   ---xx---  X offset inside 32x32 tile
  10   -----xxx  tile bank
  11   xxxxxxxx  tile number
  12   xxxxxxx-  color
  12   -------x  X position MSB
  13   xxxxxxxx  X position
  14   xxx-----  priority
  14   ---xx---  Y offset inside 32x32 tile
  14   -----xx-  Y size (16, 8, 32, 4)
  14   -------x  Y flip
  15   xxxxxxxx  Y position
  */
  
  static void draw_sprites(running_machine *machine, bitmap_t *bitmap, const rectangle *cliprect)
  {
  	const UINT8 *source = &spriteram[0x0800-0x20];	/* the last is NOT a sprite */
  	const UINT8 *finish = &spriteram[0];
  	gfx_element *gfx = machine->gfx[2];
  
  	int sprite_xoffs = spriteram[0x07f5] + ((spriteram[0x07f4] & 1) << 8);
  	int sprite_yoffs = spriteram[0x07f7];
  
  	int bank_sprites = machine->gfx[2]->total_elements / 8;
  
  	while (source >= finish)
  	{
  		static const int sprite_size[4] = { 16, 8, 32, 4 };
  		int attr1 = source[10];
  		int attr2 = source[14];
  		int color = source[12];
  		int flipx = (attr1 & 0x20) >> 5;
  		int flipy = (attr2 & 0x01);
  		int sizex = sprite_size[(attr1 & 0xc0) >> 6];
  		int sizey = sprite_size[(attr2 & 0x06) >> 1];
  		int tx = (attr1 & 0x18) & (~(sizex-1));
  		int ty = (attr2 & 0x18) & (~(sizey-1));
  		int sx = source[13] + ((color & 0x01) << 8);
  		int sy = -source[15] - sizey;
  		int sprite = source[11];
  		int sprite_bank = attr1 & 7;
  		int priority = (source[14] & 0xe0) >> 5;
  		int pri_mask = (0xff << (priority + 1)) & 0xff;
  
  		sprite &= bank_sprites-1;
  		sprite += sprite_bank * bank_sprites;
  		color = color >> 1;
  
  		sx += sprite_xoffs;
  		sy -= sprite_yoffs;
  
  		if (flip_screen_get(machine))
  		{
  			sx = -sx - sizex;
  			sy = -sy - sizey;
  			flipx ^= 1;
  			flipy ^= 1;
  		}
  
  		sy++;	/* sprites are buffered and delayed by one scanline */
  
  		gfx_element_set_source_clip(gfx, tx, sizex, ty, sizey);
  		pdrawgfx_transpen( bitmap, cliprect,gfx,
  				sprite,
  				color,
  				flipx,flipy,
  				sx & 0x1ff,
  				((sy + 16) & 0xff) - 16,
  				machine->priority_bitmap, pri_mask,0xf);
  
  		source -= 0x10;
  	}
  }
  
  
  static void set_scroll(running_machine *machine, int layer)
  {
  	static const int xdisp[4] = { 47, 49, 46, 48 };
  	int scrollx,scrolly;
  
  	scrollx = xscroll[layer] - xdisp[layer];
  	scrolly = yscroll[layer] + 9;
  	if (flip_screen_get(machine))
  	{
  		scrollx = -scrollx;
  		scrolly = -scrolly;
  	}
  	tilemap_set_scrollx(bg_tilemap[layer], 0, scrollx);
  	tilemap_set_scrolly(bg_tilemap[layer], 0, scrolly);
  }
  
  
  VIDEO_UPDATE( namcos86 )
  {
  	int layer;
  
  	/* flip screen is embedded in the sprite control registers */
  	/* can't use flip_screen_set(screen->machine, ) because the visible area is asymmetrical */
  	flip_screen_set_no_update(screen->machine, spriteram[0x07f6] & 1);
  	tilemap_set_flip_all(screen->machine,flip_screen_get(screen->machine) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
  	set_scroll(screen->machine, 0);
  	set_scroll(screen->machine, 1);
  	set_scroll(screen->machine, 2);
  	set_scroll(screen->machine, 3);
  
  	bitmap_fill(screen->machine->priority_bitmap, cliprect, 0);
  
  	bitmap_fill(bitmap,cliprect,screen->machine->gfx[0]->color_base + 8*backcolor+7);
  
  	for (layer = 0;layer < 8;layer++)
  	{
  		int i;
  
  		for (i = 3;i >= 0;i--)
  		{
  			if (((xscroll[i] & 0x0e00) >> 9) == layer)
  				tilemap_draw_primask(bitmap,cliprect,bg_tilemap[i],0,layer,0);
  		}
  	}
  
  	draw_sprites(screen->machine,bitmap,cliprect);
  	return 0;
  }
  
  
  VIDEO_EOF( namcos86 )
  {
  	if (copy_sprites)
  	{
  		int i,j;
  
  		for (i = 0;i < 0x800;i += 16)
  		{
  			for (j = 10;j < 16;j++)
  				spriteram[i+j] = spriteram[i+j - 6];
  		}
  
  		copy_sprites = 0;
  	}
  }
  