/*******************************************************************
Namco System 86 Video Hardware
*******************************************************************/
#include "emu.h"
#include "includes/namcos86.h"
/***************************************************************************
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 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
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 */
state->m_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)
{
namcos86_state *state = machine.driver_data<namcos86_state>();
int attr = vram[2*tile_index + 1];
int tile_offs;
if (layer & 2)
tile_offs = ((state->m_tile_address_prom[((layer & 1) << 4) + (attr & 0x03)] & 0xe0) >> 5) * 0x100;
else
tile_offs = ((state->m_tile_address_prom[((layer & 1) << 4) + ((attr & 0x03) << 2)] & 0x0e) >> 1) * 0x100 + state->m_tilebank * 0x800;
SET_TILE_INFO(
(layer & 2) ? 1 : 0,
vram[2*tile_index] + tile_offs,
attr,
0);
}
static TILE_GET_INFO( get_tile_info0 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
get_tile_info(machine,tileinfo,tile_index,0,&state->m_rthunder_videoram1[0x0000]);
}
static TILE_GET_INFO( get_tile_info1 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
get_tile_info(machine,tileinfo,tile_index,1,&state->m_rthunder_videoram1[0x1000]);
}
static TILE_GET_INFO( get_tile_info2 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
get_tile_info(machine,tileinfo,tile_index,2,&state->m_rthunder_videoram2[0x0000]);
}
static TILE_GET_INFO( get_tile_info3 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
get_tile_info(machine,tileinfo,tile_index,3,&state->m_rthunder_videoram2[0x1000]);
}
/***************************************************************************
Start the video hardware emulation.
***************************************************************************/
VIDEO_START( namcos86 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
state->m_bg_tilemap[0] = tilemap_create(machine, get_tile_info0,tilemap_scan_rows,8,8,64,32);
state->m_bg_tilemap[1] = tilemap_create(machine, get_tile_info1,tilemap_scan_rows,8,8,64,32);
state->m_bg_tilemap[2] = tilemap_create(machine, get_tile_info2,tilemap_scan_rows,8,8,64,32);
state->m_bg_tilemap[3] = tilemap_create(machine, get_tile_info3,tilemap_scan_rows,8,8,64,32);
tilemap_set_transparent_pen(state->m_bg_tilemap[0],7);
tilemap_set_transparent_pen(state->m_bg_tilemap[1],7);
tilemap_set_transparent_pen(state->m_bg_tilemap[2],7);
tilemap_set_transparent_pen(state->m_bg_tilemap[3],7);
state->m_spriteram = state->m_rthunder_spriteram + 0x1800;
}
/***************************************************************************
Memory handlers
***************************************************************************/
READ8_HANDLER( rthunder_videoram1_r )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
return state->m_rthunder_videoram1[offset];
}
WRITE8_HANDLER( rthunder_videoram1_w )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
state->m_rthunder_videoram1[offset] = data;
tilemap_mark_tile_dirty(state->m_bg_tilemap[offset/0x1000],(offset & 0xfff)/2);
}
READ8_HANDLER( rthunder_videoram2_r )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
return state->m_rthunder_videoram2[offset];
}
WRITE8_HANDLER( rthunder_videoram2_w )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
state->m_rthunder_videoram2[offset] = data;
tilemap_mark_tile_dirty(state->m_bg_tilemap[2+offset/0x1000],(offset & 0xfff)/2);
}
WRITE8_HANDLER( rthunder_tilebank_select_w )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
int bit = BIT(offset,10);
if (state->m_tilebank != bit)
{
state->m_tilebank = bit;
tilemap_mark_all_tiles_dirty(state->m_bg_tilemap[0]);
tilemap_mark_all_tiles_dirty(state->m_bg_tilemap[1]);
}
}
static void scroll_w(address_space *space, int offset, int data, int layer)
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
switch (offset)
{
case 0:
state->m_xscroll[layer] = (state->m_xscroll[layer]&0xff)|(data<<8);
break;
case 1:
state->m_xscroll[layer] = (state->m_xscroll[layer]&0xff00)|data;
break;
case 2:
state->m_yscroll[layer] = data;
break;
}
}
WRITE8_HANDLER( rthunder_scroll0_w )
{
scroll_w(space,offset,data,0);
}
WRITE8_HANDLER( rthunder_scroll1_w )
{
scroll_w(space,offset,data,1);
}
WRITE8_HANDLER( rthunder_scroll2_w )
{
scroll_w(space,offset,data,2);
}
WRITE8_HANDLER( rthunder_scroll3_w )
{
scroll_w(space,offset,data,3);
}
WRITE8_HANDLER( rthunder_backcolor_w )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
state->m_backcolor = data;
}
READ8_HANDLER( rthunder_spriteram_r )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
return state->m_rthunder_spriteram[offset];
}
WRITE8_HANDLER( rthunder_spriteram_w )
{
namcos86_state *state = space->machine().driver_data<namcos86_state>();
state->m_rthunder_spriteram[offset] = data;
/* a write to this offset tells the sprite chip to buffer the sprite list */
if (offset == 0x1ff2)
state->m_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)
{
namcos86_state *state = machine.driver_data<namcos86_state>();
const UINT8 *source = &state->m_spriteram[0x0800-0x20]; /* the last is NOT a sprite */
const UINT8 *finish = &state->m_spriteram[0];
gfx_element *gfx = machine.gfx[2];
int sprite_xoffs = state->m_spriteram[0x07f5] + ((state->m_spriteram[0x07f4] & 1) << 8);
int sprite_yoffs = state->m_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)
{
namcos86_state *state = machine.driver_data<namcos86_state>();
static const int xdisp[4] = { 47, 49, 46, 48 };
int scrollx,scrolly;
scrollx = state->m_xscroll[layer] - xdisp[layer];
scrolly = state->m_yscroll[layer] + 9;
if (flip_screen_get(machine))
{
scrollx = -scrollx;
scrolly = -scrolly;
}
tilemap_set_scrollx(state->m_bg_tilemap[layer], 0, scrollx);
tilemap_set_scrolly(state->m_bg_tilemap[layer], 0, scrolly);
}
SCREEN_UPDATE( namcos86 )
{
namcos86_state *state = screen->machine().driver_data<namcos86_state>();
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(), state->m_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*state->m_backcolor+7);
for (layer = 0;layer < 8;layer++)
{
int i;
for (i = 3;i >= 0;i--)
{
if (((state->m_xscroll[i] & 0x0e00) >> 9) == layer)
tilemap_draw_primask(bitmap,cliprect,state->m_bg_tilemap[i],0,layer,0);
}
}
draw_sprites(screen->machine(),bitmap,cliprect);
return 0;
}
SCREEN_EOF( namcos86 )
{
namcos86_state *state = machine.driver_data<namcos86_state>();
if (state->m_copy_sprites)
{
UINT8 *spriteram = state->m_spriteram;
int i,j;
for (i = 0;i < 0x800;i += 16)
{
for (j = 10;j < 16;j++)
spriteram[i+j] = spriteram[i+j - 6];
}
state->m_copy_sprites = 0;
}
}