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.
This commit is contained in:
David Haywood 2023-02-25 18:18:20 +00:00 committed by GitHub
parent 9028bdba54
commit ca235063b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 450 additions and 202 deletions

View File

@ -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

View File

@ -271,7 +271,10 @@ private:
//uint32_t *q2 = nullptr;
std::vector< std::pair <int, uint32_t *> > 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);

View File

@ -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,11 +40,236 @@
*/
void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
#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)
{
gfx_element *gfx;
uint32_t *source = m_spriteram;
uint32_t *finish = m_spriteram + 0xc000/4;
int srcy = dy * line + srcy_copy;
auto* destptr = &dest.pix(cury, 0);
auto* destzptr = &destz.pix(cury, 0);
const u8* srcptr = srcdata + ((srcy >> 16) & 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;
PIX_CHECKERBOARD;
PIXEL_OP_REBASE_TRANSPEN_REV(destptr[xdrawpos], destzptr[xdrawpos], srcpix);
cursrcx += dx;
}
}
else
{
uint8_t cb = 0;
// iterate over leftover pixels
for (int32_t curx = 0; curx < leftovers; curx++)
{
int xdrawpos = destx + curx;
PIX_CHECKERBOARD;
PIXEL_OP_REBASE_TRANSPEN(destptr[xdrawpos], destzptr[xdrawpos], srcpix);
cursrcx += dx;
}
}
}
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())
{
// fully transparent; do nothing
uint32_t usage = gfx->pen_usage(code);
if ((usage & ~(1 << trans_pen)) == 0)
return;
}
// render
color = gfx->colorbase() + gfx->granularity() * (color % gfx->colors());
if (blend)
color |= 0x8000;
assert(dest.valid());
assert(dest.cliprect().contains(cliprect));
// ignore empty/invalid cliprects
if (cliprect.empty())
return;
if (dstwidth < 1 || dstheight < 1)
return;
int32_t srcx = 0;
// apply X flipping
if (flipx)
{
srcx = (dstwidth - 1) * dx - srcx;
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;
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
{
gfxregion = 4;
}
else
{
gfxregion = 5;
tileno >>= 1;
pal &= 0xf;
}
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
{
gfxregion = 4;
}
else
{
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;
@ -56,143 +281,97 @@ void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, cons
// Could also be draw order related, check if it inverts the z value?
bool zsort = !(m_spriteregs[0] & 0x01000000);
#if 0
for (int iii = 0; iii < 0x0f; iii++)
osd_printf_debug("%.8x ", m_videoregs[iii]);
osd_printf_debug("\n");
#endif
// start with empty list
m_spritelist.clear();
while(source < finish)
{
if (source[4]&0x04000000) // disable bit, ss64 rankings ?
{
source += 8;
}
else
{
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;
}
}
if (zsort)
std::stable_sort(m_spritelist.begin(), m_spritelist.end(), [] (auto const &a, auto const &b) { return a.first > b.first; });
m_sprite_zbuffer.fill(0x0000, cliprect);
else
m_sprite_zbuffer.fill(0x07ff, cliprect);
for(auto it : m_spritelist)
int nextsprite = 0;
int currentsprite = 0;
while (currentsprite < ((0xc000 / 4) / 8))
{
source = it.second;
uint16_t zval = (m_spriteram[(currentsprite * 8) + 2] & 0x07ff0000) >> 16;
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;
uint16_t ypos = (m_spriteram[(currentsprite * 8) + 0] & 0xffff0000) >> 16;
uint16_t xpos = (m_spriteram[(currentsprite * 8) + 0] & 0x0000ffff) >> 0;
xpos += (spriteoffsx);
ypos += (spriteoffsy);
tileno= (source[4]&0x0007ffff);
blend= (source[4]&0x00800000);
yflip= (source[4]&0x01000000)>>24;
xflip= (source[4]&0x02000000)>>25;
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;
pal =(source[3]&0x00ff0000)>>16;
int yflip = (m_spriteram[(currentsprite * 8) + 4] & 0x01000000) >> 24;
int xflip = (m_spriteram[(currentsprite * 8) + 4] & 0x02000000) >> 25;
chainy=(source[2]&0x0000000f);
chainx=(source[2]&0x000000f0)>>4;
chaini=(source[2]&0x00000100);
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);
zoomy = (source[1]&0xffff0000)>>16;
zoomx = (source[1]&0x0000ffff)>>0;
if (!chaini)
{
nextsprite = currentsprite + 1;
}
else
{
nextsprite = currentsprite + ((chainx + 1) * (chainy + 1));
}
#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
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;
/* FIXME: regular zoom mode has precision bugs, can be easily seen in Samurai Shodown 64 intro */
zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100;
int zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100;
if (!zoomx) zoomx = zoom_factor;
if (!zoomy) zoomy = zoom_factor;
/* First, prevent any possible divide by zero errors */
foomX = (float)(zoom_factor) / (float)zoomx;
foomY = (float)(zoom_factor) / (float)zoomy;
int32_t dx, dy;
zoomx = ((int)foomX) << 16;
zoomy = ((int)foomY) << 16;
zoomx += (int)((foomX - floor(foomX)) * (float)0x10000);
zoomy += (int)((foomY - floor(foomY)) * (float)0x10000);
}
if (m_spriteregs[0] & 0x00800000) //bpp switch
if (zoom_factor == 0x100)
{
gfx= m_gfxdecode->gfx(4);
dx = zoomx << 8;
dy = zoomy << 8;
}
else
{
gfx= m_gfxdecode->gfx(5);
tileno>>=1;
pal&=0xf;
dx = zoomx << 4;
dy = zoomy << 4;
}
// Accommodate for chaining and flipping
if(xflip)
{
xinc=-(int)(16.0f*foomX);
xpos-=xinc*chainx;
}
else
{
xinc=(int)(16.0f*foomX);
}
int16_t drawy = ypos;
uint32_t srcpix_y = 0;
if(yflip)
for (int ydrw = 0; ydrw <= chainy; ydrw++)
{
yinc=-(int)(16.0f*foomY);
ypos-=yinc*chainy;
}
else
{
yinc=(int)(16.0f*foomY);
}
uint32_t dstheight = 0;
#if 0
if (((source[2) & 0xffff0000) >> 16) == 0x0001)
do
{
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]);
}
#endif
srcpix_y += dy;
dstheight++;
} while (srcpix_y < 0x100000);
srcpix_y &= 0x0fffff;
for(ydrw=0;ydrw<=chainy;ydrw++)
int32_t destendy = drawy + dstheight - 1;
for (int32_t cury = drawy, line = 0; cury <= destendy; line++, cury++)
{
for(xdrw=0;xdrw<=chainx;xdrw++)
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++)
{
int16_t drawx = xpos+(xinc*xdrw);
int16_t drawy = ypos+(yinc*ydrw);
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;
@ -201,33 +380,18 @@ void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, cons
if (drawx & 0x0200)drawx -= 0x400;
if (drawy & 0x0200)drawy -= 0x400;
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;
uint32_t tileno;
uint16_t pal;
uint8_t gfxregion;
if (m_spriteregs[0] & 0x00800000) //bpp switch
{
gfx= m_gfxdecode->gfx(4);
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;
}
else
{
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;
}
}
}
}
}

View File

@ -304,12 +304,6 @@ 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???
{
//popmessage("global_alt_scroll_register_format in linemode");
}
//else
{
int32_t xmiddle;
int32_t ymiddle;
@ -330,18 +324,37 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap
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
xtopleft = (m_videoram[(0x40000 + (scrollbase << 4)) / 4]);
xmiddle = (m_videoram[(0x40004 + (scrollbase << 4)) / 4]); // middle screen point
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
if ((xtopleft2 & 0xff) == 0x00)// set to 0x00 if we should use the line data?
xtopleft = xtopleft2;
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"