From ed55a9d407091d6279c6ee217db299a5037e3ab5 Mon Sep 17 00:00:00 2001 From: angelosa Date: Fri, 27 Mar 2020 16:13:42 +0100 Subject: malzak.cpp: convert playfield to tilemap, improve playfield colors, add playfield tile bank, add base mixing and priority, misc cleanups [Angelo Salese] --- src/mame/drivers/malzak.cpp | 78 ++++++++++++--------------- src/mame/includes/malzak.h | 23 ++++---- src/mame/video/malzak.cpp | 128 +++++++++++++++++++++++++++----------------- 3 files changed, 127 insertions(+), 102 deletions(-) diff --git a/src/mame/drivers/malzak.cpp b/src/mame/drivers/malzak.cpp index 00e82aab611..86ac06d4be3 100644 --- a/src/mame/drivers/malzak.cpp +++ b/src/mame/drivers/malzak.cpp @@ -25,11 +25,14 @@ 0x1700 - 0x17ff | Work RAM - contains hiscore table, coin count 0x1800 - 0x1fff | SAA 5050 video RAM - TODO - I/O ports (0x00 for sprite->background collisions) - sound (2x SN76477) - playfield graphics may be banked, tiles above 0x1f are incorrect - sprite->sprite collisions aren't quite perfect - (you can often fly through flying missiles) + TODO: + - implement sprite-playfield collisions; + - sprite-playfield colors are dubious at best; + - Tiles may be flipped for playfield in final stage; + - improve gfx layers superimposing, honor PAL timings; + - sound (2x SN76477) + - sprite->sprite collisions aren't quite perfect + (you can often fly through flying missiles) <- does this still occur -AS? Notes: - Test mode in Malzak II should be enabled by setting a POT to position @@ -111,7 +114,7 @@ void malzak_state::malzak_map(address_map &map) map(0x1400, 0x14ff).mirror(0x6000).rw(m_s2636[0], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data)); map(0x14cb, 0x14cb).mirror(0x6000).r(FUNC(malzak_state::fake_VRLE_r)); map(0x1500, 0x15ff).mirror(0x6000).rw(m_s2636[1], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data)); - map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::malzak_playfield_w)); + map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::playfield_w)); map(0x1700, 0x17ff).mirror(0x6000).ram(); map(0x1800, 0x1fff).mirror(0x6000).ram().share("videoram"); map(0x2000, 0x2fff).rom(); @@ -133,7 +136,7 @@ void malzak_state::malzak2_map(address_map &map) map(0x14cb, 0x14cb).mirror(0x6000).r(FUNC(malzak_state::fake_VRLE_r)); map(0x14cc, 0x14cc).mirror(0x6000).r(FUNC(malzak_state::s2636_portA_r)); map(0x1500, 0x15ff).mirror(0x6000).rw(m_s2636[1], FUNC(s2636_device::read_data), FUNC(s2636_device::write_data)); - map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::malzak_playfield_w)); + map(0x1600, 0x16ff).mirror(0x6000).ram().w(FUNC(malzak_state::playfield_w)); map(0x1700, 0x17ff).mirror(0x6000).ram().share("nvram"); map(0x1800, 0x1fff).mirror(0x6000).ram().share("videoram"); map(0x2000, 0x2fff).rom(); @@ -144,7 +147,7 @@ void malzak_state::malzak2_map(address_map &map) READ8_MEMBER(malzak_state::s2650_data_r) { - popmessage("S2650 data port read"); +// popmessage("S2650 data port read"); return 0xff; } @@ -158,22 +161,25 @@ WRITE8_MEMBER(malzak_state::port40_w) // the selected version // logerror("%s S2650: port 0x40 write: 0x%02x\n", machine().describe_context(), data); m_mainbank->set_entry((data & 0x40) >> 6); -} - -WRITE8_MEMBER(malzak_state::port60_w) -{ - m_malzak_x = data; - // logerror("I/O: port 0x60 write 0x%02x\n", data); -} - -WRITE8_MEMBER(malzak_state::portc0_w) -{ - m_malzak_y = data; - // logerror("I/O: port 0xc0 write 0x%02x\n", data); + // bit 7 is set at final stage + u8 gfx_bank = ((data & 0x80) >> 7); + if (m_playfield_bank != gfx_bank) + { + m_playfield_bank = gfx_bank; + m_playfield_tilemap->mark_all_dirty(); + } } READ8_MEMBER(malzak_state::collision_r) { + // s2636 (0 only?) <-> tilemap collision detection + // yyyy ---- y collision + // 0100 -> upper tilemap border (pixel 160) + // 1101 -> lower (pixel 448) + // pix / 32 = suggested value+1 + // ---- xxxx x collision + // TODO: verify scroll offsets + // High 4 bits seem to refer to the row affected. if(++m_collision_counter > 15) m_collision_counter = 0; @@ -259,41 +265,22 @@ static const gfx_layout charlayout = static GFXDECODE_START( gfx_malzak ) - GFXDECODE_ENTRY( "gfx1", 0x0000, charlayout, 0, 16 ) + GFXDECODE_ENTRY( "gfx1", 0x0000, charlayout, 0, 16*16 ) GFXDECODE_END - -void malzak_state::malzak_palette(palette_device &palette) const -{ - for (int i = 0; i < 8 * 8; i++) - { - palette.set_pen_color(i * 2 + 0, pal1bit(i >> 3), pal1bit(i >> 4), pal1bit(i >> 5)); - palette.set_pen_color(i * 2 + 1, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2)); - } -} - - -READ8_MEMBER(malzak_state::videoram_r) -{ - return m_videoram[offset]; -} - void malzak_state::machine_start() { m_mainbank->configure_entries(0, 2, memregion("user2")->base(), 0x400); save_item(NAME(m_playfield_code)); - save_item(NAME(m_malzak_x)); - save_item(NAME(m_malzak_y)); + save_item(NAME(m_scrollx)); + save_item(NAME(m_scrolly)); save_item(NAME(m_collision_counter)); } void malzak_state::machine_reset() { std::fill(std::begin(m_playfield_code), std::end(m_playfield_code), 0); - - m_malzak_x = 0; - m_malzak_y = 0; } void malzak_state::malzak(machine_config &config) @@ -307,6 +294,7 @@ void malzak_state::malzak(machine_config &config) /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + // TODO: convert to PAL set_raw m_screen->set_refresh_hz(50); m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); m_screen->set_size(480, 512); /* vert size is a guess */ @@ -314,7 +302,7 @@ void malzak_state::malzak(machine_config &config) m_screen->set_screen_update(FUNC(malzak_state::screen_update)); GFXDECODE(config, m_gfxdecode, m_palette, gfx_malzak); - PALETTE(config, m_palette, FUNC(malzak_state::malzak_palette), 128); + PALETTE(config, m_palette, FUNC(malzak_state::palette_init), 128); S2636(config, m_s2636[0], 0); m_s2636[0]->set_offsets(0, -16); // -8, -16 @@ -415,5 +403,5 @@ ROM_START( malzak2 ) ROM_END -GAME( 19??, malzak, 0, malzak, malzak, malzak_state, empty_init, ROT0, "Kitronix", "Malzak", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) -GAME( 19??, malzak2, malzak, malzak2, malzak2, malzak_state, empty_init, ROT0, "Kitronix", "Malzak II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +GAME( 19??, malzak, 0, malzak, malzak, malzak_state, empty_init, ROT0, "Kitronix", "Malzak", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE ) +GAME( 19??, malzak2, malzak, malzak2, malzak2, malzak_state, empty_init, ROT0, "Kitronix", "Malzak II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/includes/malzak.h b/src/mame/includes/malzak.h index f67c2aa363b..73c895c308a 100644 --- a/src/mame/includes/malzak.h +++ b/src/mame/includes/malzak.h @@ -15,6 +15,7 @@ #include "video/saa5050.h" #include "emupal.h" #include "screen.h" +#include "tilemap.h" class malzak_state : public driver_device { @@ -48,13 +49,6 @@ private: required_device m_screen; required_device m_palette; required_memory_bank m_mainbank; - /* misc */ -// int playfield_x[256]; -// int playfield_y[256]; - int m_playfield_code[256]; - int m_malzak_x; - int m_malzak_y; - int m_collision_counter; DECLARE_READ8_MEMBER(fake_VRLE_r); DECLARE_READ8_MEMBER(s2636_portA_r); @@ -63,16 +57,27 @@ private: DECLARE_WRITE8_MEMBER(port60_w); DECLARE_WRITE8_MEMBER(portc0_w); DECLARE_READ8_MEMBER(collision_r); - DECLARE_WRITE8_MEMBER(malzak_playfield_w); + DECLARE_WRITE8_MEMBER(playfield_w); DECLARE_READ8_MEMBER(videoram_r); - void malzak_palette(palette_device &palette) const; + void palette_init(palette_device &palette) const; uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual void video_start() override; void malzak2_map(address_map &map); void malzak_data_map(address_map &map); void malzak_io_map(address_map &map); void malzak_map(address_map &map); + + TILE_GET_INFO_MEMBER(get_tile_info); + std::unique_ptr m_trom_bitmap; + std::unique_ptr m_playfield_bitmap; + tilemap_t *m_playfield_tilemap; + int m_playfield_code[256]; + int m_scrollx; + int m_scrolly; + int m_collision_counter; + u8 m_playfield_bank; }; #endif // MAME_INCLUDES_MALZAK_H diff --git a/src/mame/video/malzak.cpp b/src/mame/video/malzak.cpp index 88f406cc398..864ec8df4fb 100644 --- a/src/mame/video/malzak.cpp +++ b/src/mame/video/malzak.cpp @@ -17,68 +17,100 @@ #include "emu.h" #include "includes/malzak.h" -uint32_t malzak_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +void malzak_state::palette_init(palette_device &palette) const { - const rgb_t *palette = m_palette->palette()->entry_list_raw(); + for (int i = 0; i < 8 * 8; i++) + { + palette.set_pen_color(i * 2 + 0, pal1bit(i >> 3), pal1bit(i >> 4), pal1bit(i >> 5)); + palette.set_pen_color(i * 2 + 1, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2)); + } +} - bitmap.fill(rgb_t::black(), cliprect); +READ8_MEMBER(malzak_state::videoram_r) +{ + return m_videoram[offset]; +} - m_trom->screen_update(screen, bitmap, cliprect); +WRITE8_MEMBER(malzak_state::port60_w) +{ + m_scrollx = data; +// logerror("I/O: port 0x60 write 0x%02x\n", data); + m_playfield_tilemap->set_scrollx(0, m_scrollx + 48); +} - // playfield - not sure exactly how this works... - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) - { - int sx = ((x * 16 - 48) - m_malzak_x) * 2; - int sy = ((y * 16) - m_malzak_y) * 2; +WRITE8_MEMBER(malzak_state::portc0_w) +{ + m_scrolly = data; +// logerror("I/O: port 0xc0 write 0x%02x\n", data); + m_playfield_tilemap->set_scrolly(0, m_scrolly); +} - if (sx < -271*2) - sx += 512*2; - if (sx < -15*2) - sx += 256*2; +//TODO: how readback works with this arrangement? Never occurs in-game +WRITE8_MEMBER(malzak_state::playfield_w) +{ + int tile = ((m_scrollx / 16) * 16) + (offset / 16); - m_gfxdecode->gfx(0)->zoom_transpen(bitmap,cliprect, m_playfield_code[x * 16 + y], 2, 0, 0, sx, sy, 0x20000, 0x20000, 0); - } +// m_playfield_x[tile] = m_malzak_x / 16; +// m_playfield_y[tile] = m_malzak_y; + m_playfield_code[tile] = data; + m_playfield_tilemap->mark_tile_dirty(tile); + // POST only, adds to the scrollx base address? +// if (offset & 0xf) +// popmessage("GFX: 0x16%02x write 0x%02x\n", offset, data); +} - /* update the S2636 chips */ +TILE_GET_INFO_MEMBER(malzak_state::get_tile_info) +{ + u8 code = (m_playfield_code[tile_index] & 0x1f) | (m_playfield_bank << 5); + u8 color = ((m_playfield_code[tile_index] & 0xe0) >> 5); + tileinfo.set(0, code, color, 0); +} + +void malzak_state::video_start() +{ + int width = m_screen->width(); + int height = m_screen->height(); + m_trom_bitmap = std::make_unique(width, height); + m_playfield_bitmap = std::make_unique(width, height); + m_playfield_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(malzak_state::get_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 16, 16); +} + +uint32_t malzak_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + + bitmap.fill(rgb_t::black(), cliprect); + + // prepare bitmaps + m_trom->screen_update(screen, *m_trom_bitmap, cliprect); + m_playfield_tilemap->draw(screen, *m_playfield_bitmap, cliprect, 0, 0); bitmap_ind16 const &s2636_0_bitmap = m_s2636[0]->update(cliprect); bitmap_ind16 const &s2636_1_bitmap = m_s2636[1]->update(cliprect); - /* copy the S2636 images into the main bitmap */ + // Superimpose + // TODO: update for PAL size + for (int y = cliprect.min_y; y <= cliprect.max_y; ++y) { - for (int y = cliprect.min_y; y <= cliprect.max_y / 2; y++) + int sy = y / 2; + for (int x = cliprect.min_x; x <= cliprect.max_x; ++x) { - for (int x = cliprect.min_x; x <= cliprect.max_x / 2; x++) - { - int pixel0 = s2636_0_bitmap.pix16(y, x); - int pixel1 = s2636_1_bitmap.pix16(y, x); - - if (S2636_IS_PIXEL_DRAWN(pixel0)) { - bitmap.pix32(y*2, x*2) = palette[S2636_PIXEL_COLOR(pixel0)]; - bitmap.pix32(y*2+1, x*2) = palette[S2636_PIXEL_COLOR(pixel0)]; - bitmap.pix32(y*2, x*2+1) = palette[S2636_PIXEL_COLOR(pixel0)]; - bitmap.pix32(y*2+1, x*2+1) = palette[S2636_PIXEL_COLOR(pixel0)]; - } - - if (S2636_IS_PIXEL_DRAWN(pixel1)) { - bitmap.pix32(y*2, x*2) = palette[S2636_PIXEL_COLOR(pixel1)]; - bitmap.pix32(y*2+1, x*2) = palette[S2636_PIXEL_COLOR(pixel1)]; - bitmap.pix32(y*2, x*2+1) = palette[S2636_PIXEL_COLOR(pixel1)]; - bitmap.pix32(y*2+1, x*2+1) = palette[S2636_PIXEL_COLOR(pixel1)]; - } - } + int sx = x / 2; + int s2636_pix_0 = s2636_0_bitmap.pix16(sy, sx); + int s2636_pix_1 = s2636_1_bitmap.pix16(sy, sx); + rgb_t trom_pix = m_trom_bitmap->pix32(y, x); + rgb_t play_pix = m_playfield_bitmap->pix32(sy, sx); + + // SAA5050 > s2636[1] > s2636[0] > playfield + if (trom_pix != rgb_t::black()) + bitmap.pix32(y, x) = trom_pix; + else if (S2636_IS_PIXEL_DRAWN(s2636_pix_1)) + bitmap.pix32(y, x) = palette[S2636_PIXEL_COLOR(s2636_pix_1)]; + else if (S2636_IS_PIXEL_DRAWN(s2636_pix_0)) + bitmap.pix32(y, x) = palette[S2636_PIXEL_COLOR(s2636_pix_0)]; + else + bitmap.pix32(y, x) = play_pix; } } return 0; } - -WRITE8_MEMBER(malzak_state::malzak_playfield_w) -{ - int tile = ((m_malzak_x / 16) * 16) + (offset / 16); - -// m_playfield_x[tile] = m_malzak_x / 16; -// m_playfield_y[tile] = m_malzak_y; - m_playfield_code[tile] = (data & 0x1f); - logerror("GFX: 0x16%02x write 0x%02x\n", offset, data); -} -- cgit v1.2.3