From 969b69609376ed96d6a58d9fe7407116783c3066 Mon Sep 17 00:00:00 2001 From: gm-matthew <108370479+gm-matthew@users.noreply.github.com> Date: Sun, 2 Nov 2025 03:10:02 +0000 Subject: [PATCH] sega/model2: draw polygons front to back, use fill buffer --- src/mame/sega/model2.cpp | 4 ---- src/mame/sega/model2.h | 3 +++ src/mame/sega/model2_v.cpp | 46 +++++++++----------------------------- src/mame/sega/model2rd.ipp | 14 +++++++++++- 4 files changed, 26 insertions(+), 41 deletions(-) diff --git a/src/mame/sega/model2.cpp b/src/mame/sega/model2.cpp index e77511ae14680..731be956a31dc 100644 --- a/src/mame/sega/model2.cpp +++ b/src/mame/sega/model2.cpp @@ -1387,8 +1387,6 @@ void model2b_state::model2b_crx_mem(address_map &map) map(0x11100000, 0x111fffff).ram().share("textureram0").flags(i960_cpu_device::BURST); // texture RAM 0 (2b/2c) map(0x11200000, 0x112fffff).ram().share("textureram1").flags(i960_cpu_device::BURST); // texture RAM 1 (2b/2c) map(0x11300000, 0x113fffff).ram().share("textureram1").flags(i960_cpu_device::BURST); // texture RAM 1 (2b/2c) - map(0x11400000, 0x1140ffff).rw(FUNC(model2b_state::lumaram_r), FUNC(model2b_state::lumaram_w)).flags(i960_cpu_device::BURST); // polygon "luma" RAM (2b/2c) - map(0x12800000, 0x1281ffff).rw(FUNC(model2b_state::lumaram_r), FUNC(model2b_state::lumaram_w)).umask32(0x0000ffff).flags(i960_cpu_device::BURST); // polygon "luma" RAM map(0x11400000, 0x1140ffff).rw(FUNC(model2b_state::lumaram_r), FUNC(model2b_state::lumaram_w)).umask16(0x00ff).flags(i960_cpu_device::BURST); // polygon "luma" RAM (2b/2c) map(0x01c00000, 0x01c0001f).rw("io", FUNC(sega_315_5649_device::read), FUNC(sega_315_5649_device::write)).umask32(0x00ff00ff); @@ -1424,8 +1422,6 @@ void model2c_state::model2c_crx_mem(address_map &map) map(0x11000000, 0x111fffff).ram().share("textureram0").flags(i960_cpu_device::BURST); // texture RAM 0 (2b/2c) map(0x11200000, 0x113fffff).ram().share("textureram1").flags(i960_cpu_device::BURST); // texture RAM 1 (2b/2c) - map(0x11400000, 0x1140ffff).rw(FUNC(model2c_state::lumaram_r), FUNC(model2c_state::lumaram_w)).flags(i960_cpu_device::BURST); // polygon "luma" RAM (2b/2c) - map(0x12800000, 0x1281ffff).rw(FUNC(model2c_state::lumaram_r), FUNC(model2c_state::lumaram_w)).umask32(0x0000ffff).flags(i960_cpu_device::BURST); // polygon "luma" RAM map(0x11400000, 0x1140ffff).rw(FUNC(model2c_state::lumaram_r), FUNC(model2c_state::lumaram_w)).umask16(0x00ff).flags(i960_cpu_device::BURST); // polygon "luma" RAM (2b/2c) map(0x01c00000, 0x01c0001f).rw("io", FUNC(sega_315_5649_device::read), FUNC(sega_315_5649_device::write)).umask32(0x00ff00ff); diff --git a/src/mame/sega/model2.h b/src/mame/sega/model2.h index b7ae0a30a02b2..3f06806e3c5f6 100644 --- a/src/mame/sega/model2.h +++ b/src/mame/sega/model2.h @@ -676,12 +676,14 @@ class model2_renderer : public poly_manager { &model2_renderer::draw_scanline_tex, this } }, m_state(state), m_destmap(512, 512), + m_fillmap(512, 512), m_xoffs(90), m_yoffs(-8) { } bitmap_rgb32 &destmap() { return m_destmap; } + bitmap_ind8 &fillmap() { return m_fillmap; } void model2_3d_render(triangle *tri, const rectangle &cliprect); void set_xoffset(int16_t xoffs) { m_xoffs = xoffs; } @@ -698,6 +700,7 @@ class model2_renderer : public poly_manager model2_state &m_state; bitmap_rgb32 m_destmap; + bitmap_ind8 m_fillmap; int16_t m_xoffs, m_yoffs; template diff --git a/src/mame/sega/model2_v.cpp b/src/mame/sega/model2_v.cpp index 65d77587b3605..48673705d4c16 100644 --- a/src/mame/sega/model2_v.cpp +++ b/src/mame/sega/model2_v.cpp @@ -82,6 +82,9 @@ maps to do mip mapping. More information can be found on the 2B manual, on the 'Texturing' and 'Data Format' chapters. - The rasterizer supports 128x128 'microtextures' which are typically used to add more details to a texture when it is close enough to the viewer. + - Polygons are rendered from front-to-back. A fill buffer is used to track which pixels in the framebuffer have already + been drawn to and prevents them from being overwritten. The real hardware does this to ensure that the polygons closest + to the camera are rendered first, in case the renderer runs out of time and has to skip ahead to the next frame. *********************************************************************************************************************************/ @@ -461,12 +464,6 @@ void model2_state::model2_3d_process_quad( raster_state *raster, u32 attr ) /* get our list read to add the triangles */ ztri = raster->tri_sorted_list[object.z]; - if ( ztri != nullptr ) - { - while( ztri->next != nullptr ) - ztri = (triangle *)ztri->next; - } - /* go through the clipped vertex list, adding triangles */ for( i = 2; i < clipped_verts; i++ ) { @@ -506,17 +503,8 @@ void model2_state::model2_3d_process_quad( raster_state *raster, u32 attr ) memcpy( &tri->v[2], &verts_out[i], sizeof( poly_vertex ) ); /* add to our sorted list */ - tri->next = nullptr; - - if ( ztri == nullptr ) - { - raster->tri_sorted_list[object.z] = tri; - } - else - { - ztri->next = tri; - } - + raster->tri_sorted_list[object.z] = tri; + tri->next = ztri; ztri = tri; } @@ -693,12 +681,6 @@ void model2_state::model2_3d_process_triangle( raster_state *raster, u32 attr ) /* get our list read to add the triangles */ ztri = raster->tri_sorted_list[object.z]; - if ( ztri != nullptr ) - { - while( ztri->next != nullptr ) - ztri = (triangle *)ztri->next; - } - /* go through the clipped vertex list, adding triangles */ for( i = 2; i < clipped_verts; i++ ) { @@ -738,17 +720,8 @@ void model2_state::model2_3d_process_triangle( raster_state *raster, u32 attr ) memcpy( &tri->v[2], &verts_out[i], sizeof( poly_vertex ) ); /* add to our sorted list */ - tri->next = nullptr; - - if ( ztri == nullptr ) - { - raster->tri_sorted_list[object.z] = tri; - } - else - { - ztri->next = tri; - } - + raster->tri_sorted_list[object.z] = tri; + tri->next = ztri; ztri = tri; } @@ -927,11 +900,12 @@ void model2_state::model2_3d_frame_end( bitmap_rgb32 &bitmap, const rectangle &c return; m_poly->destmap().fill(0x00000000, cliprect); + m_poly->fillmap().fill(0x00, cliprect); - for (u8 window = 0; window <= raster->cur_window; window++) + for (int window = raster->cur_window; window >= 0; window--) { /* go through the Z levels, and render each bucket */ - for ( z = raster->max_z; z >= raster->min_z; z-- ) + for (z = raster->min_z; z <= raster->max_z; z++) { /* see if we have items at this z level */ if ( raster->tri_sorted_list[z] != nullptr ) diff --git a/src/mame/sega/model2rd.ipp b/src/mame/sega/model2rd.ipp index 221e42212513b..c6456241e4cdd 100644 --- a/src/mame/sega/model2rd.ipp +++ b/src/mame/sega/model2rd.ipp @@ -17,6 +17,7 @@ void model2_renderer::draw_scanline_solid(int32_t scanline, const extent_t& exte { model2_state *state = object.state; u32 *const p = &m_destmap.pix(scanline); + u8 *const fill = &m_fillmap.pix(scanline); u8 *gamma_value = &state->m_gamma_table[0]; // extract color information @@ -59,7 +60,13 @@ void model2_renderer::draw_scanline_solid(int32_t scanline, const extent_t& exte x++; for (; x < extent.stopx; x += dx) - p[x] = color; + { + if (fill[x] == 0) + { + p[x] = color; + fill[x] = 0xff; + } + } } #define LERP(X, Y, A) (((X) + ((((Y) - (X)) * (A)) >> 8)) & 0x00ff00ff) @@ -206,6 +213,7 @@ void model2_renderer::draw_scanline_tex(int32_t scanline, const extent_t &extent { model2_state *state = object.state; u32 *const p = &m_destmap.pix(scanline); + u8 *const fill = &m_fillmap.pix(scanline); /* extract color information */ const u16 *colortable_r = &state->m_colorxlat[0x0000/2]; @@ -246,6 +254,9 @@ void model2_renderer::draw_scanline_tex(int32_t scanline, const extent_t &extent for ( ; x < extent.stopx; x += dx, ooz += dooz, uoz += duoz, voz += dvoz) { + if (fill[x] > 0) + continue; + float z = recip_approx(ooz); s32 mml = -object.texlod + fast_log2(z); // equivalent to log2(z^2) @@ -297,6 +308,7 @@ void model2_renderer::draw_scanline_tex(int32_t scanline, const extent_t &extent tb = gamma_value[tb]; p[x] = rgb_t(tr, tg, tb); + fill[x] = 0xff; } }