summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/namcoic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/namcoic.c')
-rw-r--r--src/mame/drivers/namcoic.c1742
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 */