/* Namco System NA1/2 Video Hardware */ #include "driver.h" #include "namcona1.h" #define NAMCONA1_NUM_TILEMAPS 4 /* public variables */ UINT16 *namcona1_vreg; UINT16 *namcona1_scroll; UINT16 *namcona1_workram; UINT16 *namcona1_sparevram; /* private variables */ static char *dirtychar; static char dirtygfx; static UINT16 *shaperam; static UINT16 *cgram; static tilemap *bg_tilemap[NAMCONA1_NUM_TILEMAPS]; static int tilemap_palette_bank[NAMCONA1_NUM_TILEMAPS]; static int palette_is_dirty; static void tilemap_get_info( running_machine *machine,tile_data *tileinfo,int tile_index,const UINT16 *tilemap_videoram,int tilemap_color ) { #ifdef LSB_FIRST UINT16 *source; static UINT8 mask_data[8]; #endif int data = tilemap_videoram[tile_index]; int tile = data&0xfff; if( data&0x8000 ) { SET_TILE_INFO( 0,tile,tilemap_color,TILE_FORCE_LAYER0 ); } else { SET_TILE_INFO( 0,tile,tilemap_color,0 ); #ifdef LSB_FIRST source = shaperam+4*tile; mask_data[0] = source[0]>>8; mask_data[1] = source[0]&0xff; mask_data[2] = source[1]>>8; mask_data[3] = source[1]&0xff; mask_data[4] = source[2]>>8; mask_data[5] = source[2]&0xff; mask_data[6] = source[3]>>8; mask_data[7] = source[3]&0xff; tileinfo->mask_data = mask_data; #else tileinfo->mask_data = (UINT8 *)(shaperam+4*tile); #endif } } /* tilemap_get_info */ static TILE_GET_INFO( tilemap_get_info0 ){ tilemap_get_info(machine,tileinfo,tile_index,0*0x1000+videoram16,tilemap_palette_bank[0]); } static TILE_GET_INFO( tilemap_get_info1 ){ tilemap_get_info(machine,tileinfo,tile_index,1*0x1000+videoram16,tilemap_palette_bank[1]); } static TILE_GET_INFO( tilemap_get_info2 ){ tilemap_get_info(machine,tileinfo,tile_index,2*0x1000+videoram16,tilemap_palette_bank[2]); } static TILE_GET_INFO( tilemap_get_info3 ){ tilemap_get_info(machine,tileinfo,tile_index,3*0x1000+videoram16,tilemap_palette_bank[3]); } /*************************************************************************/ WRITE16_HANDLER( namcona1_videoram_w ) { COMBINE_DATA( &videoram16[offset] ); tilemap_mark_tile_dirty( bg_tilemap[offset/0x1000], offset&0xfff ); } /* namcona1_videoram_w */ READ16_HANDLER( namcona1_videoram_r ) { return videoram16[offset]; } /* namcona1_videoram_r */ /*************************************************************************/ static void UpdatePalette(running_machine *machine, int offset ) { UINT16 color; color = paletteram16[offset]; /* -RRRRRGGGGGBBBBB */ palette_set_color_rgb( machine, offset, pal5bit(color >> 10), pal5bit(color >> 5), pal5bit(color >> 0)); } /* namcona1_paletteram_w */ READ16_HANDLER( namcona1_paletteram_r ) { return paletteram16[offset]; } /* namcona1_paletteram_r */ WRITE16_HANDLER( namcona1_paletteram_w ) { COMBINE_DATA( &paletteram16[offset] ); if( namcona1_vreg[0x8e/2] ) { /* graphics enabled; update palette immediately */ UpdatePalette(Machine, offset ); } else { palette_is_dirty = 1; } } /*************************************************************************/ static const gfx_layout shape_layout = { 8,8, 0x1000, 1, { 0 }, { 0,1,2,3,4,5,6,7 }, #ifdef LSB_FIRST { 8*1,8*0,8*3,8*2,8*5,8*4,8*7,8*6 }, #else { 8*0,8*1,8*2,8*3,8*4,8*5,8*6,8*7 }, #endif 8*8 }; /* shape_layout */ static const gfx_layout cg_layout = { 8,8, 0x1000, 8, /* 8BPP */ { 0,1,2,3,4,5,6,7 }, #ifdef LSB_FIRST { 8*1,8*0,8*3,8*2,8*5,8*4,8*7,8*6 }, #else { 8*0,8*1,8*2,8*3,8*4,8*5,8*6,8*7 }, #endif { 64*0,64*1,64*2,64*3,64*4,64*5,64*6,64*7 }, 64*8 }; /* cg_layout */ READ16_HANDLER( namcona1_gfxram_r ) { UINT16 type = namcona1_vreg[0x0c/2]; if( type == 0x03 ) { if( offset<0x4000 ) { return shaperam[offset]; } } else if( type == 0x02 ) { return cgram[offset]; } return 0x0000; } /* namcona1_gfxram_r */ WRITE16_HANDLER( namcona1_gfxram_w ) { UINT16 type = namcona1_vreg[0x0c/2]; UINT16 old_word; if( type == 0x03 ) { if( offset<0x4000 ) { old_word = shaperam[offset]; COMBINE_DATA( &shaperam[offset] ); if( shaperam[offset]!=old_word ) { dirtygfx = 1; dirtychar[offset/4] = 1; } } } else if( type == 0x02 ) { old_word = cgram[offset]; COMBINE_DATA( &cgram[offset] ); if( cgram[offset]!=old_word ) { dirtygfx = 1; dirtychar[offset/0x20] = 1; } } } /* namcona1_gfxram_w */ static void update_gfx(running_machine *machine) { const UINT16 *pSource = videoram16; int page; int i; if( dirtygfx ) { for( page = 0; page<4; page++ ) { for( i=0; i<0x1000; i++ ) { if( dirtychar[*pSource++ & 0xfff] ) { tilemap_mark_tile_dirty( bg_tilemap[page], i ); } } } for( i = 0;i < 0x1000;i++ ) { if( dirtychar[i] ) { dirtychar[i] = 0; decodechar(machine->gfx[0],i,(UINT8 *)cgram,&cg_layout); decodechar(machine->gfx[1],i,(UINT8 *)shaperam,&shape_layout); } } dirtygfx = 0; } } /* update_gfx */ VIDEO_START( namcona1 ) { int i; gfx_element *gfx0,*gfx1; static tile_get_info_callback get_info[4] = { tilemap_get_info0, tilemap_get_info1, tilemap_get_info2, tilemap_get_info3 }; for( i=0; itotal_colors = machine->drv->total_colors/256; machine->gfx[0] = gfx0; gfx1->total_colors = machine->drv->total_colors/2; machine->gfx[1] = gfx1; } /* namcona1_vh_start */ /*************************************************************************/ static void pdraw_masked_tile(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, unsigned code, int color, int sx, int sy, int flipx, int flipy, int priority, int bShadow ) { const gfx_element *gfx,*mask; const pen_t *paldata; UINT8 *gfx_addr; int gfx_pitch; UINT8 *mask_addr; int mask_pitch; int x,y; /* * custom blitter for drawing a masked 8x8x8BPP tile */ if( sx > cliprect->min_x-8 && sy > cliprect->min_y-8 && sx <= cliprect->max_x && sy <= cliprect->max_y ) /* all-or-nothing clip */ { gfx = machine->gfx[0]; mask = machine->gfx[1]; code %= gfx->total_elements; color %= gfx->total_colors; paldata = &machine->remapped_colortable[gfx->color_base + gfx->color_granularity * color]; gfx_addr = gfx->gfxdata + code * gfx->char_modulo; gfx_pitch = gfx->line_modulo; mask_addr = mask->gfxdata + code * mask->char_modulo; mask_pitch = mask->line_modulo; /* The way we render shadows makes some Emeralda text invisible. * The relevant text is composed of sprites with the shadow bit set, * displayed over a black backdrop. */ if( bShadow && namcona1_gametype!=NAMCO_EMERALDA ) { for( y=0; y<8; y++ ) { int ypos = sy+(flipy?7-y:y); if (ypos >= cliprect->min_y && ypos <= cliprect->max_y) { UINT8 *pri = BITMAP_ADDR8(priority_bitmap, ypos, 0); UINT16 *dest = BITMAP_ADDR16(bitmap, ypos, 0); if( flipx ) { dest += sx+7; pri += sx+7; for( x=0; x<8; x++ ) if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x) { if( mask_addr[x] ) { /* sprite pixel is opaque */ if( priority>=pri[-x] ) { dest[-x] |= 0x1000; } pri[-x] = 0xff; } } } else { dest += sx; pri += sx; for( x=0; x<8; x++ ) if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x) { if( mask_addr[x] ) { /* sprite pixel is opaque */ if( priority>=pri[x] ) { dest[x] |= 0x1000; } pri[x] = 0xff; } } } } mask_addr += mask_pitch; } } /* render translucent sprite */ else { for( y=0; y<8; y++ ) { int ypos = sy+(flipy?7-y:y); if (ypos >= cliprect->min_y && ypos <= cliprect->max_y) { UINT8 *pri = BITMAP_ADDR8(priority_bitmap, ypos, 0); UINT16 *dest = BITMAP_ADDR16(bitmap, ypos, 0); if( flipx ) { dest += sx+7; pri += sx+7; for( x=0; x<8; x++ ) if (sx-x >= cliprect->min_x && sx-x <= cliprect->max_x) { if( mask_addr[x] ) { /* sprite pixel is opaque */ if( priority>=pri[-x] ) { dest[-x] = paldata[gfx_addr[x]]; } pri[-x] = 0xff; } } } else { dest += sx; pri += sx; for( x=0; x<8; x++ ) if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x) { if( mask_addr[x] ) { /* sprite pixel is opaque */ if( priority>=pri[x] ) { dest[x] = paldata[gfx_addr[x]]; } pri[x] = 0xff; } } /* next x */ } /* !flipx */ } gfx_addr += gfx_pitch; mask_addr += mask_pitch; } /* next y */ } /* render normal sprite (no translucency) */ } } /* pdraw_masked_tile */ static void pdraw_opaque_tile(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, unsigned code, int color, int sx, int sy, int flipx, int flipy, int priority, int bShadow ) { const gfx_element *gfx; const pen_t *paldata; UINT8 *gfx_addr; int gfx_pitch; int x,y; int ypos; UINT8 *pri; UINT16 *dest; if( sx > cliprect->min_x-8 && sy > cliprect->min_y-8 && sx <= cliprect->max_x && sy <= cliprect->max_y ) /* all-or-nothing clip */ { gfx = machine->gfx[0]; code %= gfx->total_elements; color %= gfx->total_colors; paldata = &machine->remapped_colortable[gfx->color_base + gfx->color_granularity * color]; gfx_addr = gfx->gfxdata + code * gfx->char_modulo; gfx_pitch = gfx->line_modulo; for( y=0; y<8; y++ ) { ypos = sy+(flipy?7-y:y); if (ypos >= cliprect->min_y && ypos <= cliprect->max_y) { pri = BITMAP_ADDR8(priority_bitmap, ypos, 0); dest = BITMAP_ADDR16(bitmap, ypos, 0); if( flipx ) { dest += sx+7; pri += sx+7; for( x=0; x<8; x++ ) if (sx-x >= cliprect->min_x && sx-x <= cliprect->max_x) { if( priority>=pri[-x] ) { dest[-x] = paldata[gfx_addr[x]]; } pri[-x] = 0xff; } } else { dest += sx; pri += sx; for( x=0; x<8; x++ ) if (sx+x >= cliprect->min_x && sx+x <= cliprect->max_x) { if( priority>=pri[x] ) { dest[x] = paldata[gfx_addr[x]]; } pri[x] = 0xff; } /* next x */ } /* !flipx */ } gfx_addr += gfx_pitch; } /* next y */ } } /* pdraw_opaque_tile */ static const UINT8 pri_mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f }; static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect) { int which; const UINT16 *source = spriteram16; void (*drawtile)(running_machine *, mame_bitmap *, const rectangle *, unsigned code, int color, int sx, int sy, int flipx, int flipy, int priority, int bShadow ); UINT16 sprite_control; UINT16 ypos,tile,color,xpos; int priority; int width,height; int flipy,flipx; int row,col; int sx,sy; sprite_control = namcona1_vreg[0x22/2]; if( sprite_control&1 ) source += 0x400; /* alternate spriteram bank */ for( which=0; which<0x100; which++ ) { /* max 256 sprites */ ypos = source[0]; /* FHHH---E YYYYYYYY flipy, height, ypos */ tile = source[1]; /* O???TTTT TTTTTTTT opaque tile */ color = source[2]; /* FSWW???B CCCC?PPP flipx, shadow, width, color, pri*/ xpos = source[3]; /* -------X XXXXXXXX xpos */ priority = pri_mask[color&0x7]; width = ((color>>12)&0x3)+1; height = ((ypos>>12)&0x7)+1; flipy = ypos&0x8000; flipx = color&0x8000; if( (tile&0x8000)==0 ) { drawtile = pdraw_masked_tile; } else { drawtile = pdraw_opaque_tile; } for( row=0; row>4)&0xf, ((sx+16)&0x1ff)-8, ((sy+8)&0x1ff)-8, flipx,flipy, priority, color&0x4000 /* shadow */ ); } /* next col */ } /* next row */ source += 4; } } /* draw_sprites */ static void draw_pixel_line( UINT16 *pDest, UINT8 *pPri, UINT16 *pSource, const pen_t *paldata ) { int x; UINT16 data; memset( pPri, 0xff, 38*8 ); for( x=0; x<38*8; x+=2 ) { data = *pSource++; pDest[x] = paldata[data>>8]; pDest[x+1] = paldata[data&0xff]; } /* next x */ } /* draw_pixel_line */ static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int which, int primask ) { /* scrollx lineselect * tmap0 ffe000 ffe200 * tmap1 ffe400 ffe600 * tmap2 ffe800 ffea00 * tmap3 ffec00 ffee00 */ int xadjust = 0x3a - which*2; const UINT16 *scroll = namcona1_scroll+0x200*which; int line; UINT16 xdata, ydata; int scrollx, scrolly; rectangle clip; const pen_t *paldata; gfx_element *pGfx; pGfx = machine->gfx[0]; paldata = &machine->remapped_colortable[pGfx->color_base + pGfx->color_granularity * tilemap_palette_bank[which]]; /* draw one scanline at a time */ clip.min_x = cliprect->min_x; clip.max_x = cliprect->max_x; scrollx = 0; scrolly = 0; for( line=0; line<256; line++ ) { clip.min_y = line; clip.max_y = line; xdata = scroll[line]; if( xdata ) { /* screenwise linescroll */ scrollx = xadjust+xdata; } ydata = scroll[line+0x100]; if( ydata&0x4000 ) { /* line select: dword offset from 0xff000 or tilemap source line */ scrolly = (ydata - line)&0x1ff; } if (line >= cliprect->min_y && line <= cliprect->max_y) { if( xdata == 0xc001 ) { /* This is a simplification, but produces the correct behavior for the only game that uses this * feature, Numan Athletics. */ draw_pixel_line( BITMAP_ADDR16(bitmap, line, 0), BITMAP_ADDR8(priority_bitmap, line, 0), namcona1_sparevram + (ydata-0x4000) + 25, paldata ); } else { tilemap_set_scrollx( bg_tilemap[which], 0, scrollx ); tilemap_set_scrolly( bg_tilemap[which], 0, scrolly ); tilemap_draw( bitmap, &clip, bg_tilemap[which], 0, primask ); } } } } /* draw_background */ VIDEO_UPDATE( namcona1 ) { int which; int priority; /* int flipscreen = namcona1_vreg[0x98/2]; (TBA) */ if( namcona1_vreg[0x8e/2] ) { /* gfx enabled */ if( palette_is_dirty ) { /* palette updates are delayed when graphics are disabled */ for( which=0; which<0x1000; which++ ) { UpdatePalette(machine, which ); } palette_is_dirty = 0; } update_gfx(machine); for( which=0; which=0; which-- ) { if( (namcona1_vreg[0x50+which]&0x7) == priority ) { draw_background(machine,bitmap,cliprect,which,pri_mask[priority] ); } } /* next tilemap */ } /* next priority level */ draw_sprites(machine,bitmap,cliprect); } /* gfx enabled */ return 0; }