snk/hng64_v.cpp: Improved rendering: (#10891)

* Filter out most (but not all) the bad polygons in roadedge/xrally by handling display list more correctly.
* Fixed 4bpp texture handling (used extensively for background details on sams64/sams64_2).
* Added 4bpp texture decode for easy viewing of the 4bpp texture pages.
* Fixed some texture palette issues connected to the 4bpp textures and incorrect enable bits being used (wheels and windscreen palette in racing games for example).
* Found a flag that seems to enable backface culling, improves bbust2 school bus without breaking roadedge.
* Cleaned up logging.
This commit is contained in:
David Haywood 2023-02-14 18:04:05 +00:00 committed by GitHub
parent 2b9da4a413
commit 17d3ebd429
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 223 additions and 163 deletions

View File

@ -218,8 +218,10 @@ uint16_t l7a1045_sound_device::l7a1045_sound_r(offs_t offset, uint16_t mem_mask)
//logerror("%s: read at %x (mask %04x)\n", tag(), offset, mem_mask);
if(offset == 0)
printf("sound_select_r?\n");
if (offset == 0)
{
//logerror("sound_select_r?\n");
}
else
return sound_data_r(offset -1);
@ -255,7 +257,7 @@ void l7a1045_sound_device::sound_data_w(offs_t offset, uint16_t data)
l7a1045_voice *vptr = &m_voice[m_audiochannel];
//if(m_audioregister != 0 && m_audioregister != 1 && m_audioregister != 7)
// printf("%04x %04x (%04x %04x)\n",offset,data,m_audioregister,m_audiochannel);
// logerror("%04x %04x (%04x %04x)\n",offset,data,m_audioregister,m_audiochannel);
m_audiodat[m_audioregister][m_audiochannel].dat[offset] = data;
@ -281,9 +283,9 @@ void l7a1045_sound_device::sound_data_w(offs_t offset, uint16_t data)
break;
case 0x01:
// relative to start
//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0]);
//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[1]);
//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[2]);
//logerror("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0]);
//logerror("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[1]);
//logerror("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[2]);
if(m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x100)
{
@ -312,7 +314,7 @@ void l7a1045_sound_device::sound_data_w(offs_t offset, uint16_t data)
vptr->r_volume = (vptr->r_volume) | (vptr->r_volume << 8);
vptr->l_volume = (m_audiodat[m_audioregister][m_audiochannel].dat[0] >> 8) & 0xff;
vptr->l_volume = (vptr->l_volume) | (vptr->l_volume << 8);
//printf("%04x %02x %02x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0],vptr->l_volume,vptr->r_volume);
//logerror("%04x %02x %02x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0],vptr->l_volume,vptr->r_volume);
break;
}
@ -321,7 +323,7 @@ void l7a1045_sound_device::sound_data_w(offs_t offset, uint16_t data)
uint16_t l7a1045_sound_device::sound_data_r(offs_t offset)
{
//printf("%04x (%04x %04x)\n",offset,m_audioregister,m_audiochannel);
//logerror("%04x (%04x %04x)\n",offset,m_audioregister,m_audiochannel);
//machine().debug_break();
l7a1045_voice *vptr = &m_voice[m_audiochannel];
@ -356,11 +358,11 @@ void l7a1045_sound_device::sound_status_w(uint16_t data)
#if 0
if(vptr->start != 0)
{
printf("%08x START\n",vptr->start);
printf("%08x END\n",vptr->end);
logerror("%08x START\n",vptr->start);
logerror("%08x END\n",vptr->end);
for(int i=0;i<0x10;i++)
printf("%02x (%02x) = %04x%04x%04x\n",m_audiochannel,i,m_audiodat[i][m_audiochannel].dat[2],m_audiodat[i][m_audiochannel].dat[1],m_audiodat[i][m_audiochannel].dat[0]);
for(int i=0;i<0x10;i++)
logerror("%02x (%02x) = %04x%04x%04x\n",m_audiochannel,i,m_audiodat[i][m_audiochannel].dat[2],m_audiodat[i][m_audiochannel].dat[1],m_audiodat[i][m_audiochannel].dat[0]);
}
#endif

View File

@ -990,7 +990,7 @@ void hng64_state::hng64_sysregs_w(offs_t offset, uint32_t data, uint32_t mem_mas
#if 0
if(((offset*4) & 0xff00) == 0x1100)
printf("HNG64 writing to SYSTEM Registers 0x%08x == 0x%08x. (PC=%08x)\n", offset*4, m_sysregs[offset], m_maincpu->pc());
logerror("HNG64 writing to SYSTEM Registers 0x%08x == 0x%08x. (PC=%08x)\n", offset*4, m_sysregs[offset], m_maincpu->pc());
#endif
switch(offset*4)
@ -1720,20 +1720,47 @@ static const gfx_layout hng64_16x16x8_spritelayout =
};
static const uint32_t texlayout_xoffset[1024] = { STEP1024(0,8) };
static const uint32_t texlayout_yoffset[512] = { STEP512(0,8192) };
static const gfx_layout hng64_texlayout =
static const uint32_t texlayout_yoffset[1024] = { STEP1024(0,8192) };
static uint32_t texlayout_xoffset_4[1024];
static const uint32_t texlayout_yoffset_4[1024] = { STEP1024(0,4096) };
void hng64_state::texlayout_xoffset_4_create()
{
1024, 512,
for (int i = 0; i < 1024; i++)
{
texlayout_xoffset_4[i] = (i * 4) ^ 4;
}
}
static const gfx_layout hng64_1024x1024x8_texlayout =
{
1024, 1024,
RGN_FRAC(1,1),
8,
{ 0,1,2,3,4,5,6,7 },
EXTENDED_XOFFS,
EXTENDED_YOFFS,
1024*512*8,
1024*1024*8,
texlayout_xoffset,
texlayout_yoffset
};
static const gfx_layout hng64_1024x1024x4_texlayout =
{
1024, 1024,
RGN_FRAC(1,1),
4,
{ 0,1,2,3 },
EXTENDED_XOFFS,
EXTENDED_YOFFS,
1024*1024*4,
texlayout_xoffset_4,
texlayout_yoffset_4
};
static GFXDECODE_START( gfx_hng64 )
/* tilemap tiles */
GFXDECODE_ENTRY( "scrtile", 0, hng64_8x8x4_tilelayout, 0x0, 0x100 )
@ -1745,7 +1772,10 @@ static GFXDECODE_START( gfx_hng64 )
GFXDECODE_ENTRY( "sprtile", 0, hng64_16x16x4_spritelayout, 0x0, 0x100 )
GFXDECODE_ENTRY( "sprtile", 0, hng64_16x16x8_spritelayout, 0x0, 0x10 )
GFXDECODE_ENTRY( "textures", 0, hng64_texlayout, 0x0, 0x10 ) /* textures */
/* texture pages (not used by rendering code) */
GFXDECODE_ENTRY( "textures", 0, hng64_1024x1024x4_texlayout, 0x0, 0x100 )
GFXDECODE_ENTRY( "textures", 0, hng64_1024x1024x8_texlayout, 0x0, 0x10 )
GFXDECODE_END
static void hng64_reorder( uint8_t* gfxregion, size_t gfxregionsize)
@ -2110,7 +2140,10 @@ TIMER_CALLBACK_MEMBER(hng64_state::comhack_callback)
{
LOG("comhack_callback %04x\n\n", m_comhack[0]);
m_comhack[0] = m_comhack[0] | 0x0002;
// different network IDs give different default colours for the cars in roadedge
uint8_t network_id = 0x01;
m_comhack[0] = m_comhack[0] | network_id;
}
@ -2969,13 +3002,13 @@ ROM_START( buriki )
ROM_END
/* Bios */
GAME( 1997, hng64, 0, hng64_default, hng64, hng64_state, init_hng64, ROT0, "SNK", "Hyper NeoGeo 64 Bios", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND|MACHINE_IS_BIOS_ROOT )
GAME( 1997, hng64, 0, hng64_default, hng64, hng64_state, init_hng64, ROT0, "SNK", "Hyper NeoGeo 64 Bios", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND|MACHINE_IS_BIOS_ROOT )
/* Games */
GAME( 1997, roadedge, hng64, hng64_drive, hng64_drive, hng64_state, init_roadedge, ROT0, "SNK", "Roads Edge / Round Trip RV (rev.B)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 001 */
GAME( 1998, sams64, hng64, hng64_fight, hng64_fight, hng64_state, init_ss64, ROT0, "SNK", "Samurai Shodown 64 / Samurai Spirits 64", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 002 */
GAME( 1998, xrally, hng64, hng64_drive, hng64_drive, hng64_state, init_hng64_drive, ROT0, "SNK", "Xtreme Rally / Off Beat Racer!", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 003 */
GAME( 1998, bbust2, hng64, hng64_shoot, hng64_shoot, hng64_state, init_hng64_shoot, ROT0, "SNK", "Beast Busters: Second Nightmare", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 004 */
GAME( 1998, sams64_2, hng64, hng64_fight, hng64_fight, hng64_state, init_ss64, ROT0, "SNK", "Samurai Shodown 64: Warriors Rage / Samurai Spirits 2: Asura Zanmaden", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 005 */
GAME( 1998, fatfurwa, hng64, hng64_fight, hng64_fight, hng64_state, init_hng64_fght, ROT0, "SNK", "Fatal Fury: Wild Ambition / Garou Densetsu: Wild Ambition (rev.A)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 006 */
GAME( 1999, buriki, hng64, hng64_fight, hng64_fight, hng64_state, init_hng64_fght, ROT0, "SNK", "Buriki One: World Grapple Tournament '99 in Tokyo (rev.B)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 007 */
GAME( 1997, roadedge, hng64, hng64_drive, hng64_drive, hng64_state, init_roadedge, ROT0, "SNK", "Roads Edge / Round Trip RV (rev.B)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 001 */
GAME( 1998, sams64, hng64, hng64_fight, hng64_fight, hng64_state, init_ss64, ROT0, "SNK", "Samurai Shodown 64 / Samurai Spirits 64", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 002 */
GAME( 1998, xrally, hng64, hng64_drive, hng64_drive, hng64_state, init_hng64_drive, ROT0, "SNK", "Xtreme Rally / Off Beat Racer!", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 003 */
GAME( 1998, bbust2, hng64, hng64_shoot, hng64_shoot, hng64_state, init_hng64_shoot, ROT0, "SNK / ADK", "Beast Busters: Second Nightmare", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 004 */ // ADK credited in the ending sequence
GAME( 1998, sams64_2, hng64, hng64_fight, hng64_fight, hng64_state, init_ss64, ROT0, "SNK", "Samurai Shodown 64: Warriors Rage / Samurai Spirits 2: Asura Zanmaden", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 005 */
GAME( 1998, fatfurwa, hng64, hng64_fight, hng64_fight, hng64_state, init_hng64_fght, ROT0, "SNK", "Fatal Fury: Wild Ambition / Garou Densetsu: Wild Ambition (rev.A)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 006 */
GAME( 1999, buriki, hng64, hng64_fight, hng64_fight, hng64_state, init_hng64_fght, ROT0, "SNK", "Buriki One: World Grapple Tournament '99 in Tokyo (rev.B)", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND ) /* 007 */

View File

@ -27,7 +27,7 @@ struct polyVert
{
float worldCoords[4]{}; // World space coordinates (X Y Z 1.0)
float texCoords[4]{}; // Texture coordinates (U V 0 1.0) -> OpenGL style...
float texCoords[2]{}; // Texture coordinates (U V 0 1.0) -> OpenGL style...
float normal[4]{}; // Normal (X Y Z 1.0)
float clipCoords[4]{}; // Homogeneous screen space coordinates (X Y Z W)
@ -47,13 +47,12 @@ struct polygon
bool flatShade = false; // Flat shaded polygon, no texture, no lighting
uint8_t texIndex = 0; // Which texture to draw from (0x00-0x0f)
uint8_t texType = 0; // How to index into the texture
uint8_t tex4bpp = 0; // How to index into the texture
uint8_t texPageSmall = 0; // Does this polygon use 'small' texture pages?
uint8_t texPageHorizOffset = 0; // If it does use small texture pages, how far is this page horizontally offset?
uint8_t texPageVertOffset = 0; // If it does use small texture pages, how far is this page vertically offset?
uint32_t palOffset = 0; // The base offset where this object's palette starts.
uint32_t palPageSize = 0; // The size of the palette page that is being pointed to.
uint32_t debugColor = 0; // Will go away someday. Used to explicitly color polygons for debugging.
};
@ -82,13 +81,12 @@ typedef frustum_clip_vertex<float, 5> hng64_clip_vertex;
struct hng64_poly_data
{
uint8_t texType = 0;
uint8_t tex4bpp = 0;
uint8_t texIndex = 0;
uint8_t texPageSmall = 0;
uint8_t texPageHorizOffset = 0;
uint8_t texPageVertOffset = 0;
int palOffset = 0;
int palPageSize = 0;
int debugColor = 0;
};
@ -167,7 +165,9 @@ public:
m_in(*this, "IN%u", 0U),
m_samsho64_3d_hack(0),
m_roadedge_3d_hack(0)
{ }
{
texlayout_xoffset_4_create();
}
void hng64(machine_config &config);
void hng64_default(machine_config &config);
@ -182,6 +182,8 @@ public:
void init_ss64();
void init_hng64_fght();
static void texlayout_xoffset_4_create();
uint8_t *m_texturerom = nullptr;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
@ -457,7 +459,7 @@ private:
std::vector<polygon> m_polys; // HNG64_MAX_POLYGONS
void clear3d();
void hng64_command3d(const uint16_t* packet);
bool hng64_command3d(const uint16_t* packet);
void draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect);
void setCameraTransformation(const uint16_t* packet);

View File

@ -63,6 +63,8 @@ void hng64_state::dl_unk_w(offs_t offset, uint32_t data, uint32_t mem_mask)
void hng64_state::dl_upload_w(uint32_t data)
{
//m_paletteState3d = 0; // no, breaks fatfurwa characters
// Data is:
// 00000b50 for the sams64 games
// 00000f00 for everything else
@ -75,7 +77,8 @@ g_profiler.start(PROFILER_USER1);
for(int packetStart = 0; packetStart < 0x100; packetStart += 16)
{
// Send it off to the 3d subsystem.
hng64_command3d(&m_dl[packetStart]);
if (!hng64_command3d(&m_dl[packetStart]))
break;
}
// Schedule a small amount of time to let the 3d hardware rasterize the display buffer
@ -106,7 +109,7 @@ void hng64_state::dl_control_w(uint32_t data)
*/
/*
printf("dl_control_w %08x %08x\n", data, mem_mask);
logerror("dl_control_w %08x %08x\n", data, mem_mask);
if(data & 2) // swap buffers
{
@ -136,7 +139,7 @@ void hng64_state::printPacket(const uint16_t* packet, int hex)
{
if (hex)
{
printf("Packet : %04x %04x 2:%04x %04x 4:%04x %04x 6:%04x %04x 8:%04x %04x 10:%04x %04x 12:%04x %04x 14:%04x %04x\n",
logerror("Packet : %04x %04x 2:%04x %04x 4:%04x %04x 6:%04x %04x 8:%04x %04x 10:%04x %04x 12:%04x %04x 14:%04x %04x\n",
packet[0], packet[1],
packet[2], packet[3],
packet[4], packet[5],
@ -148,7 +151,7 @@ void hng64_state::printPacket(const uint16_t* packet, int hex)
}
else
{
printf("Packet : %04x %3.4f 2:%3.4f %3.4f 4:%3.4f %3.4f 6:%3.4f %3.4f 8:%3.4f %3.4f 10:%3.4f %3.4f 12:%3.4f %3.4f 14:%3.4f %3.4f\n",
logerror("Packet : %04x %3.4f 2:%3.4f %3.4f 4:%3.4f %3.4f 6:%3.4f %3.4f 8:%3.4f %3.4f 10:%3.4f %3.4f 12:%3.4f %3.4f 14:%3.4f %3.4f\n",
packet[0], uToF(packet[1] )*128,
uToF(packet[2] )*128, uToF(packet[3] )*128,
uToF(packet[4] )*128, uToF(packet[5] )*128,
@ -228,8 +231,8 @@ void hng64_state::setLighting(const uint16_t* packet)
// [14] - ???? ... ? Used in fatfurwa
// [15] - ???? ... ? Used in fatfurwa
////////////*/
if (packet[1] != 0x0000) printf("ZOMG! packet[1] in setLighting function is non-zero!\n");
if (packet[2] != 0x0000) printf("ZOMG! packet[2] in setLighting function is non-zero!\n");
if (packet[1] != 0x0000) logerror("packet[1] in setLighting function is non-zero!\n");
if (packet[2] != 0x0000) logerror("packet[2] in setLighting function is non-zero!\n");
m_lightVector[0] = uToF(packet[3]);
m_lightVector[1] = uToF(packet[4]);
@ -331,22 +334,14 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
/*//////////////
// PACKET FORMAT
// [0] - 0100 ... ID
// [1] - ?--- ... Flags [?000 = ???
// 0?00 = ???
// 00?0 = ???
// 000? = ???]
// [1] - -?-- ... Flags [?000 = ???
// 0?00 = ???
// 00?0 = ???
// 000x = Dynamic palette bit]
// [1] - --?- ... Flags [?000 = ???
// 0?00 = ???
// 00?0 = ???
// 000? = ???]
// [1] - ---? ... Flags [x000 = Apply lighting bit
// 0?00 = ???
// 00?0 = ???
// 000? = ???]
// [1] - --c- ---p ---b l---
// l = use lighting
// p = use dynamic palette (maybe not just this, wrong for roadedge car select where it isn't set but needs to be)
// b = backface culling?
// c = set on objects a certain distance away (maybe optimization to disable clipping against camera?)
// none of these bits appear to be connected to texture size to solve the road/banner problem in xrally/roadedge
//
//
// [2] - xxxx ... offset into ROM
// [3] - xxxx ... offset into ROM
// [4] - xxxx ... Transformation matrix
@ -430,7 +425,11 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
if (threeDOffset >= m_vertsrom_size)
{
printf("Strange geometry packet: (ignoring)\n");
// bbust2 quite often spams this invalid pointer
if ((packet[2] == 0x2347) && (packet[3] == 0x5056))
return;
logerror("Strange geometry packet: (ignoring)\n");
printPacket(packet, 1);
return;
}
@ -453,11 +452,11 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
address[2] = threeDPointer[3];
address[3] = threeDPointer[4];
if (threeDPointer[5] != 0x0000) printf("ZOMG! 3dPointer[5] is non-zero!\n");
if (threeDPointer[5] != 0x0000) logerror("3dPointer[5] is non-zero!\n");
size[0] = threeDPointer[6];
size[1] = threeDPointer[7];
if (threeDPointer[8] != 0x0000) printf("ZOMG! 3dPointer[8] is non-zero!\n");
if (threeDPointer[8] != 0x0000) logerror("3dPointer[8] is non-zero!\n");
size[2] = threeDPointer[9];
size[3] = threeDPointer[10];
@ -466,13 +465,13 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// ???? [13]; Used.
// ???? [14]; Used.
if (threeDPointer[15] != 0x0000) printf("ZOMG! 3dPointer[15] is non-zero!\n");
if (threeDPointer[16] != 0x0000) printf("ZOMG! 3dPointer[16] is non-zero!\n");
if (threeDPointer[17] != 0x0000) printf("ZOMG! 3dPointer[17] is non-zero!\n");
if (threeDPointer[15] != 0x0000) logerror("3dPointer[15] is non-zero!\n");
if (threeDPointer[16] != 0x0000) logerror("3dPointer[16] is non-zero!\n");
if (threeDPointer[17] != 0x0000) logerror("3dPointer[17] is non-zero!\n");
if (threeDPointer[18] != 0x0000) printf("ZOMG! 3dPointer[18] is non-zero!\n");
if (threeDPointer[19] != 0x0000) printf("ZOMG! 3dPointer[19] is non-zero!\n");
if (threeDPointer[20] != 0x0000) printf("ZOMG! 3dPointer[20] is non-zero!\n");
if (threeDPointer[18] != 0x0000) logerror("3dPointer[18] is non-zero!\n");
if (threeDPointer[19] != 0x0000) logerror("3dPointer[19] is non-zero!\n");
if (threeDPointer[20] != 0x0000) logerror("3dPointer[20] is non-zero!\n");
// Concatenate the megaOffset with the addresses
address[0] |= (megaOffset << 16);
@ -497,10 +496,17 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
////////////////////////////////////////////
// SINGLE POLY CHUNK FORMAT
// [0] 0000 0000 cccc cccc 0 = always 0 | c = chunk type / format of data that follows (see below)
// [1] t--l pppp pppp ssss t = texture, always on for most games, on for the backgrounds only on sams64
// [1] tu-4 pppp pppp ssss t = texture, always on for most games, on for the backgrounds only on sams64
// if not set, u,v fields of vertices are direct palette indices, used on roadedge hng64 logo animation shadows
// l = low-res texture? p = palette? s = texture sheet (1024 x 1024 pages)
// [2] S?XX *--- -YY# ---- S = use 4x4 sub-texture pages? ? = SNK logo roadedge / bbust2 / broken banners in xrally, XX = horizontal subtexture * = broken banners in xrally YY = vertical subtexture @ = broken banners in xrally
// u = unknown, set on sams64 / buriki at times, never on racing games
// 4 = 4bpp texture p = palette? s = texture sheet (1024 x 1024 pages)
// [2] S?XX *uuu -YY# uuu- S = use 4x4 sub-texture pages?
// ? = SNK logo roadedge / bbust2 / broken banners in xrally
// X = horizontal subtexture
// * = broken banners in xrally
// Y = vertical subtexture
// # = broken banners in xrally
// u = unknown, set late on 2nd race+3rd race in xrally
// we currently use one of the palette bits to enable a different palette mode.. seems hacky...
// looks like vertical / horizontal sub-pages might be 3 bits, not 2, ? could be enable bit for that..
@ -508,13 +514,12 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// 'Welcome to South Africa' roadside banner on xrally | 000e 8c0d d870 or 0096 8c0d d870 (8c0d, d870 seems key 1000 1100 0000 1101
// 1101 1000 0111 0000 )
uint8_t chunkType = chunkOffset[0] & 0x00ff;
// Debug - ajg
if (chunkOffset[0] & 0xff00)
{
printf("Weird! The top byte of the chunkType has a value %04x!\n", chunkOffset[0]);
logerror("Weird! The top byte of the chunkType has a value %04x!\n", chunkOffset[0]);
continue;
}
@ -526,13 +531,11 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
//currentPoly.debugColor = tdColor;
// Debug - ajg
//printf("%d (%08x) : %04x %04x %04x\n", k, address[k]*3*2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
//logerror("%d (%08x) : %04x %04x %04x\n", k, address[k]*3*2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
//break;
// TEXTURE
// There may be more than just high & low res texture types, so I'm keeping texType as a uint8_t. */
if (chunkOffset[1] & 0x1000) currentPoly.texType = 0x1;
else currentPoly.texType = 0x0;
if (chunkOffset[1] & 0x1000) currentPoly.tex4bpp = 0x1;
else currentPoly.tex4bpp = 0x0;
currentPoly.texPageSmall = (chunkOffset[2] & 0xc000)>>14; // Just a guess.
currentPoly.texPageHorizOffset = (chunkOffset[2] & 0x3800) >> 11;
@ -548,7 +551,6 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// PALETTE
currentPoly.palOffset = 0;
currentPoly.palPageSize = 0x100;
// FIXME: This isn't correct.
// Buriki & Xrally need this line. Roads Edge needs it removed.
@ -560,20 +562,27 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
}
//uint16_t explicitPaletteValue0 = ((chunkOffset[?] & 0x????) >> ?) * 0x800;
uint16_t explicitPaletteValue1 = ((chunkOffset[1] & 0x0f00) >> 8) * 0x080;
uint16_t explicitPaletteValue2 = ((chunkOffset[1] & 0x00f0) >> 4) * 0x008;
// The presence of 0x00f0 *probably* sets 0x10-sized palette addressing.
if (explicitPaletteValue2) currentPoly.palPageSize = 0x10;
uint16_t explicitPaletteValue = ((chunkOffset[1] & 0x0ff0) >> 4);
explicitPaletteValue = explicitPaletteValue << 3;
// HACK: this is not the enable, the cars in roadedge rely on this to switch palettes
// on the select screen, where this bit is not enabled.
// (to see the cars on the select screen disable sprite rendering, as there are
// currently priority issues)
//
// however for sams64 this is enabled on the 2nd character, but not the 1st character
// and the additional palette offset definitely only applies to the 2nd
//
// Apply the dynamic palette offset if its flag is set, otherwise stick with the fixed one
if ((packet[1] & 0x0100))
{
explicitPaletteValue1 = m_paletteState3d * 0x80;
explicitPaletteValue2 = 0; // This is probably hiding somewhere in operation 0011
// bbust2 has m_paletteState3d & 0x40 set, which takes the palette out of range
// used for 2nd car on roadedge, used for 2nd player on buriki
// used for buildings in fatfurwa intro and characters
explicitPaletteValue |= (m_paletteState3d & 0x3f) * 0x80;
}
currentPoly.palOffset += (explicitPaletteValue1 + explicitPaletteValue2);
currentPoly.palOffset += explicitPaletteValue;
#if 0
if (((chunkOffset[2] & 0xc000) == 0x4000) && (m_screen->frame_number() & 1))
@ -581,7 +590,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// if (chunkOffset[2] == 0xd870)
{
currentPoly.debugColor = 0xffff0000;
printf("%d (%08x) : %04x %04x %04x\n", k, address[k] * 3 * 2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
logerror("%d (%08x) : %04x %04x %04x\n", k, address[k] * 3 * 2, chunkOffset[0], chunkOffset[1], chunkOffset[2]);
}
}
#endif
@ -599,6 +608,9 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// ---- -x-- - 1 = Has per-vert UVs
// ---- --x- -
// ---- ---x - 1 = Has per-vert normals
//
// none of these seem directly connected to texture size to solve texturing problem in the racing games
// maybe some of the actual packet data is being used incorrectly?
/////////////////////////*/
// 33 word chunk, 3 vertices, per-vertex UVs & normals, per-face normal
@ -615,8 +627,6 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// chunkOffset[6 + (9*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
currentPoly.vert[m].texCoords[0] = uToF(chunkOffset[7 + (9*m)]);
currentPoly.vert[m].texCoords[1] = uToF(chunkOffset[8 + (9*m)]);
currentPoly.vert[m].texCoords[2] = 0.0f;
currentPoly.vert[m].texCoords[3] = 1.0f;
currentPoly.vert[m].normal[0] = uToF(chunkOffset[9 + (9*m)]);
currentPoly.vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)]);
@ -653,9 +663,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// chunkOffset[6 + (6*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
currentPoly.vert[m].texCoords[0] = uToF(chunkOffset[7 + (6*m)]);
currentPoly.vert[m].texCoords[1] = uToF(chunkOffset[8 + (6*m)]);
currentPoly.vert[m].texCoords[2] = 0.0f;
currentPoly.vert[m].texCoords[3] = 1.0f;
if (currentPoly.flatShade)
currentPoly.vert[m].colorIndex = chunkOffset[7 + (6*m)] >> 5;
@ -694,8 +702,6 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
currentPoly.vert[0].texCoords[0] = uToF(chunkOffset[7]);
currentPoly.vert[0].texCoords[1] = uToF(chunkOffset[8]);
currentPoly.vert[0].texCoords[2] = 0.0f;
currentPoly.vert[0].texCoords[3] = 1.0f;
if (currentPoly.flatShade)
currentPoly.vert[0].colorIndex = chunkOffset[7] >> 5;
@ -733,8 +739,6 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select
currentPoly.vert[0].texCoords[0] = uToF(chunkOffset[7]);
currentPoly.vert[0].texCoords[1] = uToF(chunkOffset[8]);
currentPoly.vert[0].texCoords[2] = 0.0f;
currentPoly.vert[0].texCoords[3] = 1.0f;
if (currentPoly.flatShade)
currentPoly.vert[0].colorIndex = chunkOffset[7] >> 5;
@ -754,21 +758,21 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
#if 0
// DEBUG
printf("0x?6 : %08x (%d/%d)\n", address[k]*3*2, l, size[k]-1);
logerror("0x?6 : %08x (%d/%d)\n", address[k]*3*2, l, size[k]-1);
for (int m = 0; m < 13; m++)
printf("%04x ", chunkOffset[m]);
printf("\n");
logerror("%04x ", chunkOffset[m]);
logerror("\n");
for (int m = 0; m < 13; m++)
printf("%3.4f ", uToF(chunkOffset[m]));
printf("\n\n");
logerror("%3.4f ", uToF(chunkOffset[m]));
logerror("\n\n");
#endif
chunkLength = 12;
break;
default:
printf("UNKNOWN geometry CHUNK TYPE : %02x\n", chunkType);
logerror("UNKNOWN geometry CHUNK TYPE : %02x\n", chunkType);
chunkLength = 0;
break;
}
@ -829,8 +833,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
}
}
// BACKFACE CULL
// roadedge has various one-way barriers that you can drive through, but need to be invisible from behind, so needs this culling
float cullRay[4];
float cullNorm[4];
@ -841,11 +844,18 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
// Dot product that with the normal to see if you're negative...
vecmatmul4(cullNorm, m_modelViewMatrix, currentPoly.faceNormal);
const float backfaceCullResult = vecDotProduct(cullRay, cullNorm);
if (backfaceCullResult < 0.0f)
currentPoly.visible = true;
else
currentPoly.visible = false;
// BACKFACE CULL
// roadedge has various one-way barriers that you can drive through, but need to be invisible from behind, so needs this culling
// this bit IS set on the objects that roadedge needs to vanish if viewed from behind, but it is NOT set on the bbust2 school bus
// which needs to be visible with backfacing polys. further test cases need to be found.
if (packet[1] & 0x0010)
{
const float backfaceCullResult = vecDotProduct(cullRay, cullNorm);
if (backfaceCullResult < 0.0f)
currentPoly.visible = true;
else
currentPoly.visible = false;
}
// BEHIND-THE-CAMERA CULL //
vecmatmul4(cullRay, m_modelViewMatrix, currentPoly.vert[0].worldCoords);
@ -934,25 +944,17 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys)
}
}
// note 0x0102 packets are only 8 words, it appears they can be in either the upper or lower half of the 16 word packet.
// We currently only draw 0x0102 packets where both halves contain 0x0102 (2 calls), but this causes graphics to vanish in
// xrally because in some cases the 0x0102 packet only exists in the upper or lower half with another value (often 0x0000 - NOP) in the other.
// If we also treat (0x0000 - NOP) as 8 word instead of 16 so that we can access a 0x0102 in the 2nd half of the 16 word packet
// then we end up with other invalid packets in the 2nd half which should be ignored.
// This would suggest our processing if flawed in other ways, or there is something else to indicate packet length.
void hng64_state::hng64_command3d(const uint16_t* packet)
bool hng64_state::hng64_command3d(const uint16_t* packet)
{
int numPolys = 0;
//printf("packet type : %04x %04x|%04x %04x|%04x %04x|%04x %04x | %04x %04x %04x %04x %04x %04x %04x %04x\n", packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7], packet[8], packet[9], packet[10], packet[11], packet[12], packet[13], packet[14], packet[15]);
//logerror("packet type : %04x %04x|%04x %04x|%04x %04x|%04x %04x | %04x %04x %04x %04x %04x %04x %04x %04x\n", packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7], packet[8], packet[9], packet[10], packet[11], packet[12], packet[13], packet[14], packet[15]);
switch (packet[0])
{
case 0x0000: // NOP?
/* Appears to be a NOP (or 'end of list for this frame, ignore everything after' doesn't stop stray 3d objects in game for xrally/roadedge
although does stop a partial hng64 logo being displayed assuming that's meant to be kept onscreen by some other means without valid data) */
break;
case 0x0000: // NOP? / End current list (doesn't stop additional lists being sent this frame)
return false;
case 0x0001: // Camera transformation.
setCameraTransformation(packet);
@ -970,12 +972,18 @@ void hng64_state::hng64_command3d(const uint16_t* packet)
setCameraProjectionMatrix(packet);
break;
case 0x0100:
case 0x0101: // Geometry with full transformations
case 0x0100: // Geometry with full transformations
// xrally/roadedge cars (not track, that uses 102), buriki, fatfurwa
recoverPolygonBlock(packet, numPolys);
break;
case 0x0101: // Geometry with full transformations (same as 0x100?)
// sams64, sams64_2, bbust2
recoverPolygonBlock(packet, numPolys);
break;
case 0x0102: // Geometry with only translation
// 'world' in roadedge/xrally (track, trackside objects etc.)
// Split the packet and call recoverPolygonBlock on each half.
uint16_t miniPacket[16];
memset(miniPacket, 0, sizeof(uint16_t)*16);
@ -985,27 +993,31 @@ void hng64_state::hng64_command3d(const uint16_t* packet)
miniPacket[15] = 0x7fff;
recoverPolygonBlock(miniPacket, numPolys);
if (packet[7] == 1)
{
if (packet[8] == 0x0102)
{
memset(miniPacket, 0, sizeof(uint16_t) * 16);
for (int i = 0; i < 7; i++) miniPacket[i] = packet[i + 8];
miniPacket[7] = 0x7fff;
miniPacket[11] = 0x7fff;
miniPacket[15] = 0x7fff;
recoverPolygonBlock(miniPacket, numPolys);
if (packet[8] == 0x0102)
{
memset(miniPacket, 0, sizeof(uint16_t) * 16);
for (int i = 0; i < 7; i++) miniPacket[i] = packet[i + 8];
miniPacket[7] = 0x7fff;
miniPacket[11] = 0x7fff;
miniPacket[15] = 0x7fff;
recoverPolygonBlock(miniPacket, numPolys);
}
else
{
/* if the 2nd value isn't 0x0102 don't render it
it could just be that the display list is corrupt at this point tho, see note above
*/
// packet[15] is always 1?
}
else
{
/* if the 2nd value isn't 0x0102 don't render it
it could just be that the display list is corrupt at this point tho, see note above
*/
}
}
break;
case 0x1000: // Unknown: Some sort of global flags?
//printPacket(packet, 1); printf("\n");
//printPacket(packet, 1); logerror("\n");
break;
case 0x1001: // Unknown: Some sort of global flags? Almost always comes in a group of 4 with an index [0,3].
@ -1013,7 +1025,7 @@ void hng64_state::hng64_command3d(const uint16_t* packet)
break;
default:
printf("HNG64: Unknown 3d command %04x.\n", packet[0]);
logerror("HNG64: Unknown 3d command %04x.\n", packet[0]);
break;
}
@ -1026,6 +1038,7 @@ void hng64_state::hng64_command3d(const uint16_t* packet)
}
}
m_poly_renderer->wait();
return true;
}
void hng64_state::clear3d()
@ -1040,6 +1053,8 @@ void hng64_state::clear3d()
// Clear the 3d rasterizer buffer
m_poly_renderer->colorBuffer3d().fill(0x00000000, m_screen->visible_area());
m_paletteState3d = 0;
// Set some matrices to the identity...
setIdentity(m_projectionMatrix);
setIdentity(m_modelViewMatrix);
@ -1265,18 +1280,11 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent
float textureS = 0.0f;
float textureT = 0.0f;
// Standard & Half-Res textures
if (renderData.texType == 0x0)
{
textureS = sCorrect * 1024.0f;
textureT = tCorrect * 1024.0f;
}
else if (renderData.texType == 0x1)
{
textureS = sCorrect * 512.0f;
textureT = tCorrect * 512.0f;
}
// sCorrect and tCorrect have range 0.0f - 1.0f, multiply by 1024 to get texture offset
textureS = sCorrect * 1024.0f;
textureT = tCorrect * 1024.0f;
#if 1
// Small-Page textures
if (renderData.texPageSmall == 2)
{
@ -1288,21 +1296,37 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent
}
else if (renderData.texPageSmall == 3)
{
// this can't be 128x128 textures, it is needed for the road etc. in xrally which is 256 wide,
// but also overhead objects which are 128 (eg lamps, near top left hand side on 8bpp texture page 8)
textureT = fmod(textureT, 128.0f);
textureS = fmod(textureS, 128.0f);
textureT += (128.0f * (renderData.texPageHorizOffset>>0));
textureS += (128.0f * (renderData.texPageVertOffset>>0));
textureT += (128.0f * (renderData.texPageHorizOffset >> 0));
textureS += (128.0f * (renderData.texPageVertOffset >> 0));
}
#endif
uint8_t paletteEntry = textureOffset[((int)textureS)*1024 + (int)textureT];
uint8_t paletteEntry;
int t = (int)textureT;
if (renderData.tex4bpp)
{
paletteEntry = textureOffset[((int)textureS) * 512 + (t >> 1)];
if (t & 1)
paletteEntry = (paletteEntry >> 4) & 0x0f;
else
paletteEntry &= 0x0f;
}
else
{
paletteEntry = textureOffset[((int)textureS) * 1024 + t];
}
// Naive Alpha Implementation (?) - don't draw if you're at texture index 0...
if (paletteEntry != 0)
{
// The color out of the texture
paletteEntry %= renderData.palPageSize;
rgb_t color = m_state.m_palette->pen(renderData.palOffset + paletteEntry);
rgb_t color = m_state.m_palette->pen((renderData.palOffset + paletteEntry) & 0xfff);
// Apply the lighting
float rIntensity = rCorrect / 255.0f;
@ -1390,10 +1414,9 @@ void hng64_poly_renderer::drawShaded(polygon *p)
{
// Polygon information for the rasterizer
hng64_poly_data rOptions;
rOptions.texType = p->texType;
rOptions.tex4bpp = p->tex4bpp;
rOptions.texIndex = p->texIndex;
rOptions.palOffset = p->palOffset;
rOptions.palPageSize = p->palPageSize;
rOptions.debugColor = p->debugColor;
rOptions.texPageSmall = p->texPageSmall;
rOptions.texPageHorizOffset = p->texPageHorizOffset;

View File

@ -281,11 +281,11 @@ void hng64_state::sound_comms_w(offs_t offset, uint16_t data, uint16_t mem_mask)
/* correct? */
m_audiocpu->set_input_line(5, CLEAR_LINE);
//if(data)
// printf("IRQ ACK %02x?\n",data);
// logerror("IRQ ACK %02x?\n",data);
return;
}
//printf("SOUND W %02x %04x\n",offset*2,data);
//logerror("SOUND W %02x %04x\n",offset*2,data);
}
uint16_t hng64_state::sound_comms_r(offs_t offset)
@ -297,7 +297,7 @@ uint16_t hng64_state::sound_comms_r(offs_t offset)
case 0x06:
return main_latch[1];
}
//printf("SOUND R %02x\n",offset*2);
//logerror("SOUND R %02x\n",offset*2);
return 0;
}
@ -375,7 +375,7 @@ WRITE_LINE_MEMBER(hng64_state::tcu_tm2_cb)
if(i > 7)
i = 7;
//printf("trigger %02x %d\n",i,state);
//logerror("trigger %02x %d\n",i,state);
//if(machine().input().code_pressed_once(KEYCODE_C))
{

View File

@ -569,7 +569,7 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap,
// floor mode
// life would be easier if the roz we're talking about for complex zoom wasn't setting this as well
// fprintf(stderr, "Tilemap %d is a floor using :\n", tm);
// logerror(stderr, "Tilemap %d is a floor using :\n", tm);
// const uint32_t floorAddress = 0x40000 + (scrollbase << 4);
// TODO: The row count is correct, but how is this layer clipped? m_tcram?
@ -587,7 +587,7 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap,
//
// lineCount++;
//}
//printf("lines %d\n", lineCount);
//logerror("lines %d\n", lineCount);
// Buriki uses a 2x mosaic effect on its floor, so its line count is half
// (but so does fatfurwa - maybe it overdraws a bunch of pixels?)
@ -734,7 +734,7 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap,
const int bmwidth = bm.width();
pen_t const *const paldata = m_palette->pens();
//printf("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle);
//logerror("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle);
for (int yy=0; yy<448; yy++)
{
@ -826,7 +826,7 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap,
int tmp = xtopleft;
//printf("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle);
//logerror("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle);
for (int yy=0; yy<448; yy++)
{