From 24c059a2ec8990fb35a4d96570e683347df9d245 Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Mon, 27 Feb 2023 14:55:30 +0000 Subject: snk/hng64_sprite.ipp: Improved sprite mosaic effect. (#10935) * Implemented mosaic effect in Y direction. * Improved transition control register use for fade effects on Buriki One jumbotron. * Updated notes. --- src/mame/snk/hng64.cpp | 2 +- src/mame/snk/hng64.h | 14 +- src/mame/snk/hng64_sprite.ipp | 166 +++++++++++------------ src/mame/snk/hng64_v.cpp | 298 +++++++++++++++++++++++++----------------- 4 files changed, 269 insertions(+), 211 deletions(-) diff --git a/src/mame/snk/hng64.cpp b/src/mame/snk/hng64.cpp index cde3cf6149e..48d57fe4090 100644 --- a/src/mame/snk/hng64.cpp +++ b/src/mame/snk/hng64.cpp @@ -1185,7 +1185,7 @@ void hng64_state::hng_map(address_map &map) map(0x20190000, 0x20190037).ram().w(FUNC(hng64_state::hng64_vregs_w)).share("videoregs"); // Mixing - map(0x20200000, 0x20203fff).ram().w(m_palette, FUNC(palette_device::write32)).share("palette"); + map(0x20200000, 0x20203fff).ram().w(FUNC(hng64_state::pal_w)).share("paletteram"); map(0x20208000, 0x2020805f).w(FUNC(hng64_state::tcram_w)).share("tcram"); // Transition Control map(0x20208000, 0x2020805f).r(FUNC(hng64_state::tcram_r)); diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 65e907ce3e2..58732b9cf61 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -139,6 +139,7 @@ public: driver_device(mconfig, type, tag), m_screen(*this, "screen"), m_palette(*this, "palette"), + m_paletteram(*this, "paletteram"), m_vblank(*this, "VBLANK"), m_maincpu(*this, "maincpu"), m_audiocpu(*this, "audiocpu"), @@ -185,6 +186,7 @@ public: uint8_t *m_texturerom = nullptr; required_device m_screen; required_device m_palette; + required_shared_ptr m_paletteram; required_ioport m_vblank; private: @@ -342,6 +344,8 @@ private: void dl_unk_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t dl_vreg_r(); + void update_palette_entry(int entry); + void pal_w(offs_t offset, uint32_t data, uint32_t mem_mask); void tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t tcram_r(offs_t offset); @@ -439,16 +443,16 @@ private: 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 drawline(bitmap_ind16& dest, bitmap_ind16& destz, const rectangle& cliprect, - gfx_element* gfx, uint32_t code, uint32_t color, int flipx, int flipy, int32_t destx, int32_t desty, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t dstheight, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int cury, const u8* srcdata, int32_t srcx, int32_t srcy_copy, uint32_t leftovers, int line, uint16_t &srcpix); + gfx_element* gfx, uint32_t code, uint32_t color, int flipy, int32_t xpos, + int32_t dx, int32_t dy, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int32_t ypos, const u8* srcdata, int32_t srcx, uint32_t leftovers, int line, uint16_t &srcpix); 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 destx, int32_t desty, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t dstheight, 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); + 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); - void transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect); void setCameraTransformation(const uint16_t* packet); void setLighting(const uint16_t* packet); void set3dFlags(const uint16_t* packet); diff --git a/src/mame/snk/hng64_sprite.ipp b/src/mame/snk/hng64_sprite.ipp index fb39bc5214b..2428a1c14fd 100644 --- a/src/mame/snk/hng64_sprite.ipp +++ b/src/mame/snk/hng64_sprite.ipp @@ -45,7 +45,7 @@ do \ { \ uint32_t srcdata = (SOURCE); \ - if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && cury <= cliprect.bottom() && cury >= cliprect.top()) \ + if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && ypos <= cliprect.bottom() && ypos >= cliprect.top()) \ { \ if (zval < (DESTZ)) \ { \ @@ -64,7 +64,7 @@ while (0) do \ { \ uint32_t srcdata = (SOURCE); \ - if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && cury <= cliprect.bottom() && cury >= cliprect.top()) \ + if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && ypos <= cliprect.bottom() && ypos >= cliprect.top()) \ { \ if (zval > (DESTZ)) \ { \ @@ -98,41 +98,36 @@ do \ \ if (checkerboard) \ { \ - if (cb & 1) \ + if (curx & 1) \ { \ - if (!(cury & 1)) \ + if (!(ypos & 1)) \ srcpix = 0; \ } \ else \ { \ - if ((cury & 1)) \ + if ((ypos & 1)) \ srcpix = 0; \ } \ - cb++; \ } \ } \ while (0) void hng64_state::drawline(bitmap_ind16 & dest, bitmap_ind16 & destz, const rectangle & cliprect, - gfx_element * gfx, uint32_t code, uint32_t color, int flipx, int flipy, int32_t destx, int32_t desty, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t dstheight, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int cury, const u8 *srcdata, int32_t srcx, int32_t srcy_copy, uint32_t leftovers, int line, uint16_t &srcpix) + gfx_element * gfx, uint32_t code, uint32_t color, int flipy, int32_t xpos, + int32_t dx, int32_t dy, uint32_t trans_pen, uint32_t zval, bool zrev, bool blend, bool checkerboard, uint8_t mosaic, uint8_t &mosaic_count_x, int32_t ypos, const u8 *srcdata, int32_t srcx, uint32_t leftovers, int curyy, uint16_t &srcpix) { - int srcy = dy * line + srcy_copy; + auto* destptr = &dest.pix(ypos, 0); + auto* destzptr = &destz.pix(ypos, 0); - auto* destptr = &dest.pix(cury, 0); - auto* destzptr = &destz.pix(cury, 0); - - const u8* srcptr = srcdata + ((srcy >> 16) & 0xf) * gfx->rowbytes(); + const u8* srcptr = srcdata + (flipy ? ((15-curyy) & 0xf) : (curyy & 0xf)) * gfx->rowbytes(); int32_t cursrcx = srcx; - // iterate over unrolled blocks of 4 if (zrev) { - uint8_t cb = 0; // iterate over leftover pixels for (int32_t curx = 0; curx < leftovers; curx++) { - int xdrawpos = destx + curx; + int xdrawpos = xpos + curx; PIX_CHECKERBOARD; PIXEL_OP_REBASE_TRANSPEN_REV(destptr[xdrawpos], destzptr[xdrawpos], srcpix); cursrcx += dx; @@ -140,11 +135,10 @@ void hng64_state::drawline(bitmap_ind16 & dest, bitmap_ind16 & destz, const rect } else { - uint8_t cb = 0; // iterate over leftover pixels for (int32_t curx = 0; curx < leftovers; curx++) { - int xdrawpos = destx + curx; + int xdrawpos = xpos + curx; PIX_CHECKERBOARD; PIXEL_OP_REBASE_TRANSPEN(destptr[xdrawpos], destzptr[xdrawpos], srcpix); cursrcx += dx; @@ -153,8 +147,8 @@ void hng64_state::drawline(bitmap_ind16 & dest, bitmap_ind16 & destz, const rect } 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 destx, int32_t desty, - int32_t dx, int32_t dy, uint32_t dstwidth, uint32_t dstheight, 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) + 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) { // use pen usage to optimize code %= gfx->elements(); @@ -179,7 +173,7 @@ void hng64_state::zoom_transpen(bitmap_ind16 &dest, bitmap_ind16 &destz, const r if (cliprect.empty()) return; - if (dstwidth < 1 || dstheight < 1) + if (dstwidth < 1) return; int32_t srcx = 0; @@ -190,27 +184,15 @@ void hng64_state::zoom_transpen(bitmap_ind16 &dest, bitmap_ind16 &destz, const r dx = -dx; } - int32_t srcy = 0; - // apply Y flipping - if (flipy) - { - srcy = (dstheight - 1) * dy - srcy; - dy = -dy; - } - // fetch the source data const u8 *srcdata = gfx->get_data(code); - // compute how many blocks of 4 pixels we have - int32_t destendx = destx + dstwidth - 1; - uint32_t leftovers = (destendx + 1 - destx); - - // iterate over pixels in Y - int32_t srcycopy = srcy; + int32_t destendx = xpos + dstwidth - 1; + uint32_t leftovers = (destendx + 1 - xpos); drawline(dest, destz, cliprect, - gfx, code, color, flipx, flipy, destx, desty, - dx, dy, dstwidth, dstheight, trans_pen, zval, zrev, blend, checkerboard, mosaic, mosaic_count_x, desty, srcdata, srcx, srcycopy, leftovers, line, srcpix); + gfx, code, color, flipy, xpos, + dx, dy, trans_pen, zval, zrev, blend, checkerboard, mosaic, mosaic_count_x, ypos, srcdata, srcx, leftovers, curyy, srcpix); } @@ -293,11 +275,17 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl { uint16_t zval = (m_spriteram[(currentsprite * 8) + 2] & 0x07ff0000) >> 16; - uint16_t ypos = (m_spriteram[(currentsprite * 8) + 0] & 0xffff0000) >> 16; - uint16_t xpos = (m_spriteram[(currentsprite * 8) + 0] & 0x0000ffff) >> 0; + int16_t ypos = (m_spriteram[(currentsprite * 8) + 0] & 0xffff0000) >> 16; + int16_t xpos = (m_spriteram[(currentsprite * 8) + 0] & 0x0000ffff) >> 0; + + // should the offsets also be sign extended? xpos += (spriteoffsx); ypos += (spriteoffsy); + // sams64_2 wants bit 0x200 to be the sign bit on character select screen + xpos = util::sext(xpos, 10); + ypos = util::sext(ypos, 10); + bool blend = (m_spriteram[(currentsprite * 8) + 4] & 0x00800000); bool checkerboard = (m_spriteram[(currentsprite * 8) + 4] & 0x04000000); uint8_t mosaic = (m_spriteram[(currentsprite * 8) + 4] & 0xf0000000) >> 28; @@ -339,59 +327,73 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl dy = zoomy << 4; } - int16_t drawy = ypos; - uint32_t srcpix_y = 0; - for (int ydrw = 0; ydrw <= chainy; ydrw++) + uint32_t full_srcpix_y = 0; + uint32_t full_dstheight = 0; + do { - uint32_t dstheight = 0; + full_srcpix_y += dy; + full_dstheight++; + } while (full_srcpix_y < ((chainy+1) * 0x100000)); - do + int realline = 0; + int mosaic_y_counter = 0; + for (int32_t curyy = 0; curyy <= full_dstheight - 1; curyy++) + { + if (!mosaic) { - srcpix_y += dy; - dstheight++; - } while (srcpix_y < 0x100000); - srcpix_y &= 0x0fffff; - - int32_t destendy = drawy + dstheight - 1; - for (int32_t cury = drawy, line = 0; cury <= destendy; line++, cury++) + realline = curyy; + } + else { - int16_t drawx = xpos; - uint32_t srcpix_x = 0; - - uint16_t srcpix = 0; - - uint8_t mosaic_count_x = 0; - - for (int xdrw = 0; xdrw <= chainx; xdrw++) + if (mosaic_y_counter == 0) { - uint32_t dstwidth = 0; - do - { - srcpix_x += dx; - dstwidth++; - } while (srcpix_x < 0x100000); - srcpix_x &= 0x0fffff; - - // 0x3ff (0x200 sign bit) based on sams64_2 char select - drawx &= 0x3ff; - drawy &= 0x3ff; - - if (drawx & 0x0200)drawx -= 0x400; - if (drawy & 0x0200)drawy -= 0x400; - - uint32_t tileno; - uint16_t pal; - uint8_t gfxregion; - - get_tile_details(chaini, currentsprite, xdrw, ydrw, chainx, chainy, xflip, yflip, tileno, pal, gfxregion); - zoom_transpen(m_sprite_bitmap, m_sprite_zbuffer, cliprect, m_gfxdecode->gfx(gfxregion), tileno, pal, xflip, yflip, drawx, cury, dx, dy, dstwidth, dstheight, 0, zval, zsort, blend, checkerboard, mosaic, mosaic_count_x, line, srcpix); - drawx += dstwidth; + realline = curyy; + mosaic_y_counter = mosaic; + } + else + { + mosaic_y_counter--; } } - drawy += dstheight; + + uint32_t full_srcpix_y2 = realline * dy; + 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); + ypos++; } + currentsprite = nextsprite; } } + +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) +{ + uint32_t srcpix_x = 0; + uint16_t srcpix = 0; + + uint8_t mosaic_count_x = 0; + + for (int xdrw = 0; xdrw <= chainx; xdrw++) + { + uint32_t dstwidth = 0; + do + { + srcpix_x += dx; + dstwidth++; + } while (srcpix_x < 0x100000); + srcpix_x &= 0x0fffff; + + uint32_t tileno; + uint16_t pal; + 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); + xpos += dstwidth; + } + +} diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index 319640dd91d..5368ee9e6cf 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -560,26 +560,28 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap * uint32_t | Bits | Use * | 3322 2222 2222 1111 1111 11 | * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+---------------- - * 0 | ---- -Cdd ---- -??Z ---- ---- ---- ---u | C = global complex zoom + * 0 | ---- -Cdd ---- -??Z ---- ---- ---- --uu | C = global complex zoom | 0000 0011 - road edge alt 1 | dd = global tilemap dimension selector | 0000 0111 - road edge alt 2 | ? = Always Set? | | Z = Global Zoom Disable? - | | u = explicitly cleared from initialized value in sams64 - * 1 | oooo oooo oooo oooX ---- ---- ---- ---- | unknown - X is sometimes used (1 in demo of xrally, 0 in game) not always initialized whole register gets set to 0xffff during mosaic bit of roadedge intro - * 1 | ---- ---- ---- ---- oooo oooo oYoo oooo | unknown - untouched in sams64 games, initialized elsewhere Y gets set to 4 at some points in xrally attract + | | u = bit 0 is explicitly cleared from initialized value in sams64, both bits turned on for buriki 'split' effect + * 1 | oooo oooo oooo oooX ---- ---- ---- ---- | unknown - X is sometimes used (1 in demo of xrally, 0 in game) not always initialized whole register gets set to 0xffff during mosaic bit of roadedge intro. Also buriki intro + * | ---- ---- ---- ---- oooo oooo oYoo oooo | unknown - untouched in sams64 games, initialized elsewhere Y gets set to 4 at some points in xrally attract * 2 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap0 per layer flags - * 2 | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap1 per layer flags + * | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap1 per layer flags * 3 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap2 per layer flags - * 3 | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap3 per layer flags + * | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap3 per layer flags * 4 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap0 scrollbase when not floor, lineram offset when floor - * 4 | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap1 scrollbase when not floor, lineram offset when floor + * | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap1 scrollbase when not floor, lineram offset when floor * 5 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap3 scrollbase when not floor, lineram offset when floor - * 5 | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap4 scrollbase when not floor, lineram offset when floor + * | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap4 scrollbase when not floor, lineram offset when floor * 6 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 000001ff (fatfurwa) ---- bfff (xrally, and fatfurwa despite comment? maybe reads MAME initialized value and changes it?) * 7 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 000001ff (fatfurwa) 5e00 3fff (xrally ^^ ) * 8 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 80008000 (fatfurwa) 9e00 be00 (xrally ^^ ) - * 9 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 00000000 (fatfurwa) - * a | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 00000000 (fatfurwa) + * 9 | oooo oooo oooo oooo ---- ---- ---- ---- | some kind of tilemap split effect? + | ---- ---- ---- ---- oooo oooo oooo oooo | ^ + * a | oooo oooo oooo oooo ---- ---- ---- ---- | ^ + * | ---- ---- ---- ---- oooo oooo oooo oooo | ^ * b | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | auto animation mask for tilemaps * c | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx | auto animation bits for tilemaps * d | oooo oooo oooo oooo oooo oooo oooo oooo | not used ?? @@ -734,6 +736,11 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b if (m_screen_dis) return 0; + // set during transitions, could be 'disable all palette output'? + if ((m_tcram[0x24 / 4] >> 16) & 0x0002) + return 0; + + // If the auto-animation mask or bits have changed search for tiles using them and mark as dirty const uint32_t animmask = m_videoregs[0x0b]; const uint32_t animbits = m_videoregs[0x0c]; @@ -844,61 +851,78 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } } - // Layer the global frame buffer operations on top of everything - // transition_control(bitmap, 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 TR(%04x %04x %04x %04x) SB(%04x %04x %04x %04x) %08x %08x %08x %08x %08x AA(%08x %08x) %08x", - m_videoregs[0x00], - m_videoregs[0x01], - (m_videoregs[0x02] >> 16) & 0xffff, - (m_videoregs[0x02] >> 0) & 0xffff, // ss64_2 debug mode indicates that 0x0040 is enable! - (m_videoregs[0x03] >> 16) & 0xffff, // buriki agrees (debug data on text layer) xrally agress (pink layer) - (m_videoregs[0x03] >> 0) & 0xffff, // fatal fury doesn't (all backgrounds have it set) joy - (m_videoregs[0x04] >> 16) & 0xffff, - (m_videoregs[0x04] >> 0) & 0xffff, - (m_videoregs[0x05] >> 16) & 0xffff, - (m_videoregs[0x05] >> 0) & 0xffff, - m_videoregs[0x06], - m_videoregs[0x07], - m_videoregs[0x08], - m_videoregs[0x09], - m_videoregs[0x0a], - m_videoregs[0x0b], - m_videoregs[0x0c], + 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", + // 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, + // 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? + m_videoregs[0x06], m_videoregs[0x07], m_videoregs[0x08], + // used when a single tilemap gets 'split' on Buriki player entrances? + (m_videoregs[0x09] >> 16) & 0xffff, (m_videoregs[0x09] >> 0) & 0xffff, (m_videoregs[0x0a] >> 16) & 0xffff, (m_videoregs[0x0a] >> 0) & 0xffff, + // Auto Animation registers + m_videoregs[0x0b], m_videoregs[0x0c], + // unused? m_videoregs[0x0d]); - if (0) - popmessage("TC: %08x %08x %08x %08x : %08x %08x\n%08x %08x\n%08x %08x\n%08x %08x : %08x %08x %08x %08x : %08x %08x\n%08x %08x : %08x %08x %08x %08x", - m_tcram[0x00 / 4], - m_tcram[0x04 / 4], - m_tcram[0x08 / 4], // tilemaps 0/1 ? - m_tcram[0x0c / 4], // ss64_2 debug 04000000 = 'half' on tm1 00000004 = 'half' on tm3 (used in transitions?) - m_tcram[0x10 / 4], - m_tcram[0x14 / 4], + if (1) + popmessage("TC: %08x MINX(%d) MINY(%d) MAXX(%d) MAXY(%d)\nBLEND ENABLES? %02x %02x %02x | %02x %02x %02x\nUNUSED?(%04x)\n%04x\n%04x\nMASTER FADES?(%08x %08x)\nUNUSED?(%08x)\nBITFIELD REGS(%04x)\nPALEFFECT_ENABLES(%d %d %d %d %d %d %d %d)\n PALFADES?(%08x %08x : %08x %08x : %08x %08x : %08x %08x)\n % 08x % 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) + + (m_tcram[0x0c / 4] >> 24) & 0xff, // 04 = 'blend' on tm1 + (m_tcram[0x0c / 4] >> 16) & 0xff, // 04 = blend all sprites? (buriki intro, text fades?) + (m_tcram[0x0c / 4] >> 8) & 0xff, + (m_tcram[0x0c / 4] >> 0) & 0xff, // 04 = 'blend' on tm3 (used in transitions?) + (m_tcram[0x10 / 4] >> 24) & 0xff, + (m_tcram[0x10 / 4] >> 16) & 0xff, + + m_tcram[0x10 / 4] & 0xffff, // unused? + + (m_tcram[0x14 / 4] >> 16) & 0xffff, // typically 0007 or 0001, - 0011 on ss64 ingame, 0009 on continue screen + (m_tcram[0x14 / 4] >> 0) & 0xffff, // 0xxx ? (often 0555 or 0fff, seen 56a, 57f too) // these are used for 'fade to black' in most cases, but // in xrally attract, when one image is meant to fade into another, one value increases while the other decreases m_tcram[0x18 / 4], // xRGB fade values? (roadedge attract) m_tcram[0x1c / 4], // xRGB fade values? (roadedge attract) fades on fatfurwa before buildings in intro - m_tcram[0x20 / 4], // something else? - m_tcram[0x24 / 4], // something else? + m_tcram[0x20 / 4], // unused? + + // some kind of bitfields + (m_tcram[0x24 / 4] >> 16) & 0xffff, // 0002 gets set in roadedge during some transitions (layers are disabled? blacked out?) 0001 set on SNK logo in roadedge + (m_tcram[0x24 / 4] >> 0) & 0x3, // 0001 gets set when in a tunnel on roadedge in 1st person mode (state isn't updated otherwise, switching back to 3rd person in a tunnel leaves it set until you flick back to 1st person) briefly set to 3c on roadedge car select during 'no fb clear' effect? + (m_tcram[0x24 / 4] >> 2) & 0x3, + (m_tcram[0x24 / 4] >> 4) & 0x3, + (m_tcram[0x24 / 4] >> 6) & 0x3, + (m_tcram[0x24 / 4] >> 8) & 0x3, + (m_tcram[0x24 / 4] >> 10) & 0x3, + (m_tcram[0x24 / 4] >> 12) & 0x3, + (m_tcram[0x24 / 4] >> 14) & 0x3, // 7 of these fade during the buriki SNK logo (probably redundant) // in roadedge they're just set to // 0x00000000, 0x01000000, 0x02000000, 0x03000000, 0x04000000, 0x05000000, 0x06000000, 0x07000000 + // the first 8 bits seem to be which palette this affects (so 0x0b is colours 0xb00-0xbff as you see with xrally 1st person?) + // enabled with m_tcram[0x24 / 4] regs above? (see note) + m_tcram[0x28 / 4], // ?RGB fade values (buriki jumbotron) fades on fatfurwa before high score table etc. + bottom value only on 'fade to red' part of fatfurywa intro m_tcram[0x2c / 4], // ?RGB fade values (buriki jumbotron) m_tcram[0x30 / 4], m_tcram[0x34 / 4], m_tcram[0x38 / 4], - m_tcram[0x3c / 4], + m_tcram[0x3c / 4], // gets used for the 1st person view on xrally - maybe some fade effect on the front of the car? m_tcram[0x40 / 4], m_tcram[0x44 / 4], @@ -919,6 +943,21 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b 0011057f blending? 0001057f */ + + + /* + palette manipulation note + + pal7 pal6 pal5 pal4 pal3 pal2 pal1 pal0 // which fade register those bits relate to? + 00 00 11 00 00 00 10 10 // bits in (m_tcram[0x24 / 4] >> 0) (set to 0c0a in this example) + + an entry of 00 means palette effect not in use? + an entry of 11 means subtractive? + an entry of 10 means addition? + an entry of 01 means?? + */ + + #endif return 0; @@ -971,11 +1010,73 @@ 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)... */ +void hng64_state::update_palette_entry(int entry) +{ + uint32_t data = m_paletteram[entry]; + + int16_t r = (data >> 16) & 0xff; + int16_t g = (data >> 8) & 0xff; + int16_t b = (data >> 0) & 0xff; + + for (int i = 0; i < 8; i++) + { + uint32_t tcdata = m_tcram[(0x28 / 4) + i]; + uint8_t tcregion = (tcdata & 0x0f000000) >> 24; + + if (tcregion == (entry >> 8)) + { + uint8_t bmod = (tcdata >> 16) & 0xff; + uint8_t gmod = (tcdata >> 8) & 0xff; + uint8_t rmod = (tcdata >> 0) & 0xff; + + uint8_t tcreg = (m_tcram[0x24 / 4] >> (i << 1)) & 3; + switch (tcreg) + { + case 0x00: // this entry is disabled + break; + case 0x01: // this entry is disabled(?) + break; + case 0x02: // additive blending + r = r + rmod; + if (r > 0xff) + r = 0xff; + g = g + gmod; + if (g > 0xff) + g = 0xff; + b = b + bmod; + if (b > 0xff) + b = 0xff; + break; + case 0x03: // subtractive blending + r = r - rmod; + if (r < 0x00) + r = 0x00; + g = g - gmod; + if (g < 0x00) + g = 0x00; + b = b - bmod; + if (b < 0x00) + b = 0x00; + break; + } + } + } + + m_palette->set_pen_color(entry, r,g,b); +} + +void hng64_state::pal_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + COMBINE_DATA(&m_paletteram[offset]); + update_palette_entry(offset); +} + // Transition Control memory. void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) { uint32_t *hng64_tcram = m_tcram; + uint32_t old_data = hng64_tcram[offset]; COMBINE_DATA(&hng64_tcram[offset]); if (offset == 0x02) @@ -998,6 +1099,39 @@ void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) visarea.set(min_x, min_x + max_x - 1, min_y, min_y + max_y - 1); m_screen->configure(HTOTAL, VTOTAL, visarea, m_screen->frame_period().attoseconds()); } + + if ((offset >= (0x28 / 4)) && (offset < (0x48 / 4))) + { + uint32_t new_data = hng64_tcram[offset]; + if (old_data != new_data) + { + // the old blend value no longer applies, so update the colours referenced by that + uint8_t old_tcregion = (old_data & 0x0f000000) >> 24; + for (int i = 0; i < 0x100; i++) + { + update_palette_entry((old_tcregion * 0x100) + i); + } + // update the colours referenced by the new blend register + uint8_t new_tcregion = (new_data & 0x0f000000) >> 24; + for (int i = 0; i < 0x100; i++) + { + update_palette_entry((new_tcregion * 0x100) + i); + } + } + } + + if (offset == (0x24 / 4)) + { + // lazy, just update the lot + uint32_t new_data = hng64_tcram[offset]; + if (old_data != new_data) + { + for (int i = 0; i < 0x1000; i++) + { + update_palette_entry(i); + } + } + } } uint32_t hng64_state::tcram_r(offs_t offset) @@ -1010,88 +1144,6 @@ uint32_t hng64_state::tcram_r(offs_t offset) return m_tcram[offset]; } -// Very much a work in progress - no hard testing has been done -void hng64_state::transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - // If either of the fading memory regions is non-zero... - if (m_tcram[0x00000007] != 0x00000000 || m_tcram[0x0000000a] != 0x00000000) - { - const int32_t darkR = int32_t(m_tcram[0x00000007] & 0xff); - const int32_t darkG = int32_t((m_tcram[0x00000007] >> 8) & 0xff); - const int32_t darkB = int32_t((m_tcram[0x00000007] >> 16) & 0xff); - - const int32_t brigR = int32_t(m_tcram[0x0000000a] & 0xff); - const int32_t brigG = int32_t((m_tcram[0x0000000a] >> 8) & 0xff); - const int32_t brigB = int32_t((m_tcram[0x0000000a] >> 16) & 0xff); - - for (int i = cliprect.min_x; i < cliprect.max_x; i++) - { - for (int j = cliprect.min_y; j < cliprect.max_y; j++) - { - rgb_t *thePixel = reinterpret_cast(&bitmap.pix(j, i)); - - int32_t finR = (int32_t)thePixel->r(); - int32_t finG = (int32_t)thePixel->g(); - int32_t finB = (int32_t)thePixel->b(); - -#if 0 - float colorScaleR, colorScaleG, colorScaleB; - - // Apply the darkening pass (0x07)... - colorScaleR = 1.0f - (float)(m_tcram[0x00000007] & 0xff) / 255.0f; - colorScaleG = 1.0f - (float)((m_tcram[0x00000007] >> 8) & 0xff) / 255.0f; - colorScaleB = 1.0f - (float)((m_tcram[0x00000007] >> 16) & 0xff) / 255.0f; - - finR = ((float)thePixel->r() * colorScaleR); - finG = ((float)thePixel->g() * colorScaleG); - finB = ((float)thePixel->b() * colorScaleB); - - // Apply the lightening pass (0x0a)... - colorScaleR = 1.0f + (float)(m_tcram[0x0000000a] & 0xff) / 255.0f; - colorScaleG = 1.0f + (float)((m_tcram[0x0000000a] >> 8) & 0xff) / 255.0f; - colorScaleB = 1.0f + (float)((m_tcram[0x0000000a] >> 16) & 0xff) / 255.0f; - - finR *= colorScaleR; - finG *= colorScaleG; - finB *= colorScaleB; - - // Clamp - if (finR > 255.0f) finR = 255.0f; - if (finG > 255.0f) finG = 255.0f; - if (finB > 255.0f) finB = 255.0f; -#endif - - // Subtractive fading - if (m_tcram[0x00000007] != 0x00000000) - { - finR -= darkR; - finG -= darkG; - finB -= darkB; - } - - // Additive fading - if (m_tcram[0x0000000a] != 0x00000000) - { - finR += brigR; - finG += brigG; - finB += brigB; - } - - // Clamp the high end - if (finR > 255) finR = 255; - if (finG > 255) finG = 255; - if (finB > 255) finB = 255; - - // Clamp the low end - if (finR < 0) finR = 0; - if (finG < 0) finG = 0; - if (finB < 0) finB = 0; - - *thePixel = rgb_t(255, (uint8_t)finR, (uint8_t)finG, (uint8_t)finB); - } - } - } -} void hng64_state::video_start() { -- cgit v1.2.3