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.
This commit is contained in:
David Haywood 2023-02-27 14:55:30 +00:00 committed by GitHub
parent 369ecb2f77
commit 24c059a2ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 269 additions and 211 deletions

View File

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

View File

@ -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<screen_device> m_screen;
required_device<palette_device> m_palette;
required_shared_ptr<u32> 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);

View File

@ -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,26 +327,52 @@ 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 dstheight = 0;
uint32_t full_srcpix_y = 0;
uint32_t full_dstheight = 0;
do
{
srcpix_y += dy;
dstheight++;
} while (srcpix_y < 0x100000);
srcpix_y &= 0x0fffff;
full_srcpix_y += dy;
full_dstheight++;
} while (full_srcpix_y < ((chainy+1) * 0x100000));
int32_t destendy = drawy + dstheight - 1;
for (int32_t cury = drawy, line = 0; cury <= destendy; line++, cury++)
int realline = 0;
int mosaic_y_counter = 0;
for (int32_t curyy = 0; curyy <= full_dstheight - 1; curyy++)
{
int16_t drawx = xpos;
uint32_t srcpix_x = 0;
if (!mosaic)
{
realline = curyy;
}
else
{
if (mosaic_y_counter == 0)
{
realline = curyy;
mosaic_y_counter = mosaic;
}
else
{
mosaic_y_counter--;
}
}
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;
@ -373,25 +387,13 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl
} 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;
}
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;
}
}

View File

@ -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<rgb_t *>(&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()
{