From 17d3ebd429919047fa3c7821e38b1617bb375805 Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Tue, 14 Feb 2023 18:04:05 +0000 Subject: [PATCH] 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. --- src/devices/sound/l7a1045_l6028_dsp_a.cpp | 26 ++- src/mame/snk/hng64.cpp | 63 +++-- src/mame/snk/hng64.h | 16 +- src/mame/snk/hng64_3d.ipp | 265 ++++++++++++---------- src/mame/snk/hng64_a.cpp | 8 +- src/mame/snk/hng64_v.cpp | 8 +- 6 files changed, 223 insertions(+), 163 deletions(-) diff --git a/src/devices/sound/l7a1045_l6028_dsp_a.cpp b/src/devices/sound/l7a1045_l6028_dsp_a.cpp index a9db61b5deb..fd9ff7d4ebd 100644 --- a/src/devices/sound/l7a1045_l6028_dsp_a.cpp +++ b/src/devices/sound/l7a1045_l6028_dsp_a.cpp @@ -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 diff --git a/src/mame/snk/hng64.cpp b/src/mame/snk/hng64.cpp index 9681495607e..e7ff600b22d 100644 --- a/src/mame/snk/hng64.cpp +++ b/src/mame/snk/hng64.cpp @@ -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 */ diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 3b7368135be..94fbc65dc50 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -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 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 m_screen; required_device m_palette; @@ -457,7 +459,7 @@ private: std::vector 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); diff --git a/src/mame/snk/hng64_3d.ipp b/src/mame/snk/hng64_3d.ipp index 5920a190f5b..b8fc815a85c 100644 --- a/src/mame/snk/hng64_3d.ipp +++ b/src/mame/snk/hng64_3d.ipp @@ -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; diff --git a/src/mame/snk/hng64_a.cpp b/src/mame/snk/hng64_a.cpp index 2404023417c..31e161d9f56 100644 --- a/src/mame/snk/hng64_a.cpp +++ b/src/mame/snk/hng64_a.cpp @@ -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)) { diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index 49f9a15dc31..7ab107ba81c 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -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++) {