diff options
Diffstat (limited to 'src/mame/drivers/namcoic.c')
-rw-r--r-- | src/mame/drivers/namcoic.c | 1742 |
1 files changed, 1742 insertions, 0 deletions
diff --git a/src/mame/drivers/namcoic.c b/src/mame/drivers/namcoic.c new file mode 100644 index 00000000000..507dd1dd90c --- /dev/null +++ b/src/mame/drivers/namcoic.c @@ -0,0 +1,1742 @@ +#include "driver.h" +#include "namcos2.h" /* for game-specific hacks */ +#include "namcoic.h" + +/**************************************************************************************/ +static int mPalXOR; /* XOR'd with palette select register; needed for System21 */ + +static struct +{ + UINT16 control[0x40/2]; + /** + * [0x1] 0x02/2 tilemap#0.scrollx + * [0x3] 0x06/2 tilemap#0.scrolly + * [0x5] 0x0a/2 tilemap#1.scrollx + * [0x7] 0x0e/2 tilemap#1.scrolly + * [0x9] 0x12/2 tilemap#2.scrollx + * [0xb] 0x16/2 tilemap#2.scrolly + * [0xd] 0x1a/2 tilemap#3.scrollx + * [0xf] 0x1e/2 tilemap#3.scrolly + * 0x20/2 priority + * 0x30/2 color + */ + tilemap *tmap[6]; + UINT16 *videoram; + int gfxbank; + UINT8 *maskBaseAddr; + void (*cb)( UINT16 code, int *gfx, int *mask); +} mTilemapInfo; + +void namco_tilemap_invalidate( void ) +{ + int i; + for( i=0; i<6; i++ ) + { + tilemap_mark_all_tiles_dirty( mTilemapInfo.tmap[i] ); + } +} /* namco_tilemap_invalidate */ + +INLINE void get_tile_info(running_machine *machine,tile_data *tileinfo,int tile_index,UINT16 *vram) +{ + int tile, mask; + mTilemapInfo.cb( vram[tile_index], &tile, &mask ); + tileinfo->mask_data = mTilemapInfo.maskBaseAddr+mask*8; + SET_TILE_INFO(mTilemapInfo.gfxbank,tile,0,0); +} /* get_tile_info */ + +static TILE_GET_INFO( get_tile_info0 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x0000]); } +static TILE_GET_INFO( get_tile_info1 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x1000]); } +static TILE_GET_INFO( get_tile_info2 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x2000]); } +static TILE_GET_INFO( get_tile_info3 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x3000]); } +static TILE_GET_INFO( get_tile_info4 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x4008]); } +static TILE_GET_INFO( get_tile_info5 ) { get_tile_info(machine,tileinfo,tile_index,&mTilemapInfo.videoram[0x4408]); } + +void +namco_tilemap_init( int gfxbank, void *maskBaseAddr, + void (*cb)( UINT16 code, int *gfx, int *mask) ) +{ + int i; + mTilemapInfo.gfxbank = gfxbank; + mTilemapInfo.maskBaseAddr = maskBaseAddr; + mTilemapInfo.cb = cb; + mTilemapInfo.videoram = auto_malloc( 0x10000*2 ); + + /* four scrolling tilemaps */ + mTilemapInfo.tmap[0] = tilemap_create(get_tile_info0,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + mTilemapInfo.tmap[1] = tilemap_create(get_tile_info1,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + mTilemapInfo.tmap[2] = tilemap_create(get_tile_info2,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + mTilemapInfo.tmap[3] = tilemap_create(get_tile_info3,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + + /* two non-scrolling tilemaps */ + mTilemapInfo.tmap[4] = tilemap_create(get_tile_info4,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,36,28); + mTilemapInfo.tmap[5] = tilemap_create(get_tile_info5,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,36,28); + + /* define offsets for scrolling */ + for( i=0; i<4; i++ ) + { + static const int adj[4] = { 4,2,1,0 }; + int dx = 44+adj[i]; + tilemap_set_scrolldx( mTilemapInfo.tmap[i], -dx, -(-384-dx) ); + tilemap_set_scrolldy( mTilemapInfo.tmap[i], -24, 288 ); + } + + tilemap_set_scrolldx( mTilemapInfo.tmap[4], 0, 96 ); + tilemap_set_scrolldy( mTilemapInfo.tmap[4], 0, 40 ); + + tilemap_set_scrolldx( mTilemapInfo.tmap[5], 0, 96 ); + tilemap_set_scrolldy( mTilemapInfo.tmap[5], 0, 40 ); + +} /* namco_tilemap_init */ + +void +namco_tilemap_draw( mame_bitmap *bitmap, const rectangle *cliprect, int pri ) +{ + int i; + for( i=0; i<6; i++ ) + { + /* note: priority is only in range 0..7, but Point Blank uses 0xf to hide a layer */ + if( (mTilemapInfo.control[0x20/2+i]&0xf) == pri ) + { + int color = mTilemapInfo.control[0x30/2+i] & 0x07; + tilemap_set_palette_offset( mTilemapInfo.tmap[i], color*256 ); + tilemap_draw(bitmap,cliprect,mTilemapInfo.tmap[i],0,0); + } + } +} /* namco_tilemap_draw */ + +static void +SetTilemapVideoram( int offset, UINT16 newword ) +{ + mTilemapInfo.videoram[offset] = newword; + if( offset<0x4000 ) + { + tilemap_mark_tile_dirty(mTilemapInfo.tmap[offset>>12],offset&0xfff); + } + else if( offset>=0x8010/2 && offset<0x87f0/2 ) + { /* fixed plane#1 */ + offset-=0x8010/2; + tilemap_mark_tile_dirty( mTilemapInfo.tmap[4], offset ); + } + else if( offset>=0x8810/2 && offset<0x8ff0/2 ) + { /* fixed plane#2 */ + offset-=0x8810/2; + tilemap_mark_tile_dirty( mTilemapInfo.tmap[5], offset ); + } +} /* SetTilemapVideoram */ + +WRITE16_HANDLER( namco_tilemapvideoram16_w ) +{ + UINT16 newword = mTilemapInfo.videoram[offset]; + COMBINE_DATA( &newword ); + SetTilemapVideoram( offset, newword ); +} + +READ16_HANDLER( namco_tilemapvideoram16_r ) +{ + return mTilemapInfo.videoram[offset]; +} + +static void +SetTilemapControl( int offset, UINT16 newword ) +{ + mTilemapInfo.control[offset] = newword; + if( offset<0x20/2 ) + { + if( offset == 0x02/2 ) + { + /* all planes are flipped X+Y from D15 of this word */ + int attrs = (newword & 0x8000)?(TILEMAP_FLIPX|TILEMAP_FLIPY):0; + int i; + for( i=0; i<=5; i++ ) + { + tilemap_set_flip(mTilemapInfo.tmap[i],attrs); + } + } + } + newword &= 0x1ff; + if( mTilemapInfo.control[0x02/2]&0x8000 ) + { + newword = -newword; + } + switch( offset ) + { + case 0x02/2: + tilemap_set_scrollx( mTilemapInfo.tmap[0], 0, newword ); + break; + case 0x06/2: + tilemap_set_scrolly( mTilemapInfo.tmap[0], 0, newword ); + break; + case 0x0a/2: + tilemap_set_scrollx( mTilemapInfo.tmap[1], 0, newword ); + break; + case 0x0e/2: + tilemap_set_scrolly( mTilemapInfo.tmap[1], 0, newword ); + break; + case 0x12/2: + tilemap_set_scrollx( mTilemapInfo.tmap[2], 0, newword ); + break; + case 0x16/2: + tilemap_set_scrolly( mTilemapInfo.tmap[2], 0, newword ); + break; + case 0x1a/2: + tilemap_set_scrollx( mTilemapInfo.tmap[3], 0, newword ); + break; + case 0x1e/2: + tilemap_set_scrolly( mTilemapInfo.tmap[3], 0, newword ); + break; + } +} /* SetTilemapControl */ + +WRITE16_HANDLER( namco_tilemapcontrol16_w ) +{ + UINT16 newword = mTilemapInfo.control[offset]; + COMBINE_DATA( &newword ); + SetTilemapControl( offset, newword ); +} + +READ16_HANDLER( namco_tilemapcontrol16_r ) +{ + return mTilemapInfo.control[offset]; +} + +READ32_HANDLER( namco_tilemapvideoram32_r ) +{ + offset *= 2; + return (mTilemapInfo.videoram[offset]<<16)|mTilemapInfo.videoram[offset+1]; +} + +WRITE32_HANDLER( namco_tilemapvideoram32_w ) +{ + UINT32 v; + offset *=2; + v = (mTilemapInfo.videoram[offset]<<16)|mTilemapInfo.videoram[offset+1]; + COMBINE_DATA(&v); + SetTilemapVideoram( offset, v>>16 ); + SetTilemapVideoram( offset+1, v&0xffff ); +} + +READ32_HANDLER( namco_tilemapcontrol32_r ) +{ + offset *= 2; + return (mTilemapInfo.control[offset]<<16)|mTilemapInfo.control[offset+1]; +} + +WRITE32_HANDLER( namco_tilemapcontrol32_w ) +{ + UINT32 v; + offset *=2; + v = (mTilemapInfo.control[offset]<<16)|mTilemapInfo.control[offset+1]; + COMBINE_DATA(&v); + SetTilemapControl( offset, v>>16 ); + SetTilemapControl( offset+1, v&0xffff ); +} + +READ32_HANDLER( namco_tilemapcontrol32_le_r ) +{ + offset *= 2; + return (mTilemapInfo.control[offset+1]<<16)|mTilemapInfo.control[offset]; +} + +WRITE32_HANDLER( namco_tilemapcontrol32_le_w ) +{ + UINT32 v; + offset *=2; + v = (mTilemapInfo.control[offset+1]<<16)|mTilemapInfo.control[offset]; + COMBINE_DATA(&v); + SetTilemapControl( offset+1, v>>16 ); + SetTilemapControl( offset, v&0xffff ); +} + +READ32_HANDLER( namco_tilemapvideoram32_le_r ) +{ + offset *= 2; + return (mTilemapInfo.videoram[offset+1]<<16)|mTilemapInfo.videoram[offset]; +} + +WRITE32_HANDLER( namco_tilemapvideoram32_le_w ) +{ + UINT32 v; + offset *=2; + v = (mTilemapInfo.videoram[offset+1]<<16)|mTilemapInfo.videoram[offset]; + COMBINE_DATA(&v); + SetTilemapVideoram( offset+1, v>>16 ); + SetTilemapVideoram( offset, v&0xffff ); +} + +/**************************************************************************************/ + +static void zdrawgfxzoom(running_machine *machine, + mame_bitmap *dest_bmp,const gfx_element *gfx, + UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy, + const rectangle *clip,int transparency,int transparent_color, + int scalex, int scaley, int zpos ) +{ + if (!scalex || !scaley) return; + if (dest_bmp->bpp == 16) + { + if( gfx ) + { + int shadow_offset = (machine->drv->video_attributes&VIDEO_HAS_SHADOWS)?machine->drv->total_colors:0; + const pen_t *pal = &machine->remapped_colortable[gfx->color_base + gfx->color_granularity * (color % gfx->total_colors)]; + UINT8 *source_base = gfx->gfxdata + (code % gfx->total_elements) * gfx->char_modulo; + int sprite_screen_height = (scaley*gfx->height+0x8000)>>16; + int sprite_screen_width = (scalex*gfx->width+0x8000)>>16; + if (sprite_screen_width && sprite_screen_height) + { + /* compute sprite increment per screen pixel */ + int dx = (gfx->width<<16)/sprite_screen_width; + int dy = (gfx->height<<16)/sprite_screen_height; + + int ex = sx+sprite_screen_width; + int ey = sy+sprite_screen_height; + + int x_index_base; + int y_index; + + if( flipx ) + { + x_index_base = (sprite_screen_width-1)*dx; + dx = -dx; + } + else + { + x_index_base = 0; + } + + if( flipy ) + { + y_index = (sprite_screen_height-1)*dy; + dy = -dy; + } + else + { + y_index = 0; + } + + if( clip ) + { + if( sx < clip->min_x) + { /* clip left */ + int pixels = clip->min_x-sx; + sx += pixels; + x_index_base += pixels*dx; + } + if( sy < clip->min_y ) + { /* clip top */ + int pixels = clip->min_y-sy; + sy += pixels; + y_index += pixels*dy; + } + if( ex > clip->max_x+1 ) + { /* clip right */ + int pixels = ex-clip->max_x-1; + ex -= pixels; + } + if( ey > clip->max_y+1 ) + { /* clip bottom */ + int pixels = ey-clip->max_y-1; + ey -= pixels; + } + } + + if( ex>sx ) + { /* skip if inner loop doesn't draw anything */ + int y; + if (transparency == TRANSPARENCY_PEN) + { + if( priority_bitmap ) + { + for( y=sy; y<ey; y++ ) + { + UINT8 *source = source_base + (y_index>>16) * gfx->line_modulo; + UINT16 *dest = BITMAP_ADDR16(dest_bmp, y, 0); + UINT8 *pri = BITMAP_ADDR8(priority_bitmap, y, 0); + int x, x_index = x_index_base; + if( mPalXOR ) + { + for( x=sx; x<ex; x++ ) + { + int c = source[x_index>>16]; + if( c != transparent_color ) + { + if( pri[x]<=zpos ) + { + switch( c ) + { + case 0: + dest[x] = 0x4000|(dest[x]&0x1fff); + break; + case 1: + dest[x] = 0x6000|(dest[x]&0x1fff); + break; + default: + dest[x] = pal[c]; + break; + } + pri[x] = zpos; + } + } + x_index += dx; + } + y_index += dy; + } + else + { + for( x=sx; x<ex; x++ ) + { + int c = source[x_index>>16]; + if( c != transparent_color ) + { + if( pri[x]<=zpos ) + { + if( color == 0xf && c==0xfe && shadow_offset ) + { + dest[x] |= shadow_offset; + } + else + { + dest[x] = pal[c]; + } + pri[x] = zpos; + } + } + x_index += dx; + } + y_index += dy; + } + } + } + } + } + } + } + } +} /* zdrawgfxzoom */ + +void +namcos2_draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri, int control ) +{ + int offset = (control & 0x000f) * (128*4); + int loop; + if( pri==0 ) + { + fillbitmap( priority_bitmap, 0, cliprect ); + } + for( loop=0; loop < 128; loop++ ) + { + /**************************************** + * word#0 + * Sprite Y position D00-D08 + * Sprite Size 16/32 D09 + * Sprite Size Y D10-D15 + * + * word#1 + * Sprite Quadrant D00-D01 + * Sprite Number D02-D12 + * Sprite ROM Bank select D13 + * Sprite flip X D14 + * Sprite flip Y D15 + * + * word#2 + * Sprite X position D00-D10 + * + * word#3 + * Sprite priority D00-D02 + * Sprite colour index D04-D07 + * Sprite Size X D10-D15 + */ + int word3 = namcos2_sprite_ram[offset+(loop*4)+3]; + if( (word3&0xf)==pri ) + { + int word0 = namcos2_sprite_ram[offset+(loop*4)+0]; + int word1 = namcos2_sprite_ram[offset+(loop*4)+1]; + int offset4 = namcos2_sprite_ram[offset+(loop*4)+2]; + + int sizey=((word0>>10)&0x3f)+1; + int sizex=(word3>>10)&0x3f; + + if((word0&0x0200)==0) sizex>>=1; + + if((sizey-1) && sizex ) + { + int color = (word3>>4)&0x000f; + int sprn = (word1>>2)&0x7ff; + int rgn = (word1&0x2000)?1:0; + int ypos = (0x1ff-(word0&0x01ff))-0x50+0x02; + int xpos = (offset4&0x03ff)-0x50+0x07; + int flipy = word1&0x8000; + int flipx = word1&0x4000; + int scalex = (sizex<<16)/((word0&0x0200)?0x20:0x10); + int scaley = (sizey<<16)/((word0&0x0200)?0x20:0x10); + if(scalex && scaley) + { + gfx_element gfx = *machine->gfx[rgn]; + if( (word0&0x0200)==0 ) + { + gfx.width = 16; + gfx.height = 16; + if( word1&0x0001 ) gfx.gfxdata += 16; + if( word1&0x0002 ) gfx.gfxdata += 16*gfx.line_modulo; + } + zdrawgfxzoom( + machine, + bitmap, + &gfx, + sprn, + color, + flipx,flipy, + xpos,ypos, + cliprect, + TRANSPARENCY_PEN,0xff, + //(color==0x0f ? TRANSPARENCY_PEN_TABLE : TRANSPARENCY_PEN),0xff, + scalex,scaley, + loop ); + } + } + } + } +} /* namcos2_draw_sprites */ + +void +namcos2_draw_sprites_metalhawk(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri ) +{ + /** + * word#0 + * xxxxxx---------- ysize + * ------x--------- sprite tile size + * -------xxxxxxxxx screeny + * + * word#1 + * --x------------- bank + * ----xxxxxxxxxxxx tile + * + * word#2 (unused) + * + * word#3 + * xxxxxx---------- xsize + * ------xxxxxxxxxx screenx + * + * word#4 (unused) + * word#5 (unused) + * + * word#6 (orientation) + * ---------------x rot90 + * --------------x- flipx + * -------------x-- flipy + * ------------x--- tile size + * + * word#7 + * ------------xxxx priority + * --------xxxx---- color + * x--------------- unknown + */ + const UINT16 *pSource = namcos2_sprite_ram; + rectangle rect; + int loop; + if( pri==0 ) + { + fillbitmap( priority_bitmap, 0, cliprect ); + } + for( loop=0; loop < 128; loop++ ) + { + int ypos = pSource[0]; + int tile = pSource[1]; + int xpos = pSource[3]; + int flags = pSource[6]; + int attrs = pSource[7]; + int sizey = ((ypos>>10)&0x3f)+1; + int sizex = (xpos>>10)&0x3f; + int sprn = (tile>>2)&0x7ff; + + if( tile&0x2000 ) + { + sprn&=0x3ff; + } + else + { + sprn|=0x400; + } + + if( (sizey-1) && sizex && (attrs&0xf)==pri ) + { + int bBigSprite = (flags&8); + int color = (attrs>>4)&0xf; + int sx = (xpos&0x03ff)-0x50+0x07; + int sy = (0x1ff-(ypos&0x01ff))-0x50+0x02; + int flipx = flags&2; + int flipy = flags&4; + int scalex = (sizex<<16)/(bBigSprite?0x20:0x10); + int scaley = (sizey<<16)/(bBigSprite?0x20:0x10); + + if( (flags&0x01) ) + { /* swap xy */ + sprn |= 0x800; + } + + if( bBigSprite ) + { + if( sizex < 0x20 ) + { + sx -= (0x20-sizex)/0x8; + } + if( sizey < 0x20 ) + { + sy += (0x20-sizey)/0xC; + } + } + + /* Set the clipping rect to mask off the other portion of the sprite */ + rect.min_x=sx; + rect.max_x=sx+(sizex-1); + rect.min_y=sy; + rect.max_y=sy+(sizey-1); + + if (cliprect->min_x > rect.min_x) rect.min_x = cliprect->min_x; + if (cliprect->max_x < rect.max_x) rect.max_x = cliprect->max_x; + if (cliprect->min_y > rect.min_y) rect.min_y = cliprect->min_y; + if (cliprect->max_y < rect.max_y) rect.max_y = cliprect->max_y; + + if( !bBigSprite ) + { + sizex = 16; + sizey = 16; + scalex = 1<<16; + scaley = 1<<16; + + sx -= (tile&1)?16:0; + sy -= (tile&2)?16:0; + + rect.min_x=sx; + rect.max_x=sx+(sizex-1); + rect.min_y=sy; + rect.max_y=sy+(sizey-1); + rect.min_x += (tile&1)?16:0; + rect.max_x += (tile&1)?16:0; + rect.min_y += (tile&2)?16:0; + rect.max_y += (tile&2)?16:0; + } + zdrawgfxzoom(machine, + bitmap,machine->gfx[0], + sprn, color, + flipx,flipy, + sx,sy, + &rect, + TRANSPARENCY_PEN,0xff, + scalex, scaley, + loop ); + } + pSource += 8; + } +} /* namcos2_draw_sprites_metalhawk */ + +/**************************************************************************************/ + +static UINT16 mSpritePos[4]; + +WRITE16_HANDLER( namco_spritepos16_w ) +{ + COMBINE_DATA( &mSpritePos[offset] ); +} +READ16_HANDLER( namco_spritepos16_r ) +{ + return mSpritePos[offset]; +} + +WRITE32_HANDLER( namco_spritepos32_w ) +{ + UINT32 v; + offset *= 2; + v = (mSpritePos[offset]<<16)|mSpritePos[offset+1]; + COMBINE_DATA( &v ); + mSpritePos[offset+0] = v>>16; + mSpritePos[offset+1] = v&0xffff; +} +READ32_HANDLER( namco_spritepos32_r ) +{ + offset *= 2; + return (mSpritePos[offset]<<16)|mSpritePos[offset+1]; +} + +INLINE UINT8 +nth_byte16( const UINT16 *pSource, int which ) +{ + UINT16 data = pSource[which/2]; + if( which&1 ) + { + return data&0xff; + } + else + { + return data>>8; + } +} /* nth_byte16 */ + +/* nth_word32 is a general-purpose utility function, which allows us to + * read from 32-bit aligned memory as if it were an array of 16 bit words. + */ +INLINE UINT16 +nth_word32( const UINT32 *pSource, int which ) +{ + UINT32 data = pSource[which/2]; + if( which&1 ) + { + return data&0xffff; + } + else + { + return data>>16; + } +} /* nth_word32 */ + +/* nth_byte32 is a general-purpose utility function, which allows us to + * read from 32-bit aligned memory as if it were an array of bytes. + */ +INLINE UINT8 +nth_byte32( const UINT32 *pSource, int which ) +{ + UINT32 data = pSource[which/4]; + switch( which&3 ) + { + case 0: return data>>24; + case 1: return (data>>16)&0xff; + case 2: return (data>>8)&0xff; + default: return data&0xff; + } +} /* nth_byte32 */ + +/**************************************************************************************************************/ + +static int (*mpCodeToTile)( int code ); /* sprite banking callback */ +static int mGfxC355; /* gfx bank for sprites */ + +/** + * 0x00000 sprite attr (page0) + * 0x02000 sprite list (page0) + * + * 0x02400 window attributes + * 0x04000 format + * 0x08000 tile + * 0x10000 sprite attr (page1) + * 0x14000 sprite list (page1) + */ +static void +draw_spriteC355(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, const UINT16 *pSource, int pri, int zpos ) +{ + unsigned screen_height_remaining, screen_width_remaining; + unsigned source_height_remaining, source_width_remaining; + int hpos,vpos; + UINT16 hsize,vsize; + UINT16 palette; + UINT16 linkno; + UINT16 offset; + UINT16 format; + int tile_index; + int num_cols,num_rows; + int dx,dy; + int row,col; + int sx,sy,tile; + int flipx,flipy; + UINT32 zoomx, zoomy; + int tile_screen_width; + int tile_screen_height; + const UINT16 *spriteformat16 = &spriteram16[0x4000/2]; + const UINT16 *spritetile16 = &spriteram16[0x8000/2]; + int color; + const UINT16 *pWinAttr; + rectangle clip; + int xscroll, yscroll; + + /** + * ----xxxx-------- window select + * --------xxxx---- priority + * ------------xxxx palette select + */ + palette = pSource[6]; + if( pri != ((palette>>4)&0xf) ) + { + return; + } + + linkno = pSource[0]; /* LINKNO */ + offset = pSource[1]; /* OFFSET */ + hpos = pSource[2]; /* HPOS 0x000..0x7ff (signed) */ + vpos = pSource[3]; /* VPOS 0x000..0x7ff (signed) */ + hsize = pSource[4]; /* HSIZE max 0x3ff pixels */ + vsize = pSource[5]; /* VSIZE max 0x3ff pixels */ + /* pSource[6] contains priority/palette */ + /* pSource[7] is used in Lucky & Wild, possibly for sprite-road priority */ + + if( linkno*4>=0x4000/2 ) return; /* avoid garbage memory reads */ + + xscroll = (INT16)mSpritePos[1]; + yscroll = (INT16)mSpritePos[0]; + +// xscroll &= 0x3ff; if( xscroll & 0x200 ) xscroll |= ~0x3ff; + xscroll &= 0x1ff; if( xscroll & 0x100 ) xscroll |= ~0x1ff; + yscroll &= 0x1ff; if( yscroll & 0x100 ) yscroll |= ~0x1ff; + + if( bitmap->width > 384 ) + { /* Medium Resolution: System21 adjust */ + xscroll = (INT16)mSpritePos[1]; + xscroll &= 0x3ff; if( xscroll & 0x200 ) xscroll |= ~0x3ff; + if( yscroll<0 ) + { /* solvalou */ + yscroll += 0x20; + } + yscroll += 0x10; + } + else + { + if ((namcos2_gametype == NAMCOFL_SPEED_RACER) || (namcos2_gametype == NAMCOFL_FINAL_LAP_R)) + { /* Namco FL: don't adjust and things line up fine */ + } + else + { /* Namco NB1, Namco System 2 */ + xscroll += 0x26; + yscroll += 0x19; + } + } + + hpos -= xscroll; + vpos -= yscroll; + pWinAttr = &spriteram16[0x2400/2+((palette>>8)&0xf)*4]; + clip.min_x = pWinAttr[0] - xscroll; + clip.max_x = pWinAttr[1] - xscroll; + clip.min_y = pWinAttr[2] - yscroll; + clip.max_y = pWinAttr[3] - yscroll; + if( clip.min_x < cliprect->min_x ){ clip.min_x = cliprect->min_x; } + if( clip.min_y < cliprect->min_y ){ clip.min_y = cliprect->min_y; } + if( clip.max_x > cliprect->max_x ){ clip.max_x = cliprect->max_x; } + if( clip.max_y > cliprect->max_y ){ clip.max_y = cliprect->max_y; } + hpos&=0x7ff; if( hpos&0x400 ) hpos |= ~0x7ff; /* sign extend */ + vpos&=0x7ff; if( vpos&0x400 ) vpos |= ~0x7ff; /* sign extend */ + + tile_index = spriteformat16[linkno*4+0]; + format = spriteformat16[linkno*4+1]; + dx = spriteformat16[linkno*4+2]; + dy = spriteformat16[linkno*4+3]; + num_cols = (format>>4)&0xf; + num_rows = (format)&0xf; + + if( num_cols == 0 ) num_cols = 0x10; + flipx = (hsize&0x8000)?1:0; + hsize &= 0x3ff;//0x1ff; + if( hsize == 0 ) return; + zoomx = (hsize<<16)/(num_cols*16); + dx = (dx*zoomx+0x8000)>>16; + if( flipx ) + { + hpos += dx; + } + else + { + hpos -= dx; + } + + if( num_rows == 0 ) num_rows = 0x10; + flipy = (vsize&0x8000)?1:0; + vsize &= 0x3ff; + if( vsize == 0 ) return; + zoomy = (vsize<<16)/(num_rows*16); + dy = (dy*zoomy+0x8000)>>16; + if( flipy ) + { + vpos += dy; + } + else + { + vpos -= dy; + } + + color = (palette&0xf)^mPalXOR; + + source_height_remaining = num_rows*16; + screen_height_remaining = vsize; + sy = vpos; + for( row=0; row<num_rows; row++ ) + { + tile_screen_height = 16*screen_height_remaining/source_height_remaining; + zoomy = (screen_height_remaining<<16)/source_height_remaining; + if( flipy ) + { + sy -= tile_screen_height; + } + source_width_remaining = num_cols*16; + screen_width_remaining = hsize; + sx = hpos; + for( col=0; col<num_cols; col++ ) + { + tile_screen_width = 16*screen_width_remaining/source_width_remaining; + zoomx = (screen_width_remaining<<16)/source_width_remaining; + if( flipx ) + { + sx -= tile_screen_width; + } + tile = spritetile16[tile_index++]; + if( (tile&0x8000)==0 ) + { + zdrawgfxzoom(machine, + bitmap,machine->gfx[mGfxC355], + mpCodeToTile(tile) + offset, + color, + flipx,flipy, + sx,sy, + &clip, + TRANSPARENCY_PEN,0xff, + zoomx, zoomy, zpos ); + } + if( !flipx ) + { + sx += tile_screen_width; + } + screen_width_remaining -= tile_screen_width; + source_width_remaining -= 16; + } /* next col */ + if( !flipy ) + { + sy += tile_screen_height; + } + screen_height_remaining -= tile_screen_height; + source_height_remaining -= 16; + } /* next row */ +} /* draw_spriteC355 */ + + +static int DefaultCodeToTile( int code ) +{ + return code; +} + +void +namco_obj_init( int gfxbank, int palXOR, int (*codeToTile)( int code ) ) +{ + mGfxC355 = gfxbank; + mPalXOR = palXOR; + if( codeToTile ) + { + mpCodeToTile = codeToTile; + } + else + { + mpCodeToTile = DefaultCodeToTile; + } + spriteram16 = auto_malloc(0x20000); + memset( spriteram16, 0, 0x20000 ); /* needed for Nebulas Ray */ + memset( mSpritePos,0x00,sizeof(mSpritePos) ); +} /* namcosC355_init */ + +static void +DrawObjectList(running_machine *machine, + mame_bitmap *bitmap, + const rectangle *cliprect, + int pri, + const UINT16 *pSpriteList16, + const UINT16 *pSpriteTable ) +{ + int i; + /* draw the sprites */ + for( i=0; i<256; i++ ) + { + UINT16 which = pSpriteList16[i]; + draw_spriteC355(machine, bitmap, cliprect, &pSpriteTable[(which&0xff)*8], pri, i ); + if( which&0x100 ) break; + } +} /* DrawObjectList */ + +void +namco_obj_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri ) +{ +// int offs = spriteram16[0x18000/2]; /* end-of-sprite-list */ + if( pri==0 ) + { + fillbitmap( priority_bitmap, 0, cliprect ); + } +// if( offs==0 ) + { /* boot */ + DrawObjectList(machine, bitmap,cliprect,pri,&spriteram16[0x02000/2], &spriteram16[0x00000/2] ); + } +// else + { + DrawObjectList(machine, bitmap,cliprect,pri,&spriteram16[0x14000/2], &spriteram16[0x10000/2] ); + } +} /* namco_obj_draw */ + +WRITE16_HANDLER( namco_obj16_w ) +{ + COMBINE_DATA( &spriteram16[offset] ); +} /* namco_obj16_w */ + +READ16_HANDLER( namco_obj16_r ) +{ + return spriteram16[offset]; +} /* namco_obj16_r */ + +WRITE32_HANDLER( namco_obj32_w ) +{ + UINT32 v; + offset *= 2; + v = (spriteram16[offset]<<16)|spriteram16[offset+1]; + COMBINE_DATA( &v ); + spriteram16[offset] = v>>16; + spriteram16[offset+1] = v&0xffff; +} /* namco_obj32_w */ + +READ32_HANDLER( namco_obj32_r ) +{ + offset *= 2; + return (spriteram16[offset]<<16)|spriteram16[offset+1]; +} /* namco_obj32_r */ + +WRITE32_HANDLER( namco_obj32_le_w ) +{ + UINT32 v; + offset *= 2; + v = (spriteram16[offset+1]<<16)|spriteram16[offset]; + COMBINE_DATA( &v ); + spriteram16[offset+1] = v>>16; + spriteram16[offset] = v&0xffff; +} /* namco_obj32_w */ + +READ32_HANDLER( namco_obj32_le_r ) +{ + offset *= 2; + return (spriteram16[offset+1]<<16)|spriteram16[offset]; +} /* namco_obj32_r */ + +/**************************************************************************************************************/ + +/** + * Advanced rotate-zoom chip manages two layers. + * Each layer uses a designated subset of a master 256x256 tile tilemap (4096x4096 pixels). + * Each layer has configurable color and tile banking. + * ROZ attributes may be specified independently for each scanline. + * + * Used by: + * Namco NB2 - The Outfoxies, Mach Breakers + * Namco System 2 - Metal Hawk, Lucky and Wild + * Namco System FL - Final Lap R, Speed Racer + */ +#define ROZ_TILEMAP_COUNT 2 +static tilemap *mRozTilemap[ROZ_TILEMAP_COUNT]; +static UINT16 *rozbank16; +static UINT16 *rozvideoram16; +static UINT16 *rozcontrol16; +static int mRozGfxBank; +static int mRozMaskRegion; + +/** + * Graphics ROM addressing varies across games. + */ +static void +roz_get_info( running_machine *machine, tile_data *tileinfo, int tile_index, int which) +{ + UINT16 tile = rozvideoram16[tile_index]; + int bank, mangle; + + switch( namcos2_gametype ) + { + case NAMCONB2_MACH_BREAKERS: + bank = nth_byte16( &rozbank16[which*8/2], (tile>>11)&0x7 ); + tile = (tile&0x7ff)|(bank*0x800); + mangle = tile; + break; + + case NAMCONB2_OUTFOXIES: + bank = nth_byte16( &rozbank16[which*8/2], (tile>>11)&0x7 ); + tile = (tile&0x7ff)|(bank*0x800); + mangle = tile&~(0x50); + if( tile&0x10 ) mangle |= 0x40; + if( tile&0x40 ) mangle |= 0x10; + break; + + case NAMCOS2_LUCKY_AND_WILD: + mangle = tile&0x01ff; + tile &= 0x3fff; + switch( tile>>9 ) + { + case 0x00: mangle |= 0x1c00; break; + case 0x01: mangle |= 0x0800; break; + case 0x02: mangle |= 0x0000; break; + + case 0x08: mangle |= 0x1e00; break; + case 0x09: mangle |= 0x0a00; break; + case 0x0a: mangle |= 0x0200; break; + + case 0x10: mangle |= 0x2000; break; + case 0x11: mangle |= 0x0c00; break; + case 0x12: mangle |= 0x0400; break; + + case 0x18: mangle |= 0x2200; break; + case 0x19: mangle |= 0x0e00; break; + case 0x1a: mangle |= 0x0600; break; + } + break; + + case NAMCOS2_METAL_HAWK: + mangle = tile&0x01ff; + if( tile&0x1000 ) mangle |= 0x0200; + if( tile&0x0200 ) mangle |= 0x0400; + if( tile&0x0400 ) mangle |= 0x0800; + if( tile&0x0800 ) mangle |= 0x1000; + break; + + default: + case NAMCOFL_SPEED_RACER: + case NAMCOFL_FINAL_LAP_R: + mangle = tile; + tile &= 0x3fff; /* cap mask offset */ + break; + } + SET_TILE_INFO( mRozGfxBank,mangle,0/*color*/,0/*flag*/ ); + tileinfo->mask_data = 32*tile + (UINT8 *)memory_region( mRozMaskRegion ); +} /* roz_get_info */ + +static +TILE_GET_INFO( roz_get_info0 ) +{ + roz_get_info( machine,tileinfo,tile_index,0 ); +} /* roz_get_info0 */ + +static +TILE_GET_INFO( roz_get_info1 ) +{ + roz_get_info( machine,tileinfo,tile_index,1 ); +} /* roz_get_info1 */ + +static +TILEMAP_MAPPER( namco_roz_scan ) +{ + if( col>=128 ) + { + col %= 128; + row += 256; + } + return row*128+col; +} /* namco_roz_scan*/ + +void +namco_roz_init( int gfxbank, int maskregion ) +{ + int i; + static tile_get_info_callback roz_info[ROZ_TILEMAP_COUNT] = + { + roz_get_info0, + roz_get_info1 + }; + + mRozGfxBank = gfxbank; + mRozMaskRegion = maskregion; + + rozbank16 = auto_malloc(0x10); + rozvideoram16 = auto_malloc(0x20000); + rozcontrol16 = auto_malloc(0x20); + + for( i=0; i<ROZ_TILEMAP_COUNT; i++ ) + { + mRozTilemap[i] = tilemap_create( + roz_info[i], + namco_roz_scan, + TILEMAP_TYPE_PEN, + 16,16, + 256,256 ); + } +} /* namco_roz_init */ + +struct RozParam +{ + UINT32 left, top, size; + UINT32 startx,starty; + int incxx,incxy,incyx,incyy; + int color,priority; +}; + +static void +UnpackRozParam( const UINT16 *pSource, struct RozParam *pRozParam ) +{ + const int xoffset = 36, yoffset = 3; + + /** + * x-------.-------- disable layer + * ----x---.-------- wrap? + * ------xx.-------- size + * --------.xxxx---- priority + * --------.----xxxx color + */ + UINT16 temp = pSource[1]; + pRozParam->size = 512<<((temp&0x0300)>>8); + if ((namcos2_gametype == NAMCOFL_SPEED_RACER) || (namcos2_gametype == NAMCOFL_FINAL_LAP_R)) + { + pRozParam->color = (temp&0x0007)*256; + } + else + { + pRozParam->color = (temp&0x000f)*256; + } + pRozParam->priority = (temp&0x00f0)>>4; + + temp = pSource[2]; + pRozParam->left = (temp&0x7000)>>3; + if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */ + pRozParam->incxx = (INT16)temp; + + temp = pSource[3]; + pRozParam->top = (temp&0x7000)>>3; + if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */ + pRozParam->incxy = (INT16)temp; + + temp = pSource[4]; + if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */ + pRozParam->incyx = (INT16)temp; + + temp = pSource[5]; + if( temp&0x8000 ) temp |= 0xf000; else temp&=0x0fff; /* sign extend */ + pRozParam->incyy = (INT16)temp; + + pRozParam->startx = (INT16)pSource[6]; + pRozParam->starty = (INT16)pSource[7]; + pRozParam->startx <<= 4; + pRozParam->starty <<= 4; + + pRozParam->startx += xoffset * pRozParam->incxx + yoffset * pRozParam->incyx; + pRozParam->starty += xoffset * pRozParam->incxy + yoffset * pRozParam->incyy; + + /* normalize */ + pRozParam->startx <<= 8; + pRozParam->starty <<= 8; + pRozParam->incxx <<= 8; + pRozParam->incxy <<= 8; + pRozParam->incyx <<= 8; + pRozParam->incyy <<= 8; +} /* UnpackRozParam */ + +static void +DrawRozHelper( + mame_bitmap *bitmap, + tilemap *tmap, + const rectangle *clip, + const struct RozParam *rozInfo ) +{ + + if( (bitmap->bpp == 16) && + (namcos2_gametype != NAMCOFL_SPEED_RACER) && + (namcos2_gametype != NAMCOFL_FINAL_LAP_R)) + { + UINT32 size_mask = rozInfo->size-1; + mame_bitmap *srcbitmap = tilemap_get_pixmap( tmap ); + mame_bitmap *flagsbitmap = tilemap_get_flagsmap( tmap ); + UINT32 startx = rozInfo->startx + clip->min_x * rozInfo->incxx + clip->min_y * rozInfo->incyx; + UINT32 starty = rozInfo->starty + clip->min_x * rozInfo->incxy + clip->min_y * rozInfo->incyy; + int sx = clip->min_x; + int sy = clip->min_y; + while( sy <= clip->max_y ) + { + int x = sx; + UINT32 cx = startx; + UINT32 cy = starty; + UINT16 *dest = BITMAP_ADDR16(bitmap, sy, sx); + while( x <= clip->max_x ) + { + UINT32 xpos = (((cx>>16)&size_mask) + rozInfo->left)&0xfff; + UINT32 ypos = (((cy>>16)&size_mask) + rozInfo->top)&0xfff; + if( *BITMAP_ADDR8(flagsbitmap, ypos, xpos)&TILEMAP_PIXEL_LAYER0 ) + { + *dest = *BITMAP_ADDR16(srcbitmap,ypos,xpos)+rozInfo->color; + } + cx += rozInfo->incxx; + cy += rozInfo->incxy; + x++; + dest++; + } /* next x */ + startx += rozInfo->incyx; + starty += rozInfo->incyy; + sy++; + } /* next y */ + } + else + + { + tilemap_set_palette_offset( tmap, rozInfo->color ); + + tilemap_draw_roz( + bitmap, + clip, + tmap, + rozInfo->startx, rozInfo->starty, + rozInfo->incxx, rozInfo->incxy, + rozInfo->incyx, rozInfo->incyy, + 1,0,0); // wrap, flags, pri + } +} /* DrawRozHelper */ + +static void +DrawRozScanline( mame_bitmap *bitmap, int line, int which, int pri, const rectangle *cliprect ) +{ + if( line>=cliprect->min_y && line<=cliprect->max_y ) + { + struct RozParam rozInfo; + rectangle clip; + int row = line/8; + int offs = row*0x100+(line&7)*0x10 + 0xe080; + UINT16 *pSource = &rozvideoram16[offs/2]; + if( (pSource[1]&0x8000)==0 ) + { + UnpackRozParam( pSource, &rozInfo ); + if( pri == rozInfo.priority ) + { + clip.min_x = 0; + clip.max_x = bitmap->width-1; + clip.min_y = clip.max_y = line; + + if( clip.min_x < cliprect->min_x ){ clip.min_x = cliprect->min_x; } + if( clip.min_y < cliprect->min_y ){ clip.min_y = cliprect->min_y; } + if( clip.max_x > cliprect->max_x ){ clip.max_x = cliprect->max_x; } + if( clip.max_y > cliprect->max_y ){ clip.max_y = cliprect->max_y; } + + DrawRozHelper( bitmap, mRozTilemap[which], &clip, &rozInfo ); + } /* priority */ + } /* enabled */ + } +} /* DrawRozScanline */ + +void +namco_roz_draw( mame_bitmap *bitmap, const rectangle *cliprect, int pri ) +{ + int mode = rozcontrol16[0]; /* 0x8000 or 0x1000 */ + int which, special = 1; + + if ((namcos2_gametype == NAMCOFL_SPEED_RACER) || (namcos2_gametype == NAMCOFL_FINAL_LAP_R)) + { + special = 0; + } + + for( which=1; which>=0; which-- ) + { + const UINT16 *pSource = &rozcontrol16[which*8]; + UINT16 attrs = pSource[1]; + if( (attrs&0x8000)==0 ) + { /* layer is enabled */ + if( which==special && mode==0x8000 ) + { /* second ROZ layer is configured to use per-scanline registers */ + int line; + for( line=0; line<224; line++ ) + { + DrawRozScanline( bitmap, line, which, pri, cliprect/*, tmap*/ ); + } + } + else + { + struct RozParam rozInfo; + UnpackRozParam( pSource, &rozInfo ); + if( rozInfo.priority == pri ) + { + DrawRozHelper( bitmap, mRozTilemap[which], cliprect, &rozInfo ); + } /* roz_pri==pri */ + } + } /* enable */ + } /* which */ +} /* namco_roz_draw */ + +READ16_HANDLER( namco_rozcontrol16_r ) +{ + return rozcontrol16[offset]; +} /* namco_rozcontrol16_r */ + +WRITE16_HANDLER( namco_rozcontrol16_w ) +{ + COMBINE_DATA( &rozcontrol16[offset] ); +} /* namco_rozcontrol16_w */ + +READ16_HANDLER( namco_rozbank16_r ) +{ + return rozbank16[offset]; +} /* namco_rozbank16_r */ + +WRITE16_HANDLER( namco_rozbank16_w ) +{ + UINT16 old_data = rozbank16[offset]; + COMBINE_DATA( &rozbank16[offset] ); + if( rozbank16[offset]!=old_data ) + { + int i; + for( i=0; i<ROZ_TILEMAP_COUNT; i++ ) + { + tilemap_mark_all_tiles_dirty( mRozTilemap[i] ); + } + } +} /* namco_rozbank16_w */ + +static void +writerozvideo( int offset, UINT16 data ) +{ + int i; + rozvideoram16[offset] = data; + for( i=0; i<ROZ_TILEMAP_COUNT; i++ ) + { + tilemap_mark_tile_dirty( mRozTilemap[i], offset ); + } +} /* writerozvideo */ + +READ16_HANDLER( namco_rozvideoram16_r ) +{ + return rozvideoram16[offset]; +} /* namco_rozvideoram16_r */ + +WRITE16_HANDLER( namco_rozvideoram16_w ) +{ + UINT16 v = rozvideoram16[offset]; + COMBINE_DATA( &v ); + writerozvideo( offset, v ); +} /* namco_rozvideoram16_w */ + +READ32_HANDLER( namco_rozcontrol32_r ) +{ + offset *= 2; + return (rozcontrol16[offset]<<16)|rozcontrol16[offset+1]; +} /* namco_rozcontrol32_r */ + +WRITE32_HANDLER( namco_rozcontrol32_w ) +{ + UINT32 v; + offset *=2; + v = (rozcontrol16[offset]<<16)|rozcontrol16[offset+1]; + COMBINE_DATA(&v); + rozcontrol16[offset] = v>>16; + rozcontrol16[offset+1] = v&0xffff; +} /* namco_rozcontrol32_w */ + +READ32_HANDLER( namco_rozcontrol32_le_r ) +{ + offset *= 2; + return (rozcontrol16[offset]<<16)|rozcontrol16[offset+1]; +} /* namco_rozcontrol32_le_r */ + +WRITE32_HANDLER( namco_rozcontrol32_le_w ) +{ + UINT32 v; + offset *=2; + v = (rozcontrol16[offset+1]<<16)|rozcontrol16[offset]; + COMBINE_DATA(&v); + rozcontrol16[offset+1] = v>>16; + rozcontrol16[offset] = v&0xffff; +} /* namco_rozcontrol32_le_w */ + +READ32_HANDLER( namco_rozbank32_r ) +{ + offset *= 2; + return (rozbank16[offset]<<16)|rozbank16[offset+1]; +} /* namco_rozbank32_r */ + +WRITE32_HANDLER( namco_rozbank32_w ) +{ + UINT32 v; + offset *=2; + v = (rozbank16[offset]<<16)|rozbank16[offset+1]; + COMBINE_DATA(&v); + rozbank16[offset] = v>>16; + rozbank16[offset+1] = v&0xffff; +} /* namco_rozbank32_w */ + +READ32_HANDLER( namco_rozvideoram32_r ) +{ + offset *= 2; + return (rozvideoram16[offset]<<16)|rozvideoram16[offset+1]; +} /* namco_rozvideoram32_r */ + +WRITE32_HANDLER( namco_rozvideoram32_w ) +{ + UINT32 v; + offset *= 2; + v = (rozvideoram16[offset]<<16)|rozvideoram16[offset+1]; + COMBINE_DATA( &v ); + writerozvideo(offset,v>>16); + writerozvideo(offset+1,v&0xffff); +} /* namco_rozvideoram32_w */ + +READ32_HANDLER( namco_rozvideoram32_le_r ) +{ + offset *= 2; + return (rozvideoram16[offset+1]<<16)|rozvideoram16[offset]; +} /* namco_rozvideoram32_le_r */ + +WRITE32_HANDLER( namco_rozvideoram32_le_w ) +{ + UINT32 v; + offset *= 2; + v = (rozvideoram16[offset+1]<<16)|rozvideoram16[offset]; + COMBINE_DATA( &v ); + writerozvideo(offset+1,v>>16); + writerozvideo(offset,v&0xffff); +} /* namco_rozvideoram32_le_w */ + +/**************************************************************************************************************/ +/* + Land Line Buffer + Land Generator + 0xf,0x7,0xe,0x6,0xd,0x5,0xc,0x4, + 0xb,0x3,0xa,0x2,0x9,0x1,0x8,0x0 + +*/ + +/* Preliminary! The road circuitry is identical for all the driving games. + * + * There are several chunks of RAM + * + * Road Tilemap: + * 0x00000..0x0ffff 64x512 tilemap + * + * Road Tiles: + * 0x10000..0x1f9ff 16x16x2bpp tiles + * + * + * Line Attributes: + * + * 0x1fa00..0x1fbdf xxx- ---- ---- ---- priority + * ---- xxxx xxxx xxxx xscroll + * + * 0x1fbfe horizontal adjust? + * 0x0017 + * 0x0018 (Final Lap3) + * + * 0x1fc00..0x1fddf selects line in source bitmap + * 0x1fdfe yscroll + * + * 0x1fe00..0x1ffdf ---- --xx xxxx xxxx zoomx + * 0x1fffd always 0xffff 0xffff? + */ +static UINT16 *mpRoadRAM; /* at 0x880000 in Final Lap; at 0xa00000 in Lucky&Wild */ +static UINT8 *mpRoadDirty; +static int mbRoadSomethingIsDirty; +static int mRoadGfxBank; +static tilemap *mpRoadTilemap; +static pen_t mRoadTransparentColor; +static int mbRoadNeedTransparent; + +#define ROAD_COLS 64 +#define ROAD_ROWS 512 +#define ROAD_TILE_SIZE 16 +#define ROAD_TILEMAP_WIDTH (ROAD_TILE_SIZE*ROAD_COLS) +#define ROAD_TILEMAP_HEIGHT (ROAD_TILE_SIZE*ROAD_ROWS) + +#define ROAD_TILE_COUNT_MAX (0xfa00/0x40) /* 0x3e8 */ +#define WORDS_PER_ROAD_TILE (0x40/2) + +static const gfx_layout RoadTileLayout = +{ + ROAD_TILE_SIZE, + ROAD_TILE_SIZE, + ROAD_TILE_COUNT_MAX, + 2, + { +#ifndef LSB_FIRST + 0,8 +#else + 8,0 +#endif + }, + {/* x offset */ + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 + }, + {/* y offset */ + 0x000,0x020,0x040,0x060,0x080,0x0a0,0x0c0,0x0e0, + 0x100,0x120,0x140,0x160,0x180,0x1a0,0x1c0,0x1e0 + }, + 0x200, /* offset to next tile */ +}; + +static TILE_GET_INFO( get_road_info ) +{ + UINT16 data = mpRoadRAM[tile_index]; + /* ------xx xxxxxxxx tile number + * xxxxxx-- -------- palette select + */ + int tile = (data&0x3ff); + int color = (data>>10); + + SET_TILE_INFO( mRoadGfxBank, tile, color , 0 ); +} /* get_road_info */ + +READ16_HANDLER( namco_road16_r ) +{ + return mpRoadRAM[offset]; +} + +WRITE16_HANDLER( namco_road16_w ) +{ + COMBINE_DATA( &mpRoadRAM[offset] ); + if( offset<0x10000/2 ) + { + tilemap_mark_tile_dirty( mpRoadTilemap, offset ); + } + else + { + offset -= 0x10000/2; + if( offset<ROAD_TILE_COUNT_MAX*WORDS_PER_ROAD_TILE ) + { + mpRoadDirty[offset/WORDS_PER_ROAD_TILE] = 1; + mbRoadSomethingIsDirty = 1; + } + } +} + +static void +UpdateRoad(running_machine *machine) +{ + int i; + if( mbRoadSomethingIsDirty ) + { + for( i=0; i<ROAD_TILE_COUNT_MAX; i++ ) + { + if( mpRoadDirty[i] ) + { + decodechar( + machine->gfx[mRoadGfxBank], + i, + 0x10000+(UINT8 *)mpRoadRAM, + &RoadTileLayout ); + mpRoadDirty[i] = 0; + } + } + tilemap_mark_all_tiles_dirty( mpRoadTilemap ); + mbRoadSomethingIsDirty = 0; + } +} + +static void +RoadMarkAllDirty(void) +{ + memset( mpRoadDirty,0x01,ROAD_TILE_COUNT_MAX ); + mbRoadSomethingIsDirty = 1; +} + +void +namco_road_init(running_machine *machine, int gfxbank ) +{ + mbRoadNeedTransparent = 0; + mRoadGfxBank = gfxbank; + mpRoadDirty = auto_malloc(ROAD_TILE_COUNT_MAX); + { + memset( mpRoadDirty,0x00,ROAD_TILE_COUNT_MAX ); + mbRoadSomethingIsDirty = 0; + mpRoadRAM = auto_malloc(0x20000); + { + gfx_element *pGfx = allocgfx( &RoadTileLayout ); + decodegfx(pGfx, 0x10000+(UINT8 *)mpRoadRAM, 0, pGfx->total_elements); + pGfx->color_base = 0xf00; + pGfx->total_colors = 0x3f; + + machine->gfx[gfxbank] = pGfx; + mpRoadTilemap = tilemap_create( + get_road_info,tilemap_scan_rows, + TILEMAP_TYPE_PEN, + ROAD_TILE_SIZE,ROAD_TILE_SIZE, + ROAD_COLS,ROAD_ROWS); + + state_save_register_global_pointer(mpRoadDirty, ROAD_TILE_COUNT_MAX); + state_save_register_global_pointer(mpRoadRAM, 0x20000 / 2); + state_save_register_func_postload(RoadMarkAllDirty); + + } + } +} /* namco_road_init */ + +void +namco_road_set_transparent_color(pen_t pen) +{ + mbRoadNeedTransparent = 1; + mRoadTransparentColor = pen; +} + +void +namco_road_draw(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int pri ) +{ + const UINT8 *clut = (void *)memory_region(REGION_USER3); + mame_bitmap *pSourceBitmap; + unsigned yscroll; + int i; + + UpdateRoad(machine); + + pSourceBitmap = tilemap_get_pixmap(mpRoadTilemap); + yscroll = mpRoadRAM[0x1fdfe/2]; + + for( i=cliprect->min_y; i<=cliprect->max_y; i++ ) + { + int screenx = mpRoadRAM[0x1fa00/2+i+15]; + if( pri == ((screenx&0xf000)>>12) ) + { + unsigned zoomx = mpRoadRAM[0x1fe00/2+i+15]&0x3ff; + if( zoomx ) + { + unsigned sourcey = mpRoadRAM[0x1fc00/2+i+15]+yscroll; + const UINT16 *pSourceGfx = BITMAP_ADDR16(pSourceBitmap, sourcey&(ROAD_TILEMAP_HEIGHT-1), 0); + unsigned dsourcex = (ROAD_TILEMAP_WIDTH<<16)/zoomx; + if( dsourcex ) + { + UINT16 *pDest = BITMAP_ADDR16(bitmap, i, 0); + unsigned sourcex = 0; + int numpixels = (44*ROAD_TILE_SIZE<<16)/dsourcex; + int clipPixels; + + screenx &= 0x0fff; /* mask off priority bits */ + if( screenx&0x0800 ) + { + /* sign extend */ + screenx |= ~0x7ff; + } + + /* adjust the horizontal placement */ + screenx -= 64; /*needs adjustment to left*/ + + clipPixels = cliprect->min_x - screenx; + if( clipPixels>0 ) + { /* crop left */ + numpixels -= clipPixels; + sourcex += dsourcex*clipPixels; + screenx = cliprect->min_x; + } + + clipPixels = (screenx+numpixels) - (cliprect->max_x+1); + if( clipPixels>0 ) + { /* crop right */ + numpixels -= clipPixels; + } + + /* TBA: work out palette mapping for Final Lap, Suzuka */ + + /* BUT: support transparent color for Thunder Ceptor */ + if( mbRoadNeedTransparent ) + { + while( numpixels-- > 0 ) + { + int pen = pSourceGfx[sourcex>>16]; + if (pen != mRoadTransparentColor) + { + if( clut ) + { + pen = (pen&~0xff)|clut[pen&0xff]; + } + pDest[screenx] = pen; + } + screenx++; + sourcex += dsourcex; + } + } + else + { + while( numpixels-- > 0 ) + { + int pen = pSourceGfx[sourcex>>16]; + if( clut ) + { + pen = (pen&~0xff)|clut[pen&0xff]; + } + pDest[screenx++] = pen; + sourcex += dsourcex; + } + } + } /* dsourcex!=0 */ + } /* zoomx!=0 */ + } /* priority */ + } /* next scanline */ +} /* namco_road_draw */ |