From 032b35e2dcb9eff47aaf01bfb134ae44af0762ca Mon Sep 17 00:00:00 2001 From: hap Date: Mon, 27 Apr 2026 23:58:03 +0200 Subject: namcos21_c67: small improvement to sprite layer 0 priority --- src/mame/namco/namcos21_3d.cpp | 31 +++++------- src/mame/namco/namcos21_3d.h | 4 ++ src/mame/namco/namcos21_c67.cpp | 105 ++++++++++++++++++++++++++-------------- 3 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/mame/namco/namcos21_3d.cpp b/src/mame/namco/namcos21_3d.cpp index fdb15b8a8f0..0ad76bd087f 100644 --- a/src/mame/namco/namcos21_3d.cpp +++ b/src/mame/namco/namcos21_3d.cpp @@ -127,12 +127,12 @@ void namcos21_3d_device::renderscanline_flat(const edge *e1, const edge *e2, int int depth = 0; if (m_depth_reverse) { - depth = (zz >> m_zz_shift)*m_zzmult; + depth = (zz >> m_zz_shift) * m_zzmult; pen += depth; } else { - depth = (zz >> m_zz_shift)*m_zzmult; + depth = (zz >> m_zz_shift) * m_zzmult; pen -= depth; } } @@ -267,26 +267,17 @@ void namcos21_3d_device::blit_single_quad(int sx[4], int sy[4], int zcode[4], u1 color = base | (color & 0xff); } - n21_vertex a, b, c, d; + n21_vertex v[4]; - a.x = sx[0]; - a.y = sy[0]; - a.z = zcode[0]; - - b.x = sx[1]; - b.y = sy[1]; - b.z = zcode[1]; - - c.x = sx[2]; - c.y = sy[2]; - c.z = zcode[2]; - - d.x = sx[3]; - d.y = sy[3]; - d.z = zcode[3]; + for (int i = 0; i < 4; i++) + { + v[i].x = sx[i]; + v[i].y = sy[i]; + v[i].z = zcode[i] & 0x7fff; + } - rendertri(&a, &b, &c, color, depthcueenable); - rendertri(&c, &d, &a, color, depthcueenable); + rendertri(&v[0], &v[1], &v[2], color, depthcueenable); + rendertri(&v[2], &v[3], &v[0], color, depthcueenable); } void namcos21_3d_device::draw_direct_quad(const u16 *source, u16 color) diff --git a/src/mame/namco/namcos21_3d.h b/src/mame/namco/namcos21_3d.h index dad4f59cc60..239aa139283 100644 --- a/src/mame/namco/namcos21_3d.h +++ b/src/mame/namco/namcos21_3d.h @@ -22,8 +22,12 @@ public: m_framebuffer_size_in_bytes = sizeof(u16) * m_poly_frame_width * m_poly_frame_height; } + int width() { return m_poly_frame_width; } + int height() { return m_poly_frame_height; } + void copy_visible_poly_framebuffer(bitmap_ind16 &bitmap, const rectangle &cliprect, int zlo, int zhi); void swap_and_clear_poly_framebuffer(); + u16 *get_visible_zbuffer() { return m_mpPolyFrameBufferZ2.get(); } void draw_direct_quad(const u16 *source, u16 color); void draw_quads(const u16 *source, const u8 *pointram, const u32 ptram_size, u32 quad_idx); diff --git a/src/mame/namco/namcos21_c67.cpp b/src/mame/namco/namcos21_c67.cpp index 20814fdbb97..2afd8167a50 100644 --- a/src/mame/namco/namcos21_c67.cpp +++ b/src/mame/namco/namcos21_c67.cpp @@ -8,18 +8,15 @@ TODO: - lamp/vibration outputs, from MCU? (particularly starblad); - verify DSP clocks, they should be 40MHz, currently underclocked on purpose on MAME, otherwise polygons may disappear on some frames (try playing starblad until after the asteroids), tightening quantum by - a factor of 40/24 does not fix it, actually it also happens when underclocked, but less; + a factor of 40/24 does not fix it (actually it also happens when underclocked, but less); - verify video timing, pixel clock is from 38.76922?; -- verify audiocpu irq frequency; -- is m_layer0_pivot software-controlled and if so, where? (solvalou sprite layer 0 is further back than - starblad and cybsled); +- mix_layer0_sprites can be improved when namcos21_3d_device removes the z-buffer, there are currently + glitches in cybsled, eg. missile pickups behind pillars; - wrong global sprite layer offsets in service mode for all games except aircomb, it's fine in-game though; - aircomb: z-fighting issue on attract mode with the plane renders (after the first title screen), and on pilot parachuting with a time over; - aircomb: missing background on attract mode ranking screen (masking? cfr. shared/namco_c355spr.cpp); - aircomb: bad sprite colors on debriefing medal screen; -- cybsled: sprite priority issues with explosions, and eg. missile pick-ups, is it related to unemulated - z-sorted polygons, and/or from m_layer0_pivot?; - solvalou: service mode polygon test is crashy when testing invalid polygons (the good old IDC overflow); - solvalou: sprite blend is wrong during water stages (look at the blaster/score panel), the palette bank for the water is at 0x2200, but the blend palette is at 0x6000 instead of 0x6200?; @@ -52,29 +49,32 @@ The memory map below reflects DSP RAM as seen by the 68000 CPUs. 0x2000a0: B-M: 0x2000b0: P-M: 0x2000c0: S-M: - 0x200100 status: 2=upload needed, 4=error (abort) - 0x200102 status - 0x200104 0x0002 - 0x200106 addr written by main cpu - 0x20010a point rom checksum (starblade expects 0xed53) - 0x20010c point rom checksum (starblade expects 0xd5df) - 0x20010e 1: upload-code-to-dsp request trigger - 0x200110 status - 0x200112 status - 0x200114 master dsp code size - 0x200116 slave dsp code size - 0x200120 upload source1 addr hi - 0x200122 upload source1 addr lo - 0x200124 upload source2 addr hi - 0x200126 upload source2 addr lo - 0x200200 enable - 0x200202 status - 0x200206 work page select - 0x200208 0xa2c2 (air combat) - 0x208000..0x2080ff camera attributes for page#0 - 0x208200..0x208fff 3d object attribute display list for page#0 - 0x20c000..0x20c0ff camera attributes for page#1 - 0x20c200..0x20cfff 3d object attribute display list for page#1 + + 0x200100: status: 2=upload needed, 4=error (abort) + 0x200102: status + 0x200104: 0x0002 + 0x200106: addr written by main cpu + 0x20010a: point rom checksum (starblade expects 0xed53) + 0x20010c: point rom checksum (starblade expects 0xd5df) + 0x20010e: 1: upload-code-to-dsp request trigger + 0x200110: status + 0x200112: status + 0x200114: master dsp code size + 0x200116: slave dsp code size + 0x200120: upload source1 addr hi + 0x200122: upload source1 addr lo + 0x200124: upload source2 addr hi + 0x200126: upload source2 addr lo + + 0x200200: enable + 0x200202: status + 0x200206: work page select + 0x200208: 0xa2c2 (air combat) + + 0x208000..0x2080ff: camera attributes for page#0 + 0x208200..0x208fff: 3d object attribute display list for page#0 + 0x20c000..0x20c0ff: camera attributes for page#1 + 0x20c200..0x20cfff: 3d object attribute display list for page#1 Starblade Cybersled AirCombat22 Solvalou [400]:= 00 0000 00 0000 00 0000 00 0000 @@ -331,6 +331,7 @@ public: void init_solvalou(); protected: + virtual void video_start() override ATTR_COLD; virtual void machine_start() override ATTR_COLD; virtual void machine_reset() override ATTR_COLD; @@ -354,8 +355,8 @@ private: required_device m_namcos21_3d; required_device m_namcos21_dsp_c67; - u16 m_layer0_pivot = 0x800; u16 m_video_enable = 0; + bitmap_ind16 m_mix_layer0_bitmap; u16 video_enable_r(); void video_enable_w(offs_t offset, u16 data, u16 mem_mask = ~0); @@ -377,6 +378,7 @@ private: TIMER_DEVICE_CALLBACK_MEMBER(screen_scanline); bool sprite_mix_callback(u16 &dest, u8 &destpri, u16 colbase, u16 src, int srcpri, int pri); + void mix_layer0_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void common_map(address_map &map) ATTR_COLD; @@ -388,6 +390,13 @@ private: }; +void namcos21_c67_state::video_start() +{ + m_screen->register_screen_bitmap(m_mix_layer0_bitmap); + + save_item(NAME(m_video_enable)); +} + bool namcos21_c67_state::sprite_mix_callback(u16 &dest, u8 &destpri, u16 colbase, u16 src, int srcpri, int pri) { if ((srcpri & 3) == pri) @@ -427,6 +436,34 @@ bool namcos21_c67_state::sprite_mix_callback(u16 &dest, u8 &destpri, u16 colbase return false; } +void namcos21_c67_state::mix_layer0_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(m_mix_layer0_bitmap, bitmap, 0, 0, 0, 0, cliprect); + m_c355spr->draw(screen, m_mix_layer0_bitmap, cliprect, 0); + + assert(cliprect.bottom < m_namcos21_3d->height() && cliprect.right() < m_namcos21_3d->width()); + + // create priority table, this is not accurate + u16 pri[0x10]; + for (int i = 0; i < 0x10; i++) + pri[i] = (i == 0) ? 0x7fc0 : pri[i - 1] / 1.25; + + // mix layer 0 sprites with polygons + for (int y = cliprect.top(); y <= cliprect.bottom(); y++) + { + const u16 *z = m_namcos21_3d->get_visible_zbuffer() + m_namcos21_3d->width() * y; + const u16 *src = &m_mix_layer0_bitmap.pix(y); + u16 *dest = &bitmap.pix(y); + + for (int x = cliprect.left(); x <= cliprect.right(); x++) + { + // priority is from sprite high palette bits + if ((src[x] & 0x5000 && pri[src[x] >> 8 & 0xf] <= z[x]) || src[x] < 0x1000) + dest[x] = src[x]; + } + } +} + u32 namcos21_c67_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { bitmap.fill(0xff, cliprect); @@ -452,9 +489,8 @@ u32 namcos21_c67_state::screen_update(screen_device &screen, bitmap_ind16 &bitma break; case 4: // default gameplay for all games, aircomb attract mode default: - m_namcos21_3d->copy_visible_poly_framebuffer(bitmap, cliprect, m_layer0_pivot, 0x7ffe); - m_c355spr->draw(screen, bitmap, cliprect, 0); - m_namcos21_3d->copy_visible_poly_framebuffer(bitmap, cliprect, 0, m_layer0_pivot - 1); + m_namcos21_3d->copy_visible_poly_framebuffer(bitmap, cliprect, 0, 0x7ffe); + mix_layer0_sprites(screen, bitmap, cliprect); break; } @@ -773,8 +809,6 @@ void namcos21_c67_state::machine_start() u32 max = memregion("audiocpu")->bytes() / 0x4000; for (int i = 0; i < 0x10; i++) m_audiobank->configure_entry(i, memregion("audiocpu")->base() + (i % max) * 0x4000); - - save_item(NAME(m_video_enable)); } TIMER_DEVICE_CALLBACK_MEMBER(namcos21_c67_state::screen_scanline) @@ -912,7 +946,6 @@ void namcos21_c67_state::solvalou(machine_config &config) m_namcos21_3d->set_fixed_palbase(0x3f00); m_namcos21_3d->set_zz_shift_mult(10, 0x100); - m_layer0_pivot = 0x7fc0; } -- cgit v1.2.3