diff options
Diffstat (limited to 'src/mame/video/twin16.c')
-rw-r--r-- | src/mame/video/twin16.c | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/src/mame/video/twin16.c b/src/mame/video/twin16.c new file mode 100644 index 00000000000..76a69254b6f --- /dev/null +++ b/src/mame/video/twin16.c @@ -0,0 +1,463 @@ +/* + + Konami Twin16 Hardware - Video + + TODO: + + - convert background to tilemap + - clean up sprite drawing + - sprite-background priorities + - sprite lag in devilw + - sprite Y axis lag in vulcan + - add shadow sprites (alpha blending) to sprites in at least devilw + +*/ + +#include "driver.h" + +extern UINT16 twin16_custom_video; +extern UINT16 *twin16_gfx_rom; +extern UINT16 *twin16_videoram2; +extern UINT16 *twin16_sprite_gfx_ram; +extern UINT16 *twin16_tile_gfx_ram; +extern int twin16_spriteram_process_enable( void ); + +static int need_process_spriteram; +static UINT16 gfx_bank; +static UINT16 scrollx[3], scrolly[3]; +static UINT16 video_register; + +enum { + TWIN16_SCREEN_FLIPY = 0x01, /* ? breaks devils world text layer */ + TWIN16_SCREEN_FLIPX = 0x02, /* confirmed: Hard Puncher Intro */ + TWIN16_UNKNOWN1 = 0x04, /* ?Hard Puncher uses this */ + TWIN16_PLANE_ORDER = 0x08, /* confirmed: Devil Worlds */ + TWIN16_TILE_FLIPY = 0x20 /* confirmed? Vulcan Venture */ +}; + +static tilemap *fg_tilemap; + +WRITE16_HANDLER( twin16_videoram2_w ) +{ + COMBINE_DATA(&twin16_videoram2[offset]); + tilemap_mark_tile_dirty(fg_tilemap, offset); +} + +WRITE16_HANDLER( twin16_paletteram_word_w ) +{ // identical to tmnt_paletteram_w + COMBINE_DATA(paletteram16 + offset); + offset &= ~1; + + data = ((paletteram16[offset] & 0xff) << 8) | (paletteram16[offset + 1] & 0xff); + palette_set_color_rgb(Machine, offset / 2, pal5bit(data >> 0), pal5bit(data >> 5), pal5bit(data >> 10)); +} + +WRITE16_HANDLER( fround_gfx_bank_w ) +{ + COMBINE_DATA(&gfx_bank); +} + +WRITE16_HANDLER( twin16_video_register_w ) +{ + switch (offset) { + case 0: + COMBINE_DATA( &video_register ); + + flip_screen_x_set(video_register & TWIN16_SCREEN_FLIPX); + + if (twin16_custom_video) + flip_screen_y_set(video_register & TWIN16_SCREEN_FLIPY); + else + flip_screen_y_set(~video_register & TWIN16_SCREEN_FLIPY); + + break; + + case 1: COMBINE_DATA( &scrollx[0] ); break; + case 2: COMBINE_DATA( &scrolly[0] ); break; + case 3: COMBINE_DATA( &scrollx[1] ); break; + case 4: COMBINE_DATA( &scrolly[1] ); break; + case 5: COMBINE_DATA( &scrollx[2] ); break; + case 6: COMBINE_DATA( &scrolly[2] ); break; + + default: + logerror("unknown video_register write:%d", data ); + break; + } +} + +static void draw_sprite( /* slow slow slow, but it's ok for now */ + mame_bitmap *bitmap, + const UINT16 *pen_data, + const pen_t *pal_data, + int xpos, int ypos, + int width, int height, + int flipx, int flipy, int pri ) +{ + + int x,y,pval; + if( xpos>=320 ) xpos -= 65536; + if( ypos>=256 ) ypos -= 65536; + + if (pri) pval=2; else pval=8; + + { + { + for( y=0; y<height; y++ ) + { + int sy = (flipy)?(ypos+height-1-y):(ypos+y); + if( sy>=16 && sy<256-16 ) + { + UINT16 *dest = BITMAP_ADDR16(bitmap, sy, 0); + UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, sy, 0); + + for( x=0; x<width; x++ ) + { + int sx = (flipx)?(xpos+width-1-x):(xpos+x); + if( sx>=0 && sx<320 ) + { + UINT16 pen = pen_data[x/4]; + switch( x%4 ) + { + case 0: pen = pen>>12; break; + case 1: pen = (pen>>8)&0xf; break; + case 2: pen = (pen>>4)&0xf; break; + case 3: pen = pen&0xf; break; + } + + if( pen ) + { + if(pdest[sx]<pval) { dest[sx] = pal_data[pen]; } + + pdest[sx]|=0x10; + } + } + } + } + pen_data += width/4; + } + } + } +} + +void twin16_spriteram_process( void ) +{ + UINT16 dx = scrollx[0]; + UINT16 dy = scrolly[0]; + + const UINT16 *source = &spriteram16[0x0000]; + const UINT16 *finish = &spriteram16[0x1800]; + + memset( &spriteram16[0x1800], 0, 0x800 ); + while( source<finish ){ + UINT16 priority = source[0]; + if( priority & 0x8000 ){ + UINT16 *dest = &spriteram16[0x1800 + 4*(priority&0xff)]; + + INT32 xpos = (0x10000*source[4])|source[5]; + INT32 ypos = (0x10000*source[6])|source[7]; + + UINT16 attributes = source[2]&0x03ff; /* scale,size,color */ + if( priority & 0x0200 ) attributes |= 0x4000; + /* Todo: priority & 0x0100 is also used */ + attributes |= 0x8000; + + dest[0] = source[3]; /* gfx data */ + dest[1] = ((xpos>>8) - dx)&0xffff; + dest[2] = ((ypos>>8) - dy)&0xffff; + dest[3] = attributes; + } + source += 0x50/2; + } + need_process_spriteram = 0; +} + +/* + * Sprite Format + * ---------------------------------- + * + * Word | Bit(s) | Use + * -----+-fedcba9876543210-+---------------- + * 0 | --xxxxxxxxxxxxxx | code + * -----+------------------+ + * 1 | -------xxxxxxxxx | ypos + * -----+------------------+ + * 2 | -------xxxxxxxxx | xpos + * -----+------------------+ + * 3 | x--------------- | enble + * 3 | -x-------------- | priority? + * 3 | ------x--------- | yflip? + * 3 | -------x-------- | xflip + * 3 | --------xx------ | height + * 3 | ----------xx---- | width + * 3 | ------------xxxx | color + +shadow bit? + + */ + +static void draw_sprites( mame_bitmap *bitmap ) +{ + int count = 0; + + const UINT16 *source = 0x1800+buffered_spriteram16 + 0x800 - 4; + const UINT16 *finish = 0x1800+buffered_spriteram16; + + for (; source >= finish; source -= 4) { + UINT16 attributes = source[3]; + UINT16 code = source[0]; + + if((code!=0xffff) && (attributes&0x8000)) { + int xpos = source[1]; + int ypos = source[2]; + + const pen_t *pal_data = Machine->pens+((attributes&0xf)+0x10)*16; + int height = 16<<((attributes>>6)&0x3); + int width = 16<<((attributes>>4)&0x3); + const UINT16 *pen_data = 0; + int flipy = attributes&0x0200; + int flipx = attributes&0x0100; + + if( twin16_custom_video == 1 ) { + pen_data = twin16_gfx_rom + 0x80000; + } + else { + switch( (code>>12)&0x3 ){ /* bank select */ + case 0: + pen_data = twin16_gfx_rom; + break; + + case 1: + pen_data = twin16_gfx_rom + 0x40000; + break; + + case 2: + pen_data = twin16_gfx_rom + 0x80000; + if( code&0x4000 ) pen_data += 0x40000; + break; + + case 3: + pen_data = twin16_sprite_gfx_ram; + break; + } + code &= 0xfff; + } + + /* some code masking */ + if(height == 64 && width == 64) + { + code &= ~8; // fixes bad sprites in vulcan ending sequence + } + else if(height == 32 && width == 32) + { + code &= ~3; // fixes bad sprites in devilw + } + else if(height == 32 && width == 16) + { + code &= ~1; // fixes bad sprites in devilw + } + else if(height == 16 && width == 32) + { + code &= ~1; // fixes bad sprites in devilw + } + + pen_data += code*0x40; + + if( video_register&TWIN16_SCREEN_FLIPY ){ + if (ypos>65000) ypos=ypos-65536; /* Bit hacky */ + ypos = 256-ypos-height; + flipy = !flipy; + } + if( video_register&TWIN16_SCREEN_FLIPX ){ + if (xpos>65000) xpos=xpos-65536; /* Bit hacky */ + xpos = 320-xpos-width; + flipx = !flipx; + } + + //if( sprite_which==count || !input_code_pressed( KEYCODE_B ) ) + draw_sprite( bitmap, pen_data, pal_data, xpos, ypos, width, height, flipx, flipy, (attributes&0x4000) ); + } + + count++; + } +} + +static void draw_layer( mame_bitmap *bitmap, int opaque ){ + const UINT16 *gfx_base; + const UINT16 *source = videoram16; + int i, xxor, yxor; + int bank_table[4]; + int dx, dy, palette; + int tile_flipx = 0; // video_register&TWIN16_TILE_FLIPX; + int tile_flipy = video_register&TWIN16_TILE_FLIPY; + + if( ((video_register&TWIN16_PLANE_ORDER)?1:0) != opaque ){ + source += 0x1000; + dx = scrollx[2]; + dy = scrolly[2]; + palette = 1; + } + else { + source += 0x0000; + dx = scrollx[1]; + dy = scrolly[1]; + palette = 0; + } + + if( twin16_custom_video == 1 ){ + gfx_base = twin16_gfx_rom; + bank_table[3] = (gfx_bank>>(4*3))&0xf; + bank_table[2] = (gfx_bank>>(4*2))&0xf; + bank_table[1] = (gfx_bank>>(4*1))&0xf; + bank_table[0] = (gfx_bank>>(4*0))&0xf; + } + else { + gfx_base = twin16_tile_gfx_ram; + bank_table[0] = 0; + bank_table[1] = 1; + bank_table[2] = 2; + bank_table[3] = 3; + } + + if( video_register&TWIN16_SCREEN_FLIPX ){ + dx = 256-dx-64; + tile_flipx = !tile_flipx; + } + + if( video_register&TWIN16_SCREEN_FLIPY ){ + dy = 256-dy; + tile_flipy = !tile_flipy; + } + + xxor = tile_flipx ? 7 : 0; + yxor = tile_flipy ? 7 : 0; + + for( i=0; i<64*64; i++ ) + { + int y1, y2, x1, x2; + int sx = (i%64)*8; + int sy = (i/64)*8; + int xpos,ypos; + + if( video_register&TWIN16_SCREEN_FLIPX ) sx = 63*8 - sx; + if( video_register&TWIN16_SCREEN_FLIPY ) sy = 63*8 - sy; + + xpos = (sx-dx)&0x1ff; + ypos = (sy-dy)&0x1ff; + if( xpos>=320 ) xpos -= 512; + if( ypos>=256 ) ypos -= 512; + + x1 = MAX(xpos, 0); + x2 = MIN(xpos+7, bitmap->width-1); + y1 = MAX(ypos, 0); + y2 = MIN(ypos+7, bitmap->height-1); + + if (x1 <= x2 && y1 <= y2) + { + int code = source[i]; + /* + xxx------------- color + ---xx----------- tile bank + -----xxxxxxxxxxx tile number + */ + const UINT16 *gfx_data = gfx_base + (code&0x7ff)*16 + bank_table[(code>>11)&0x3]*0x8000; + int color = (code>>13); + const pen_t *pal_data = Machine->pens + 16*(0x20+color+8*palette); + int x, y; + + if( opaque ) + { + for (y = y1; y <= y2; y++) + { + const UINT16 *gfxptr = gfx_data + ((y - ypos) ^ yxor) * 2; + UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0); + UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, y, 0); + + for (x = x1; x <= x2; x++) + { + int effx = (x - xpos) ^ xxor; + UINT16 data = gfxptr[effx / 4]; + dest[x] = pal_data[(data >> 4*(~effx & 3)) & 0x0f]; + pdest[x] |= 1; + } + } + } + else + { + for (y = y1; y <= y2; y++) + { + const UINT16 *gfxptr = gfx_data + ((y - ypos) ^ yxor) * 2; + UINT16 *dest = BITMAP_ADDR16(bitmap, y, 0); + UINT8 *pdest = BITMAP_ADDR8(priority_bitmap, y, 0); + + for (x = x1; x <= x2; x++) + { + int effx = (x - xpos) ^ xxor; + UINT16 data = gfxptr[effx / 4]; + UINT8 pen = (data >> 4*(~effx & 3)) & 0x0f; + if (pen) + { + dest[x] = pal_data[pen]; + pdest[x] |= 4; + } + } + } + } + } + } +} + +static TILE_GET_INFO( get_fg_tile_info ) +{ + const UINT16 *source = twin16_videoram2; + int attr = source[tile_index]; + int code = attr & 0x1ff; + int color = (attr >> 9) & 0x0f; + + SET_TILE_INFO(0, code, color, 0); +} + +VIDEO_START( twin16 ) +{ + fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows_flip_y, + TILEMAP_TYPE_PEN, 8, 8, 64, 32); + + tilemap_set_transparent_pen(fg_tilemap, 0); +} + +VIDEO_START( fround ) +{ + fg_tilemap = tilemap_create(get_fg_tile_info, tilemap_scan_rows, + TILEMAP_TYPE_PEN, 8, 8, 64, 32); + + tilemap_set_transparent_pen(fg_tilemap, 0); +} + +VIDEO_EOF( twin16 ) +{ + if( twin16_spriteram_process_enable() && need_process_spriteram ) + twin16_spriteram_process(); + + need_process_spriteram = 1; + + buffer_spriteram16_w(0,0,0); +} + +VIDEO_UPDATE( twin16 ) +{ + fillbitmap(priority_bitmap,0,cliprect); + draw_layer( bitmap,1 ); + draw_layer( bitmap,0 ); + draw_sprites( bitmap ); + tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0); + return 0; +} + +VIDEO_UPDATE( vulcan ) +{ + fillbitmap(priority_bitmap,0,cliprect); + draw_layer( bitmap,1 ); + draw_sprites( bitmap ); + draw_layer( bitmap,0 ); + tilemap_draw(bitmap, cliprect, fg_tilemap, 0, 0); + return 0; +} |