diff options
Diffstat (limited to 'src/mame/video/twincobr.c')
-rw-r--r-- | src/mame/video/twincobr.c | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/src/mame/video/twincobr.c b/src/mame/video/twincobr.c new file mode 100644 index 00000000000..d60e7cdc19a --- /dev/null +++ b/src/mame/video/twincobr.c @@ -0,0 +1,521 @@ +/*************************************************************************** + video.c + + Functions to emulate the video hardware of these machines. + Video is 30x40 tiles. (200x320 for Twin Cobra/Flying shark) + Video is 40x30 tiles. (320x200 for Wardner) + + Video has 3 scrolling tile layers (Background, Foreground and Text) and + Sprites that have 4 priorities. Lowest priority is "Off". + Wardner has an unusual sprite priority in the shop scenes, whereby a + middle level priority Sprite appears over a high priority Sprite ? + +***************************************************************************/ + +#include "driver.h" +#include "video/crtc6845.h" +#include "twincobr.h" + + +void twincobr_flipscreen(int flip); +void twincobr_display(int enable); +static void twincobr_restore_screen(void); + +INT32 twincobr_fg_rom_bank; +INT32 twincobr_bg_ram_bank; +INT32 wardner_sprite_hack; /* Required for weird sprite priority in wardner */ + /* when hero is in shop. Hero should cover shop owner */ + +static UINT16 *twincobr_bgvideoram16; +static UINT16 *twincobr_fgvideoram16; +static UINT16 *twincobr_txvideoram16; + +static size_t twincobr_bgvideoram_size; +static size_t twincobr_fgvideoram_size; +static size_t twincobr_txvideoram_size; + +static INT32 txscrollx; +static INT32 txscrolly; +static INT32 fgscrollx; +static INT32 fgscrolly; +static INT32 bgscrollx; +static INT32 bgscrolly; +static INT32 txoffs; +static INT32 fgoffs; +static INT32 bgoffs; +static INT32 scroll_x; +static INT32 scroll_y; +static INT32 twincobr_display_on; +static INT32 twincobr_flip_screen; + +static tilemap *bg_tilemap, *fg_tilemap, *tx_tilemap; + + +/*************************************************************************** + Callbacks for the TileMap code +***************************************************************************/ + +static TILE_GET_INFO( get_bg_tile_info ) +{ + int code, tile_number, color; + + code = twincobr_bgvideoram16[tile_index+twincobr_bg_ram_bank]; + tile_number = code & 0x0fff; + color = (code & 0xf000) >> 12; + SET_TILE_INFO( + 2, + tile_number, + color, + 0); +} + +static TILE_GET_INFO( get_fg_tile_info ) +{ + int code, tile_number, color; + + code = twincobr_fgvideoram16[tile_index]; + tile_number = (code & 0x0fff) | twincobr_fg_rom_bank; + color = (code & 0xf000) >> 12; + SET_TILE_INFO( + 1, + tile_number, + color, + 0); +} + +static TILE_GET_INFO( get_tx_tile_info ) +{ + int code, tile_number, color; + + code = twincobr_txvideoram16[tile_index]; + tile_number = code & 0x07ff; + color = (code & 0xf800) >> 11; + SET_TILE_INFO( + 0, + tile_number, + color, + 0); +} + +/*************************************************************************** + Start the video hardware emulation. +***************************************************************************/ + +static void twincobr_create_tilemaps(void) +{ + bg_tilemap = tilemap_create(get_bg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + fg_tilemap = tilemap_create(get_fg_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,64); + tx_tilemap = tilemap_create(get_tx_tile_info,tilemap_scan_rows,TILEMAP_TYPE_PEN,8,8,64,32); + + tilemap_set_transparent_pen(fg_tilemap,0); + tilemap_set_transparent_pen(tx_tilemap,0); +} + +VIDEO_START( toaplan0 ) +{ + /* the video RAM is accessed via ports, it's not memory mapped */ + twincobr_txvideoram_size = 0x0800; + twincobr_bgvideoram_size = 0x2000; /* banked two times 0x1000 */ + twincobr_fgvideoram_size = 0x1000; + + twincobr_create_tilemaps(); + + twincobr_txvideoram16 = auto_malloc(twincobr_txvideoram_size*2); + memset(twincobr_txvideoram16,0,twincobr_txvideoram_size*2); + + twincobr_fgvideoram16 = auto_malloc(twincobr_fgvideoram_size*2); + memset(twincobr_fgvideoram16,0,twincobr_fgvideoram_size*2); + + twincobr_bgvideoram16 = auto_malloc(twincobr_bgvideoram_size*2); + memset(twincobr_bgvideoram16,0,twincobr_bgvideoram_size*2); + + twincobr_display_on = 0; + twincobr_display(twincobr_display_on); + + state_save_register_global_pointer(twincobr_txvideoram16, twincobr_txvideoram_size); + state_save_register_global_pointer(twincobr_fgvideoram16, twincobr_fgvideoram_size); + state_save_register_global_pointer(twincobr_bgvideoram16, twincobr_bgvideoram_size); + state_save_register_global(txoffs); + state_save_register_global(fgoffs); + state_save_register_global(bgoffs); + state_save_register_global(scroll_x); + state_save_register_global(scroll_y); + state_save_register_global(txscrollx); + state_save_register_global(fgscrollx); + state_save_register_global(bgscrollx); + state_save_register_global(txscrolly); + state_save_register_global(fgscrolly); + state_save_register_global(bgscrolly); + state_save_register_global(twincobr_display_on); + state_save_register_global(twincobr_fg_rom_bank); + state_save_register_global(twincobr_bg_ram_bank); + state_save_register_global(twincobr_flip_screen); + state_save_register_global(wardner_sprite_hack); + state_save_register_func_postload(twincobr_restore_screen); +} + +static void twincobr_restore_screen(void) +{ + twincobr_display(twincobr_display_on); + twincobr_flipscreen(twincobr_flip_screen); +} + + +/*************************************************************************** + Video I/O interface +***************************************************************************/ + +void twincobr_display(int enable) +{ + twincobr_display_on = enable; + tilemap_set_enable(bg_tilemap, enable); + tilemap_set_enable(fg_tilemap, enable); + tilemap_set_enable(tx_tilemap, enable); +} + +void twincobr_flipscreen(int flip) +{ + tilemap_set_flip(ALL_TILEMAPS, (flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0)); + twincobr_flip_screen = flip; + if (flip) { + scroll_x = -58; + scroll_y = -29; + if (toaplan_main_cpu == 1) scroll_y += 256; /* Wardner */ + } + else { + scroll_x = 55; + scroll_y = 30; + } +} + +WRITE16_HANDLER( twincobr_crtc_reg_sel_w ) +{ + crtc6845_address_w(offset, data); +} + +WRITE16_HANDLER( twincobr_crtc_data_w ) +{ + crtc6845_register_w(offset, data); +} + +WRITE16_HANDLER( twincobr_txoffs_w ) +{ + COMBINE_DATA(&txoffs); + txoffs %= twincobr_txvideoram_size; +} +READ16_HANDLER( twincobr_txram_r ) +{ + return twincobr_txvideoram16[txoffs]; +} +WRITE16_HANDLER( twincobr_txram_w ) +{ + COMBINE_DATA(&twincobr_txvideoram16[txoffs]); + tilemap_mark_tile_dirty(tx_tilemap,txoffs); +} + +WRITE16_HANDLER( twincobr_bgoffs_w ) +{ + COMBINE_DATA(&bgoffs); + bgoffs %= (twincobr_bgvideoram_size >> 1); +} +READ16_HANDLER( twincobr_bgram_r ) +{ + return twincobr_bgvideoram16[bgoffs+twincobr_bg_ram_bank]; +} +WRITE16_HANDLER( twincobr_bgram_w ) +{ + COMBINE_DATA(&twincobr_bgvideoram16[bgoffs+twincobr_bg_ram_bank]); + tilemap_mark_tile_dirty(bg_tilemap,(bgoffs+twincobr_bg_ram_bank)); +} + +WRITE16_HANDLER( twincobr_fgoffs_w ) +{ + COMBINE_DATA(&fgoffs); + fgoffs %= twincobr_fgvideoram_size; +} +READ16_HANDLER( twincobr_fgram_r ) +{ + return twincobr_fgvideoram16[fgoffs]; +} +WRITE16_HANDLER( twincobr_fgram_w ) +{ + COMBINE_DATA(&twincobr_fgvideoram16[fgoffs]); + tilemap_mark_tile_dirty(fg_tilemap,fgoffs); +} + + +WRITE16_HANDLER( twincobr_txscroll_w ) +{ + if (offset == 0) { + COMBINE_DATA(&txscrollx); + tilemap_set_scrollx(tx_tilemap,0,(txscrollx+scroll_x) & 0x1ff); + } + else { + COMBINE_DATA(&txscrolly); + tilemap_set_scrolly(tx_tilemap,0,(txscrolly+scroll_y) & 0x1ff); + } +} + +WRITE16_HANDLER( twincobr_bgscroll_w ) +{ + if (offset == 0) { + COMBINE_DATA(&bgscrollx); + tilemap_set_scrollx(bg_tilemap,0,(bgscrollx+scroll_x) & 0x1ff); + } + else { + COMBINE_DATA(&bgscrolly); + tilemap_set_scrolly(bg_tilemap,0,(bgscrolly+scroll_y) & 0x1ff); + } +} + +WRITE16_HANDLER( twincobr_fgscroll_w ) +{ + if (offset == 0) { + COMBINE_DATA(&fgscrollx); + tilemap_set_scrollx(fg_tilemap,0,(fgscrollx+scroll_x) & 0x1ff); + } + else { + COMBINE_DATA(&fgscrolly); + tilemap_set_scrolly(fg_tilemap,0,(fgscrolly+scroll_y) & 0x1ff); + } +} + +WRITE16_HANDLER( twincobr_exscroll_w ) /* Extra unused video layer */ +{ + if (offset == 0) logerror("PC - write %04x to unknown video scroll Y register\n",data); + else logerror("PC - write %04x to unknown video scroll X register\n",data); +} + +/******************** Wardner interface to this hardware ********************/ +WRITE8_HANDLER( wardner_txlayer_w ) +{ + int shift = 8 * (offset & 1); + twincobr_txoffs_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_bglayer_w ) +{ + int shift = 8 * (offset & 1); + twincobr_bgoffs_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_fglayer_w ) +{ + int shift = 8 * (offset & 1); + twincobr_fgoffs_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_txscroll_w ) +{ + int shift = 8 * (offset & 1); + twincobr_txscroll_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_bgscroll_w ) +{ + int shift = 8 * (offset & 1); + twincobr_bgscroll_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_fgscroll_w ) +{ + int shift = 8 * (offset & 1); + twincobr_fgscroll_w(offset / 2, data << shift, 0xff00 >> shift); +} + +WRITE8_HANDLER( wardner_exscroll_w ) /* Extra unused video layer */ +{ + switch (offset) + { + case 01: data <<= 8; + case 00: logerror("PC - write %04x to unknown video scroll X register\n",data); break; + case 03: data <<= 8; + case 02: logerror("PC - write %04x to unknown video scroll Y register\n",data); break; + } +} + +READ8_HANDLER( wardner_videoram_r ) +{ + int shift = 8 * (offset & 1); + switch (offset/2) { + case 0: return twincobr_txram_r(0,0) >> shift; break; + case 1: return twincobr_bgram_r(0,0) >> shift; break; + case 2: return twincobr_fgram_r(0,0) >> shift; break; + } + return 0; +} + +WRITE8_HANDLER( wardner_videoram_w ) +{ + int shift = 8 * (offset & 1); + switch (offset/2) { + case 0: twincobr_txram_w(0,data << shift, 0xff00 >> shift); break; + case 1: twincobr_bgram_w(0,data << shift, 0xff00 >> shift); break; + case 2: twincobr_fgram_w(0,data << shift, 0xff00 >> shift); break; + } +} + +READ8_HANDLER( wardner_sprite_r ) +{ + int shift = (offset & 1) * 8; + return spriteram16[offset/2] >> shift; +} + +WRITE8_HANDLER( wardner_sprite_w ) +{ + if (offset & 1) + spriteram16[offset/2] = (spriteram16[offset/2] & 0x00ff) | (data << 8); + else + spriteram16[offset/2] = (spriteram16[offset/2] & 0xff00) | data; +} + +WRITE8_HANDLER( wardner_CRTC_reg_sel_w ) +{ + crtc6845_address_w(offset, data); +} + +WRITE8_HANDLER( wardner_CRTC_data_w ) +{ + crtc6845_register_w(0, data); +} + + +/*************************************************************************** + Ugly sprite hack for Wardner when hero is in shop +***************************************************************************/ + +static void wardner_sprite_priority_hack(void) +{ + if (fgscrollx != bgscrollx) { + if ((fgscrollx==0x1c9) || (twincobr_flip_screen && (fgscrollx==0x17a))) { /* in the shop ? */ + int wardner_hack = buffered_spriteram16[0x0b04/2]; + /* sprite position 0x6300 to 0x8700 -- hero on shop keeper (normal) */ + /* sprite position 0x3900 to 0x5e00 -- hero on shop keeper (flip) */ + if ((wardner_hack > 0x3900) && (wardner_hack < 0x8700)) { /* hero at shop keeper ? */ + wardner_hack = buffered_spriteram16[0x0b02/2]; + wardner_hack |= 0x0400; /* make hero top priority */ + buffered_spriteram16[0x0b02/2] = wardner_hack; + wardner_hack = buffered_spriteram16[0x0b0a/2]; + wardner_hack |= 0x0400; + buffered_spriteram16[0x0b0a/2] = wardner_hack; + wardner_hack = buffered_spriteram16[0x0b12/2]; + wardner_hack |= 0x0400; + buffered_spriteram16[0x0b12/2] = wardner_hack; + wardner_hack = buffered_spriteram16[0x0b1a/2]; + wardner_hack |= 0x0400; + buffered_spriteram16[0x0b1a/2] = wardner_hack; + } + } + } +} + + + +#ifdef MAME_DEBUG +void twincobr_log_vram(void) +{ + if ( input_code_pressed(KEYCODE_M) ) + { + offs_t tile_voffs; + int tcode[3]; + while (input_code_pressed(KEYCODE_M)) ; + logerror("Scrolls BG-X BG-Y FG-X FG-Y TX-X TX-Y\n"); + logerror("------> %04x %04x %04x %04x %04x %04x\n",bgscrollx,bgscrolly,fgscrollx,fgscrolly,txscrollx,txscrolly); + for ( tile_voffs = 0; tile_voffs < (twincobr_txvideoram_size/2); tile_voffs++ ) + { + tcode[1] = twincobr_bgvideoram16[tile_voffs]; + tcode[2] = twincobr_fgvideoram16[tile_voffs]; + tcode[3] = twincobr_txvideoram16[tile_voffs]; + logerror("$(%04x) (Col-Tile) BG1:%01x-%03x FG1:%01x-%03x TX1:%02x-%03x\n", tile_voffs, + tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff, + tcode[2] & 0xf000 >> 12, tcode[2] & 0x0fff, + tcode[3] & 0xf800 >> 11, tcode[3] & 0x07ff); + } + for ( tile_voffs = (twincobr_txvideoram_size/2); tile_voffs < (twincobr_fgvideoram_size/2); tile_voffs++ ) + { + tcode[1] = twincobr_bgvideoram16[tile_voffs]; + tcode[2] = twincobr_fgvideoram16[tile_voffs]; + logerror("$(%04x) (Col-Tile) BG1:%01x-%03x FG1:%01x-%03x\n", tile_voffs, + tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff, + tcode[2] & 0xf000 >> 12, tcode[2] & 0x0fff); + } + for ( tile_voffs = (twincobr_fgvideoram_size/2); tile_voffs < (twincobr_bgvideoram_size/2); tile_voffs++ ) + { + tcode[1] = twincobr_bgvideoram16[tile_voffs]; + logerror("$(%04x) (Col-Tile) BG1:%01x-%03x\n", tile_voffs, + tcode[1] & 0xf000 >> 12, tcode[1] & 0x0fff); + } + } +} +#endif + + +/*************************************************************************** + Sprite Handlers +***************************************************************************/ + +static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect, int priority ) +{ + int offs; + + if (twincobr_display_on) + { + for (offs = 0;offs < spriteram_size/2;offs += 4) + { + int attribute,sx,sy,flipx,flipy; + int sprite, color; + + attribute = buffered_spriteram16[offs + 1]; + if ((attribute & 0x0c00) == priority) { /* low priority */ + sy = buffered_spriteram16[offs + 3] >> 7; + if (sy != 0x0100) { /* sx = 0x01a0 or 0x0040*/ + sprite = buffered_spriteram16[offs] & 0x7ff; + color = attribute & 0x3f; + sx = buffered_spriteram16[offs + 2] >> 7; + flipx = attribute & 0x100; + if (flipx) sx -= 14; /* should really be 15 */ + flipy = attribute & 0x200; + drawgfx(bitmap,machine->gfx[3], + sprite, + color, + flipx,flipy, + sx-32,sy-16, + cliprect,TRANSPARENCY_PEN,0); + } + } + } + } +} + + +/*************************************************************************** + Draw the game screen in the given mame_bitmap. +***************************************************************************/ + +VIDEO_UPDATE( toaplan0 ) +{ +#ifdef MAME_DEBUG + twincobr_log_vram(); +#endif + + if (wardner_sprite_hack) wardner_sprite_priority_hack(); + + fillbitmap(bitmap,machine->pens[0],cliprect); + + tilemap_draw(bitmap,cliprect,bg_tilemap,TILEMAP_DRAW_OPAQUE,0); + draw_sprites(machine, bitmap,cliprect,0x0400); + tilemap_draw(bitmap,cliprect,fg_tilemap,0,0); + draw_sprites(machine, bitmap,cliprect,0x0800); + tilemap_draw(bitmap,cliprect,tx_tilemap,0,0); + draw_sprites(machine, bitmap,cliprect,0x0c00); + return 0; +} + + +VIDEO_EOF( toaplan0 ) +{ + /* Spriteram is always 1 frame ahead, suggesting spriteram buffering. + There are no CPU output registers that control this so we + assume it happens automatically every frame, at the end of vblank */ + buffer_spriteram16_w(0,0,0); +} |