// license:BSD-3-Clause // copyright-holders:Luca Elia /*************************************************************************** orca40c.cpp ORCA OVG-40c GFX board used by at least: * all games in zodiack.cpp * dogfightp in vastar.cpp ***************************************************************************/ #include "emu.h" #include "video/orca40c.h" #include "emupal.h" #include "screen.h" #define PIXEL_CLOCK (XTAL(18'432'000)/3) #define HTOTAL (396) #define HBEND (0) #define HBSTART (256) #define VTOTAL (256) #define VBEND (16) #define VBSTART (240) DEFINE_DEVICE_TYPE(ORCA_OVG_40C, orca_ovg_40c_device, "orca_ovg_40c", "Orca OVG 40c video PCB") orca_ovg_40c_device::orca_ovg_40c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ORCA_OVG_40C, tag, owner, clock), device_gfx_interface(mconfig, *this, nullptr, "palette"), device_video_interface(mconfig, *this), m_videoram(*this, "videoram"), m_videoram_2(*this,"videoram_2"), m_attributeram(*this, "attributeram"), m_spriteram(*this, "spriteram"), m_bulletsram(*this, "bulletsram"), m_percuss_hardware(false), m_flip_screen(false) { } /************************************* * * Graphics definitions * *************************************/ static const gfx_layout charlayout = { 8,8, /* 8*8 chars */ 256, /* 256 characters */ 1, /* 1 bit per pixel */ { 0 } , /* single bitplane */ { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, 8*8 /* every char takes 8 consecutive bytes */ }; static const gfx_layout charlayout_2 = { 8,8, /* 8*8 chars */ 256, /* 256 characters */ 2, /* 2 bits per pixel */ { 0, 512*8*8 }, /* The bitplanes are separate */ { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, 8*8 /* every char takes 8 consecutive bytes */ }; static const gfx_layout spritelayout = { 16,16, /* 16*16 sprites */ 64, /* 64 sprites */ 2, /* 2 bits per pixel */ { 0, 128*32*8 }, /* the two bitplanes are separated */ { 0, 1, 2, 3, 4, 5, 6, 7, 8*8+0, 8*8+1, 8*8+2, 8*8+3, 8*8+4, 8*8+5, 8*8+6, 8*8+7 }, { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 16*8, 17*8, 18*8, 19*8, 20*8, 21*8, 22*8, 23*8 }, 32*8 /* every sprite takes 32 consecutive bytes */ }; static const gfx_layout bulletlayout = { /* there is no gfx ROM for this one, it is generated by the hardware */ 7,1, /* it's just 1 pixel, but we use 7*1 to position it correctly */ 1, /* just one */ 1, /* 1 bit per pixel */ { 10*8*8 }, /* point to letter "A" */ { 3, 7, 7, 7, 7, 7, 7 }, /* I "know" that this bit of the */ { 1*8 }, /* graphics ROMs is 1 */ 0 /* no use */ }; GFXDECODE_MEMBER(orca_ovg_40c_device::gfxinfo) GFXDECODE_DEVICE( DEVICE_SELF, 0x0000, charlayout, 8*4 , 8 ) GFXDECODE_DEVICE( DEVICE_SELF, 0x0800, spritelayout, 0 , 8 ) GFXDECODE_DEVICE( DEVICE_SELF, 0x0000, bulletlayout, 8*4+8*2, 1 ) GFXDECODE_DEVICE( DEVICE_SELF, 0x1000, charlayout_2, 0 , 8 ) GFXDECODE_END //------------------------------------------------- // device_start: Start up the device //------------------------------------------------- void orca_ovg_40c_device::device_start() { decode_gfx(gfxinfo); m_bg_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(orca_ovg_40c_device::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32); m_fg_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(*this, FUNC(orca_ovg_40c_device::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32); m_fg_tilemap->set_transparent_pen(0); m_fg_tilemap->set_scroll_cols(32); save_item(NAME(m_flip_screen)); } WRITE8_MEMBER(orca_ovg_40c_device::videoram_w) { m_videoram[offset] = data; m_fg_tilemap->mark_tile_dirty(offset); } WRITE8_MEMBER(orca_ovg_40c_device::videoram2_w) { m_videoram_2[offset] = data; m_bg_tilemap->mark_tile_dirty(offset); } WRITE8_MEMBER(orca_ovg_40c_device::attributes_w) { if ((offset & 1) && m_attributeram[offset] != data) { int i; for (i = offset / 2; i < m_videoram.bytes(); i += 32) { m_bg_tilemap->mark_tile_dirty(i); m_fg_tilemap->mark_tile_dirty(i); } } m_attributeram[offset] = data; } WRITE8_MEMBER(orca_ovg_40c_device::flipscreen_w) { m_flip_screen = ~data & 1; m_bg_tilemap->set_flip(m_flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0); m_fg_tilemap->set_flip(m_flip_screen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0); } void orca_ovg_40c_device::palette_init(palette_device &palette) { const uint8_t *color_prom = memregion("proms")->base(); /* create a lookup table for the palette */ for (int i = 0; i < 0x30; i++) { /* red component */ int bit0 = (color_prom[i] >> 0) & 0x01; int bit1 = (color_prom[i] >> 1) & 0x01; int bit2 = (color_prom[i] >> 2) & 0x01; int r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; /* green component */ bit0 = (color_prom[i] >> 3) & 0x01; bit1 = (color_prom[i] >> 4) & 0x01; bit2 = (color_prom[i] >> 5) & 0x01; int g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; /* blue component */ bit0 = 0; bit1 = (color_prom[i] >> 6) & 0x01; bit2 = (color_prom[i] >> 7) & 0x01; int b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2; palette.set_indirect_color(i, rgb_t(r, g, b)); } /* white for bullets */ palette.set_indirect_color(0x30, rgb_t::white()); for (int i = 0; i < 0x20; i++) palette.set_pen_indirect(i, (i & 3) ? i : 0); for (int i = 0; i < 0x10; i += 2) { palette.set_pen_indirect(0x20 + i, 32 + (i / 2)); palette.set_pen_indirect(0x21 + i, 40 + (i / 2)); } /* bullet */ palette.set_pen_indirect(0x30, 0); palette.set_pen_indirect(0x31, 0x30); } TILE_GET_INFO_MEMBER(orca_ovg_40c_device::get_bg_tile_info) { int code = m_videoram_2[tile_index]; int color = (m_attributeram[(tile_index & 0x1f) << 1 | 1] >> 4) & 0x07; SET_TILE_INFO_MEMBER(0, code, color, 0); } TILE_GET_INFO_MEMBER(orca_ovg_40c_device::get_fg_tile_info) { int code = m_videoram[tile_index]; int color = (m_attributeram[(tile_index & 0x1f) << 1 | 1] >> 0) & 0x07; SET_TILE_INFO_MEMBER(3, code, color, 0); } void orca_ovg_40c_device::draw_bullets( bitmap_rgb32 &bitmap, const rectangle &cliprect ) { for (int offs = 0; offs < m_bulletsram.bytes(); offs += 4) { int sx = m_bulletsram[offs + 3] + 7; int sy = m_bulletsram[offs + 1]; if (!(m_flip_screen && m_percuss_hardware)) sy = 255 - sy; gfx(2)->transpen( bitmap, cliprect, 0, /* this is just a dot, generated by the hardware */ 0, 0, 0, sx, sy, 0); } } void orca_ovg_40c_device::draw_sprites( bitmap_rgb32 &bitmap, const rectangle &cliprect ) { for (int offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4) { int sx = 240 - m_spriteram[offs + 3]; int sy = 240 - m_spriteram[offs]; int flipx = !(m_spriteram[offs + 1] & 0x40); int flipy = m_spriteram[offs + 1] & 0x80; int spritecode = m_spriteram[offs + 1] & 0x3f; if (m_flip_screen && m_percuss_hardware) { sy = 240 - sy; flipy = !flipy; } gfx(1)->transpen(bitmap,cliprect, spritecode, m_spriteram[offs + 2] & 0x07, flipx, flipy, sx, sy, 0); } } uint32_t orca_ovg_40c_device::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ) { for (int i = 0; i < 32; i++) m_fg_tilemap->set_scrolly(i, m_attributeram[i * 2]); m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0); draw_bullets(bitmap, cliprect); draw_sprites(bitmap, cliprect); return 0; } void orca_ovg_40c_device::device_config_complete() { if (!has_screen()) return; if (!screen().refresh_attoseconds()) screen().set_raw(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, VBSTART); if (!screen().has_screen_update()) screen().set_screen_update(*this, FUNC(orca_ovg_40c_device::screen_update)); } void orca_ovg_40c_device::device_add_mconfig(machine_config &config) { PALETTE(config, "palette", FUNC(orca_ovg_40c_device::palette_init), 4*8+2*8+2*1, 48+1); }