From 847dd5d886e68c96daa232397c6e01292e8eb770 Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:51:06 +0000 Subject: snk/hng64.cpp: Implemented raster interrups and improved layer mixing. (#10971) * Implemented raster interrupt (used to enable fatfurwa floor layer). * Improved layer priorities - still needs a proper per-pixel mixer. * Improved colour mixer effects - still imperfect, but highlights areas needing attention. --- src/mame/snk/hng64.cpp | 86 ++++++++- src/mame/snk/hng64.h | 14 +- src/mame/snk/hng64_3d.ipp | 32 ++-- src/mame/snk/hng64_sprite.ipp | 11 +- src/mame/snk/hng64_v.cpp | 408 ++++++++++++++++++++++++++++++++---------- 5 files changed, 422 insertions(+), 129 deletions(-) diff --git a/src/mame/snk/hng64.cpp b/src/mame/snk/hng64.cpp index 21d80ee8402..34d2715bdbc 100644 --- a/src/mame/snk/hng64.cpp +++ b/src/mame/snk/hng64.cpp @@ -984,6 +984,13 @@ uint32_t hng64_state::hng64_sysregs_r(offs_t offset, uint32_t mem_mask) return m_sysregs[offset]; } +void hng64_state::raster_irq_pos_w(uint32_t data) +{ + m_raster_irq_pos[m_irq_pos_half] = data; + + m_irq_pos_half ^= 1; +} + void hng64_state::hng64_sysregs_w(offs_t offset, uint32_t data, uint32_t mem_mask) { COMBINE_DATA (&m_sysregs[offset]); @@ -992,15 +999,40 @@ void hng64_state::hng64_sysregs_w(offs_t offset, uint32_t data, uint32_t mem_mas if(((offset*4) & 0xff00) == 0x1100) logerror("HNG64 writing to SYSTEM Registers 0x%08x == 0x%08x. (PC=%08x)\n", offset*4, m_sysregs[offset], m_maincpu->pc()); #endif + int scanline = m_screen->vpos(); switch(offset*4) { + /* + case 0x0014: + break; + case 0x001c: + break; + */ + case 0x100c: + raster_irq_pos_w(data); + break; + + /* + case 0x1014: + break; + case 0x101c: + break; + case 0x106c: // also reads from this one when writing 100c regs + break; + case 0x1074: + break; + */ case 0x1084: //MIPS->MCU latch port m_mcu_en = (data & 0xff); //command-based, i.e. doesn't control halt line and such? LOG("%s: HNG64 writing to MCU control port %08x (%08x)\n", machine().describe_context(), data, mem_mask); break; + /* + case 0x108c: + break; + */ default: - LOG("%s: HNG64 writing to SYSTEM Registers %08x %08x (%08x)\n", machine().describe_context(), offset*4, data, mem_mask); + logerror("%s: HNG64 writing to SYSTEM Registers %08x %08x (%08x) on scanline %d\n", machine().describe_context(), offset * 4, data, mem_mask, scanline); } } @@ -1113,8 +1145,20 @@ void hng64_state::hng64_sprite_clear_odd_w(offs_t offset, uint32_t data, uint32_ void hng64_state::hng64_vregs_w(offs_t offset, uint32_t data, uint32_t mem_mask) { - LOGMASKED(LOG_DMA, "hng64_vregs_w %02x, %08x %08x\n", offset * 4, data, mem_mask); - COMBINE_DATA(&m_videoregs[offset]); + LOGMASKED(LOG_VREGS, "hng64_vregs_w %02x, %08x %08x\n", offset * 4, data, mem_mask); + + uint32_t newval = m_videoregs[offset]; + COMBINE_DATA(&newval); + + if (newval != m_videoregs[offset]) + { + int vpos = m_screen->vpos(); + + if (vpos > 0) + m_screen->update_partial(vpos - 1); + + m_videoregs[offset] = newval; + } } uint16_t hng64_state::main_sound_comms_r(offs_t offset) @@ -2098,14 +2142,29 @@ TIMER_DEVICE_CALLBACK_MEMBER(hng64_state::hng64_irq) { int scanline = param; - switch(scanline) + if (!(scanline & 1)) // in reality there are half as many scanlines, as we're running in interlace mode { - case 224*2: set_irq(0x0001); break; // lv 0 vblank irq -// case 0*2: set_irq(0x0002); break; // lv 1 -// case 32*2: set_irq(0x0008); break; // lv 2 -// case 64*2: set_irq(0x0008); break; // lv 2 - case 128*2: set_irq(0x0800); break; // lv 11 network irq? + const int scanline_shifted = scanline >> 1; + + switch (scanline_shifted) + { + case 224: set_irq(0x0001); break; // lv 0 vblank irq +// case 32: set_irq(0x0008); break; // lv 2 +// case 64: set_irq(0x0008); break; // lv 2 + case 240: set_irq(0x0800); break; // lv 11 network irq? + + default: + { + // raster / timer irq, used to split tilemaps for fatfurwa floor + if (scanline_shifted == m_raster_irq_pos[0]+8) + if (scanline_shifted <224) + set_irq(0x0002); + break; + } + + } } + } void hng64_state::machine_start() @@ -2175,6 +2234,9 @@ void hng64_state::machine_start() save_item(NAME(main_latch)); save_item(NAME(sound_latch)); + + save_item(NAME(m_irq_pos_half)); + save_item(NAME(m_raster_irq_pos)); } TIMER_CALLBACK_MEMBER(hng64_state::comhack_callback) @@ -2212,6 +2274,10 @@ void hng64_state::machine_reset() m_fbcontrol[2] = 0x00; m_fbcontrol[3] = 0x00; + m_irq_pos_half = 0; + m_raster_irq_pos[0] = 0xffffffff; + m_raster_irq_pos[1] = 0xffffffff; + clear3d(); } @@ -2516,6 +2582,8 @@ void hng64_state::hng64(machine_config &config) m_screen->screen_vblank().set(FUNC(hng64_state::screen_vblank_hng64)); PALETTE(config, m_palette).set_format(palette_device::xRGB_888, 0x1000); + PALETTE(config, m_palette_fade0).set_format(palette_device::xRGB_888, 0x1000); + PALETTE(config, m_palette_fade1).set_format(palette_device::xRGB_888, 0x1000); PALETTE(config, m_palette_3d).set_format(palette_device::xRGB_888, 0x1000 * 0x10); hng64_audio(config); diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 0fa46213fb1..90f0d6516b2 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -144,6 +144,8 @@ public: driver_device(mconfig, type, tag), m_screen(*this, "screen"), m_palette(*this, "palette"), + m_palette_fade0(*this, "palette0"), + m_palette_fade1(*this, "palette1"), m_palette_3d(*this, "palette3d"), m_paletteram(*this, "paletteram"), m_vblank(*this, "VBLANK"), @@ -195,6 +197,8 @@ public: uint8_t *m_texturerom = nullptr; required_device m_screen; required_device m_palette; + required_device m_palette_fade0; + required_device m_palette_fade1; required_device m_palette_3d; required_shared_ptr m_paletteram; required_ioport m_vblank; @@ -290,6 +294,8 @@ private: bitmap_ind16 m_sprite_bitmap; bitmap_ind16 m_sprite_zbuffer; + uint8_t m_irq_pos_half; + uint32_t m_raster_irq_pos[2]; uint8_t m_screen_dis = 0U; @@ -335,6 +341,7 @@ private: uint32_t hng64_irqc_r(offs_t offset, uint32_t mem_mask = ~0); void hng64_irqc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); void hng64_mips_to_iomcu_irq_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + void raster_irq_pos_w(uint32_t data); uint8_t hng64_dualport_r(offs_t offset); void hng64_dualport_w(offs_t offset, uint8_t data); @@ -363,6 +370,7 @@ private: void dl_unk_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t dl_vreg_r(); + void set_palette_entry_with_faderegs(int entry, uint8_t r, uint8_t g, uint8_t b, uint32_t rgbfade, uint8_t r_mode, uint8_t g_mode, uint8_t b_mode, palette_device *palette); void set_single_palette_entry(int entry, uint8_t r, uint8_t g, uint8_t b); void update_palette_entry(int entry); void pal_w(offs_t offset, uint32_t data, uint32_t mem_mask); @@ -461,9 +469,11 @@ private: void clear3d(); bool hng64_command3d(const uint16_t* packet); + void mixsprites_test(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect, uint16_t priority, int y); + void get_tile_details(bool chain, uint16_t spritenum, uint8_t xtile, uint8_t ytile, uint8_t xsize, uint8_t ysize, bool xflip, bool yflip, uint32_t& tileno, uint16_t& pal, uint8_t &gfxregion); void draw_sprites_buffer(screen_device &screen, const rectangle &cliprect); - void draw_sprite_line(screen_device& screen, const rectangle& cliprect, int32_t curyy, int16_t cury, int16_t xpos, int chainx, int32_t dx, int32_t dy, int ytileblock, int chaini, int currentsprite, int chainy, int xflip, int yflip, uint16_t zval, bool zsort, bool blend, bool checkerboard, uint8_t mosaic); + void draw_sprite_line(screen_device& screen, const rectangle& cliprect, int32_t curyy, int16_t cury, int16_t xpos, int chainx, int32_t dx, int32_t dy, int ytileblock, int chaini, int currentsprite, int chainy, int xflip, int yflip, uint16_t zval, bool zsort, bool blend, uint16_t group, bool checkerboard, uint8_t mosaic); void drawline(bitmap_ind16& dest, bitmap_ind16& destz, const rectangle& cliprect, gfx_element* gfx, uint32_t code, uint32_t color, int flipy, int32_t xpos, @@ -471,7 +481,7 @@ private: void zoom_transpen(bitmap_ind16 &dest, bitmap_ind16 &destz, const rectangle &cliprect, gfx_element *gfx, uint32_t code, uint32_t color, int flipx, int flipy, int32_t xpos, int32_t ypos, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int line, uint16_t &srcpix); + int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, uint16_t group, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int line, uint16_t &srcpix); void setCameraTransformation(const uint16_t* packet); void setLighting(const uint16_t* packet); diff --git a/src/mame/snk/hng64_3d.ipp b/src/mame/snk/hng64_3d.ipp index fe7dd6a5340..85ce34d9f1b 100644 --- a/src/mame/snk/hng64_3d.ipp +++ b/src/mame/snk/hng64_3d.ipp @@ -1311,6 +1311,9 @@ void hng64_state::normalize(float* x) void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent_t& extent, const hng64_poly_data& renderData, int threadid) { + if ((scanline > 511) | (scanline < 0)) + return; + // Pull the parameters out of the extent structure float z = extent.param[0].start; float w = extent.param[1].start; @@ -1325,15 +1328,15 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent const float dt = extent.param[6].dpdx; // Pointers to the pixel buffers - uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512) + extent.startx]; - float* depthBuffer = &m_depthBuffer3d[(scanline * 512) + extent.startx]; + uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512)]; + float* depthBuffer = &m_depthBuffer3d[(scanline * 512)]; const uint8_t *textureOffset = &m_state.m_texturerom[renderData.texIndex * 1024 * 1024]; // Step over each pixel in the horizontal span for(int x = extent.startx; x < extent.stopx; x++) { - if (z < *depthBuffer) + if (z < depthBuffer[x & 511]) { // Multiply back through by w for everything that was interpolated perspective-correctly const float sCorrect = s / w; @@ -1400,8 +1403,8 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent if (renderData.blend) color |= 0x800; - *colorBuffer = color; - *depthBuffer = z; + colorBuffer[x & 511] = color; + depthBuffer[x & 511] = z; } } } @@ -1411,35 +1414,32 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent light += dlight; s += ds; t += dt; - - colorBuffer++; - depthBuffer++; } } void hng64_poly_renderer::render_flat_scanline(int32_t scanline, const extent_t& extent, const hng64_poly_data& renderData, int threadid) { + if ((scanline > 511) | (scanline < 0)) + return; + // Pull the parameters out of the extent structure float z = extent.param[0].start; const float dz = extent.param[0].dpdx; // Pointers to the pixel buffers - float* depthBuffer = &m_depthBuffer3d[(scanline * 512) + extent.startx]; - uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512) + extent.startx]; + float* depthBuffer = &m_depthBuffer3d[(scanline * 512)]; + uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512)]; // Step over each pixel in the horizontal span for(int x = extent.startx; x < extent.stopx; x++) { - if (z < *depthBuffer) + if (z < depthBuffer[x & 511]) { - *colorBuffer = renderData.palOffset + renderData.colorIndex; - *depthBuffer = z; + colorBuffer[x & 511] = renderData.palOffset + renderData.colorIndex; + depthBuffer[x & 511] = z; } z += dz; - - colorBuffer++; - depthBuffer++; } } diff --git a/src/mame/snk/hng64_sprite.ipp b/src/mame/snk/hng64_sprite.ipp index c85f872d264..f9933feca63 100644 --- a/src/mame/snk/hng64_sprite.ipp +++ b/src/mame/snk/hng64_sprite.ipp @@ -148,7 +148,7 @@ inline void hng64_state::drawline(bitmap_ind16 & dest, bitmap_ind16 & destz, con inline void hng64_state::zoom_transpen(bitmap_ind16 &dest, bitmap_ind16 &destz, const rectangle &cliprect, gfx_element *gfx, uint32_t code, uint32_t color, int flipx, int flipy, int32_t xpos, int32_t ypos, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int curyy, uint16_t &srcpix) + int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, uint16_t group, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int curyy, uint16_t &srcpix) { // use pen usage to optimize code %= gfx->elements(); @@ -166,6 +166,8 @@ inline void hng64_state::zoom_transpen(bitmap_ind16 &dest, bitmap_ind16 &destz, if (blend) color |= 0x8000; + color |= group; + assert(dest.valid()); assert(dest.cliprect().contains(cliprect)); @@ -287,6 +289,7 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl ypos = util::sext(ypos, 10); bool blend = (m_spriteram[(currentsprite * 8) + 4] & 0x00800000); + uint16_t group = (m_spriteram[(currentsprite * 8) + 4] & 0x00700000) >> 8; bool checkerboard = (m_spriteram[(currentsprite * 8) + 4] & 0x04000000); uint8_t mosaic = (m_spriteram[(currentsprite * 8) + 4] & 0xf0000000) >> 28; @@ -368,7 +371,7 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl int used_ysource_pos = full_srcpix_y2 >> 16; int ytilebbb = used_ysource_pos / 0x10; int use_tile_line = used_ysource_pos & 0xf; - draw_sprite_line(screen, cliprect, use_tile_line, ypos, xpos, chainx, dx, dy, ytilebbb, chaini, currentsprite, chainy, xflip, yflip, zval, zsort, blend, checkerboard, mosaic); + draw_sprite_line(screen, cliprect, use_tile_line, ypos, xpos, chainx, dx, dy, ytilebbb, chaini, currentsprite, chainy, xflip, yflip, zval, zsort, blend, group, checkerboard, mosaic); } ypos++; } @@ -378,7 +381,7 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl } -inline void hng64_state::draw_sprite_line(screen_device& screen, const rectangle& cliprect, int32_t curyy, int16_t ypos, int16_t xpos, int chainx, int32_t dx, int32_t dy, int ytileblock, int chaini, int currentsprite, int chainy, int xflip, int yflip, uint16_t zval, bool zsort, bool blend, bool checkerboard, uint8_t mosaic) +inline void hng64_state::draw_sprite_line(screen_device& screen, const rectangle& cliprect, int32_t curyy, int16_t ypos, int16_t xpos, int chainx, int32_t dx, int32_t dy, int ytileblock, int chaini, int currentsprite, int chainy, int xflip, int yflip, uint16_t zval, bool zsort, bool blend, uint16_t group, bool checkerboard, uint8_t mosaic) { uint32_t srcpix_x = 0; uint16_t srcpix = 0; @@ -400,7 +403,7 @@ inline void hng64_state::draw_sprite_line(screen_device& screen, const rectangle uint8_t gfxregion; get_tile_details(chaini, currentsprite, xdrw, ytileblock, chainx, chainy, xflip, yflip, tileno, pal, gfxregion); - zoom_transpen(m_sprite_bitmap, m_sprite_zbuffer, cliprect, m_gfxdecode->gfx(gfxregion), tileno, pal, xflip, yflip, xpos, ypos, dx, dy, dstwidth, 0, zval, zsort, blend, checkerboard, mosaic, mosaic_count_x, curyy, srcpix); + zoom_transpen(m_sprite_bitmap, m_sprite_zbuffer, cliprect, m_gfxdecode->gfx(gfxregion), tileno, pal, xflip, yflip, xpos, ypos, dx, dy, dstwidth, 0, zval, zsort, blend, group, checkerboard, mosaic, mosaic_count_x, curyy, srcpix); xpos += dstwidth; } diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index 59e323e31c0..73d53670c5e 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -394,7 +394,28 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap // we have the scroll values for the current line, draw - pen_t const *const clut = &m_palette->pen(0); + pen_t* clut; + + // allow one of the 2 pairs of fade values to be used (complete guess! but fatfurwa turns this bit on whenever it wants to do a fade effect and off when it's done) + if ((get_tileregs(tm) & 0x0080) >> 7) + { + // which one depends on target layer? (also complete guess!) + // (buriki intro suggests this is wrong, it should be fading tilemaps to black on the discipline name screens with a full subtractive blend, but picks the wrong register? + // as we're already using this to decide which layer we're on for blending, it's probably not got a double use) + if (get_tileregs(tm) & 0x0020) + { + clut = (pen_t*)&m_palette_fade0->pen(0); + } + else + { + clut = (pen_t*)&m_palette_fade1->pen(0); + } + } + else + { + clut = (pen_t*)&m_palette->pen(0); + } + bitmap_ind8 &priority_bitmap = screen.priority(); bitmap_rgb32 &destbitmap = dest; const bitmap_ind16 &srcbitmap = tmap->pixmap(); @@ -621,19 +642,6 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap // 08e0 - fatal fury wa during transitions // 0940 - samurai shodown 64 // 0880 - buriki - - // Individual tilemap regs format - // ------------------------------ - // mmmm dbr? ??ez zzzz - // m = Tilemap mosaic level [0-15] - confirmed in sams64 demo mode - // -- they seem to enable mosaic at the same time as rowscroll in several cases (floor in buriki / ff) - // and also on the rotating logo in buriki.. does it cause some kind of aliasing side-effect, or.. ? - // d = line (floor) mode - buriki, fatafurwa, some backgrounds in ss64_2 - // b = 4bpp/8bpp (seems correct) (beast busters, samsh64, sasm64 2, xrally switch it for some screens) - // r = tile size (seems correct) - // e = tilemap enable bit according to sams64_2 - // z = z depth/priority? tilemaps might also be affected by min / max clip values somewhere? - // (debug layer on buriki has priority 0x020, which would be highest) */ @@ -651,23 +659,19 @@ uint16_t hng64_state::get_scrollbase(int tm) int hng64_state::get_blend_mode(int tm) { // this is based on xrally and sams64/sams64_2 use, it could be incorrect - // it doesn't seem to be 100% on sams64_2 select screen when the mode select circle moves down + // it doesn't seem to be 100% on sams64_2 select screen when the mode select circle moves down - that is a blended sprite and blended tilemap mixing in a weird way to produce a darker than expected image as there are can be no other components in said mix - // m_tcram[0x14/4] may be some additional per layer for this? uint8_t blendmode = 1; - if ((m_tcram[0x0c / 4] & 0x04000000) && (tm == 1)) // only enable it for the 2nd tilemap right now, find other use cases! - blendmode = 2; - - - // the bit below also gets set for certain blending effects - // for example a mist effect in the long tunnel on the South America course - // ( https://youtu.be/9rOPkNHTmYA?t=403 6:43 ) - // this is the only course which has this bit set (it is set all the time) and is the only course using blending - // - // the problem here however is that the tilemap used for blending has a lower tilemap priority than the background tilemap?! - // the bit also gets set on the buriki title screen, and how that blends is unclear even with reference footage - //if ((m_tcram[0x0c / 4] & 0x00000004) && (tm == 3)) - // blendmode = 2; + if ((get_tileregs(tm) & 0x0020) >> 5) // for layers with L(1) + { + if ((m_tcram[0x0c / 4] >> 2) & 0x1) + blendmode = 2; + } + else // for layers with L(0) + { + if ((m_tcram[0x0c / 4] >> 26) & 0x1) + blendmode = 2; + } return blendmode; } @@ -688,22 +692,13 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, // Useful bits from the tilemap registers const uint8_t mosaic = (tileregs & 0xf000) >> 12; - const uint8_t not_line_mode = (tileregs & 0x0800) >> 11; //const uint8_t bpp = (tileregs & 0x0400) >> 10; // not used? const uint8_t big = (tileregs & 0x0200) >> 9; const uint8_t enable = (tileregs & 0x0040) >> 6; - // Tilemap drawing enable? - // - // Definitely used to disable tilemaps in sams64_2 demo mode - // and is also set on the 'debug layer' of buriki - // however the floor layer of fatfurwa also has it set, and that must be enabled! - // - // Speculate that floormode ignores this flag, because lines can be disabled on - // a per-line basis? - // - // Could also just be another priority bits with some priorities being filtered - if (!enable && not_line_mode) + // this bit is used to disable tilemaps, note on fatfurwa a raster interrupt is used to change this mid-screen, swapping between + // the background layers and the floor being enabled! + if (!enable) { return; } @@ -753,6 +748,65 @@ g_profiler.stop(); } +void hng64_state::mixsprites_test(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect, uint16_t priority, int y) +{ + // this correctly allows buriki intro sprites to use regular alpha, not additive + // while also being correct for sams64, which wants additive, but appears to be + // incorrect for Fatal Fury's hit effects which want additive + // + // the 6 regs around here have the same values in fatfur and buriki, so are unlikely + // to control the blend type. + //uint8_t spriteblendtype = (m_tcram[0x10 / 4] >> 16) & 0x10; + + // would be an odd place for it, after the 'vblank' flag but... + uint8_t spriteblendtype = (m_tcram[0x4c / 4] >> 16) & 0x01; + pen_t const* const spriteclut = &m_palette->pen(0); + + if (true) + { + const uint16_t* spritesrc = &m_sprite_bitmap.pix(y, cliprect.min_x); + uint32_t* spritedst = &bitmap.pix(y, cliprect.min_x); + + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + { + uint16_t srcpix = *spritesrc; + if (srcpix & 0x0fff) + { + // if ((srcpix & 0x7000) == 0x7000) // buriki jumbotron (behind all tilemaps, behind 3d) (behind tilemap prio 1b) + // if ((srcpix & 0x7000) == 0x6000) // people behind arena walls (above lowest tilemap, behind others, behind 3d) (behind tilemap prio 16) + + //if ((srcpix & 0x7000) == 0x5000) // not used on buriki? + //if ((srcpix & 0x7000) == 0x4000) // character portraits on buriki select screen (still behind 3d) + + //if ((srcpix & 0x7000) == 0x3000) // character names and bio (above 3D graphics) + + //if ((srcpix & 0x7000) == 0x2000) // select cursor, second system graphic, timers etc. (above ring tilemap, above 3d) + + //if ((srcpix & 0x7000) == 0x1000) // credit text etc. + //if ((srcpix & 0x7000) == 0x0000 // not used on buriki ? + + if ((srcpix & 0x7000) == priority) + { + if (srcpix & 0x8000) + { + if (spriteblendtype) + *spritedst = alpha_blend_r32(*(uint32_t*)spritedst, spriteclut[srcpix & 0x0fff], 0x80); + else + *spritedst = add_blend_r32(*spritedst, spriteclut[srcpix & 0x0fff]); + } + else + { + *spritedst = spriteclut[srcpix & 0x0fff]; + } + } + } + + spritedst++; + spritesrc++; + } + + } +} uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { @@ -834,17 +888,21 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } } + // tilemaps with 'priority' 0x10 - 0x1f are always behind the 3d? for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - for (int i = 0x3f; i >= 0; i--) + for (int i = 0x1f; i >= 0x10; i--) { for (int j = 0; j < 4; j++) { - uint16_t pri = get_tileregs(j) & 0x3f; + uint16_t pri = get_tileregs(j) & 0x1f; if (pri == i) hng64_drawtilemap(screen, bitmap, cliprect, j, 0, y); } + + if ((i&3) == 0) + mixsprites_test(screen, bitmap, cliprect, (i/4)<<12, y); } } @@ -888,7 +946,7 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b // Blit the color buffer into the primary bitmap for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - int realy = (((y-cliprect.min_y) * yinc) >> 16); + int realy = (((y-visarea.min_y) * yinc) >> 16); const uint16_t* src = &m_poly_renderer->colorBuffer3d()[((realy) & 0x1ff) * 512]; uint32_t* dst = &bitmap.pix(y, cliprect.min_x); @@ -913,66 +971,53 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } } } - // Draw the sprites on top of everything - draw_sprites_buffer(screen, cliprect); - // copy sprites into display - - if (true) + // tilemaps with 'priority' 0x00 - 0x0f are always above the 3d? - could bit 0x10 really be a 'relative to 3d' bit, rather than a 'relative to other tilemaps' bit? + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - // this correctly allows buriki intro sprites to use regular alpha, not additive - // while also being correct for sams64, which wants additive, but appears to be - // incorrect for Fatal Fury's hit effects which want additive - // - // the 6 regs around here have the same values in fatfur and buriki, so are unlikely - // to control the blend type. - //uint8_t spriteblendtype = (m_tcram[0x10 / 4] >> 16) & 0x10; - - // would be an odd place for it, after the 'vblank' flag but... - uint8_t spriteblendtype = (m_tcram[0x4c / 4] >> 16) & 0x01; - - pen_t const* const clut = &m_palette->pen(0); - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + for (int i = 0x0f; i >= 0x00; i--) { - const uint16_t* src = &m_sprite_bitmap.pix(y, cliprect.min_x); - uint32_t* dst = &bitmap.pix(y, cliprect.min_x); - - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + for (int j = 0; j < 4; j++) { - uint16_t srcpix = *src; - if (srcpix & 0x7fff) - { - if (srcpix & 0x8000) - { - if (spriteblendtype) - *dst = alpha_blend_r32(*(uint32_t*)dst, clut[srcpix & 0x7fff], 0x80); - else - *dst = add_blend_r32(*dst, clut[srcpix & 0x7fff]); - } - else - { - *dst = clut[srcpix & 0x7fff]; - } - } + uint16_t pri = get_tileregs(j) & 0x1f; - dst++; - src++; + if (pri == i) + hng64_drawtilemap(screen, bitmap, cliprect, j, 0, y); } + + if ((i&3) == 0) + mixsprites_test(screen, bitmap, cliprect, (i/4)<<12, y); } } + // Draw the sprites on top of everything + draw_sprites_buffer(screen, cliprect); + + + #if HNG64_VIDEO_DEBUG if (0) popmessage("%08x %08x %08x %08x %08x", m_spriteregs[0], m_spriteregs[1], m_spriteregs[2], m_spriteregs[3], m_spriteregs[4]); - // see notes at top for more detailed info on these - if (0) - popmessage("%08x %08x\nTR(%04x %04x %04x %04x)\nSB(%04x %04x %04x %04x)\n%08x %08x %08x\nSPLIT?(%04x %04x %04x %04x)\nAA(%08x %08x)\n%08x", + + if (1) + popmessage("%08x %08x\n\ + TR0(MO(%01x) NL(%d) BPP(%d) TSIZE(%d) U(%d) F(%d) E(%d) L(%d) DEPTH( %d %d %d %d %d (%02x))\n\ + TR1(MO(%01x) NL(%d) BPP(%d) TSIZE(%d) U(%d) F(%d) E(%d) L(%d) DEPTH( %d %d %d %d %d (%02x))\n\ + TR2(MO(%01x) NL(%d) BPP(%d) TSIZE(%d) U(%d) F(%d) E(%d) L(%d) DEPTH( %d %d %d %d %d (%02x))\n\ + TR3(MO(%01x) NL(%d) BPP(%d) TSIZE(%d) U(%d) F(%d) E(%d) L(%d) DEPTH( %d %d %d %d %d (%02x))\n\ + SB(%04x %04x %04x %04x)\n\ + %08x %08x %08x\n\ + SPLIT?(%04x %04x %04x %04x)\n\ + AA(%08x %08x)\n%08x\n", // global tilemap control regs? m_videoregs[0x00], m_videoregs[0x01], // general per-tilemap regs - (m_videoregs[0x02] >> 16) & 0xffff, (m_videoregs[0x02] >> 0) & 0xffff, (m_videoregs[0x03] >> 16) & 0xffff, (m_videoregs[0x03] >> 0) & 0xffff, + (get_tileregs(0) & 0xf000)>>12, (get_tileregs(0) & 0x0800)>>11, (get_tileregs(0) & 0x0400)>>10,(get_tileregs(0) & 0x0200)>>9,(get_tileregs(0) & 0x0100)>>8,(get_tileregs(0) & 0x0080)>>7,(get_tileregs(0) & 0x0040)>>6,(get_tileregs(0) & 0x0020)>>5,(get_tileregs(0) & 0x0010)>>4,(get_tileregs(0) & 0x0008)>>3,(get_tileregs(0) & 0x0004)>>2,(get_tileregs(0) & 0x0002)>>1,(get_tileregs(0) & 0x0001)>>0,(get_tileregs(0) & 0x001f)>>0, + (get_tileregs(1) & 0xf000)>>12, (get_tileregs(1) & 0x0800)>>11, (get_tileregs(1) & 0x0400)>>10,(get_tileregs(1) & 0x0200)>>9,(get_tileregs(1) & 0x0100)>>8,(get_tileregs(1) & 0x0080)>>7,(get_tileregs(1) & 0x0040)>>6,(get_tileregs(1) & 0x0020)>>5,(get_tileregs(1) & 0x0010)>>4,(get_tileregs(1) & 0x0008)>>3,(get_tileregs(1) & 0x0004)>>2,(get_tileregs(1) & 0x0002)>>1,(get_tileregs(1) & 0x0001)>>0,(get_tileregs(1) & 0x001f)>>0, + (get_tileregs(2) & 0xf000)>>12, (get_tileregs(2) & 0x0800)>>11, (get_tileregs(2) & 0x0400)>>10,(get_tileregs(2) & 0x0200)>>9,(get_tileregs(2) & 0x0100)>>8,(get_tileregs(2) & 0x0080)>>7,(get_tileregs(2) & 0x0040)>>6,(get_tileregs(2) & 0x0020)>>5,(get_tileregs(2) & 0x0010)>>4,(get_tileregs(2) & 0x0008)>>3,(get_tileregs(2) & 0x0004)>>2,(get_tileregs(2) & 0x0002)>>1,(get_tileregs(2) & 0x0001)>>0,(get_tileregs(2) & 0x001f)>>0, + (get_tileregs(3) & 0xf000)>>12, (get_tileregs(3) & 0x0800)>>11, (get_tileregs(3) & 0x0400)>>10,(get_tileregs(3) & 0x0200)>>9,(get_tileregs(3) & 0x0100)>>8,(get_tileregs(3) & 0x0080)>>7,(get_tileregs(3) & 0x0040)>>6,(get_tileregs(3) & 0x0020)>>5,(get_tileregs(3) & 0x0010)>>4,(get_tileregs(3) & 0x0008)>>3,(get_tileregs(3) & 0x0004)>>2,(get_tileregs(3) & 0x0002)>>1,(get_tileregs(3) & 0x0001)>>0,(get_tileregs(3) & 0x001f)>>0, // scrollbase regs (m_videoregs[0x04] >> 16) & 0xffff, (m_videoregs[0x04] >> 0) & 0xffff, (m_videoregs[0x05] >> 16) & 0xffff, (m_videoregs[0x05] >> 0) & 0xffff, // initialized to fixed values? @@ -982,22 +1027,106 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b // Auto Animation registers m_videoregs[0x0b], m_videoregs[0x0c], // unused? - m_videoregs[0x0d]); + m_videoregs[0x0d] + ); + + // Individual tilemap regs format + // ------------------------------ + // mmmm dbr? FELz zzzz + // m = Tilemap mosaic level [0-15] - confirmed in sams64 demo mode + // -- they seem to enable mosaic at the same time as rowscroll in several cases (floor in buriki / ff) + // and also on the rotating logo in buriki.. does it cause some kind of aliasing side-effect, or.. ? + // d = line (floor) mode - buriki, fatafurwa, some backgrounds in ss64_2 + // b = 4bpp/8bpp (seems correct) (beast busters, samsh64, sasm64 2, xrally switch it for some screens) + // r = tile size (seems correct) + // F = allow fade1 or fade2 to apply? (complete guess!) + // E = tilemap enable bit according to sams64_2 + // L = related to output layer? seems to be tied to which mixing bits are used to enable blending + // z = z depth/priority? tilemaps might also be affected by min / max clip values somewhere? + // (debug layer on buriki has priority 0x020, which would be highest) + + if (0) - popmessage("TC: %08x MINX(%d) MINY(%d) MAXX(%d) MAXY(%d)\nBLEND ENABLES? %02x %02x %02x | %02x %02x %02x\nUNUSED?(%04x)\n%04x\nUNUSED?(%d %d)\nFor FADE1 or 1st in PALFADES group per-RGB blend modes(%d %d %d)\nFor FADE2 or 2nd in PALFADES group per-RGB blend modes(%d %d %d)\nMASTER FADES - FADE1?(%08x)\nMASTER FADES - FADE2?(%08x)\nUNUSED?(%08x)\nUNUSED?&0xfffc(%04x) DISABLE_DISPLAY(%d) ALSO USE REGS BELOW FOR MASTER FADE(%d)\nPALEFFECT_ENABLES(%d %d %d %d %d %d %d %d)\n PALFADES?(%08x %08x : %08x %08x : %08x %08x : %08x %08x)\n %08x SPRITE_BLEND_TYPE?(%08x) : %08x %08x %08x %08x", + popmessage("TC: %08x MINX(%d) MINY(%d) MAXX(%d) MAXY(%d)\n\ + MIX BITSA Nv(%d%d%d%d) P:%d B:%d Nv(%d) Al(%d) : Nv(%d) p:%d Nv(%d%d%d) b:%d Nv(%d%d) : Nv(%d) (%d) (%d %d %d) (%d %d %d)\n\ + MIX BITSB Nv(%d%d%d%d) P:%d B:%d Nv(%d) Al(%d) : Nv(%d) p:%d Nv(%d%d%d) b:%d Nv(%d%d) : Nv(%d) (%d) (%d %d %d) (%d %d %d)\n\ + UNUSED?(%04x)\n%04x\nUNUSED?(%d %d)\n\ + For FADE1 or 1st in PALFADES group per-RGB blend modes(%d %d %d)\n\ + For FADE2 or 2nd in PALFADES group per-RGB blend modes(%d %d %d)\n\ + MASTER FADES - FADE1?(%08x)\n\ + MASTER FADES - FADE2?(%08x)\n\ + UNUSED?(%08x)\n\ + UNUSED?&0xfffc(%04x) DISABLE_DISPLAY(%d) ALSO USE REGS BELOW FOR MASTER FADE(%d)\n\ + PALEFFECT_ENABLES(%d %d %d %d %d %d %d %d)\n PALFADES?(%08x %08x : %08x %08x : %08x %08x : %08x %08x)\n\ + %08x SPRITE_BLEND_TYPE?(%08x) : %08x %08x %08x %08x", m_tcram[0x00 / 4], // 0007 00e4 (fatfurwa, bbust2) (m_tcram[0x04 / 4] >> 16) & 0xffff, (m_tcram[0x04 / 4] >> 0) & 0xffff, // 0000 0010 (fatfurwa) 0000 0000 (bbust2, xrally) (m_tcram[0x08 / 4] >> 16) & 0xffff, (m_tcram[0x08 / 4] >> 0) & 0xffff, // 0200 01b0 (fatfurwa) 0200 01c0 (bbust2, xrally) // is this 2 groups of 3 regs? - (m_tcram[0x0c / 4] >> 24) & 0xff, // 04 = 'blend' on tm1 - (m_tcram[0x0c / 4] >> 16) & 0xff, // 04 = set when fades are going on with blended sprites in buriki intro? otherwise usually 00 - (m_tcram[0x0c / 4] >> 8) & 0xff, // upper bit not used? value usually 2x, 4x, 5x or 6x + //(m_tcram[0x0c / 4] >> 24) & 0xff, // 04 = 'blend' on tm1 + //(m_tcram[0x0c / 4] >> 16) & 0xff, // 04 = set when fades are going on with blended sprites in buriki intro? otherwise usually 00 + //(m_tcram[0x0c / 4] >> 8) & 0xff, // upper bit not used? value usually 2x, 4x, 5x or 6x + (m_tcram[0x0c / 4] >> 31) & 0x1, + (m_tcram[0x0c / 4] >> 30) & 0x1, + (m_tcram[0x0c / 4] >> 29) & 0x1, + (m_tcram[0x0c / 4] >> 28) & 0x1, + (m_tcram[0x0c / 4] >> 27) & 0x1, + (m_tcram[0x0c / 4] >> 26) & 0x1, // set for blends in on tm1 (pink bits on xrally etc.) (U 1 1) E(1) L(0) DEPTH (0 1 0 0 1) in sams64 intro it expects it on tm2, but it gets applied to tm1 TM2 = U(1 1) E(1) L(0) DEPTH(1 0 1 0 1) + + (m_tcram[0x0c / 4] >> 25) & 0x1, + (m_tcram[0x0c / 4] >> 24) & 0x1, // always set + + (m_tcram[0x0c / 4] >> 23) & 0x1, + (m_tcram[0x0c / 4] >> 22) & 0x1, // set on POST in xrally etc. + (m_tcram[0x0c / 4] >> 21) & 0x1, + (m_tcram[0x0c / 4] >> 20) & 0x1, + (m_tcram[0x0c / 4] >> 19) & 0x1, + (m_tcram[0x0c / 4] >> 18) & 0x1, // set on some fades in buriki attract intro (related to the sprites being blended during the fade?) + (m_tcram[0x0c / 4] >> 17) & 0x1, + (m_tcram[0x0c / 4] >> 16) & 0x1, + + (m_tcram[0x0c / 4] >> 15) & 0x1, + (m_tcram[0x0c / 4] >> 14) & 0x1, + (m_tcram[0x0c / 4] >> 13) & 0x1, + (m_tcram[0x0c / 4] >> 12) & 0x1, + (m_tcram[0x0c / 4] >> 11) & 0x1, + (m_tcram[0x0c / 4] >> 10) & 0x1, + (m_tcram[0x0c / 4] >> 9) & 0x1, + (m_tcram[0x0c / 4] >> 8) & 0x1, + // 2nd group? - (m_tcram[0x0c / 4] >> 0) & 0xff, // 04 = 'blend' on tm3 (used in transitions?) - (m_tcram[0x10 / 4] >> 24) & 0xff, // usually (always?) 00 - (m_tcram[0x10 / 4] >> 16) & 0xff, // upper bit not used? value usually 2x, 4x, 5x or 6x + //(m_tcram[0x0c / 4] >> 0) & 0xff, // 04 = 'blend' on tm3 (used in transitions?) + //(m_tcram[0x10 / 4] >> 24) & 0xff, // usually (always?) 00 + //(m_tcram[0x10 / 4] >> 16) & 0xff, // upper bit not used? value usually 2x, 4x, 5x or 6x + (m_tcram[0x0c / 4] >> 7) & 0x1, + (m_tcram[0x0c / 4] >> 6) & 0x1, + (m_tcram[0x0c / 4] >> 5) & 0x1, + (m_tcram[0x0c / 4] >> 4) & 0x1, + (m_tcram[0x0c / 4] >> 3) & 0x1, // set in POST on xrally etc. + (m_tcram[0x0c / 4] >> 2) & 0x1, // set on buriki when blends are used. tm0 blends on fatfurwa frontmost layer U(0 1) E(1) L(1) DEPTH ( 0 0 0 0 0 ) set on SS64 Portrait Win blend TM1 (U1 1 ) E(1) L(1) DEPT( 0 0 1 0 1) (other blend enabled here too!) + + (m_tcram[0x0c / 4] >> 1) & 0x1, + (m_tcram[0x0c / 4] >> 0) & 0x1, // always set + + (m_tcram[0x10 / 4] >> 31) & 0x1, + (m_tcram[0x10 / 4] >> 30) & 0x1, + (m_tcram[0x10 / 4] >> 29) & 0x1, + (m_tcram[0x10 / 4] >> 28) & 0x1, + (m_tcram[0x10 / 4] >> 27) & 0x1, + (m_tcram[0x10 / 4] >> 26) & 0x1, + (m_tcram[0x10 / 4] >> 25) & 0x1, + (m_tcram[0x10 / 4] >> 24) & 0x1, + + (m_tcram[0x10 / 4] >> 23) & 0x1, + (m_tcram[0x10 / 4] >> 22) & 0x1, + (m_tcram[0x10 / 4] >> 21) & 0x1, + (m_tcram[0x10 / 4] >> 20) & 0x1, + (m_tcram[0x10 / 4] >> 19) & 0x1, + (m_tcram[0x10 / 4] >> 18) & 0x1, + (m_tcram[0x10 / 4] >> 17) & 0x1, + (m_tcram[0x10 / 4] >> 16) & 0x1, m_tcram[0x10 / 4] & 0xffff, // unused? @@ -1130,10 +1259,86 @@ WRITE_LINE_MEMBER(hng64_state::screen_vblank_hng64) * Or maybe they set transition type (there seems to be a cute scaling-squares transition in there somewhere)... */ + + +inline void hng64_state::set_palette_entry_with_faderegs(int entry, uint8_t r, uint8_t g, uint8_t b, uint32_t rgbfade, uint8_t r_mode, uint8_t g_mode, uint8_t b_mode, palette_device *palette) +{ + + int r_fadeval = (rgbfade >> 16) & 0xff; + int g_fadeval = (rgbfade >> 8) & 0xff; + int b_fadeval = (rgbfade >> 0) & 0xff; + + int r_new = r; + int g_new = g; + int b_new = b; + + switch (r_mode) + { + case 0x00: + case 0x02: + break; + + case 0x01: // additive + r_new = r_new + r_fadeval; + if (r_new > 255) + r_new = 255; + break; + + case 0x03: // subtractive + r_new = r_new - r_fadeval; + if (r_new < 0) + r_new = 0; + break; + } + + switch (g_mode) + { + case 0x00: + case 0x02: + break; + + case 0x01: // additive + g_new = g_new + g_fadeval; + if (g_new > 255) + g_new = 255; + break; + + case 0x03: // subtractive + g_new = g_new - g_fadeval; + if (g_new < 0) + g_new = 0; + break; + } + + switch (b_mode) + { + case 0x00: + case 0x02: + break; + + case 0x01: // additive + b_new = b_new + b_fadeval; + if (b_new > 255) + b_new = 255; + break; + + case 0x03: // subtractive + b_new = b_new - b_fadeval; + if (b_new < 0) + b_new = 0; + break; + } + + palette->set_pen_color(entry, r_new, g_new, b_new); +} + inline void hng64_state::set_single_palette_entry(int entry, uint8_t r, uint8_t g, uint8_t b) { m_palette->set_pen_color(entry, r, g, b); + set_palette_entry_with_faderegs(entry, r, g, b, m_tcram[0x18 / 4], (m_tcram[0x14 / 4] >> 10) & 0x3, (m_tcram[0x14 / 4] >> 8) & 0x3, (m_tcram[0x14 / 4] >> 6) & 0x3, m_palette_fade0); + set_palette_entry_with_faderegs(entry, r, g, b, m_tcram[0x1c / 4], (m_tcram[0x14 / 4] >> 4) & 0x3, (m_tcram[0x14 / 4] >> 2) & 0x3, (m_tcram[0x14 / 4] >> 0) & 0x3, m_palette_fade1); + // our code assumes the 'lighting' values from the 3D framebuffer can be 4-bit precision // based on 'banding' seen in buriki reference videos. precalculate those here to avoid // having to do it in the video update function @@ -1153,7 +1358,11 @@ inline void hng64_state::set_single_palette_entry(int entry, uint8_t r, uint8_t if (newb > 255) newb = 255; - m_palette_3d->set_pen_color((intensity * 0x1000) + entry, newr, newg, newb); + //m_palette_3d->set_pen_color((intensity * 0x1000) + entry, newr, newg, newb); + // always use 1nd fade register for 3D (very unlikely!) (allows 3d to flash correctly in sams64 how to play, but applies wrong fade register on 3d in buriki discipline intro screens, assuming those are meant to be blacked out this way) + set_palette_entry_with_faderegs((intensity * 0x1000) + entry, newr, newg, newb, m_tcram[0x18 / 4], (m_tcram[0x14 / 4] >> 10) & 0x3, (m_tcram[0x14 / 4] >> 8) & 0x3, (m_tcram[0x14 / 4] >> 6) & 0x3, m_palette_3d); + // always use 2nd fade register for 3D (very unlikely!) + //set_palette_entry_with_faderegs((intensity * 0x1000) + entry, newr, newg, newb, m_tcram[0x1c / 4], (m_tcram[0x14 / 4] >> 4) & 0x3, (m_tcram[0x14 / 4] >> 2) & 0x3, (m_tcram[0x14 / 4] >> 0) & 0x3, m_palette_3d); } } @@ -1173,7 +1382,10 @@ void hng64_state::update_palette_entry(int entry) // // however this logic fails on fatal fury fades, as the msb is 00, indicating apply to palette entries 000-0ff but the actual // palette needing the changes is 0x900 - 0x9ff (hng64 logo white flash) so there must be further ways in which this is - // configured + // configured ** NO, see below! + // + // ** this is instead meant to apply to the tm0 in fatfurwa, basically a full screen blended layer so IS being applied to the + // correct palettes, it's currently a blend / priority issue causing it to not show uint8_t tcregion = (tcdata & 0x0f000000) >> 24; if (tcregion == (entry >> 8)) @@ -1273,7 +1485,7 @@ void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) } } - if (offset == (0x24 / 4)) + if ((offset == (0x24 / 4)) || (offset == (0x14 / 4)) || (offset == (0x18 / 4)) || (offset == (0x1c / 4))) { // lazy, just update the lot uint32_t new_data = hng64_tcram[offset]; -- cgit v1.2.3