From ca235063b49bfb416ac9db90ceefbb41eeac7aff Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Sat, 25 Feb 2023 18:18:20 +0000 Subject: snk/hng64_sprite.ipp, snk/hng64_v.cpp: Improved Hyper Neo Geo 64 sprite drawing. (#10914) * Render sprites to intermediate buffer buffer and blend when mixing (fixes sprite/sprite priorities). * Implemented mesh/checkerboard fake transparency (previously sprites using this were skipped). * Improved precision of sprite scaling (fixes gaps and smoothness of scale in many places). * Improved floor layer rendering for buriki and fatfurwa. * Added preliminary sprite mosaic effect support. --- src/mame/snk/hng64.cpp | 17 +- src/mame/snk/hng64.h | 18 +- src/mame/snk/hng64_sprite.ipp | 444 +++++++++++++++++++++++++++++------------- src/mame/snk/hng64_v.cpp | 141 ++++++++++---- 4 files changed, 434 insertions(+), 186 deletions(-) diff --git a/src/mame/snk/hng64.cpp b/src/mame/snk/hng64.cpp index c8aed843e2a..cde3cf6149e 100644 --- a/src/mame/snk/hng64.cpp +++ b/src/mame/snk/hng64.cpp @@ -2141,6 +2141,13 @@ TIMER_CALLBACK_MEMBER(hng64_state::comhack_callback) // different network IDs give different default colours for the cars in roadedge uint8_t network_id = 0x01; + // this fixes the stuck scroller text in the xrally intro (largest pink text) but prevents the inputs from working. + // It's probably trying to sync the scroller with another unit? however the original machines can run as singles + // if you loop some of the pins on the network connector back, so maybe MAME is just confused about the mode it's + // running in. + // network_id |= 0x08; + + m_comhack[0] = m_comhack[0] | network_id; } @@ -2582,7 +2589,8 @@ void hng64_state::hng64_fight(machine_config &config) ROM_REGION( 0x100, "eeprom", 0 ) /* EEPROMs on the I/O boards, mostly empty, currently not used by the emulation */ \ ROM_LOAD( "lvs-ioj-br9020f.u2", 0x000, 0x100, CRC(78b7020d) SHA1(2b8549532ef5e1e8102dbe71af55fdfb27ccbba6) ) \ ROM_LOAD( "lvs-igx-br9020f.u3", 0x000, 0x100, CRC(af9f4287) SHA1(6df0e35c77dbfee2fab7ff490dcd651db420e367) ) \ - ROM_LOAD( "lvs-jam-br9020f.u3", 0x000, 0x100, CRC(dabec5d2) SHA1(19c5be89c57387d6ea563b3dc55674d0692af98e) ) + ROM_LOAD( "lvs-jam-br9020f.u3", 0x000, 0x100, CRC(dabec5d2) SHA1(19c5be89c57387d6ea563b3dc55674d0692af98e) ) \ + ROM_DEFAULT_BIOS( "export" ) ROM_START( hng64 ) /* BIOS */ @@ -2930,6 +2938,13 @@ ROM_START( fatfurwa ) ROM_LOAD( "006sd02a.78", 0x0400000, 0x400000, CRC(f7f020c7) SHA1(b72fde4ff6384b80166a3cb67d31bf7afda750bc) ) ROM_LOAD( "006sd03a.79", 0x0800000, 0x400000, CRC(1a678084) SHA1(f52efb6145102d289f332d8341d89a5d231ba003) ) ROM_LOAD( "006sd04a.80", 0x0c00000, 0x400000, CRC(3c280a5c) SHA1(9d3fc78e18de45382878268db47ff9d9716f1505) ) + + /* this game does not initialize EEPROM automatically otherwise (each region requires different defaults) */ + ROM_REGION( 0x4000, "nvram", 0 ) + ROMX_LOAD( "default_nvram_japan", 0x00000, 0x4000, CRC(1f618d44) SHA1(c007c5f94b28b8c56c8c539d2f82336515c0ed84), ROM_BIOS(0) ) + ROMX_LOAD( "default_nvram_usa", 0x00000, 0x4000, CRC(f139f4a5) SHA1(6f7e2fc5d902c1499f3c55f9ca2ef7becc49103b), ROM_BIOS(1) ) + ROMX_LOAD( "default_nvram_others", 0x00000, 0x4000, CRC(bf1c3e4a) SHA1(454c6e5e505293bfdeb87d08e72420bba84c3b7b), ROM_BIOS(2) ) + ROMX_LOAD( "default_nvram_korea", 0x00000, 0x4000, CRC(e8fb68df) SHA1(3170e7465b93319c0550f35f8906b5bdc5332eec), ROM_BIOS(3) ) ROM_END diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 178a51fbbe2..65e907ce3e2 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -271,7 +271,10 @@ private: //uint32_t *q2 = nullptr; - std::vector< std::pair > m_spritelist; + + bitmap_ind16 m_sprite_bitmap; + bitmap_ind16 m_sprite_zbuffer; + uint8_t m_screen_dis = 0U; @@ -433,7 +436,18 @@ private: void clear3d(); bool hng64_command3d(const uint16_t* packet); - void draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + 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 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); + + 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); + void transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect); void setCameraTransformation(const uint16_t* packet); void setLighting(const uint16_t* packet); diff --git a/src/mame/snk/hng64_sprite.ipp b/src/mame/snk/hng64_sprite.ipp index fcdd792ca75..fb39bc5214b 100644 --- a/src/mame/snk/hng64_sprite.ipp +++ b/src/mame/snk/hng64_sprite.ipp @@ -7,25 +7,25 @@ * Sprite Format * ------------------ * - * uint32_t | Bits | Use + * offset | Bits | Use * | 3322 2222 2222 1111 1111 11 | * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+---------------- * 0 | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position * 1 | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*) - * 2 | ---- -zzz zzzz zzzz ---- ---I cccc CCCC | Z-buffer value, 'Inline' chain flag, x/y chain + * 2 | ---- Szzz zzzz zzzz ---- ---I cccc CCCC | S = set on CPU car markers above cars (in roadedge) z = Z-buffer value, i = 'Inline' chain flag, cC = x/y chain * 3 | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry - * 4 | mmmm -?fF a??? tttt tttt tttt tttt tttt | mosaic factor, unknown (**) , flip bits, additive blending, unknown (***), tile number + * 4 | mmmm -cfF aggg tttt tttt tttt tttt tttt | mosaic factor, unknown (x1), checkerboard, flip bits, blend, group?, tile number * 5 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? * 6 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? * 7 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? * + * in (4) ggg seems to be either group, or priority against OTHER layers (7 being the lowest, 0 being the highest in normal situations eg most of the time in buriki) + * * (*) Fatal Fury WA standard elements are 0x1000-0x1000, all the other games sets 0x100-0x100, related to the bit 27 of sprite regs 0? - * (**) setted by black squares in ranking screen in Samurai Shodown 64 1, sprite disable? - * (***) bit 22 is setted on some Fatal Fury WA snow (not all of them), bit 21 is setted on Xrally how to play elements in attract mode ** Sprite Global Registers * ----------------------- * - * uint32_t | Bits | Use + * offset | Bits | Use * | 3322 2222 2222 1111 1111 11 | * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+---------------- * 0 | ssss z--f b--- -aap ---- ---- ---- ---- | s = unknown, samsho z = zooming mode, f = priority sort mode (unset set in roadedge ingame) b = bpp select a = always, p = post, disable? @@ -40,194 +40,358 @@ */ -void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - gfx_element *gfx; - uint32_t *source = m_spriteram; - uint32_t *finish = m_spriteram + 0xc000/4; - - // global offsets in sprite regs - int spriteoffsx = (m_spriteregs[1]>>0)&0xffff; - int spriteoffsy = (m_spriteregs[1]>>16)&0xffff; - // This flips between ingame and other screens for roadedge, where the sprites which are filtered definitely needs to change and the game explicitly swaps the values in the sprite list at the same time. - // m_spriteregs[2] could also play a part as it also flips between 0x00000000 and 0x000fffff at the same time - // Samsho games also set the upper 3 bits which could be related, samsho games still have some unwanted sprites (but also use the other 'sprite clear' mechanism) - // Could also be draw order related, check if it inverts the z value? - bool zsort = !(m_spriteregs[0] & 0x01000000); +#define PIXEL_OP_REBASE_TRANSPEN(DEST, DESTZ, SOURCE) \ +do \ +{ \ + uint32_t srcdata = (SOURCE); \ + if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && cury <= cliprect.bottom() && cury >= cliprect.top()) \ + { \ + if (zval < (DESTZ)) \ + { \ + if (srcdata != trans_pen) \ + { \ + (DESTZ) = zval; \ + (DEST) = color + srcdata; \ + } \ + } \ + } \ +} \ +while (0) + + +#define PIXEL_OP_REBASE_TRANSPEN_REV(DEST, DESTZ, SOURCE) \ +do \ +{ \ + uint32_t srcdata = (SOURCE); \ + if (xdrawpos <= cliprect.right() && xdrawpos >= cliprect.left() && cury <= cliprect.bottom() && cury >= cliprect.top()) \ + { \ + if (zval > (DESTZ)) \ + { \ + if (srcdata != trans_pen) \ + { \ + (DESTZ) = zval; \ + (DEST) = color + srcdata; \ + } \ + } \ + } \ +} \ +while (0) + +#define PIX_CHECKERBOARD \ +do \ +{ \ + if (!mosaic) \ + srcpix = srcptr[(cursrcx >> 16) & 0xf]; \ + else \ + { \ + if (mosaic_count_x == 0) \ + { \ + srcpix = srcptr[(cursrcx >> 16) & 0xf]; \ + mosaic_count_x = mosaic; \ + } \ + else \ + { \ + mosaic_count_x--; \ + } \ + } \ + \ + if (checkerboard) \ + { \ + if (cb & 1) \ + { \ + if (!(cury & 1)) \ + srcpix = 0; \ + } \ + else \ + { \ + if ((cury & 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) +{ + int srcy = dy * line + srcy_copy; -#if 0 - for (int iii = 0; iii < 0x0f; iii++) - osd_printf_debug("%.8x ", m_videoregs[iii]); - osd_printf_debug("\n"); -#endif + auto* destptr = &dest.pix(cury, 0); + auto* destzptr = &destz.pix(cury, 0); - // start with empty list - m_spritelist.clear(); + const u8* srcptr = srcdata + ((srcy >> 16) & 0xf) * gfx->rowbytes(); + int32_t cursrcx = srcx; - while(source < finish) + // iterate over unrolled blocks of 4 + if (zrev) { - if (source[4]&0x04000000) // disable bit, ss64 rankings ? + uint8_t cb = 0; + // iterate over leftover pixels + for (int32_t curx = 0; curx < leftovers; curx++) { - source += 8; + int xdrawpos = destx + curx; + PIX_CHECKERBOARD; + PIXEL_OP_REBASE_TRANSPEN_REV(destptr[xdrawpos], destzptr[xdrawpos], srcpix); + cursrcx += dx; } - else + } + else + { + uint8_t cb = 0; + // iterate over leftover pixels + for (int32_t curx = 0; curx < leftovers; curx++) { - if ((!zsort && (source[2]&0x07ff0000) != 0x07ff0000) || (zsort && (source[2]&0x07ff0000) != 0)) - { - m_spritelist.emplace_back((source[2]&0x7ff0000)>>16, source); - if (source[2]&0x00000100) // inline chain mode - source += 8 * (1 + (source[2]&0x0000000f)) * (1 + ((source[2]&0x000000f0)>>4)); - else - source += 8; - } - else - source += 8; + int xdrawpos = destx + curx; + PIX_CHECKERBOARD; + PIXEL_OP_REBASE_TRANSPEN(destptr[xdrawpos], destzptr[xdrawpos], srcpix); + cursrcx += dx; } } +} - if (zsort) - std::stable_sort(m_spritelist.begin(), m_spritelist.end(), [] (auto const &a, auto const &b) { return a.first > b.first; }); - - for(auto it : m_spritelist) +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) +{ + // use pen usage to optimize + code %= gfx->elements(); + if (gfx->has_pen_usage()) { - source = it.second; - - int tileno,chainx,chainy,xflip; - int pal,xinc,yinc,yflip; - uint16_t xpos, ypos; - int xdrw,ydrw; - int chaini; - uint32_t zoomx,zoomy; - float foomX, foomY; - int blend; - - ypos = (source[0]&0xffff0000)>>16; - xpos = (source[0]&0x0000ffff)>>0; - xpos += (spriteoffsx); - ypos += (spriteoffsy); + // fully transparent; do nothing + uint32_t usage = gfx->pen_usage(code); + if ((usage & ~(1 << trans_pen)) == 0) + return; + } - tileno= (source[4]&0x0007ffff); - blend= (source[4]&0x00800000); - yflip= (source[4]&0x01000000)>>24; - xflip= (source[4]&0x02000000)>>25; + // render + color = gfx->colorbase() + gfx->granularity() * (color % gfx->colors()); - pal =(source[3]&0x00ff0000)>>16; + if (blend) + color |= 0x8000; - chainy=(source[2]&0x0000000f); - chainx=(source[2]&0x000000f0)>>4; - chaini=(source[2]&0x00000100); + assert(dest.valid()); + assert(dest.cliprect().contains(cliprect)); - zoomy = (source[1]&0xffff0000)>>16; - zoomx = (source[1]&0x0000ffff)>>0; + // ignore empty/invalid cliprects + if (cliprect.empty()) + return; -#if 0 - if (!(source[4] == 0x00000000 || source[4] == 0x000000aa)) - osd_printf_debug("unknown : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x \n", source[0], source[1], source[2], source[3], - source[4], source[5], source[6], source[7]); -#endif + if (dstwidth < 1 || dstheight < 1) + return; - /* Calculate the zoom */ - { - int zoom_factor; + int32_t srcx = 0; + // apply X flipping + if (flipx) + { + srcx = (dstwidth - 1) * dx - srcx; + dx = -dx; + } - /* FIXME: regular zoom mode has precision bugs, can be easily seen in Samurai Shodown 64 intro */ - zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100; - if(!zoomx) zoomx=zoom_factor; - if(!zoomy) zoomy=zoom_factor; + int32_t srcy = 0; + // apply Y flipping + if (flipy) + { + srcy = (dstheight - 1) * dy - srcy; + dy = -dy; + } - /* First, prevent any possible divide by zero errors */ - foomX = (float)(zoom_factor) / (float)zoomx; - foomY = (float)(zoom_factor) / (float)zoomy; + // fetch the source data + const u8 *srcdata = gfx->get_data(code); - zoomx = ((int)foomX) << 16; - zoomy = ((int)foomY) << 16; + // compute how many blocks of 4 pixels we have + int32_t destendx = destx + dstwidth - 1; + uint32_t leftovers = (destendx + 1 - destx); - zoomx += (int)((foomX - floor(foomX)) * (float)0x10000); - zoomy += (int)((foomY - floor(foomY)) * (float)0x10000); - } + // iterate over pixels in Y + int32_t srcycopy = srcy; + + 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); + +} + +void hng64_state::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) +{ + int offset; + if (!xflip) + { + if (!yflip) + offset = (xtile + (ytile * (xsize + 1))); + else + offset = (xtile + ((ysize - ytile) * (xsize + 1))); + } + else + { + if (!yflip) + offset = ((xsize - xtile) + (ytile * (xsize + 1))); + else + offset = ((xsize - xtile) + ((ysize - ytile) * (xsize + 1))); + } + + if (!chain) + { + tileno = (m_spriteram[(spritenum * 8) + 4] & 0x0007ffff); + pal = (m_spriteram[(spritenum * 8) + 3] & 0x00ff0000) >> 16; if (m_spriteregs[0] & 0x00800000) //bpp switch { - gfx= m_gfxdecode->gfx(4); + gfxregion = 4; } else { - gfx= m_gfxdecode->gfx(5); - tileno>>=1; - pal&=0xf; + gfxregion = 5; + tileno >>= 1; + pal &= 0xf; } - // Accommodate for chaining and flipping - if(xflip) + tileno += offset; + } + else + { + tileno = (m_spriteram[((spritenum + offset) * 8) + 4] & 0x0007ffff); + pal = (m_spriteram[((spritenum + offset) * 8) + 3] & 0x00ff0000) >> 16; + if (m_spriteregs[0] & 0x00800000) //bpp switch { - xinc=-(int)(16.0f*foomX); - xpos-=xinc*chainx; + gfxregion = 4; } else { - xinc=(int)(16.0f*foomX); + gfxregion = 5; + tileno >>= 1; + pal &= 0xf; } + } +} + +void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cliprect) +{ + m_sprite_bitmap.fill(0x0000, cliprect); + + // global offsets in sprite regs + int spriteoffsx = (m_spriteregs[1] >> 0) & 0xffff; + int spriteoffsy = (m_spriteregs[1] >> 16) & 0xffff; + + // This flips between ingame and other screens for roadedge, where the sprites which are filtered definitely needs to change and the game explicitly swaps the values in the sprite list at the same time. + // m_spriteregs[2] could also play a part as it also flips between 0x00000000 and 0x000fffff at the same time + // Samsho games also set the upper 3 bits which could be related, samsho games still have some unwanted sprites (but also use the other 'sprite clear' mechanism) + // Could also be draw order related, check if it inverts the z value? + bool zsort = !(m_spriteregs[0] & 0x01000000); + + if (zsort) + m_sprite_zbuffer.fill(0x0000, cliprect); + else + m_sprite_zbuffer.fill(0x07ff, cliprect); + + int nextsprite = 0; + int currentsprite = 0; + + while (currentsprite < ((0xc000 / 4) / 8)) + { + 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; + xpos += (spriteoffsx); + ypos += (spriteoffsy); + + 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; + + int yflip = (m_spriteram[(currentsprite * 8) + 4] & 0x01000000) >> 24; + int xflip = (m_spriteram[(currentsprite * 8) + 4] & 0x02000000) >> 25; - if(yflip) + int chainy = (m_spriteram[(currentsprite * 8) + 2] & 0x0000000f); + int chainx = (m_spriteram[(currentsprite * 8) + 2] & 0x000000f0) >> 4; + int chaini = (m_spriteram[(currentsprite * 8) + 2] & 0x00000100); + + if (!chaini) { - yinc=-(int)(16.0f*foomY); - ypos-=yinc*chainy; + nextsprite = currentsprite + 1; } else { - yinc=(int)(16.0f*foomY); + nextsprite = currentsprite + ((chainx + 1) * (chainy + 1)); } -#if 0 - if (((source[2) & 0xffff0000) >> 16) == 0x0001) + uint32_t zoomy = (m_spriteram[(currentsprite * 8) + 1] & 0xffff0000) >> 16; + uint32_t zoomx = (m_spriteram[(currentsprite * 8) + 1] & 0x0000ffff) >> 0; + + /* Calculate the zoom */ + int zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100; + if (!zoomx) zoomx = zoom_factor; + if (!zoomy) zoomy = zoom_factor; + + int32_t dx, dy; + + if (zoom_factor == 0x100) { - popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]); - //popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]); + dx = zoomx << 8; + dy = zoomy << 8; } -#endif + else + { + dx = zoomx << 4; + dy = zoomy << 4; + } + + int16_t drawy = ypos; + uint32_t srcpix_y = 0; - for(ydrw=0;ydrw<=chainy;ydrw++) + for (int ydrw = 0; ydrw <= chainy; ydrw++) { - for(xdrw=0;xdrw<=chainx;xdrw++) + uint32_t dstheight = 0; + + do { - int16_t drawx = xpos+(xinc*xdrw); - int16_t drawy = ypos+(yinc*ydrw); + srcpix_y += dy; + dstheight++; + } while (srcpix_y < 0x100000); + srcpix_y &= 0x0fffff; - // 0x3ff (0x200 sign bit) based on sams64_2 char select - drawx &= 0x3ff; - drawy &= 0x3ff; + int32_t destendy = drawy + dstheight - 1; + for (int32_t cury = drawy, line = 0; cury <= destendy; line++, cury++) + { + int16_t drawx = xpos; + uint32_t srcpix_x = 0; - if (drawx&0x0200)drawx-=0x400; - if (drawy&0x0200)drawy-=0x400; + uint16_t srcpix = 0; - if (!chaini) - { - if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0); - else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0); - tileno++; - } - else // inline chain mode, used by ss64 - { - tileno=(source[4]&0x0007ffff); - pal =(source[3]&0x00ff0000)>>16; + uint8_t mosaic_count_x = 0; - if (m_spriteregs[0] & 0x00800000) //bpp switch - { - gfx= m_gfxdecode->gfx(4); - } - else + for (int xdrw = 0; xdrw <= chainx; xdrw++) + { + uint32_t dstwidth = 0; + do { - gfx= m_gfxdecode->gfx(5); - tileno>>=1; - pal&=0xf; - } - - if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0); - else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0); - source +=8; + 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; } } + drawy += dstheight; } + currentsprite = nextsprite; } } + diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index b79e718adc3..319640dd91d 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -304,44 +304,57 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap else // line mode { const int global_alt_scroll_register_format = m_videoregs[0x00] & 0x04000000; - if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? + int32_t xmiddle; + int32_t ymiddle; + + const uint32_t& global_tileregs = m_videoregs[0x00]; + const int global_zoom_disable = global_tileregs & 0x00010000; + if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) { - //popmessage("global_alt_scroll_register_format in linemode"); + // If this bit is active the scroll registers don't seem valid at all? + // It either disables zooming, or disables use of the scroll registers completely + // - used at startup + + xtopleft = 0; + xmiddle = 256 << 16; + + ytopleft = 0; + ymiddle = 256 << 16; } - //else + else { - int32_t xmiddle; - int32_t ymiddle; + uint16_t line = source_line_to_use; + xtopleft = (m_videoram[(0x40000 + (scrollbase << 4)) / 4]); + xmiddle = (m_videoram[(0x40004 + (scrollbase << 4)) / 4]); // middle screen point - const uint32_t& global_tileregs = m_videoregs[0x00]; - const int global_zoom_disable = global_tileregs & 0x00010000; - if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) - { - // If this bit is active the scroll registers don't seem valid at all? - // It either disables zooming, or disables use of the scroll registers completely - // - used at startup + uint32_t xtopleft2 = (m_videoram[(0x40000 + (line * 0x10) + (scrollbase << 4)) / 4]); + uint32_t xmiddle2 = (m_videoram[(0x40004 + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point - xtopleft = 0; - xmiddle = 256 << 16; + if ((xtopleft2 & 0xff) == 0x00)// set to 0x00 if we should use the line data? + xtopleft = xtopleft2; - ytopleft = 0; - ymiddle = 256 << 16; - } - else - { - uint16_t line = source_line_to_use; - xtopleft = (m_videoram[(0x40000 + (line * 0x10) + (scrollbase << 4)) / 4]); - xmiddle = (m_videoram[(0x40004 + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point - ytopleft = (m_videoram[(0x40008 + (line * 0x10) + (scrollbase << 4)) / 4]); - ymiddle = (m_videoram[(0x4000c + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point - } + if ((xmiddle2 & 0xff) == 0x00) // also set to 0x00 if we should use the line data? + xmiddle = xmiddle2; + ytopleft = (m_videoram[(0x40008 + (line * 0x10) + (scrollbase << 4)) / 4]); + ymiddle = (m_videoram[(0x4000c + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point + } + + if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? + { + xinc = (xmiddle - xtopleft) / 512; + yinc = 0; + xinc2 = 0; + yinc2 = (ymiddle - ytopleft) / 512; + } + else + { xinc = (xmiddle - xtopleft) / 512; yinc = (ymiddle - ytopleft) / 512; - // TODO: if global_alt_scroll_register_format is enabled uses incxy / incyx into calculation somehow ... xinc2 = 0; yinc2 = 0; } + } uint32_t startx = xtopleft; @@ -547,12 +560,13 @@ 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 ---- ---- ---- ---- | C = global complex zoom + * 0 | ---- -Cdd ---- -??Z ---- ---- ---- ---u | 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? - * 1 | oooo oooo oooo oooo ---- ---- ---- ---- | unknown - 0001 is a popular value. Explore. - * 1 | ---- ---- ---- ---- oooo oooo oooo oooo | unknown - untouched in sams64 games, initialized elsewhere + | | 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 * 2 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap0 per layer flags * 2 | ---- ---- ---- ---- xxxx xxxx xxxx xxxx | tilemap1 per layer flags * 3 | xxxx xxxx xxxx xxxx ---- ---- ---- ---- | tilemap2 per layer flags @@ -561,15 +575,14 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap * 4 | ---- ---- ---- ---- 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 - * 6 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 000001ff (fatfurwa) - * 7 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 000001ff (fatfurwa) - * 8 | oooo oooo oooo oooo oooo oooo oooo oooo | unknown - always seems to be 80008000 (fatfurwa) + * 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) * 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 ?? - * e | oooo oooo oooo oooo oooo oooo oooo oooo | not used ?? // tilemap0 per layer flags // 0840 - startup tests, 8x8x4 layer @@ -802,7 +815,34 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } // Draw the sprites on top of everything - draw_sprites(screen, bitmap, cliprect); + draw_sprites_buffer(screen, cliprect); + + // copy sprites into display + pen_t const *const clut = &m_palette->pen(0); + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + 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++) + { + uint16_t srcpix = *src; + if (srcpix & 0x7fff) + { + if (srcpix & 0x8000) + { + *dst = add_blend_r32(*dst, clut[srcpix & 0x7fff]); + } + else + { + *dst = clut[srcpix & 0x7fff]; + } + } + + dst++; + src++; + } + } // Layer the global frame buffer operations on top of everything // transition_control(bitmap, cliprect); @@ -812,7 +852,7 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b if (0) popmessage("%08x %08x %08x %08x %08x", m_spriteregs[0], m_spriteregs[1], m_spriteregs[2], m_spriteregs[3], m_spriteregs[4]); - if (1) + 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], @@ -834,26 +874,36 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b m_videoregs[0x0d]); if (0) - popmessage("TC: %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x", + 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], - m_tcram[0x18 / 4], - m_tcram[0x1c / 4], - m_tcram[0x20 / 4], - m_tcram[0x24 / 4], - m_tcram[0x28 / 4], - m_tcram[0x2c / 4], + + // 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? + + // 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 + 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[0x40 / 4], m_tcram[0x44 / 4], - m_tcram[0x48 / 4], + + + m_tcram[0x48 / 4], // this is where the 'vblank' thing lives m_tcram[0x4c / 4], m_tcram[0x50 / 4], m_tcram[0x54 / 4], @@ -1085,7 +1135,12 @@ void hng64_state::video_start() m_texturerom = memregion("textures")->base(); m_vertsrom = (uint16_t*)memregion("verts")->base(); m_vertsrom_size = memregion("verts")->bytes(); + + m_screen->register_screen_bitmap(m_sprite_bitmap); + m_screen->register_screen_bitmap(m_sprite_zbuffer); + } + #include "hng64_3d.ipp" #include "hng64_sprite.ipp" -- cgit v1.2.3