summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/ladybug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/ladybug.cpp')
-rw-r--r--src/mame/video/ladybug.cpp429
1 files changed, 348 insertions, 81 deletions
diff --git a/src/mame/video/ladybug.cpp b/src/mame/video/ladybug.cpp
index 7228eb78b32..eb280f142bd 100644
--- a/src/mame/video/ladybug.cpp
+++ b/src/mame/video/ladybug.cpp
@@ -9,9 +9,232 @@
***************************************************************************/
#include "emu.h"
-#include "video/resnet.h"
+#include "ladybug.h"
#include "includes/ladybug.h"
+#include "video/resnet.h"
+
+#include <algorithm>
+
+
+DEFINE_DEVICE_TYPE(LADYBUG_VIDEO, ladybug_video_device, "ladybug_video", "Lady Bug/Space Raider background")
+DEFINE_DEVICE_TYPE(ZEROHOUR_STARS, zerohour_stars_device, "zerohour_stars", "Zero Hour/Red Clash/Space Raider starfield")
+
+
+/***************************************************************************
+
+ ladybug/sraider video
+
+***************************************************************************/
+
+ladybug_video_device::ladybug_video_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, LADYBUG_VIDEO, tag, owner, clock)
+ , m_gfxdecode(*this, finder_base::DUMMY_TAG)
+ , m_spr_ram()
+ , m_bg_ram()
+ , m_bg_tilemap(nullptr)
+{
+}
+
+WRITE8_MEMBER(ladybug_video_device::bg_w)
+{
+ m_bg_ram[offset & 0x07ff] = data;
+ m_bg_tilemap->mark_tile_dirty(offset & 0x03ff);
+}
+
+void ladybug_video_device::draw(screen_device &screen, bitmap_ind16 &bitmap, rectangle const &cliprect, bool flip)
+{
+ // TODO: confirm whether sraider hardware actually does this - not used by the game
+ for (unsigned offs = 0; offs < 32; ++offs)
+ {
+ int const scroll = m_bg_ram[((offs & 0x03) << 5) | (offs >> 2)];
+ m_bg_tilemap->set_scrollx(offs, flip ? -scroll : scroll);
+ }
+
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 0);
+
+ for (int offs = 0x400 - (0x40 << 1); (0x40 << 1) <= offs; offs -= 0x40)
+ {
+ int i = 0;
+ while ((0x40 > i) && m_spr_ram[offs + i])
+ i += 4;
+
+ while (0 < i)
+ {
+ /*
+ abccdddd eeeeeeee fffghhhh iiiiiiii
+
+ a enable?
+ b size (0 = 8x8, 1 = 16x16)
+ cc flip
+ dddd y offset
+ eeeeeeee sprite code (shift right 2 bits for 16x16 sprites)
+ fff unknown
+ g sprite bank
+ hhhh color
+ iiiiiiii x position
+ */
+ i -= 4;
+ bool const enable(m_spr_ram[offs + i] & 0x80);
+ if (enable)
+ {
+ bool const big(m_spr_ram[offs + i] & 0x40);
+ bool const xflip(m_spr_ram[offs + i] & 0x20);
+ bool const yflip(m_spr_ram[offs + i] & 0x10);
+ int const code(m_spr_ram[offs + i + 1] | (BIT(m_spr_ram[offs + i + 2], 4) << 8));
+ int const color(m_spr_ram[offs + i + 2] & 0x0f);
+ int const xpos(m_spr_ram[offs + i + 3]);
+ int const ypos((offs >> 2) | (m_spr_ram[offs + i] & 0x0f));
+ if (big) // 16x16
+ m_gfxdecode->gfx(1)->transpen(bitmap, cliprect, code >> 2, color, xflip, yflip, xpos, ypos - 8, 0);
+ else // 8x8
+ m_gfxdecode->gfx(2)->transpen(bitmap, cliprect, code, color, xflip, yflip, xpos, ypos, 0);
+ }
+ }
+ }
+}
+
+void ladybug_video_device::device_start()
+{
+ m_spr_ram = std::make_unique<u8 []>(0x0400);
+ m_bg_ram = std::make_unique<u8 []>(0x0800);
+ std::fill_n(m_spr_ram.get(), 0x0800, 0);
+ std::fill_n(m_bg_ram.get(), 0x0800, 0);
+
+ m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ladybug_video_device::get_bg_tile_info), this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
+ m_bg_tilemap->set_scroll_rows(32);
+ m_bg_tilemap->set_transparent_pen(0);
+
+ save_pointer(NAME(m_spr_ram.get()), 0x0400);
+ save_pointer(NAME(m_bg_ram.get()), 0x0800);
+}
+
+TILE_GET_INFO_MEMBER(ladybug_video_device::get_bg_tile_info)
+{
+ int const code = m_bg_ram[tile_index] + (BIT(m_bg_ram[0x0400 | tile_index], 3) << 8);
+ int const color = m_bg_ram[0x0400 | tile_index] & 0x07;
+
+ SET_TILE_INFO_MEMBER(0, code, color, 0);
+}
+
+
+/***************************************************************************
+
+ zerohour/redclash/sraider stars
+
+ These functions emulate the star generator board
+ All this comes from the schematics for Zero Hour
+
+ It has a 17-bit LFSR which has a period of 2^17-1 clocks
+ (This is one pixel shy of "two screens" worth.)
+ So, there are two starfields drawn on alternate frames
+ These will scroll at a rate controlled by the speed register
+
+ I'm basically doing the same thing by drawing each
+ starfield on alternate frames, and then offseting them
+
+***************************************************************************/
+
+zerohour_stars_device::zerohour_stars_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, ZEROHOUR_STARS, tag, owner, clock)
+ , m_enable(0)
+ , m_speed(0)
+ , m_offset(0)
+ , m_count(0)
+{
+}
+
+// This line can reset the LFSR to zero and disables the star generator
+void zerohour_stars_device::set_enable(bool on)
+{
+ if (!m_enable && on)
+ m_offset = 0;
+
+ m_enable = on ? 1 : 0;
+}
+
+// This sets up which starfield to draw and the offset, to be called from screen_vblank_*()
+void zerohour_stars_device::update_state()
+{
+ if (m_enable)
+ {
+ m_count = m_count ? 0 : 1;
+ if (!m_count)
+ {
+ m_offset += ((m_speed * 2) - 0x09);
+ m_offset %= 256 * 256;
+ m_state = 0;
+ }
+ else
+ {
+ m_state = 0x1fc71;
+ }
+ }
+}
+
+// Set the speed register (3 bits)
+void zerohour_stars_device::set_speed(u8 speed, u8 mask)
+{
+ // 0 left/down fastest (-9/2 pix per frame)
+ // 1 left/down faster (-7/2 pix per frame)
+ // 2 left/down fast (-5/2 pix per frame)
+ // 3 left/down medium (-3/2 pix per frame)
+ // 4 left/down slow (-1/2 pix per frame)
+ // 5 right/up slow (+1/2 pix per frame)
+ // 6 right/up medium (+3/2 pix per frame)
+ // 7 right/up fast (+5/2 pix per frame)
+ m_speed = (m_speed & ~mask) | (speed & mask);
+}
+
+// Draw the stars
+// Space Raider doesn't use the Va bit, and it is also set up to window the stars to a certain x range
+void zerohour_stars_device::draw(bitmap_ind16 &bitmap, rectangle const &cliprect, u8 pal_offs, bool has_va, u8 firstx, u8 lastx)
+{
+ if (m_enable)
+ {
+ u32 state(m_state);
+ for (int i = 0; (256 * 256) > i; ++i)
+ {
+ u8 const xloc((m_offset + i) & 0x00ff);
+ u8 const yloc(((m_offset + i) >> 8) & 0x00ff);
+
+ bool const tempbit(!(state & 0x10000));
+ bool const feedback((state & 0x00020) ? !tempbit : tempbit);
+
+ bool const hcond(BIT(xloc + 8, 4));
+ bool const vcond(!has_va || BIT(yloc, 0));
+
+ if (cliprect.contains(xloc, yloc) && (hcond == vcond))
+ {
+ if (((state & 0x000ff) == 0x000ff) && !feedback && (xloc >= firstx) && (xloc <= lastx))
+ bitmap.pix16(yloc, xloc) = pal_offs + ((state >> 9) & 0x1f);
+ }
+
+ // update LFSR state
+ state = ((state << 1) & 0x1fffe) | (feedback ? 1 : 0);
+ }
+ }
+}
+
+void zerohour_stars_device::device_start()
+{
+ save_item(NAME(m_enable));
+ save_item(NAME(m_speed));
+ save_item(NAME(m_state));
+ save_item(NAME(m_offset));
+ save_item(NAME(m_count));
+}
+
+void zerohour_stars_device::device_reset()
+{
+ m_enable = 0;
+ m_speed = 0;
+ m_state = 0;
+ m_offset = 0;
+ m_count = 0;
+}
+
+
/***************************************************************************
Convert the color PROMs into a more useable format.
@@ -30,9 +253,27 @@
bit 0 -- inverter -- 470 ohm resistor -- RED
***************************************************************************/
+/***************************************************************************
-void ladybug_state::palette_init_common( palette_device &palette, const uint8_t *color_prom,
- int r_bit0, int r_bit1, int g_bit0, int g_bit1, int b_bit0, int b_bit1 )
+ Convert the color PROMs into a more useable format.
+
+ Lady Bug has a 32 bytes palette PROM and a 32 bytes sprite color lookup
+ table PROM.
+ The palette PROM is connected to the RGB output this way:
+
+ bit 7 -- inverter -- 220 ohm resistor -- BLUE
+ -- inverter -- 220 ohm resistor -- GREEN
+ -- inverter -- 220 ohm resistor -- RED
+ -- inverter -- 470 ohm resistor -- BLUE
+ -- unused
+ -- inverter -- 470 ohm resistor -- GREEN
+ -- unused
+ bit 0 -- inverter -- 470 ohm resistor -- RED
+
+***************************************************************************/
+
+void ladybug_base_state::palette_init_common(palette_device &palette, const uint8_t *color_prom,
+ int r_bit0, int r_bit1, int g_bit0, int g_bit1, int b_bit0, int b_bit1)
{
static const int resistances[2] = { 470, 220 };
double rweights[2], gweights[2], bweights[2];
@@ -92,24 +333,12 @@ void ladybug_state::palette_init_common( palette_device &palette, const uint8_t
}
-PALETTE_INIT_MEMBER(ladybug_state,ladybug)
+PALETTE_INIT_MEMBER(ladybug_state, ladybug)
{
const uint8_t *color_prom = memregion("proms")->base();
palette_init_common(palette, color_prom, 0, 5, 2, 6, 4, 7);
}
-WRITE8_MEMBER(ladybug_state::ladybug_videoram_w)
-{
- m_videoram[offset] = data;
- m_bg_tilemap->mark_tile_dirty(offset);
-}
-
-WRITE8_MEMBER(ladybug_state::ladybug_colorram_w)
-{
- m_colorram[offset] = data;
- m_bg_tilemap->mark_tile_dirty(offset);
-}
-
WRITE_LINE_MEMBER(ladybug_state::flipscreen_w)
{
if (flip_screen() != state)
@@ -119,18 +348,57 @@ WRITE_LINE_MEMBER(ladybug_state::flipscreen_w)
}
}
-TILE_GET_INFO_MEMBER(ladybug_state::get_bg_tile_info)
+uint32_t ladybug_state::screen_update_ladybug(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+ m_video->draw(screen, bitmap, cliprect, flip_screen());
+ return 0;
+}
+
+
+PALETTE_INIT_MEMBER(sraider_state, sraider)
{
- int code = m_videoram[tile_index] + 32 * (m_colorram[tile_index] & 0x08);
- int color = m_colorram[tile_index] & 0x07;
+ const uint8_t *color_prom = memregion("proms")->base();
- SET_TILE_INFO_MEMBER(0, code, color, 0);
+ // the resistor net may be probably different than Lady Bug
+ palette_init_common(palette, color_prom, 3, 0, 5, 4, 7, 6);
+
+ // star colors
+ for (int i = 0x20; i < 0x40; i++)
+ {
+ int bit0, bit1;
+ int r, g, b;
+
+ // red component
+ bit0 = ((i - 0x20) >> 3) & 0x01;
+ bit1 = ((i - 0x20) >> 4) & 0x01;
+ b = 0x47 * bit0 + 0x97 * bit1;
+
+ // green component
+ bit0 = ((i - 0x20) >> 1) & 0x01;
+ bit1 = ((i - 0x20) >> 2) & 0x01;
+ g = 0x47 * bit0 + 0x97 * bit1;
+
+ // blue component
+ bit0 = ((i - 0x20) >> 0) & 0x01;
+ r = 0x47 * bit0;
+
+ palette.set_indirect_color(i, rgb_t(r, g, b));
+ }
+
+ for (int i = 0x60; i < 0x80; i++)
+ palette.set_pen_indirect(i, (i - 0x60) + 0x20);
+
+ // stationary part of grid
+ palette.set_pen_indirect(0x81, 0x40);
}
-TILE_GET_INFO_MEMBER(ladybug_state::get_grid_tile_info)
+TILE_GET_INFO_MEMBER(sraider_state::get_grid_tile_info)
{
if (tile_index < 512)
+ {
SET_TILE_INFO_MEMBER(3, tile_index, 0, 0);
+ }
else
{
int temp = tile_index / 32;
@@ -139,82 +407,81 @@ TILE_GET_INFO_MEMBER(ladybug_state::get_grid_tile_info)
}
}
-void ladybug_state::video_start()
+WRITE8_MEMBER(sraider_state::sraider_io_w)
{
- m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ladybug_state::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
- m_bg_tilemap->set_scroll_rows(32);
- m_bg_tilemap->set_transparent_pen(0);
-}
+ // bit7 = flip
+ // bit6 = grid red
+ // bit5 = grid green
+ // bit4 = grid blue
+ // bit3 = enable stars
+ // bit210 = stars speed/dir
+
+ if (flip_screen() != (data & 0x80))
+ {
+ flip_screen_set(data & 0x80);
+ machine().tilemap().mark_all_dirty();
+ }
-void ladybug_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
-{
- uint8_t *spriteram = m_spriteram;
- int offs;
+ m_grid_color = data & 0x70;
- for (offs = m_spriteram.bytes() - 2 * 0x40; offs >= 2 * 0x40; offs -= 0x40)
- {
- int i = 0;
+ m_stars->set_enable(BIT(data, 3));
- while (i < 0x40 && spriteram[offs + i] != 0)
- i += 4;
+ // There must be a subtle clocking difference between
+ // Space Raider and the other games using this star generator,
+ // hence the -1 here
+ m_stars->set_speed((data & 0x07) - 1, 0x07);
+}
- while (i > 0)
- {
-/*
- abccdddd eeeeeeee fffghhhh iiiiiiii
-
- a enable?
- b size (0 = 8x8, 1 = 16x16)
- cc flip
- dddd y offset
- eeeeeeee sprite code (shift right 2 bits for 16x16 sprites)
- fff unknown
- g sprite bank
- hhhh color
- iiiiiiii x position
-*/
- i -= 4;
+void sraider_state::video_start()
+{
+ ladybug_base_state::video_start();
- if (spriteram[offs + i] & 0x80)
- {
- if (spriteram[offs + i] & 0x40) /* 16x16 */
- m_gfxdecode->gfx(1)->transpen(bitmap,cliprect,
- (spriteram[offs + i + 1] >> 2) + 4 * (spriteram[offs + i + 2] & 0x10),
- spriteram[offs + i + 2] & 0x0f,
- spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
- spriteram[offs + i + 3],
- offs / 4 - 8 + (spriteram[offs + i] & 0x0f),0);
- else /* 8x8 */
- m_gfxdecode->gfx(2)->transpen(bitmap,cliprect,
- spriteram[offs + i + 1] + 16 * (spriteram[offs + i + 2] & 0x10),
- spriteram[offs + i + 2] & 0x0f,
- spriteram[offs + i] & 0x20,spriteram[offs + i] & 0x10,
- spriteram[offs + i + 3],
- offs / 4 + (spriteram[offs + i] & 0x0f),0);
- }
- }
- }
+ m_grid_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(sraider_state::get_grid_tile_info), this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
+ m_grid_tilemap->set_scroll_rows(32);
+ m_grid_tilemap->set_transparent_pen(0);
}
-uint32_t ladybug_state::screen_update_ladybug(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+WRITE_LINE_MEMBER(sraider_state::screen_vblank_sraider)/* update starfield position */
{
- int offs;
+ // falling edge
+ if (!state)
+ m_stars->update_state();
+}
+uint32_t sraider_state::screen_update_sraider(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
// clear the bg bitmap
bitmap.fill(0, cliprect);
- for (offs = 0; offs < 32; offs++)
+ // draw the stars
+ if (flip_screen())
+ m_stars->draw(bitmap, cliprect, 0x60, false, 0x27, 0xff);
+ else
+ m_stars->draw(bitmap, cliprect, 0x60, false, 0x00, 0xd8);
+
+ // draw the gridlines
+ m_palette->set_indirect_color(0x40, rgb_t(
+ m_grid_color & 0x40 ? 0xff : 0,
+ m_grid_color & 0x20 ? 0xff : 0,
+ m_grid_color & 0x10 ? 0xff : 0));
+ m_grid_tilemap->draw(screen, bitmap, cliprect, 0, flip_screen());
+
+ for (unsigned i = 0; i < 0x100; i++)
{
- int sx = offs % 4;
- int sy = offs / 4;
+ if (m_grid_data[i] != 0)
+ {
+ uint8_t x = i;
+ int height = cliprect.max_y - cliprect.min_y + 1;
- if (flip_screen())
- m_bg_tilemap->set_scrollx(offs, -m_videoram[32 * sx + sy]);
- else
- m_bg_tilemap->set_scrollx(offs, m_videoram[32 * sx + sy]);
+ if (flip_screen())
+ x = ~x;
+
+ bitmap.plot_box(x, cliprect.min_y, 1, height, 0x81);
+ }
}
- m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
- draw_sprites(bitmap, cliprect);
+ // now the chars/sprites
+ m_video->draw(screen, bitmap, cliprect, flip_screen());
+
return 0;
}