// license:BSD-3-Clause // copyright-holders:Nicola Salmoria, David Haywood // Video System Sprites (type 2) // todo: // move various vsystem sprite functions here // unify common ones + convert to device // this is probably the VS 8904/8905 combo // Spinal Breakers // Power Spikes // Karate Blazers // Turbo Force // Aero Fighters (older hardware types) // World Beach Championships 97 (modern Power Spikes bootleg, not original hw) // Welltris // Formula 1 Grand Prix (1) // Pipe Dream // there were lots of comments saying drivers using the // static const uint8_t zoomtable[16] = { 0,7,14,20,25,30,34,38,42,46,49,52,54,57,59,61 }; // table for zooming needed upgrading, are we sure this isn't one of the // differences between this sprite chip and the one in vsystem_spr.c, pspikes zooming is very rough #include "emu.h" #include "vsystem_spr2.h" DEFINE_DEVICE_TYPE(VSYSTEM_SPR2, vsystem_spr2_device, "vsystem2_spr", "Video System VS8904/VS8905 Sprites") vsystem_spr2_device::vsystem_spr2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, VSYSTEM_SPR2, tag, owner, clock) , m_newtilecb(*this, DEVICE_SELF, FUNC(vsystem_spr2_device::tile_callback_noindirect)) , m_pritype(0) // hack until we have better handling , m_gfx_region(0) , m_xoffs(0) , m_yoffs(0) , m_curr_sprite() , m_gfxdecode(*this, finder_base::DUMMY_TAG) { } uint32_t vsystem_spr2_device::tile_callback_noindirect(uint32_t tile) { return tile; } void vsystem_spr2_device::device_start() { // bind our handler m_newtilecb.resolve(); } void vsystem_spr2_device::device_reset() { } bool vsystem_spr2_device::sprite_attributes::get(uint16_t const *ram) { // sprite is disabled if (!(ram[2] & 0x0080)) return false; oy = (ram[0] & 0x01ff); zoomy = (ram[0] & 0xf000) >> 12; ox = (ram[1] & 0x01ff); zoomx = (ram[1] & 0xf000) >> 12; xsize = (ram[2] & 0x0700) >> 8; flipx = (ram[2] & 0x0800); ysize = (ram[2] & 0x7000) >> 12; flipy = (ram[2] & 0x8000); color = (ram[2] & 0x000f); pri = (ram[2] & 0x0010); map = (ram[3]); return true; } void vsystem_spr2_device::sprite_attributes::handle_xsize_map_inc() { if (xsize == 2) map += 1; if (xsize == 4) map += 3; if (xsize == 5) map += 2; if (xsize == 6) map += 1; } template void vsystem_spr2_device::turbofrc_draw_sprites_common(uint16_t const *spriteram3, int spriteram3_bytes, int spritepalettebank, BitmapClass &bitmap, const rectangle &cliprect, bitmap_ind8 &priority_bitmap, int pri_param, bool flip_screen) { int attr_start, first; first = 4 * spriteram3[0x1fe]; first &= 0x1ff; if (first>0x200-4) first = 0x200-4; int start,end,inc; if (m_pritype == 0 || m_pritype == 1 || m_pritype == 2) // prdrawgfx cases { start = 0x200 - 8; end = first-4; inc = -4; } else // drawgfx cases { start = first; end = 0x200 -4; inc = 4; } for (attr_start = start; attr_start != end; attr_start += inc) { int x, y; if (!m_curr_sprite.get(&spriteram3[attr_start])) continue; // pipedrm m_curr_sprite.ox += m_xoffs; m_curr_sprite.oy += m_yoffs; int usepri = 0; // these are still calling the function multiple times to filter out priorities, even if some are also using pdrawgfx(!) if (m_pritype == 0 || m_pritype == 1 || m_pritype == 3) // turbo force, spinlbrk, pipedrm etc. { if ((m_curr_sprite.pri>>4) != pri_param) continue; } if (m_pritype == 0) // turbo force etc. { usepri = m_curr_sprite.pri ? 0 : 2; } else if (m_pritype == 1) // spinlbrk { usepri = m_curr_sprite.pri ? 2 : 0; } else if (m_pritype == 2) // f1gp { usepri = pri_param; } bool fx = m_curr_sprite.flipx != 0; bool fy = m_curr_sprite.flipy != 0; if (flip_screen) { m_curr_sprite.ox = 308 - m_curr_sprite.ox; m_curr_sprite.oy = 208 - m_curr_sprite.oy; fx = !fx; fy = !fy; } m_curr_sprite.color += 16 * spritepalettebank; m_curr_sprite.zoomx = 32 - m_curr_sprite.zoomx; m_curr_sprite.zoomy = 32 - m_curr_sprite.zoomy; for (y = 0; y <= m_curr_sprite.ysize; y++) { int cy = m_curr_sprite.flipy ? (m_curr_sprite.ysize - y) : y; int sy = ((m_curr_sprite.oy + m_curr_sprite.zoomy * (flip_screen ? -cy : cy) / 2 + 16) & 0x1ff) - 16; for (x = 0; x <= m_curr_sprite.xsize; x++) { int cx = m_curr_sprite.flipx ? (m_curr_sprite.xsize - x) : x; int sx = ((m_curr_sprite.ox + m_curr_sprite.zoomx * (flip_screen ? -cx : cx) / 2 + 16) & 0x1ff) - 16; int curr = m_newtilecb(m_curr_sprite.map++); if (m_pritype == 0 || m_pritype == 1 || m_pritype == 2) // pdrawgfx cases { m_gfxdecode->gfx(m_gfx_region)->prio_zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x000,sy-0x000, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap,usepri,15); m_gfxdecode->gfx(m_gfx_region)->prio_zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x200,sy-0x000, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap,usepri,15); m_gfxdecode->gfx(m_gfx_region)->prio_zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x000,sy-0x200, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap,usepri,15); m_gfxdecode->gfx(m_gfx_region)->prio_zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x200,sy-0x200, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap,usepri,15); } else // drawgfx cases (welltris, pipedrm) { m_gfxdecode->gfx(m_gfx_region)->zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x000,sy-0x000, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11,15); m_gfxdecode->gfx(m_gfx_region)->zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x200,sy-0x000, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11,15); m_gfxdecode->gfx(m_gfx_region)->zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x000,sy-0x200, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11,15); m_gfxdecode->gfx(m_gfx_region)->zoom_transpen(bitmap,cliprect, curr, m_curr_sprite.color, fx, fy, sx-0x200,sy-0x200, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11,15); } } m_curr_sprite.handle_xsize_map_inc(); } } } void vsystem_spr2_device::turbofrc_draw_sprites(uint16_t const *spriteram3, int spriteram3_bytes, int spritepalettebank, bitmap_ind16 &bitmap, const rectangle &cliprect, bitmap_ind8 &priority_bitmap, int pri_param, bool flip_screen) { turbofrc_draw_sprites_common(spriteram3, spriteram3_bytes, spritepalettebank, bitmap, cliprect, priority_bitmap, pri_param, flip_screen); } void vsystem_spr2_device::turbofrc_draw_sprites(uint16_t const *spriteram3, int spriteram3_bytes, int spritepalettebank, bitmap_rgb32 &bitmap, const rectangle &cliprect, bitmap_ind8 &priority_bitmap, int pri_param, bool flip_screen) { turbofrc_draw_sprites_common(spriteram3, spriteram3_bytes, spritepalettebank, bitmap, cliprect, priority_bitmap, pri_param, flip_screen); }