// license:BSD-3-Clause // copyright-holders:Bryan McPhail /*************************************************************************** Rohga Video emulation - Bryan McPhail, mish@tendril.co.uk ***************************************************************************/ #include "emu.h" #include "includes/rohga.h" #include "screen.h" WRITE16_MEMBER(rohga_state::rohga_buffer_spriteram16_w) { // Spriteram seems to be triple buffered (no sprite lag on real pcb, but there // is on driver with only double buffering) m_spriteram[0]->copy(); } /******************************************************************************/ uint32_t rohga_state::screen_update_rohga(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { address_space &space = machine().dummy_space(); uint16_t flip = m_deco_tilegen[0]->pf_control_r(space, 0, 0xffff); uint16_t priority = m_decocomn->priority_r(); // sprites are flipped relative to tilemaps flip_screen_set(BIT(flip, 7)); m_sprgen[0]->set_flip_screen(!BIT(flip, 7)); /* Update playfields */ m_deco_tilegen[0]->pf_update(m_pf_rowscroll[0], m_pf_rowscroll[1]); m_deco_tilegen[1]->pf_update(m_pf_rowscroll[2], m_pf_rowscroll[3]); /* Draw playfields */ screen.priority().fill(0, cliprect); bitmap.fill(m_palette->pen(768), cliprect); switch (priority & 3) { case 0: if (priority & 4) { // Draw as 1 8BPP layer m_deco_tilegen[1]->tilemap_12_combine_draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 3); } else { // Draw as 2 4BPP layers m_deco_tilegen[1]->tilemap_2_draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 1); m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 2); } m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 4); break; case 1: m_deco_tilegen[1]->tilemap_2_draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 1); m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 2); m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 4); break; case 2: m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0/*TILEMAP_DRAW_OPAQUE*/, 1); m_deco_tilegen[1]->tilemap_2_draw(screen, bitmap, cliprect, 0, 2); m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 4); break; } m_sprgen[0]->draw_sprites(bitmap, cliprect, m_spriteram[0]->buffer(), 0x400); m_deco_tilegen[0]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0); return 0; } VIDEO_START_MEMBER(rohga_state,wizdfire) { m_sprgen[0]->alloc_sprite_bitmap(); m_sprgen[1]->alloc_sprite_bitmap(); } // not amazingly efficient, called multiple times to pull a layer out of the sprite bitmaps, but keeps correct sprite<->sprite priorities void rohga_state::mixwizdfirelayer(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t pri, uint16_t primask) { int y, x; const pen_t *paldata = m_palette->pens(); bitmap_ind16* sprite_bitmap; int penbase; sprite_bitmap = &m_sprgen[1]->get_sprite_temp_bitmap(); penbase = 0x600; uint16_t* srcline; uint32_t* dstline; for (y=cliprect.min_y;y<=cliprect.max_y;y++) { srcline=&sprite_bitmap->pix16(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.min_x;x<=cliprect.max_x;x++) { uint16_t pix = srcline[x]; if ((pix & primask) != pri) continue; if (pix&0xf) { uint16_t pen = pix&0x1ff; if (pen&0x100) { uint32_t base = dstline[x]; pen &=0xff; dstline[x] = alpha_blend_r32(base, paldata[pen+penbase], 0x80); } else { dstline[x] = paldata[pen+penbase]; } } } } } uint32_t rohga_state::screen_update_wizdfire(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { address_space &space = machine().dummy_space(); uint16_t flip = m_deco_tilegen[0]->pf_control_r(space, 0, 0xffff); uint16_t priority = m_decocomn->priority_r(); // sprites are flipped relative to tilemaps flip_screen_set(BIT(flip, 7)); m_sprgen[0]->set_flip_screen(!BIT(flip, 7)); m_sprgen[1]->set_flip_screen(!BIT(flip, 7)); /* draw sprite gfx to temp bitmaps */ m_sprgen[1]->draw_sprites(bitmap, cliprect, m_spriteram[1]->buffer(), 0x400); m_sprgen[0]->draw_sprites(bitmap, cliprect, m_spriteram[0]->buffer(), 0x400); /* Update playfields */ m_deco_tilegen[0]->pf_update(nullptr, nullptr); m_deco_tilegen[1]->pf_update(m_pf_rowscroll[2], m_pf_rowscroll[3]); /* Draw playfields - Palette of 2nd playfield chip visible if playfields turned off */ bitmap.fill(m_palette->pen(512), cliprect); m_deco_tilegen[1]->tilemap_2_draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0); m_sprgen[0]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0600, 0x0600, 0x400, 0x1ff); m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 0); m_sprgen[0]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0400, 0x0600, 0x400, 0x1ff); if ((priority & 0x1f) == 0x1f) /* Wizdfire has bit 0x40 always set, Dark Seal 2 doesn't?! */ m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, TILEMAP_DRAW_ALPHA(0x80), 0); else m_deco_tilegen[1]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0); m_sprgen[0]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0000, 0x0400, 0x400, 0x1ff); // 0x000 and 0x200 of 0x600 mixwizdfirelayer(bitmap, cliprect, 0x000, 0x000); m_deco_tilegen[0]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0); return 0; } void rohga_state::mixnitroballlayer(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { int y, x; const pen_t *paldata = &m_palette->pen(0); bitmap_ind16 *sprite_bitmap1, *sprite_bitmap2; bitmap_ind8* priority_bitmap; uint16_t priority = m_decocomn->priority_r(); sprite_bitmap1 = &m_sprgen[0]->get_sprite_temp_bitmap(); sprite_bitmap2 = &m_sprgen[1]->get_sprite_temp_bitmap(); priority_bitmap = &screen.priority(); uint32_t* dstline; uint16_t *srcline1, *srcline2; uint8_t *srcpriline; for (y=cliprect.min_y;y<=cliprect.max_y;y++) { srcline1=&sprite_bitmap1->pix16(y,0); srcline2=&sprite_bitmap2->pix16(y,0); srcpriline=&priority_bitmap->pix8(y,0); dstline=&bitmap.pix32(y,0); for (x=cliprect.min_x;x<=cliprect.max_x;x++) { uint16_t pix1 = srcline1[x]; uint16_t pix2 = srcline2[x]; /* Here we have pix1 - raw pixel / colour / priority data from first 1st chip pix2 - raw pixel / colour / priority data from first 2nd chip */ int pri1, pri2; // pix1 sprite vs playfield switch (priority) // TODO : Verify this from real pcb { case 0x00: default: { switch (pix1 & 0xe00) { case 0x000: default: pri1 = 0x200; break; case 0x200: pri1 = 0x020; break; case 0x400: pri1 = 0x008; break; case 0x600: pri1 = 0x002; break; case 0x800: pri1 = 0x100; break; case 0xa00: pri1 = 0x040; break; case 0xc00: pri1 = 0x004; break; case 0xe00: pri1 = 0x001; break; } } break; case 0x20: { switch (pix1 & 0xe00) { case 0x000: default: pri1 = 0x080; break; case 0x200: pri1 = 0x004; break; case 0x400: pri1 = 0x002; break; case 0x600: pri1 = 0x001; break; case 0x800: pri1 = 0x100; break; case 0xa00: pri1 = 0x020; break; case 0xc00: pri1 = 0x008; break; case 0xe00: pri1 = 0x200; break; } } break; } // pix2 sprite vs pix1 sprite pri2 = 0x080; switch (priority) { case 0x00: default: pri2 = 0x080; break; case 0x20: pri2 = 0x010; break; } uint8_t bgpri = srcpriline[x]; /* once we get here we have pri1 - 0x001/0x002/0x004/0x008/0x010/0x020/0x040/0x080/0x100/0x200 (sprite chip 1 pixel priority relative to bg) pri2 - 0x080/0x010 (sprite chip 2 pixel priority relative to bg) bgpri - 0x008/0x040 (from drawing tilemaps earlier, to compare above pri1/pri2 priorities against) pix1 - same as before (ready to extract just colour data from) pix2 - same as before ^^ */ int drawnpixe1 = 0; if (pix1 & 0xf) { if (pri1 > bgpri) { dstline[x] = paldata[(pix1&0x1ff)+0x400]; drawnpixe1 = 1; } } if (pix2 & 0xf) { if (pri2 > bgpri) { if ((!drawnpixe1) || (pri2 > pri1)) { if (pix2 & 0x100) { uint32_t base = dstline[x]; dstline[x] = alpha_blend_r32(base, paldata[(pix2&0xff)+0x600], 0x80); } else { dstline[x] = paldata[(pix2&0xff)+0x600]; } } } } } } } uint32_t rohga_state::screen_update_nitrobal(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { address_space &space = machine().dummy_space(); uint16_t flip = m_deco_tilegen[0]->pf_control_r(space, 0, 0xffff); uint16_t priority = m_decocomn->priority_r(); flip_screen_set(BIT(flip, 7)); m_sprgen[0]->set_flip_screen(BIT(flip, 7)); m_sprgen[1]->set_flip_screen(BIT(flip, 7)); /* draw sprite gfx to temp bitmaps */ m_sprgen[0]->set_alt_format(true); m_sprgen[1]->set_alt_format(true); m_sprgen[1]->draw_sprites(bitmap, cliprect, m_spriteram[1]->buffer(), 0x400); m_sprgen[0]->draw_sprites(bitmap, cliprect, m_spriteram[0]->buffer(), 0x400); /* Update playfields */ m_deco_tilegen[0]->pf_update(m_pf_rowscroll[0], m_pf_rowscroll[1]); m_deco_tilegen[1]->pf_update(m_pf_rowscroll[2], m_pf_rowscroll[3]); /* Draw playfields - Palette of 2nd playfield chip visible if playfields turned off */ bitmap.fill(m_palette->pen(512), cliprect); screen.priority().fill(0); /* pf3 and pf4 are combined into a single 8bpp bitmap */ m_deco_tilegen[1]->tilemap_12_combine_draw(screen, bitmap, cliprect, TILEMAP_DRAW_OPAQUE, 0); switch (priority) { case 0: default: m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 0x008); break; case 0x20: m_deco_tilegen[0]->tilemap_2_draw(screen, bitmap, cliprect, 0, 0x040); break; } /* TODO verify priorities + mixing / alpha */ mixnitroballlayer(screen,bitmap,cliprect); m_deco_tilegen[0]->tilemap_1_draw(screen, bitmap, cliprect, 0, 0); return 0; }