/*************************************************************************** Midway MCR-68k system ***************************************************************************/ #include "emu.h" #include "includes/mcr68.h" #define LOW_BYTE(x) ((x) & 0xff) /************************************* * * Tilemap callbacks * *************************************/ static TILE_GET_INFO( get_bg_tile_info ) { mcr68_state *state = machine.driver_data(); UINT16 *videoram = state->m_videoram; int data = LOW_BYTE(videoram[tile_index * 2]) | (LOW_BYTE(videoram[tile_index * 2 + 1]) << 8); int code = (data & 0x3ff) | ((data >> 4) & 0xc00); int color = (~data >> 12) & 3; SET_TILE_INFO(0, code, color, TILE_FLIPYX((data >> 10) & 3)); if (machine.gfx[0]->total_elements < 0x1000) tileinfo->category = (data >> 15) & 1; } static TILE_GET_INFO( zwackery_get_bg_tile_info ) { mcr68_state *state = machine.driver_data(); UINT16 *videoram = state->m_videoram; int data = videoram[tile_index]; int color = (data >> 13) & 7; SET_TILE_INFO(0, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3)); } static TILE_GET_INFO( zwackery_get_fg_tile_info ) { mcr68_state *state = machine.driver_data(); UINT16 *videoram = state->m_videoram; int data = videoram[tile_index]; int color = (data >> 13) & 7; SET_TILE_INFO(2, data & 0x3ff, color, TILE_FLIPYX((data >> 11) & 3)); tileinfo->category = (color != 0); } /************************************* * * Video startup * *************************************/ VIDEO_START( mcr68 ) { mcr68_state *state = machine.driver_data(); /* initialize the background tilemap */ state->m_bg_tilemap = tilemap_create(machine, get_bg_tile_info, tilemap_scan_rows, 16,16, 32,32); tilemap_set_transparent_pen(state->m_bg_tilemap, 0); } VIDEO_START( zwackery ) { mcr68_state *state = machine.driver_data(); const UINT8 *colordatabase = (const UINT8 *)machine.region("gfx3")->base(); gfx_element *gfx0 = machine.gfx[0]; gfx_element *gfx2 = machine.gfx[2]; UINT8 *srcdata0, *dest0; UINT8 *srcdata2, *dest2; int code, y, x; /* initialize the background tilemap */ state->m_bg_tilemap = tilemap_create(machine, zwackery_get_bg_tile_info, tilemap_scan_rows, 16,16, 32,32); /* initialize the foreground tilemap */ state->m_fg_tilemap = tilemap_create(machine, zwackery_get_fg_tile_info, tilemap_scan_rows, 16,16, 32,32); tilemap_set_transparent_pen(state->m_fg_tilemap, 0); /* allocate memory for the assembled gfx data */ srcdata0 = auto_alloc_array(machine, UINT8, gfx0->total_elements * gfx0->width * gfx0->height); srcdata2 = auto_alloc_array(machine, UINT8, gfx2->total_elements * gfx2->width * gfx2->height); /* "colorize" each code */ dest0 = srcdata0; dest2 = srcdata2; for (code = 0; code < gfx0->total_elements; code++) { const UINT8 *coldata = colordatabase + code * 32; const UINT8 *gfxdata0 = gfx_element_get_data(gfx0, code); const UINT8 *gfxdata2 = gfx_element_get_data(gfx2, code); /* assume 16 rows */ for (y = 0; y < 16; y++) { const UINT8 *gd0 = gfxdata0; const UINT8 *gd2 = gfxdata2; /* 16 columns */ for (x = 0; x < 16; x++, gd0++, gd2++) { int coloffs = (y & 0x0c) | ((x >> 2) & 0x03); int pen0 = coldata[coloffs * 2 + 0]; int pen1 = coldata[coloffs * 2 + 1]; int tp0, tp1; /* every 4 pixels gets its own foreground/background colors */ *dest0++ = *gd0 ? pen1 : pen0; /* for gfx 2, we convert all low-priority pens to 0 */ tp0 = (pen0 & 0x80) ? pen0 : 0; tp1 = (pen1 & 0x80) ? pen1 : 0; *dest2++ = *gd2 ? tp1 : tp0; } /* advance */ gfxdata0 += gfx0->line_modulo; gfxdata2 += gfx2->line_modulo; } } /* create a simple target layout */ gfx0->layout.planes = gfx2->layout.planes = 8; for (x = 0; x < 8; x++) gfx0->layout.planeoffset[x] = gfx2->layout.planeoffset[x] = x; for (x = 0; x < gfx0->width; x++) gfx0->layout.xoffset[x] = gfx2->layout.xoffset[x] = 8 * x; for (y = 0; y < gfx0->height; y++) gfx0->layout.yoffset[y] = gfx2->layout.yoffset[y] = 8 * y * gfx0->width; gfx0->layout.charincrement = gfx2->layout.charincrement = 8 * gfx0->width * gfx0->height; /* make the assembled data our new source data */ gfx_element_set_source(gfx0, srcdata0); gfx_element_set_source(gfx2, srcdata2); } /************************************* * * Palette RAM writes * *************************************/ WRITE16_HANDLER( mcr68_paletteram_w ) { int newword; COMBINE_DATA(&space->machine().generic.paletteram.u16[offset]); newword = space->machine().generic.paletteram.u16[offset]; palette_set_color_rgb(space->machine(), offset, pal3bit(newword >> 6), pal3bit(newword >> 0), pal3bit(newword >> 3)); } WRITE16_HANDLER( zwackery_paletteram_w ) { int newword; COMBINE_DATA(&space->machine().generic.paletteram.u16[offset]); newword = space->machine().generic.paletteram.u16[offset]; palette_set_color_rgb(space->machine(), offset, pal5bit(~newword >> 10), pal5bit(~newword >> 0), pal5bit(~newword >> 5)); } /************************************* * * Video RAM writes * *************************************/ WRITE16_HANDLER( mcr68_videoram_w ) { mcr68_state *state = space->machine().driver_data(); UINT16 *videoram = state->m_videoram; COMBINE_DATA(&videoram[offset]); tilemap_mark_tile_dirty(state->m_bg_tilemap, offset / 2); } WRITE16_HANDLER( zwackery_videoram_w ) { mcr68_state *state = space->machine().driver_data(); UINT16 *videoram = state->m_videoram; COMBINE_DATA(&videoram[offset]); tilemap_mark_tile_dirty(state->m_bg_tilemap, offset); tilemap_mark_tile_dirty(state->m_fg_tilemap, offset); } WRITE16_HANDLER( zwackery_spriteram_w ) { mcr68_state *state = space->machine().driver_data(); /* yech -- Zwackery relies on the upper 8 bits of a spriteram read being $ff! */ /* to make this happen we always write $ff in the upper 8 bits */ COMBINE_DATA(&state->m_spriteram[offset]); state->m_spriteram[offset] |= 0xff00; } /************************************* * * Sprite update * *************************************/ static void mcr68_update_sprites(running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect, int priority) { mcr68_state *state = machine.driver_data(); rectangle sprite_clip = machine.primary_screen->visible_area(); UINT16 *spriteram16 = state->m_spriteram; int offs; /* adjust for clipping */ sprite_clip.min_x += state->m_sprite_clip; sprite_clip.max_x -= state->m_sprite_clip; sect_rect(&sprite_clip, cliprect); bitmap_fill(machine.priority_bitmap,&sprite_clip,1); /* loop over sprite RAM */ for (offs = state->m_spriteram_size / 2 - 4;offs >= 0;offs -= 4) { int code, color, flipx, flipy, x, y, flags; flags = LOW_BYTE(spriteram16[offs + 1]); code = LOW_BYTE(spriteram16[offs + 2]) + 256 * ((flags >> 3) & 0x01) + 512 * ((flags >> 6) & 0x03); /* skip if zero */ if (code == 0) continue; /* also skip if this isn't the priority we're drawing right now */ if (((flags >> 2) & 1) != priority) continue; /* extract the bits of information */ color = ~flags & 0x03; flipx = flags & 0x10; flipy = flags & 0x20; x = LOW_BYTE(spriteram16[offs + 3]) * 2 + state->m_sprite_xoffset; y = (241 - LOW_BYTE(spriteram16[offs])) * 2; /* allow sprites to clip off the left side */ if (x > 0x1f0) x -= 0x200; /* sprites use color 0 for background pen and 8 for the 'under tile' pen. The color 8 is used to cover over other sprites. */ /* first draw the sprite, visible */ pdrawgfx_transmask(bitmap, &sprite_clip, machine.gfx[1], code, color, flipx, flipy, x, y, machine.priority_bitmap, 0x00, 0x0101); /* then draw the mask, behind the background but obscuring following sprites */ pdrawgfx_transmask(bitmap, &sprite_clip, machine.gfx[1], code, color, flipx, flipy, x, y, machine.priority_bitmap, 0x02, 0xfeff); } } static void zwackery_update_sprites(running_machine &machine, bitmap_t *bitmap, const rectangle *cliprect, int priority) { mcr68_state *state = machine.driver_data(); UINT16 *spriteram16 = state->m_spriteram; int offs; bitmap_fill(machine.priority_bitmap,cliprect,1); /* loop over sprite RAM */ for (offs = state->m_spriteram_size / 2 - 4;offs >= 0;offs -= 4) { int code, color, flipx, flipy, x, y, flags; /* get the code and skip if zero */ code = LOW_BYTE(spriteram16[offs + 2]); if (code == 0) continue; /* extract the flag bits and determine the color */ flags = LOW_BYTE(spriteram16[offs + 1]); color = ((~flags >> 2) & 0x0f) | ((flags & 0x02) << 3); /* for low priority, draw everything but color 7 */ if (!priority) { if (color == 7) continue; } /* for high priority, only draw color 7 */ else { if (color != 7) continue; } /* determine flipping and coordinates */ flipx = ~flags & 0x40; flipy = flags & 0x80; x = (231 - LOW_BYTE(spriteram16[offs + 3])) * 2; y = (241 - LOW_BYTE(spriteram16[offs])) * 2; if (x <= -32) x += 512; /* sprites use color 0 for background pen and 8 for the 'under tile' pen. The color 8 is used to cover over other sprites. */ /* first draw the sprite, visible */ pdrawgfx_transmask(bitmap, cliprect, machine.gfx[1], code, color, flipx, flipy, x, y, machine.priority_bitmap, 0x00, 0x0101); /* then draw the mask, behind the background but obscuring following sprites */ pdrawgfx_transmask(bitmap, cliprect, machine.gfx[1], code, color, flipx, flipy, x, y, machine.priority_bitmap, 0x02, 0xfeff); } } /************************************* * * General MCR/68k update * *************************************/ SCREEN_UPDATE( mcr68 ) { mcr68_state *state = screen->machine().driver_data(); /* draw the background */ tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, TILEMAP_DRAW_OPAQUE | TILEMAP_DRAW_ALL_CATEGORIES, 0); /* draw the low-priority sprites */ mcr68_update_sprites(screen->machine(), bitmap, cliprect, 0); /* redraw tiles with priority over sprites */ tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 1, 0); /* draw the high-priority sprites */ mcr68_update_sprites(screen->machine(), bitmap, cliprect, 1); return 0; } SCREEN_UPDATE( zwackery ) { mcr68_state *state = screen->machine().driver_data(); /* draw the background */ tilemap_draw(bitmap, cliprect, state->m_bg_tilemap, 0, 0); /* draw the low-priority sprites */ zwackery_update_sprites(screen->machine(), bitmap, cliprect, 0); /* redraw tiles with priority over sprites */ tilemap_draw(bitmap, cliprect, state->m_fg_tilemap, 1, 0); /* draw the high-priority sprites */ zwackery_update_sprites(screen->machine(), bitmap, cliprect, 1); return 0; }