From 5b5b5019109ea177b54266910df923e1692d95e1 Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Tue, 7 Mar 2023 13:07:25 +0000 Subject: snk/hng64_v.cpp: urther video improvements: (#10947) * Identified 'blend' flag for 3D objects and added minimal implementation. * Emulated 'split' tilemap effect. * Don't draw sprites with zero zoom values, rather than using an unscaled sprite, * Made 'sprite erase' code less aggressive (prevent it from wiping out palette values). * Implemented 'texture scrolling' (used for glass and water effects). --- src/mame/snk/hng64.cpp | 25 ++-- src/mame/snk/hng64.h | 35 +++-- src/mame/snk/hng64_3d.ipp | 290 ++++++++++++++++++++++++++++++++---------- src/mame/snk/hng64_sprite.ipp | 25 ++-- src/mame/snk/hng64_v.cpp | 200 +++++++++++++++++++++-------- 5 files changed, 426 insertions(+), 149 deletions(-) diff --git a/src/mame/snk/hng64.cpp b/src/mame/snk/hng64.cpp index 355562ed125..607e0cab48b 100644 --- a/src/mame/snk/hng64.cpp +++ b/src/mame/snk/hng64.cpp @@ -1061,13 +1061,15 @@ void hng64_state::hng64_dualport_w(offs_t offset, uint8_t data) /************************************************************************************************************/ /* The following is guesswork, needs confirmation with a test on the real board. */ +// every sprite is 0x20 bytes +// void hng64_state::hng64_sprite_clear_even_w(offs_t offset, uint32_t data, uint32_t mem_mask) { auto &mspace = m_maincpu->space(AS_PROGRAM); uint32_t spr_offs; - spr_offs = (offset) * 0x10 * 4; - + spr_offs = (offset) * 0x40; + // for one sprite if(ACCESSING_BITS_16_31) { mspace.write_dword(0x20000000+0x00+0x00+spr_offs, 0x00000000); @@ -1075,6 +1077,7 @@ void hng64_state::hng64_sprite_clear_even_w(offs_t offset, uint32_t data, uint32 mspace.write_dword(0x20000000+0x10+0x00+spr_offs, 0x00000000); mspace.write_dword(0x20000000+0x18+0x00+spr_offs, 0x00000000); } + // for another sprite if(ACCESSING_BITS_8_15) { mspace.write_dword(0x20000000+0x00+0x20+spr_offs, 0x00000000); @@ -1089,19 +1092,20 @@ void hng64_state::hng64_sprite_clear_odd_w(offs_t offset, uint32_t data, uint32_ auto &mspace = m_maincpu->space(AS_PROGRAM); uint32_t spr_offs; - spr_offs = (offset) * 0x10 * 4; - + spr_offs = (offset) * 0x40; + // for one sprite if(ACCESSING_BITS_16_31) { mspace.write_dword(0x20000000+0x04+0x00+spr_offs, 0x00000000); - mspace.write_dword(0x20000000+0x0c+0x00+spr_offs, 0x00000000); + // mspace.write_dword(0x20000000+0x0c+0x00+spr_offs, 0x00000000); // erases part of the slash palette in the sams64 2nd intro when we don't want it to! (2nd slash) mspace.write_dword(0x20000000+0x14+0x00+spr_offs, 0x00000000); mspace.write_dword(0x20000000+0x1c+0x00+spr_offs, 0x00000000); } + // for another sprite if(ACCESSING_BITS_0_15) { mspace.write_dword(0x20000000+0x04+0x20+spr_offs, 0x00000000); - mspace.write_dword(0x20000000+0x0c+0x20+spr_offs, 0x00000000); + // mspace.write_dword(0x20000000+0x0c+0x20+spr_offs, 0x00000000); // erases part of the slash palette in the sams64 2nd intro when we don't want it to! (1st slash) mspace.write_dword(0x20000000+0x14+0x20+spr_offs, 0x00000000); mspace.write_dword(0x20000000+0x1c+0x20+spr_offs, 0x00000000); } @@ -1198,9 +1202,9 @@ void hng64_state::hng_map(address_map &map) // 3D framebuffer map(0x30000000, 0x30000003).rw(FUNC(hng64_state::hng64_fbcontrol_r), FUNC(hng64_state::hng64_fbcontrol_w)).umask32(0xffffffff); - map(0x30000004, 0x30000007).w(FUNC(hng64_state::hng64_fbunkpair_w)).umask32(0xffff); - map(0x30000008, 0x3000000b).w(FUNC(hng64_state::hng64_fbscroll_w)).umask32(0xffff); - map(0x3000000c, 0x3000000f).w(FUNC(hng64_state::hng64_fbunkbyte_w)).umask32(0xffffffff); + map(0x30000004, 0x30000007).w(FUNC(hng64_state::hng64_fbscale_w)).share("fbscale"); + map(0x30000008, 0x3000000b).w(FUNC(hng64_state::hng64_fbscroll_w)).share("fbscroll"); + map(0x3000000c, 0x3000000f).w(FUNC(hng64_state::hng64_fbunkbyte_w)).share("fbunk"); map(0x30000010, 0x3000002f).rw(FUNC(hng64_state::hng64_fbtable_r), FUNC(hng64_state::hng64_fbtable_w)).share("fbtable"); map(0x30100000, 0x3015ffff).rw(FUNC(hng64_state::hng64_fbram1_r), FUNC(hng64_state::hng64_fbram1_w)).share("fbram1"); // 3D Display Buffer A @@ -2126,6 +2130,8 @@ void hng64_state::machine_start() m_videoregs[i] = 0xdeadbeef; } + m_videoregs[0] = 0x00000000; + m_irq_pending = 0; m_3dfifo_timer = timer_alloc(FUNC(hng64_state::hng64_3dfifo_processed), this); @@ -2206,6 +2212,7 @@ void hng64_state::machine_reset() m_fbcontrol[2] = 0x00; m_fbcontrol[3] = 0x00; + clear3d(); } /*********************************************** diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 2111aeee95a..0fa46213fb1 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -44,6 +44,7 @@ struct polygon float faceNormal[4]{}; // Normal of the face overall - for calculating visibility and flat-shading... bool visible = false; // Polygon visibility in scene bool flatShade = false; // Flat shaded polygon, no texture, no lighting + bool blend = false; uint8_t texIndex = 0; // Which texture to draw from (0x00-0x0f) uint8_t tex4bpp = 0; // How to index into the texture @@ -53,6 +54,9 @@ struct polygon uint32_t palOffset = 0; // The base offset where this object's palette starts. uint16_t colorIndex = 0; + + uint16_t texscrollx = 0; + uint16_t texscrolly = 0; }; @@ -86,6 +90,9 @@ struct hng64_poly_data uint8_t texPageVertOffset = 0; uint32_t palOffset = 0; uint16_t colorIndex = 0; + bool blend = false; + uint16_t texscrollx = 0; + uint16_t texscrolly = 0; }; class hng64_state; @@ -100,15 +107,15 @@ public: void render_flat_scanline(int32_t scanline, const extent_t& extent, const hng64_poly_data& renderData, int threadid); hng64_state& state() { return m_state; } - bitmap_ind16& colorBuffer3d() { return m_colorBuffer3d; } float* depthBuffer3d() { return m_depthBuffer3d.get(); } + uint16_t* colorBuffer3d() { return m_colorBuffer3d.get(); } private: hng64_state& m_state; // (Temporarily class members - someday they will live in the memory map) - bitmap_ind16 m_colorBuffer3d; std::unique_ptr m_depthBuffer3d; + std::unique_ptr m_colorBuffer3d; }; @@ -161,6 +168,9 @@ public: m_comhack(*this, "comhack"), m_fbram1(*this, "fbram1"), m_fbram2(*this, "fbram2"), + m_fbscale(*this, "fbscale"), + m_fbscroll(*this, "fbscroll"), + m_fbunk(*this, "fbunk"), m_idt7133_dpram(*this, "com_ram"), m_gfxdecode(*this, "gfxdecode"), m_in(*this, "IN%u", 0U), @@ -227,6 +237,9 @@ private: required_shared_ptr m_comhack; required_shared_ptr m_fbram1; required_shared_ptr m_fbram2; + required_shared_ptr m_fbscale; + required_shared_ptr m_fbscroll; + required_shared_ptr m_fbunk; required_shared_ptr m_idt7133_dpram; //required_shared_ptr m_com_mmu_mem; @@ -293,7 +306,13 @@ private: uint16_t m_old_tileflags[4]{}; // 3d State - int m_paletteState3d = 0; + uint16_t m_texturescrollx = 0; + uint16_t m_texturescrolly = 0; + uint16_t m_paletteState3d = 0; + uint16_t m_modelscalex = 0; + uint16_t m_modelscaley = 0; + uint16_t m_modelscalez = 0; + float m_projectionMatrix[16]{}; float m_modelViewMatrix[16]{}; float m_cameraMatrix[16]{}; @@ -323,10 +342,10 @@ private: uint8_t hng64_fbcontrol_r(offs_t offset); void hng64_fbcontrol_w(offs_t offset, uint8_t data); - void hng64_fbunkpair_w(offs_t offset, uint16_t data); - void hng64_fbscroll_w(offs_t offset, uint16_t data); + void hng64_fbscale_w(offs_t offset, uint32_t data, uint32_t mem_mask); + void hng64_fbscroll_w(offs_t offset, uint32_t data, uint32_t mem_mask); - void hng64_fbunkbyte_w(offs_t offset, uint8_t data); + void hng64_fbunkbyte_w(offs_t offset, uint32_t data, uint32_t mem_mask); uint32_t hng64_fbtable_r(offs_t offset, uint32_t mem_mask = ~0); void hng64_fbtable_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); @@ -428,7 +447,7 @@ private: void hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm, int flags, int line); void hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - int wraparound, uint8_t drawformat, uint8_t alpha, uint8_t mosaic, uint8_t tm); + int wraparound, uint8_t drawformat, uint8_t alpha, uint8_t mosaic, uint8_t tm, int splitside); std::unique_ptr m_poly_renderer; @@ -458,7 +477,7 @@ private: void setLighting(const uint16_t* packet); void set3dFlags(const uint16_t* packet); void setCameraProjectionMatrix(const uint16_t* packet); - void recoverStandardVerts(polygon& currentPoly, int m, uint16_t* chunkOffset_verts, int& counter); + void recoverStandardVerts(polygon& currentPoly, int m, uint16_t* chunkOffset_verts, int& counter, const uint16_t *packet); void recoverPolygonBlock(const uint16_t* packet, int& numPolys); void printPacket(const uint16_t* packet, int hex); float uToF(uint16_t input); diff --git a/src/mame/snk/hng64_3d.ipp b/src/mame/snk/hng64_3d.ipp index e9be258b0ee..221c3dbf99b 100644 --- a/src/mame/snk/hng64_3d.ipp +++ b/src/mame/snk/hng64_3d.ipp @@ -9,10 +9,11 @@ hng64_poly_renderer::hng64_poly_renderer(hng64_state& state) : poly_manager(state.machine()) , m_state(state) - , m_colorBuffer3d(state.m_screen->visible_area().width(), state.m_screen->visible_area().height()) { - const int32_t bufferSize = state.m_screen->visible_area().width() * state.m_screen->visible_area().height(); + const int32_t bufferSize = 512 * 512; m_depthBuffer3d = std::make_unique(bufferSize); + m_colorBuffer3d = std::make_unique(bufferSize); + } @@ -182,6 +183,7 @@ void hng64_state::setCameraTransformation(const uint16_t* packet) // [10] - xxxx ... Extrinsic camera matrix // [11] - xxxx ... Extrinsic camera matrix // [12] - xxxx ... Extrinsic camera matrix + // following might be unused leftover data // [13] - ???? ... ? Flips per-frame during fatfurwa 'HNG64' // [14] - ???? ... ? Could be some floating-point values during buriki 'door run' // [15] - ???? ... ? Same as 13 & 14 @@ -224,6 +226,7 @@ void hng64_state::setLighting(const uint16_t* packet) // [7] - ???? ... ? Seems to be another light vector ? // [8] - ???? ... ? Seems to be another light vector ? // [9] - xxxx ... Strength according to sams64_2 (in combination with vector length) [0,512] + // following could just be leftover data // [10] - ???? ... ? Used in fatfurwa // [11] - ???? ... ? Used in fatfurwa // [12] - ???? ... ? Used in fatfurwa @@ -247,14 +250,15 @@ void hng64_state::set3dFlags(const uint16_t* packet) /*////////////// // PACKET FORMAT // [0] - 0011 ... ID - // [1] - ???? ... - // [2] - ???? ... + // [1] - ???? ... texture scrolling x (c000 - ffff) + // [2] - ???? ... texture scrolling y (c000 - ffff) // [3] - ???? ... // [4] - ???? ... - // [5] - ???? ... - // [6] - ???? ... - // [7] - ???? ... + // [5] - ???? ... scale? + // [6] - ???? ... scale? + // [7] - ???? ... scale? // [8] - xx?? ... Palette offset & ?? + // following could just be leftover data // [9] - ???? ... ? Very much used - seem to bounce around when characters are on screen // [10] - ???? ... ? '' '' // [11] - ???? ... ? '' '' @@ -263,7 +267,13 @@ void hng64_state::set3dFlags(const uint16_t* packet) // [14] - ???? ... ? '' '' // [15] - ???? ... ? '' '' ////////////*/ - m_paletteState3d = (packet[8] & 0xff00) >> 8; + m_texturescrollx = packet[1]; + m_texturescrolly = packet[2]; + m_paletteState3d = packet[8]; + + m_modelscalex = packet[5]; + m_modelscaley = packet[6]; + m_modelscalez = packet[7]; } // Operation 0012 @@ -273,19 +283,20 @@ void hng64_state::setCameraProjectionMatrix(const uint16_t* packet) /*////////////// // PACKET FORMAT // [0] - 0012 ... ID - // [1] - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset. - // [2] - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset. - // [3] - ???? ... ? Contains a value + // [1] - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset. value used is 0xffc0 ( -0x40 ) 64 pixels? not used anywhere else? + // [2] - ???? ... ? Contains a value in buriki's 'how to play' - probably a projection window/offset. value used is 0x0018 24 pixels? not used anywhere else? + // [3] - ???? ... ? Contains a value (always? 0x0a00) // [4] - xxxx ... Camera projection Z scale // [5] - xxxx ... Camera projection near Z // [6] - xxxx ... Camera projection screen Z - // [7] - xxxx ... Camera projection (?) - // [8] - xxxx ... Camera projection (?) - // [9] - xxxx ... Camera projection (?) + // [7] - xxxx ... Camera projection (?) (always? 0x0b10) + // [8] - xxxx ... Camera projection (?) (always? 0x0a00) + // [9] - xxxx ... Camera projection (?) (always? 0x0b00) // [10] - xxxx ... Camera projection right - confirmed by sams64_2 // [11] - xxxx ... Camera projection left - confirmed by sams64_2 // [12] - xxxx ... Camera projection top - confirmed by sams64_2 // [13] - xxxx ... Camera projection bottom - confirmed by sams64_2 + // following could just be leftover data // [14] - ???? ... ? Gets data during buriki door-run // [15] - ???? ... ? Gets data during buriki door-run ////////////*/ @@ -323,9 +334,26 @@ void hng64_state::setCameraProjectionMatrix(const uint16_t* packet) m_projectionMatrix[13] = 0.0f; m_projectionMatrix[14] = -((2.0f*far*near)/(far-near)); m_projectionMatrix[15] = 0.0f; + +#if 0 + if ((packet[1] != 0x0000) || (packet[2] != 0x0000)) + printf("camera packet[1] %04x packet[2] %04x\n", packet[1], packet[2]); + + if (packet[3] != 0x0a00) + printf("camera packet[3] %04x\n", packet[3]); + + if (packet[7] != 0x0b10) + printf("camera packet[7] %04x\n", packet[7]); + + if (packet[8] != 0x0a00) + printf("camera packet[7] %04x\n", packet[8]); + + if (packet[9] != 0x0b00) + printf("camera packet[9] %04x\n", packet[9]); +#endif } -void hng64_state::recoverStandardVerts(polygon& currentPoly, int m, uint16_t* chunkOffset_verts, int& counter) +void hng64_state::recoverStandardVerts(polygon& currentPoly, int m, uint16_t* chunkOffset_verts, int& counter, const uint16_t* packet) { currentPoly.vert[m].worldCoords[0] = uToF(chunkOffset_verts[counter++]); currentPoly.vert[m].worldCoords[1] = uToF(chunkOffset_verts[counter++]); @@ -333,13 +361,34 @@ void hng64_state::recoverStandardVerts(polygon& currentPoly, int m, uint16_t* ch currentPoly.vert[m].worldCoords[3] = 1.0f; currentPoly.n = 3; - [[maybe_unused]] uint16_t unused = chunkOffset_verts[counter++]; // chunkOffset_verts[ xxxx+3 ] is set to 0x70 on some 'blended' objects (fatfurwa translucent globe, buriki shadows, but not on fatfurwa shadows) + // this seems to be some kind of default lighting value / brightness, probably for unlit polys? used in various places, eg side of house in ice stage of ss64, some shadows + [[maybe_unused]] uint16_t maybe_blend = chunkOffset_verts[counter++]; currentPoly.vert[m].texCoords[0] = uToF(chunkOffset_verts[counter]); if (currentPoly.flatShade) currentPoly.colorIndex = chunkOffset_verts[counter] >> 5; counter++; currentPoly.vert[m].texCoords[1] = uToF(chunkOffset_verts[counter++]); + + + // set on the Hyper 64 logos for roadedge and xrally which are known to be scaled + // also set on the car select screen in roadedge, and the car on the stage name screen + // not set anywhere else? + // + // params for car select screen / stage name screen are always 0x100, which would be + // 'no scale' anyway, and no scaling is observed in hardware videos + // + // the m_modelscalex etc. do contain values in fatal fury intro, but not valid looking + // ones, so probably unrelated to how that screen is scaled + if (packet[1] & 0x0040) + { + currentPoly.vert[m].worldCoords[0] = (currentPoly.vert[m].worldCoords[0] * m_modelscalez) / 0x100; + currentPoly.vert[m].worldCoords[1] = (currentPoly.vert[m].worldCoords[1] * m_modelscaley) / 0x100; + currentPoly.vert[m].worldCoords[2] = (currentPoly.vert[m].worldCoords[2] * m_modelscalex) / 0x100; + + // if ((m_modelscalex != 0x100) || (m_modelscaley != 0x100) || (m_modelscalez != 0x100)) + // logerror("maybe using model scale %04x %04x %04x\n", m_modelscalex, m_modelscaley, m_modelscalez); + } } // Operation 0100 @@ -351,11 +400,17 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) /*////////////// // PACKET FORMAT // [0] - 0100 ... ID - // [1] - --c- ---p ---b l--- + // [1] - ---- --cp os0b 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) + // o = use dynamic texture offset (sky reflection in xrally/roadedge windows, also waterfalls?) + // s = use dynamic scaling (hyper64 logos on xrally/roadedge) + // 0 = always 0? // b = backface culling? // c = set on objects a certain distance away (maybe optimization to disable clipping against camera?) + // ? = roadedge: all vehicles ingame + select screen (also 3d maps on select screen), vehicle lights+windows only in attract, nothing else? + // all vehicles ingame + select screen, vehicle lights+windows only in attract, NOT on vehicles between stages, nothing else? + // nothing on other games? // none of these bits appear to be connected to texture size to solve the road/banner problem in xrally/roadedge // // @@ -477,10 +532,13 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) size[2] = threeDPointer[9]; size[3] = threeDPointer[10]; - // ???? [11]; Used. - // ???? [12]; Used. - // ???? [13]; Used. - // ???? [14]; Used. + + // the low 8-bits of each of these is used (or at least contains data, probably one byte for each hunk?) + //if (threeDPointer[11] != 0x0000) logerror("3dPointer[11] is %04x!\n", threeDPointer[11]); // ???? [11]; Used. + //if (threeDPointer[12] != 0x0000) logerror("3dPointer[12] is %04x!\n", threeDPointer[12]); // ???? [12]; Used. + //if (threeDPointer[13] != 0x0000) logerror("3dPointer[13] is %04x!\n", threeDPointer[13]); // ???? [13]; Used. + //if (threeDPointer[14] != 0x0000) logerror("3dPointer[14] is %04x!\n", threeDPointer[14]); // ???? [14]; Used. + if (threeDPointer[15] != 0x0000) logerror("3dPointer[15] is non-zero!\n"); if (threeDPointer[16] != 0x0000) logerror("3dPointer[16] is non-zero!\n"); @@ -507,9 +565,9 @@ 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] tu-4 pppp pppp ssss t = texture, always on for most games, on for the backgrounds only on sams64 + // [1] ta-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 - // u = unknown, set on sams64 / buriki at times, never on racing games + // a = blend this sprite (blend might use 'lighting' level as alpha?) // 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 @@ -556,18 +614,11 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) else currentPoly.flatShade = true; + currentPoly.blend = false; + // PALETTE currentPoly.palOffset = 0; - // FIXME: This isn't correct. - // Buriki & Xrally need this line. Roads Edge needs it removed. - // So instead we're looking for a bit that is on for XRally & Buriki, but noone else. - if (m_fbcontrol[2] & 0x20) - { - if (!m_roadedge_3d_hack) - currentPoly.palOffset += 0x800; - } - //uint16_t explicitPaletteValue0 = ((chunkOffset[?] & 0x????) >> ?) * 0x800; uint16_t explicitPaletteValue = ((chunkOffset[1] & 0x0ff0) >> 4); explicitPaletteValue = explicitPaletteValue << 3; @@ -586,11 +637,38 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) // 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; + explicitPaletteValue |= ((m_paletteState3d >>8) & 0x3f) * 0x80; } currentPoly.palOffset += explicitPaletteValue; + //if (chunkOffset[1] & 0x4000) + // currentPoly.palOffset = machine().rand()&0x3ff; + + //if (packet[1] & 0x0006) + // currentPoly.palOffset = machine().rand()&0x3ff; + + if (chunkOffset[1] & 0x4000) + currentPoly.blend = true; + + // These are definitely the scroll values, used on player car windows and waterfalls + // but if we always use them things get very messy when they're used for the waterfalls on xrally + // as they never get turned back off again for the objects after the waterfalls + // Must be a conditional enable? + // 0x0100 is set on the cars, but not the waterfall + // 0x0080 is set on the cars, and the waterfall - maybe correct? + // 0x0001 is set on the cars, but not the waterfall + if ((packet[1] & 0x0080)) + { + currentPoly.texscrollx = m_texturescrollx; + currentPoly.texscrolly = m_texturescrolly; + } + else + { + currentPoly.texscrollx = 0; + currentPoly.texscrolly = 0; + } + uint8_t chunkLength = 0; int counter = 3; switch(chunkType) @@ -616,7 +694,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) { for (int m = 0; m < 3; m++) { - recoverStandardVerts(currentPoly, m, chunkOffset, counter); + recoverStandardVerts(currentPoly, m, chunkOffset, counter, packet); currentPoly.vert[m].normal[0] = uToF(chunkOffset[counter++]); currentPoly.vert[m].normal[1] = uToF(chunkOffset[counter++]); @@ -643,7 +721,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) { for (int m = 0; m < 3; m++) { - recoverStandardVerts(currentPoly, m, chunkOffset, counter); + recoverStandardVerts(currentPoly, m, chunkOffset, counter, packet); } currentPoly.vert[0].normal[0] = currentPoly.vert[1].normal[0] = currentPoly.vert[2].normal[0] = uToF(chunkOffset[counter++]); @@ -671,7 +749,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) memcpy(¤tPoly.vert[1], &lastPoly.vert[0], sizeof(polyVert)); memcpy(¤tPoly.vert[2], &lastPoly.vert[2], sizeof(polyVert)); - recoverStandardVerts(currentPoly, 0, chunkOffset, counter); + recoverStandardVerts(currentPoly, 0, chunkOffset, counter, packet); currentPoly.vert[0].normal[0] = uToF(chunkOffset[counter++]); currentPoly.vert[0].normal[1] = uToF(chunkOffset[counter++]); @@ -698,7 +776,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) memcpy(¤tPoly.vert[1], &lastPoly.vert[0], sizeof(polyVert)); memcpy(¤tPoly.vert[2], &lastPoly.vert[2], sizeof(polyVert)); - recoverStandardVerts(currentPoly, 0, chunkOffset, counter); + recoverStandardVerts(currentPoly, 0, chunkOffset, counter, packet); // This normal could be right, but I'm not entirely sure - there is no normal in the 18 bytes! currentPoly.vert[0].normal[0] = lastPoly.faceNormal[0]; @@ -801,6 +879,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) currentPoly.visible = false; } + // BEHIND-THE-CAMERA CULL // vecmatmul4(cullRay, m_modelViewMatrix, currentPoly.vert[0].worldCoords); if (cullRay[2] > 0.0f) // Camera is pointing down -Z @@ -848,7 +927,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) currentPoly.vert[m].light = clipVerts[m].p[2]; } - const rectangle& visarea = m_screen->visible_area(); + //const rectangle& visarea = m_screen->visible_area(); for (int m = 0; m < currentPoly.n; m++) { // Convert into normalized device coordinates... @@ -860,12 +939,12 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) // Final pixel values are garnered here : float windowCoords[4]; // Mapped ndCoordinates to screen space - windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(visarea.max_x) / 2.0f) + 0.0f; - windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(visarea.max_y) / 2.0f) + 0.0f; + windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(512.0f) / 2.0f) + 0.0f; + windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(512.0f) / 2.0f) + 0.0f; windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f; // Flip Y - windowCoords[1] = (float)visarea.max_y - windowCoords[1]; + windowCoords[1] = (float)512.0f - windowCoords[1]; // Store the points in a list for later use... currentPoly.vert[m].clipCoords[0] = windowCoords[0]; @@ -984,14 +1063,14 @@ bool hng64_state::hng64_command3d(const uint16_t* packet) void hng64_state::clear3d() { // Reset the buffers... - const rectangle& visarea = m_screen->visible_area(); - for (int i = 0; i < (visarea.max_x)*(visarea.max_y); i++) + //const rectangle& visarea = m_screen->visible_area(); + for (int i = 0; i < 512*512; i++) { m_poly_renderer->depthBuffer3d()[i] = 100.0f; + m_poly_renderer->colorBuffer3d()[i] = 0; } - // Clear the 3d rasterizer buffer - m_poly_renderer->colorBuffer3d().fill(0x00000000, m_screen->visible_area()); + m_paletteState3d = 0; @@ -1035,6 +1114,8 @@ void hng64_state::hng64_fbcontrol_w(offs_t offset, uint8_t data) other games use either mix of 0x18 and 0x38. bit 0x08 must prevent the framebuffer clear tho according to above table bit 0x20 is color base, but implementation for it is a hack + roadedge ends up leaving 0x20 set after the car selection, which breaks ingame 3D palette if + we use it as a palette base? see hack (3d car currently not visible on roadedge select screen due to priority issue, disable sprites to see it) @@ -1044,34 +1125,99 @@ void hng64_state::hng64_fbcontrol_w(offs_t offset, uint8_t data) m_fbcontrol[offset] = data; } -void hng64_state::hng64_fbunkpair_w(offs_t offset, uint16_t data) + +// the framebuffer scroll and scale registers are used in fatfurwa (intro scaling) and xrally (course select, car select) +// they are NOT used for buriki 'how to play' scren, which uses unhandled values in the 3d packets to reposition the fighters instead +void hng64_state::hng64_fbscale_w(offs_t offset, uint32_t data, uint32_t mem_mask) { - // set to fixed values? + COMBINE_DATA(&m_fbscale[offset]); - logerror("%s: hng64_fbunkpair_w (%03x) %04x\n", machine().describe_context(), offset, data); -} + if (mem_mask & 0xffff0000) + { + // NORMAL value is 3fe0 (0x400 / 2 = 0x200 = 512) + // ':maincpu' (8006E46C): hng64_fb_scale_x 3fe00000 ffff0000 -void hng64_state::hng64_fbscroll_w(offs_t offset, uint16_t data) -{ - // this is used ingame on the samsho games, and on the car select screen in xrally (youtube video confirms position of car needs to change) + // on xrally course select this is 39e0 (0x3a0 / 2 = 0x1d0 = 464) + // hng64_fb_scale_x 39e00000 ffff0000 + + //logerror("%s: hng64_fb_scale_x %08x %08x\n", machine().describe_context(), data, mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + // NORMAL value is 37e0 (0x380 / 2 = 0x1c0 = 448) + // hng64_fb_scale_y 000037e0 0000ffff + + // on xrally course select this is 32e0 (0x330 / 2 = 408) + // hng64_fb_scale_y 000032e0 0000ffff - logerror("%s: hng64_fbscroll_w (%03x) %04x\n", machine().describe_context(), offset, data); + // during fatfurwa scaled intro it uses 2de0, although writes 37e0 in the same frame; presumably rendering takes place while it is 2de0 though + // 0x2e0 / 2 = 0x170 = 368 (needs to be ~287 pixels though) + // ':maincpu' (800667A0): hng64_fb_scale_y 00002de0 0000ffff + //logerror("%s: hng64_fb_scale_y %08x %08x\n", machine().describe_context(), data, mem_mask); + } } -void hng64_state::hng64_fbunkbyte_w(offs_t offset, uint8_t data) +void hng64_state::hng64_fbscroll_w(offs_t offset, uint32_t data, uint32_t mem_mask) { - if (offset == 0) + COMBINE_DATA(&m_fbscroll[offset]); + + // this is used ingame on the samsho games, and on the car select screen in xrally (youtube video confirms position of car needs to change) + if (mem_mask & 0xffff0000) { - // | ---- --?x | unknown, unsetted by Buriki One and set by Fatal Fury WA, buffering mode? - logerror("%s: hng64_unkbyte_w (%03x) %02x\n", machine().describe_context(), offset, data); + // NORMAL value is e000 (e0 = 224) + // hng64_fbscroll x e0000000 ffff0000 + + // on xrally course select this is e600 (+0600 from normal) + // ':maincpu' (8002327C): hng64_fbscroll x e6000000 ffff0000 + + // on xrally car select this is e680 + // hng64_fbscroll x e6800000 ffff0000 + //logerror("%s: hng64_fbscroll x %08x (%d) %08x\n", machine().describe_context(), data, ((data&0x7fff0000) >> 21), mem_mask); } - else + + if (mem_mask & 0x0000ffff) { - logerror("%s: hng64_unkbyte_w (%03x - unexpected) %02x \n", machine().describe_context(), offset, data); + // NORMAL value is 1c00 (1c0 = 448) /2 = 224 (midpoint y?) + // ':maincpu' (8006FA18): hng64_fbscroll y 00001c00 0000ffff + + // on xrally course select this is 1700 (0x170 = 368) + // ':maincpu' (8002327C): hng64_fbscroll y 00001700 0000ffff (-0500 from normal) + + // on xrally car select this is 1260 (and needs to be higher up) + // ':maincpu' (80012820): hng64_fbscroll y 00001260 0000ffff + // 00001a60 on screen after, not quite as high up, but higher than 1c00 + //logerror("%s: hng64_fbscroll y %08x (%d) %08x\n", machine().describe_context(), data, (data >> 5), mem_mask); } } -// this is a table filled with 0x0? data, seems to be 16-bit values +void hng64_state::hng64_fbunkbyte_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + COMBINE_DATA(&m_fbunk[offset]); + + // | ---- --?x ---- ---- ---- ---- ---- ----| unknown + // is 02 in most games, 03 in samsh4 games + // could be related to how fbscrolly is applied? + + logerror("%s: hng64_unkbyte_w %08x %08x\n", machine().describe_context(), data, mem_mask); +} + +/* +this is a table filled with 0x0? data, seems to be 8-bit values + +roadedge 08080808 08080808 08080808 08080808 08080808 08080808 08080707 08080909 (ingame) + 08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808 (hyper logo) + +xrally 08080808 08080808 08070707 08070807 07070807 08070707 08070707 07070808 (comms screen + ingame) + 08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808 (hyper logo) + +buriki 08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808 +fatfurwa 08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808 +bbust2 08080808 08080808 08080808 08080808 08080808 08080808 08080808 08080808 + +sams64 00000000 00000000 00000000 00000000 00000000 07070000 00000000 00000000 (only inits one value to 0707?) +sams64_2 00000000 00000000 00000000 00000000 00000000 07070000 00000000 00000000 (only inits one value to 0707?) +*/ uint32_t hng64_state::hng64_fbtable_r(offs_t offset, uint32_t mem_mask) { logerror("%s: hng64_fbtable_r (%03x) (%08x)\n", machine().describe_context(), offset * 4, mem_mask); @@ -1179,8 +1325,8 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent const float dt = extent.param[6].dpdx; // Pointers to the pixel buffers - uint16_t* colorBuffer = &m_colorBuffer3d.pix(scanline, extent.startx); - float* depthBuffer = &m_depthBuffer3d[(scanline * m_state.m_screen->visible_area().width()) + extent.startx]; + uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512) + extent.startx]; + float* depthBuffer = &m_depthBuffer3d[(scanline * 512) + extent.startx]; const uint8_t *textureOffset = &m_state.m_texturerom[renderData.texIndex * 1024 * 1024]; @@ -1203,6 +1349,10 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent textureS = sCorrect * 1024.0f; textureT = tCorrect * 1024.0f; + textureS += (renderData.texscrolly & 0x3fff)>>4; + textureT += (renderData.texscrollx & 0x3fff)>>4; + + #if 1 // Small-Page textures if (renderData.texPageSmall == 2) @@ -1246,7 +1396,10 @@ void hng64_poly_renderer::render_texture_scanline(int32_t scanline, const extent { float rIntensity = rCorrect / 16.0f; uint8_t lightval = (uint8_t)rIntensity; - uint16_t color = ((renderData.palOffset + paletteEntry) & 0xfff) | (lightval << 12); + uint16_t color = ((renderData.palOffset + paletteEntry) & 0x7ff) | (lightval << 12); + if (renderData.blend) + color |= 0x800; + *colorBuffer = color; *depthBuffer = z; } @@ -1271,8 +1424,8 @@ void hng64_poly_renderer::render_flat_scanline(int32_t scanline, const extent_t& const float dz = extent.param[0].dpdx; // Pointers to the pixel buffers - uint16_t* colorBuffer = &m_colorBuffer3d.pix(scanline, extent.startx); - float* depthBuffer = &m_depthBuffer3d[(scanline * m_state.m_screen->visible_area().width()) + extent.startx]; + float* depthBuffer = &m_depthBuffer3d[(scanline * 512) + extent.startx]; + uint16_t* colorBuffer = &m_colorBuffer3d[(scanline * 512) + extent.startx]; // Step over each pixel in the horizontal span for(int x = extent.startx; x < extent.stopx; x++) @@ -1301,12 +1454,17 @@ void hng64_poly_renderer::drawShaded(polygon *p) rOptions.texPageHorizOffset = p->texPageHorizOffset; rOptions.texPageVertOffset = p->texPageVertOffset; rOptions.colorIndex = p->colorIndex; + rOptions.blend = p->blend; + rOptions.texscrollx = p->texscrollx; + rOptions.texscrolly = p->texscrolly; // Pass the render data into the rasterizer hng64_poly_data& renderData = object_data().next(); renderData = rOptions; - const rectangle& visibleArea = m_state.m_screen->visible_area(); + rectangle visibleArea; + visibleArea.set(0, 512, 0, 512); + if (p->flatShade) { diff --git a/src/mame/snk/hng64_sprite.ipp b/src/mame/snk/hng64_sprite.ipp index 1d5564596b3..501af726c1b 100644 --- a/src/mame/snk/hng64_sprite.ipp +++ b/src/mame/snk/hng64_sprite.ipp @@ -10,14 +10,14 @@ * offset | Bits | Use * | 3322 2222 2222 1111 1111 11 | * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+---------------- - * 0 | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position - * 1 | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*) - * 2 | ---- Szzz zzzz zzzz ---- ---I cccc CCCC | S = set on CPU car markers above cars (in roadedge) z = Z-buffer value, i = 'Inline' chain flag, cC = x/y chain - * 3 | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry - * 4 | mmmm -cfF aggg tttt tttt tttt tttt tttt | mosaic factor, unknown (x1), checkerboard, flip bits, blend, group?, tile number - * 5 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? - * 6 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? - * 7 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? + * 0 0 | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position + * 1 4 | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*) + * 2 8 | ---- Szzz zzzz zzzz ---- ---I cccc CCCC | S = set on CPU car markers above cars (in roadedge) z = Z-buffer value, i = 'Inline' chain flag, cC = x/y chain + * 3 c | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry + * 4 10 | mmmm -cfF aggg tttt tttt tttt tttt tttt | mosaic factor, unknown (x1), checkerboard, flip bits, blend, group?, tile number + * 5 14 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? + * 6 18 | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? + * 7 1c | ---- ---- ---- ---- ---- ---- ---- ---- | not used ?? * * in (4) ggg seems to be either group, or priority against OTHER layers (7 being the lowest, 0 being the highest in normal situations eg most of the time in buriki) * @@ -311,8 +311,13 @@ void hng64_state::draw_sprites_buffer(screen_device& screen, const rectangle& cl /* Calculate the zoom */ int zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100; - if (!zoomx) zoomx = zoom_factor; - if (!zoomy) zoomy = zoom_factor; + + /* Sprites after 'Fair and Square' have a zoom of 0 in sams64 for one frame, they shouldn't be seen? */ + if (!zoomx || !zoomy) + { + currentsprite = nextsprite; + continue; + }; int32_t dx, dy; diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index 9d6c123c31a..6a3d884607c 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -3,6 +3,15 @@ #include "emu.h" #include "hng64.h" +/* + final mix can clearly only process 2 possibilities for any screen pixel; a 'top' and 'bottom' pixel option + one of those can be blended. + blended pixels can't be stacked (only one still appears as blended, the other becomes solid) + + many examples can be found where using alpha effects just cuts holes in sprites/3D or erases other alpha + tilemap layers due to this +*/ + #define HNG64_VIDEO_DEBUG 0 @@ -189,7 +198,7 @@ do { \ } while (0) void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - int wraparound, uint8_t drawformat, uint8_t alpha, uint8_t mosaic, uint8_t tm) + int wraparound, uint8_t drawformat, uint8_t alpha, uint8_t mosaic, uint8_t tm, int splitside) { int source_line_to_use = cliprect.min_y; source_line_to_use = (source_line_to_use / (mosaic+1)) * (mosaic+1); @@ -206,6 +215,7 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap // 0x1000 is set up the buriki 2nd title screen with rotating logo and in fatal fury at various times? const int global_alt_scroll_register_format = m_videoregs[0x00] & 0x04000000; + if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? { // xrally 'mist in tunnel' does NOT use this mode @@ -255,6 +265,7 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap } else { + /* simple zoom mode? - only 4 regs? */ /* in this mode they can only specify the top left and middle screen points for each tilemap, this allows simple zooming, but not rotation */ @@ -293,6 +304,23 @@ void hng64_state::hng64_tilemap_draw_roz_core_line(screen_device &screen, bitmap xmiddle = (m_videoram[(0x40004 + (scrollbase << 4)) / 4]); // middle screen point ytopleft = (m_videoram[(0x40008 + (scrollbase << 4)) / 4]); ymiddle = (m_videoram[(0x4000c + (scrollbase << 4)) / 4]); // middle screen point + + if (splitside == 1) + { + xtopleft += ((m_videoregs[0x0a] >> 0) & 0xffff) << 16; + ytopleft += ((m_videoregs[0x0a] >> 16) & 0xffff) << 16; + + xmiddle += ((m_videoregs[0x0a] >> 0) & 0xffff) << 16; + ymiddle += ((m_videoregs[0x0a] >> 16) & 0xffff) << 16; + } + else if (splitside == 2) + { + xtopleft += ((m_videoregs[0x9] >> 0) & 0xffff) << 16; + ytopleft += ((m_videoregs[0x9] >> 16) & 0xffff) << 16; + + xmiddle += ((m_videoregs[0x09] >> 0) & 0xffff) << 16; + ymiddle += ((m_videoregs[0x09] >> 16) & 0xffff) << 16; + } } xinc = (xmiddle - xtopleft) / 512; @@ -701,7 +729,26 @@ g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); tilemap->pixmap(); /* then do the roz copy */ - hng64_tilemap_draw_roz_core_line(screen, bitmap, clip, tilemap, 1, get_blend_mode(tm), 0x80, mosaic, tm); + + // buriki also turns on bit 0x00000002 and the effect is expected to apply to tm2 and tm3 at least (tm0/tm1 not used at this time) + // sams64 does not initialize bit 0x00000002 though, only 0x00000001 to 0 + const int global_split_format = m_videoregs[0x00] & 0x00000001; + + if (global_split_format) + { + clip.min_x = 256; + clip.max_x = 512; + hng64_tilemap_draw_roz_core_line(screen, bitmap, clip, tilemap, 1, get_blend_mode(tm), 0x80, mosaic, tm, 1); + clip.min_x = 0; + clip.max_x = 256; + hng64_tilemap_draw_roz_core_line(screen, bitmap, clip, tilemap, 1, get_blend_mode(tm), 0x80, mosaic, tm, 2); + + } + else + { + hng64_tilemap_draw_roz_core_line(screen, bitmap, clip, tilemap, 1, get_blend_mode(tm), 0x80, mosaic, tm, 0); + } + g_profiler.stop(); } @@ -813,82 +860,114 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b */ // 3d gets drawn next - pen_t const *const clut_3d = &m_palette_3d->pen(0); - if (!(m_fbcontrol[0] & 0x01)) + uint16_t palbase = 0x000; + if (m_fbcontrol[2] & 0x20) + { + if (!m_roadedge_3d_hack) + palbase = 0x800; + } + + rectangle visarea = m_screen->visible_area(); + int ysize = visarea.max_y - visarea.min_y; + + if (ysize) { - // Blit the color buffer into the primary bitmap - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + int yinc = (512 << 16) / ysize; + + pen_t const* const clut_3d = &m_palette_3d->pen(0); + if (!(m_fbcontrol[0] & 0x01)) { - const uint16_t *src = &m_poly_renderer->colorBuffer3d().pix(y, cliprect.min_x); - uint32_t *dst = &bitmap.pix(y, cliprect.min_x); + // this moves the car in the xrally selection screen the correct number of pixels to the left + int xscroll = (m_fbscroll[0] >> 21); + if (xscroll & 0x400) + xscroll -= 0x800; - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + // value is midpoint? + xscroll += 256; + + // Blit the color buffer into the primary bitmap + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - uint16_t srcpix = *src; - if (srcpix & 0x0fff) + int realy = (((y-cliprect.min_y) * yinc) >> 16); + + const uint16_t* src = &m_poly_renderer->colorBuffer3d()[((realy) & 0x1ff) * 512]; + uint32_t* dst = &bitmap.pix(y, cliprect.min_x); + + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) { - *dst = clut_3d[srcpix]; + uint16_t srcpix = src[((cliprect.min_x + x) + xscroll) & 0x1ff]; + if (srcpix & 0x07ff) + { + if (srcpix & 0x0800) + { + *dst = alpha_blend_r32(*(uint32_t*)dst, clut_3d[(srcpix & 0x7ff) | palbase], 0x80); + } + else + { + *dst = clut_3d[(srcpix & 0x7ff) | palbase]; + } + } + + dst++; } - - dst++; - src++; } } } - // Draw the sprites on top of everything draw_sprites_buffer(screen, cliprect); // copy sprites into display - // this correctly allows buriki intro sprites to use regular alpha, not additive - // while also being correct for sams64, which wants additive, but appears to be - // incorrect for Fatal Fury's hit effects which want additive - // - // the 6 regs around here have the same values in fatfur and buriki, so are unlikely - // to control the blend type. - //uint8_t spriteblendtype = (m_tcram[0x10 / 4] >> 16) & 0x10; - - // would be an odd place for it, after the 'vblank' flag but... - uint8_t spriteblendtype = (m_tcram[0x4c / 4] >> 16) & 0x01; - - pen_t const *const clut = &m_palette->pen(0); - for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + if (true) { - const uint16_t *src = &m_sprite_bitmap.pix(y, cliprect.min_x); - uint32_t *dst = &bitmap.pix(y, cliprect.min_x); - - for (int x = cliprect.min_x; x <= cliprect.max_x; x++) + // this correctly allows buriki intro sprites to use regular alpha, not additive + // while also being correct for sams64, which wants additive, but appears to be + // incorrect for Fatal Fury's hit effects which want additive + // + // the 6 regs around here have the same values in fatfur and buriki, so are unlikely + // to control the blend type. + //uint8_t spriteblendtype = (m_tcram[0x10 / 4] >> 16) & 0x10; + + // would be an odd place for it, after the 'vblank' flag but... + uint8_t spriteblendtype = (m_tcram[0x4c / 4] >> 16) & 0x01; + + pen_t const* const clut = &m_palette->pen(0); + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { - uint16_t srcpix = *src; - if (srcpix & 0x7fff) + const uint16_t* src = &m_sprite_bitmap.pix(y, cliprect.min_x); + uint32_t* dst = &bitmap.pix(y, cliprect.min_x); + + for (int x = cliprect.min_x; x <= cliprect.max_x; x++) { - if (srcpix & 0x8000) + uint16_t srcpix = *src; + if (srcpix & 0x7fff) { - if (spriteblendtype) - *dst = alpha_blend_r32(*(uint32_t *)dst, clut[srcpix & 0x7fff], 0x80); + if (srcpix & 0x8000) + { + if (spriteblendtype) + *dst = alpha_blend_r32(*(uint32_t*)dst, clut[srcpix & 0x7fff], 0x80); + else + *dst = add_blend_r32(*dst, clut[srcpix & 0x7fff]); + } else - *dst = add_blend_r32(*dst, clut[srcpix & 0x7fff]); + { + *dst = clut[srcpix & 0x7fff]; + } } - else - { - *dst = clut[srcpix & 0x7fff]; - } - } - dst++; - src++; + dst++; + src++; + } } } - #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) + if (1) 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], @@ -905,13 +984,13 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b // unused? m_videoregs[0x0d]); - 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 - ADD?(%08x) - SUBTRACT?(%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", + if (0) + popmessage("TC: %08x MINX(%d) MINY(%d) MAXX(%d) MAXY(%d)\nBLEND ENABLES? %02x %02x %02x | %02x %02x %02x\nUNUSED?(%04x)\n%04x\nUNUSED?(%d %d)\nFor FADE1 or 1st in PALFADES group per-RGB blend modes(%d %d %d)\nFor FADE2 or 2nd in PALFADES group per-RGB blend modes(%d %d %d)\nMASTER FADES - FADE1?(%08x)\nMASTER FADES - FADE2?(%08x)\nUNUSED?(%08x)\nUNUSED?&0xfffc(%04x) DISABLE_DISPLAY(%d) ALSO USE REGS BELOW FOR MASTER FADE(%d)\nPALEFFECT_ENABLES(%d %d %d %d %d %d %d %d)\n PALFADES?(%08x %08x : %08x %08x : %08x %08x : %08x %08x)\n %08x SPRITE_BLEND_TYPE?(%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) - // is this 2 groups of 3 regS? + // is this 2 groups of 3 regs? (m_tcram[0x0c / 4] >> 24) & 0xff, // 04 = 'blend' on tm1 (m_tcram[0x0c / 4] >> 16) & 0xff, // 04 = set when fades are going on with blended sprites in buriki intro? otherwise usually 00 (m_tcram[0x0c / 4] >> 8) & 0xff, // upper bit not used? value usually 2x, 4x, 5x or 6x @@ -922,18 +1001,27 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b m_tcram[0x10 / 4] & 0xffff, // unused? + // also seems fade mode related? (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) + + // 0xxx ? (often 0555 or 0fff, seen 56a, 57f too) - register split into 2 bits - typically a bit will be 3 or 1 depending if the effect is additive / subtractive + // usually relate to the RGB pairings at m_tcram[0x18 / 4] & m_tcram[0x1c / 4] but m_tcram[0x24 / 4] & 1 may cause it to use the registers at m_tcram[0x28 / 4] instead? + (m_tcram[0x14 / 4] >> 14) & 0x3, (m_tcram[0x14 / 4] >> 12) & 0x3, // unused? + (m_tcram[0x14 / 4] >> 10) & 0x3, (m_tcram[0x14 / 4] >> 8) & 0x3, (m_tcram[0x14 / 4] >> 6) & 0x3, // for 'fade1' or first register in group of 8? + (m_tcram[0x14 / 4] >> 4) & 0x3, (m_tcram[0x14 / 4] >> 2) & 0x3, (m_tcram[0x14 / 4] >> 0) & 0x3, // for 'fade2' or 2nd register in group of 8? // 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], // unused? + m_tcram[0x20 / 4], // unused? + + (m_tcram[0x24 / 4] >> 16) & 0xfffc, + ((m_tcram[0x24 / 4] >> 16) & 0x0002)>>1, // 0002 gets set in roadedge during some transitions (layers are disabled? blacked out?) 0001 + (m_tcram[0x24 / 4] >> 16) & 0x0001, // 0001 may indicate if to use the 8 below for standard fade, set on SNK logo in roadedge, in FFWA - // 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 + // some kind of bitfields, these appear related to fade mode for the registers at 0x28 / 4, set to either 3 or 2 which is additive or subtractive (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, @@ -1003,7 +1091,7 @@ WRITE_LINE_MEMBER(hng64_state::screen_vblank_hng64) } -/* Transition Control Video Registers +/* Transition Control Video Registers **OUTDATED, see notes with popmessage** * ---------------------------------- * * uint32_t | Bits | Use -- cgit v1.2.3