diff options
-rw-r--r-- | src/mame/snk/hng64.h | 40 | ||||
-rw-r--r-- | src/mame/snk/hng64_3d.ipp | 6 | ||||
-rw-r--r-- | src/mame/snk/hng64_v.cpp | 1151 |
3 files changed, 495 insertions, 702 deletions
diff --git a/src/mame/snk/hng64.h b/src/mame/snk/hng64.h index 931dfafdf3d..178a51fbbe2 100644 --- a/src/mame/snk/hng64.h +++ b/src/mame/snk/hng64.h @@ -139,6 +139,7 @@ public: driver_device(mconfig, type, tag), m_screen(*this, "screen"), m_palette(*this, "palette"), + m_vblank(*this, "VBLANK"), m_maincpu(*this, "maincpu"), m_audiocpu(*this, "audiocpu"), m_iomcu(*this, "iomcu"), @@ -184,6 +185,7 @@ public: uint8_t *m_texturerom = nullptr; required_device<screen_device> m_screen; required_device<palette_device> m_palette; + required_ioport m_vblank; private: static constexpr int HNG64_MASTER_CLOCK = 50'000'000; @@ -199,24 +201,6 @@ private: static constexpr int VBEND = 0; static constexpr int VBSTART = 224*2; - enum hng64trans_t - { - HNG64_TILEMAP_NORMAL = 1, - HNG64_TILEMAP_ADDITIVE, - HNG64_TILEMAP_ALPHA - }; - - struct blit_parameters - { - bitmap_rgb32 * bitmap = nullptr; - rectangle cliprect; - uint32_t tilemap_priority_code = 0; - uint8_t mask = 0; - uint8_t value = 0; - uint8_t alpha = 0; - hng64trans_t drawformat; - }; - required_device<mips3_device> m_maincpu; required_device<v53a_device> m_audiocpu; required_device<tmp87ph40an_device> m_iomcu; @@ -299,8 +283,6 @@ private: hng64_tilemap m_tilemap[4]{}; - uint8_t m_additive_tilemap_debug = 0U; - uint32_t m_old_animmask = 0U; uint32_t m_old_animbits = 0U; uint16_t m_old_tileflags[4]{}; @@ -429,22 +411,16 @@ private: void hng64_mark_all_tiles_dirty(int tilemap); void hng64_mark_tile_dirty(int tilemap, int tile_index); - void hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm); - - void hng64_tilemap_draw_roz_core(screen_device &screen, tilemap_t *tmap, const blit_parameters *blit, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, int wraparound); - - void hng64_tilemap_draw_roz(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, uint32_t flags, uint8_t priority, hng64trans_t drawformat); - void hng64_tilemap_draw_roz_primask(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, uint32_t flags, uint8_t priority, uint8_t priority_mask, hng64trans_t drawformat); + uint16_t get_tileregs(int tm); + uint16_t get_scrollbase(int tm); - static void hng64_configure_blit_parameters(blit_parameters *blit, tilemap_t *tmap, bitmap_rgb32 &dest, const rectangle &cliprect, uint32_t flags, uint8_t priority, uint8_t priority_mask, hng64trans_t drawformat); + int get_blend_mode(int tm); + 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); std::unique_ptr<hng64_poly_renderer> m_poly_renderer; diff --git a/src/mame/snk/hng64_3d.ipp b/src/mame/snk/hng64_3d.ipp index b8fc815a85c..9722359a5c0 100644 --- a/src/mame/snk/hng64_3d.ipp +++ b/src/mame/snk/hng64_3d.ipp @@ -64,7 +64,7 @@ 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 @@ -569,7 +569,7 @@ void hng64_state::recoverPolygonBlock(const uint16_t* packet, int& numPolys) // 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 // @@ -663,7 +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)]); - + if (currentPoly.flatShade) currentPoly.vert[m].colorIndex = chunkOffset[7 + (6*m)] >> 5; diff --git a/src/mame/snk/hng64_v.cpp b/src/mame/snk/hng64_v.cpp index 7ab107ba81c..b79e718adc3 100644 --- a/src/mame/snk/hng64_v.cpp +++ b/src/mame/snk/hng64_v.cpp @@ -3,27 +3,24 @@ #include "emu.h" #include "hng64.h" -#define BLEND_TEST 0 - #define HNG64_VIDEO_DEBUG 0 -void hng64_state::hng64_mark_all_tiles_dirty( int tilemap ) +void hng64_state::hng64_mark_all_tiles_dirty(int tilemap) { m_tilemap[tilemap].m_tilemap_8x8->mark_all_dirty(); m_tilemap[tilemap].m_tilemap_16x16->mark_all_dirty(); m_tilemap[tilemap].m_tilemap_16x16_alt->mark_all_dirty(); } -void hng64_state::hng64_mark_tile_dirty( int tilemap, int tile_index ) +void hng64_state::hng64_mark_tile_dirty(int tilemap, int tile_index) { m_tilemap[tilemap].m_tilemap_8x8->mark_tile_dirty(tile_index); m_tilemap[tilemap].m_tilemap_16x16->mark_tile_dirty(tile_index); m_tilemap[tilemap].m_tilemap_16x16_alt->mark_tile_dirty(tile_index); } - -// make this a function! +// make this a template function! // pppppppp ffattttt tttttttt tttttttt #define HNG64_GET_TILE_INFO \ { \ @@ -152,21 +149,21 @@ void hng64_state::hng64_videoram_w(offs_t offset, uint32_t data, uint32_t mem_ma const int realoff = (offset * 4); COMBINE_DATA(&m_videoram[offset]); - if ((realoff>=0) && (realoff<0x10000)) + if ((realoff >= 0) && (realoff < 0x10000)) { - hng64_mark_tile_dirty(0, offset&0x3fff); + hng64_mark_tile_dirty(0, offset & 0x3fff); } - else if ((realoff>=0x10000) && (realoff<0x20000)) + else if ((realoff >= 0x10000) && (realoff < 0x20000)) { - hng64_mark_tile_dirty(1, offset&0x3fff); + hng64_mark_tile_dirty(1, offset & 0x3fff); } - else if ((realoff>=0x20000) && (realoff<0x30000)) + else if ((realoff >= 0x20000) && (realoff < 0x30000)) { - hng64_mark_tile_dirty(2, offset&0x3fff); + hng64_mark_tile_dirty(2, offset & 0x3fff); } - else if ((realoff>=0x30000) && (realoff<0x40000)) + else if ((realoff >= 0x30000) && (realoff < 0x40000)) { - hng64_mark_tile_dirty(3, offset&0x3fff); + hng64_mark_tile_dirty(3, offset & 0x3fff); } // Offsets 0x40000 - 0x58000 are for "floor" scanline control @@ -175,94 +172,208 @@ void hng64_state::hng64_videoram_w(offs_t offset, uint32_t data, uint32_t mem_ma /* internal set of transparency states for rendering */ +/*------------------------------------------------- + tilemap_draw_roz_core - render the tilemap's + pixmap to the destination with rotation + and zoom +-------------------------------------------------*/ + +#define HNG64_ROZ_PLOT_PIXEL(INPUT_VAL) \ +do { \ + if (drawformat == 1) \ + *(uint32_t *)dest = clut[INPUT_VAL]; \ + else if (drawformat == 2) \ + *(uint32_t *)dest = add_blend_r32(*(uint32_t *)dest, clut[INPUT_VAL]); \ + else if (drawformat == 3) \ + *(uint32_t *)dest = alpha_blend_r32(*(uint32_t *)dest, clut[INPUT_VAL], alpha); \ +} while (0) -void hng64_state::hng64_configure_blit_parameters(blit_parameters *blit, tilemap_t *tmap, bitmap_rgb32 &dest, const rectangle &cliprect, uint32_t flags, uint8_t priority, uint8_t priority_mask, hng64trans_t drawformat) +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) { - /* start with nothing */ - memset(blit, 0, sizeof(*blit)); + int source_line_to_use = cliprect.min_y; + source_line_to_use = (source_line_to_use / (mosaic+1)) * (mosaic+1); + + int xinc, xinc2, yinc, yinc2; + int32_t xtopleft; + int32_t ytopleft; + uint16_t scrollbase = get_scrollbase(tm); + uint16_t tileregs = get_tileregs(tm); + const uint8_t not_line_mode = (tileregs & 0x0800) >> 11; + + if (not_line_mode) + { + // 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 + // buriki title screen tm==3 DOES use this mode + + /* complex zoom mode? */ + /* with this scroll register layout rotation effects are possible + the most obvious use of rotation is the Buriki One logo after + attract mode; the text around the outside of the logo is rotated + onto the screen - /* set the target bitmap */ - blit->bitmap = &dest; + see 1:32 in http://www.youtube.com/watch?v=PoYaHOILuGs - /* if we have a cliprect, copy */ - blit->cliprect = cliprect; + Xtreme Rally seems to have an issue with this mode on the communication check + screen at startup, however during the period in which the values are invalid + it looks like the display shouldn't even be enabled (only gets enabled when + the value starts counting up) - /* set the priority code and alpha */ - //blit->tilemap_priority_code = priority | (priority_mask << 8) | (tmap->palette_offset << 16); // fixit - blit->alpha = (flags & TILEMAP_DRAW_ALPHA_FLAG) ? (flags >> 24) : 0xff; + */ +#if HNG64_VIDEO_DEBUG + if (0) + if (tm == 3) + popmessage("X %08x X %08x X %08x X(?) %08x | Y %08x Y %08x Y %08x Y(?) %08x", + m_videoram[(0x40000 + (scrollbase << 4)) / 4], + m_videoram[(0x40004 + (scrollbase << 4)) / 4], + m_videoram[(0x40010 + (scrollbase << 4)) / 4], + m_videoram[(0x40014 + (scrollbase << 4)) / 4], // unused? (dupe value on fatfurwa, 00 on rest) + + m_videoram[(0x40008 + (scrollbase << 4)) / 4], + m_videoram[(0x40018 + (scrollbase << 4)) / 4], + m_videoram[(0x4000c + (scrollbase << 4)) / 4], + m_videoram[(0x4001c + (scrollbase << 4)) / 4]); // unused? (dupe value on fatfurwa, 00 on rest) +#endif - blit->drawformat = drawformat; + xtopleft = (m_videoram[(0x40000 + (scrollbase << 4)) / 4]); + const int32_t xalt = (m_videoram[(0x40004 + (scrollbase << 4)) / 4]); // middle screen point + const int32_t xmiddle = (m_videoram[(0x40010 + (scrollbase << 4)) / 4]); - /* tile priority; unless otherwise specified, draw anything in layer 0 */ - blit->mask = TILEMAP_PIXEL_CATEGORY_MASK; - blit->value = flags & TILEMAP_PIXEL_CATEGORY_MASK; + ytopleft = (m_videoram[(0x40008 + (scrollbase << 4)) / 4]); + const int32_t yalt = (m_videoram[(0x40018 + (scrollbase << 4)) / 4]); // middle screen point + const int32_t ymiddle = (m_videoram[(0x4000c + (scrollbase << 4)) / 4]); - /* if no layers specified, draw layer 0 */ - if ((flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2)) == 0) - flags |= TILEMAP_DRAW_LAYER0; + xinc = (xmiddle - xtopleft) / 512; + yinc = (ymiddle - ytopleft) / 512; + xinc2 = (xalt - xtopleft) / 512; + yinc2 = (yalt - ytopleft) / 512; + } + 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 */ - /* OR in the bits from the draw masks */ - blit->mask |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2); - blit->value |= flags & (TILEMAP_DRAW_LAYER0 | TILEMAP_DRAW_LAYER1 | TILEMAP_DRAW_LAYER2); +#if HNG64_VIDEO_DEBUG + if (0) + if (tm == 3) + popmessage("%08x %08x %08x %08x", + m_videoram[(0x40010 + (scrollbase << 4)) / 4], + m_videoram[(0x40014 + (scrollbase << 4)) / 4], + m_videoram[(0x40018 + (scrollbase << 4)) / 4], + m_videoram[(0x4001c + (scrollbase << 4)) / 4]); +#endif - /* for all-opaque rendering, don't check any of the layer bits */ - if (flags & TILEMAP_DRAW_OPAQUE) - { - blit->mask &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2); - blit->value &= ~(TILEMAP_PIXEL_LAYER0 | TILEMAP_PIXEL_LAYER1 | TILEMAP_PIXEL_LAYER2); - } + int32_t xmiddle; + int32_t ymiddle; - /* don't check category if requested */ - if (flags & TILEMAP_DRAW_ALL_CATEGORIES) - { - blit->mask &= ~TILEMAP_PIXEL_CATEGORY_MASK; - blit->value &= ~TILEMAP_PIXEL_CATEGORY_MASK; + const uint32_t& global_tileregs = m_videoregs[0x00]; + const int global_zoom_disable = global_tileregs & 0x00010000; + if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) + { + /* If this bit is active the scroll registers don't seem valid at all? + It either disables zooming, or disables use of the scroll registers completely + - used at startup + */ + + xtopleft = 0; + xmiddle = 256 << 16; + + ytopleft = 0; + ymiddle = 256 << 16; + } + else + { + xtopleft = (m_videoram[(0x40000 + (scrollbase << 4)) / 4]); + 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 + } + + xinc = (xmiddle - xtopleft) / 512; + yinc = (ymiddle - ytopleft) / 512; + xinc2 = 0; + yinc2 = 0; + } } -} + else // line mode + { + const int global_alt_scroll_register_format = m_videoregs[0x00] & 0x04000000; + if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? + { + //popmessage("global_alt_scroll_register_format in linemode"); + } + //else + { + int32_t xmiddle; + int32_t ymiddle; + + const uint32_t& global_tileregs = m_videoregs[0x00]; + const int global_zoom_disable = global_tileregs & 0x00010000; + if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) + { + // If this bit is active the scroll registers don't seem valid at all? + // It either disables zooming, or disables use of the scroll registers completely + // - used at startup + xtopleft = 0; + xmiddle = 256 << 16; -/*------------------------------------------------- - tilemap_draw_roz_core - render the tilemap's - pixmap to the destination with rotation - and zoom --------------------------------------------------*/ + ytopleft = 0; + ymiddle = 256 << 16; + } + else + { + uint16_t line = source_line_to_use; + xtopleft = (m_videoram[(0x40000 + (line * 0x10) + (scrollbase << 4)) / 4]); + xmiddle = (m_videoram[(0x40004 + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point + ytopleft = (m_videoram[(0x40008 + (line * 0x10) + (scrollbase << 4)) / 4]); + ymiddle = (m_videoram[(0x4000c + (line * 0x10) + (scrollbase << 4)) / 4]); // middle screen point + } -#define HNG64_ROZ_PLOT_PIXEL(INPUT_VAL) \ -do { \ - if (blit->drawformat == HNG64_TILEMAP_NORMAL) \ - *(uint32_t *)dest = clut[INPUT_VAL]; \ - else if (blit->drawformat == HNG64_TILEMAP_ADDITIVE) \ - *(uint32_t *)dest = add_blend_r32(*(uint32_t *)dest, clut[INPUT_VAL]); \ - else if (blit->drawformat == HNG64_TILEMAP_ALPHA) \ - *(uint32_t *)dest = alpha_blend_r32(*(uint32_t *)dest, clut[INPUT_VAL], alpha); \ -} while (0) + xinc = (xmiddle - xtopleft) / 512; + yinc = (ymiddle - ytopleft) / 512; + // TODO: if global_alt_scroll_register_format is enabled uses incxy / incyx into calculation somehow ... + xinc2 = 0; + yinc2 = 0; + } + } -void hng64_state::hng64_tilemap_draw_roz_core(screen_device &screen, tilemap_t *tmap, const blit_parameters *blit, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, int wraparound) -{ - pen_t const *const clut = &m_palette->pen(blit->tilemap_priority_code >> 16); + uint32_t startx = xtopleft; + uint32_t starty = ytopleft; + const int incxx = xinc << 1; + const int incxy = yinc2 << 1; + const int incyx = xinc2 << 1; + const int incyy = yinc << 1; + + // we have the scroll values for the current line, draw + + pen_t const *const clut = &m_palette->pen(0); bitmap_ind8 &priority_bitmap = screen.priority(); - bitmap_rgb32 &destbitmap = *blit->bitmap; + bitmap_rgb32 &destbitmap = dest; const bitmap_ind16 &srcbitmap = tmap->pixmap(); const bitmap_ind8 &flagsmap = tmap->flagsmap(); const int xmask = srcbitmap.width()-1; const int ymask = srcbitmap.height()-1; const int widthshifted = srcbitmap.width() << 16; const int heightshifted = srcbitmap.height() << 16; - uint32_t priority = blit->tilemap_priority_code; - uint8_t mask = blit->mask; - uint8_t value = blit->value; - uint8_t alpha = blit->alpha; + uint32_t priority = 0; + uint8_t mask = 0x1f; + uint8_t value = 0x10; /* pre-advance based on the cliprect */ - startx += blit->cliprect.min_x * incxx + blit->cliprect.min_y * incyx; - starty += blit->cliprect.min_x * incxy + blit->cliprect.min_y * incyy; + startx += cliprect.min_x * incxx + source_line_to_use * incyx; + starty += cliprect.min_x * incxy + source_line_to_use * incyy; /* extract start/end points */ - int sx = blit->cliprect.min_x; - int sy = blit->cliprect.min_y; - int ex = blit->cliprect.max_x; - int ey = blit->cliprect.max_y; + int sx = cliprect.min_x; + int sy = cliprect.min_y; + int ex = cliprect.max_x; /* optimized loop for the not rotated case */ if (incxy == 0 && incyx == 0 && !wraparound) @@ -278,167 +389,157 @@ void hng64_state::hng64_tilemap_draw_roz_core(screen_device &screen, tilemap_t * if (sx > ex) return; - /* loop over rows */ - while (sy <= ey) - { - /* only draw if Y is within range */ - if (starty < heightshifted) - { - /* initialize X counters */ - int x = sx; - uint32_t cx = startx; - uint32_t cy = starty >> 16; - - /* get source and priority pointers */ - uint8_t *pri = &priority_bitmap.pix(sy, sx); - uint16_t const *const src = &srcbitmap.pix(cy); - uint8_t const *const maskptr = &flagsmap.pix(cy); - uint32_t *dest = &destbitmap.pix(sy, sx); - - /* loop over columns */ - while (x <= ex && cx < widthshifted) - { - /* plot if we match the mask */ - if ((maskptr[cx >> 16] & mask) == value) - { - HNG64_ROZ_PLOT_PIXEL(src[cx >> 16]); - *pri = (*pri & (priority >> 8)) | priority; - } - - /* advance in X */ - cx += incxx; - x++; - dest++; - pri++; - } - } - - /* advance in Y */ - starty += incyy; - sy++; - } - } - - /* wraparound case */ - else if (wraparound) - { - /* loop over rows */ - while (sy <= ey) + /* only draw if Y is within range */ + if (starty < heightshifted) { /* initialize X counters */ int x = sx; uint32_t cx = startx; - uint32_t cy = starty; + uint32_t cy = starty >> 16; - /* get dest and priority pointers */ - uint32_t *dest = &destbitmap.pix(sy, sx); + /* get source and priority pointers */ uint8_t *pri = &priority_bitmap.pix(sy, sx); + uint16_t const *const src = &srcbitmap.pix(cy); + uint8_t const *const maskptr = &flagsmap.pix(cy); + uint32_t *dest = &destbitmap.pix(sy, sx); /* loop over columns */ - while (x <= ex) + int mosaic_counter = 0; + uint16_t masksrc = 0; + uint16_t datasrc = 0; + + while (x <= ex && cx < widthshifted) { + uint16_t srcoffset = cx >> 16; + + if (mosaic_counter == 0) + { + masksrc = (maskptr[srcoffset] & mask); + datasrc = src[srcoffset]; + mosaic_counter = mosaic; + } + else + { + mosaic_counter--; + } + /* plot if we match the mask */ - if ((flagsmap.pix((cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value) + if (masksrc == value) { - HNG64_ROZ_PLOT_PIXEL(srcbitmap.pix((cy >> 16) & ymask, (cx >> 16) & xmask)); + HNG64_ROZ_PLOT_PIXEL(datasrc); *pri = (*pri & (priority >> 8)) | priority; } /* advance in X */ cx += incxx; - cy += incxy; x++; dest++; pri++; } - - /* advance in Y */ - startx += incyx; - starty += incyy; - sy++; } } - - /* non-wraparound case */ - else + /* wraparound case */ + else if (wraparound) { - /* loop over rows */ - while (sy <= ey) - { - /* initialize X counters */ - int x = sx; - uint32_t cx = startx; - uint32_t cy = starty; + /* initialize X counters */ + int x = sx; + uint32_t cx = startx; + uint32_t cy = starty; - /* get dest and priority pointers */ - uint32_t *dest = &destbitmap.pix(sy, sx); - uint8_t *pri = &priority_bitmap.pix(sy, sx); + /* get dest and priority pointers */ + uint32_t *dest = &destbitmap.pix(sy, sx); + uint8_t *pri = &priority_bitmap.pix(sy, sx); - /* loop over columns */ - while (x <= ex) - { - /* plot if we're within the bitmap and we match the mask */ - if (cx < widthshifted && cy < heightshifted) - if ((flagsmap.pix(cy >> 16, cx >> 16) & mask) == value) - { - HNG64_ROZ_PLOT_PIXEL(srcbitmap.pix(cy >> 16, cx >> 16)); - *pri = (*pri & (priority >> 8)) | priority; - } + /* loop over columns */ + int mosaic_counter = 0; + uint16_t masksrc = 0; + uint16_t datasrc = 0; - /* advance in X */ - cx += incxx; - cy += incxy; - x++; - dest++; - pri++; + while (x <= ex) + { + uint16_t srcoffset = (cx >> 16) & xmask; + uint16_t srcyoffset = (cy >> 16) & ymask; + + if (mosaic_counter == 0) + { + masksrc = (flagsmap.pix(srcyoffset, srcoffset) & mask); + datasrc = srcbitmap.pix(srcyoffset, srcoffset); + mosaic_counter = mosaic; + } + else + { + mosaic_counter--; + } + /* plot if we match the mask */ + if (masksrc == value) + { + HNG64_ROZ_PLOT_PIXEL(datasrc); + *pri = (*pri & (priority >> 8)) | priority; } - /* advance in Y */ - startx += incyx; - starty += incyy; - sy++; + /* advance in X */ + cx += incxx; + cy += incxy; + x++; + dest++; + pri++; } } -} - - - -void hng64_state::hng64_tilemap_draw_roz_primask(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, uint32_t flags, uint8_t priority, uint8_t priority_mask, hng64trans_t drawformat) -{ - blit_parameters blit; + /* non-wraparound case */ + else + { + /* initialize X counters */ + int x = sx; + uint32_t cx = startx; + uint32_t cy = starty; - // notes: - // - startx and starty MUST be uint32_t for calculations to work correctly - // - srcbitmap->width and height are assumed to be a power of 2 to speed up wraparound + /* get dest and priority pointers */ + uint32_t *dest = &destbitmap.pix(sy, sx); + uint8_t *pri = &priority_bitmap.pix(sy, sx); - // skip if disabled - //if (!tmap->enable) - // return; + int mosaic_counter = 0; + uint16_t masksrc = 0; + uint16_t datasrc = 0; -g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); - /* configure the blit parameters */ - hng64_configure_blit_parameters(&blit, tmap, dest, cliprect, flags, priority, priority_mask, drawformat); + /* loop over columns */ + while (x <= ex) + { + uint16_t srcoffset = cx >> 16; + uint16_t srcyoffset = cy >> 16; - /* get the full pixmap for the tilemap */ - tmap->pixmap(); + /* plot if we're within the bitmap and we match the mask */ - /* then do the roz copy */ - hng64_tilemap_draw_roz_core(screen, tmap, &blit, startx, starty, incxx, incxy, incyx, incyy, wraparound); -g_profiler.stop(); -} + if (cx < widthshifted && cy < heightshifted) + { + if (mosaic_counter == 0) + { + masksrc = (flagsmap.pix(srcyoffset, srcoffset) & mask); + datasrc = srcbitmap.pix(srcyoffset, srcoffset); + mosaic_counter = mosaic; + } + else + { + mosaic_counter--; + } + if (masksrc == value) + { + HNG64_ROZ_PLOT_PIXEL(datasrc); + *pri = (*pri & (priority >> 8)) | priority; + } -inline void hng64_state::hng64_tilemap_draw_roz(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - uint32_t startx, uint32_t starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, uint32_t flags, uint8_t priority, hng64trans_t drawformat) -{ - hng64_tilemap_draw_roz_primask(screen, dest, cliprect, tmap, startx, starty, incxx, incxy, incyx, incyy, wraparound, flags, priority, 0xff, drawformat); + } + /* advance in X */ + cx += incxx; + cy += incxy; + x++; + dest++; + pri++; + } + } } - /* * Video Regs Format (appear to just be tilemap regs) * -------------------------------------------------- @@ -493,18 +594,46 @@ inline void hng64_state::hng64_tilemap_draw_roz(screen_device &screen, bitmap_rg */ -void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm) + +uint16_t hng64_state::get_tileregs(int tm) { - // Useful bits from the global tilemap flags - const uint32_t& global_tileregs = m_videoregs[0x00]; - const int global_dimensions = (global_tileregs & 0x03000000) >> 24; - const int global_alt_scroll_register_format = global_tileregs & 0x04000000; - const int global_zoom_disable = global_tileregs & 0x00010000; + return (m_videoregs[0x02 + BIT(tm, 1)] >> (BIT(tm, 0) ? 0 : 16)) & 0x0000ffff; +} - // Debug blending on/off based on m_additive_tilemap_debug - int debug_blend_enabled = 0; - if ((m_additive_tilemap_debug&(1 << tm))) - debug_blend_enabled = 1; +uint16_t hng64_state::get_scrollbase(int tm) +{ + return (m_videoregs[0x04 + BIT(tm, 1)] >> (BIT(tm, 0) ? 0 : 16)) & 0x00003fff; +} + +int hng64_state::get_blend_mode(int tm) +{ + // this is based on xrally and sams64/sams64_2 use, it could be incorrect + // it doesn't seem to be 100% on sams64_2 select screen when the mode select circle moves down + + // m_tcram[0x14/4] may be some additional per layer for this? + uint8_t blendmode = 1; + if ((m_tcram[0x0c / 4] & 0x04000000) && (tm == 1)) // only enable it for the 2nd tilemap right now, find other use cases! + blendmode = 2; + + + // the bit below also gets set for certain blending effects + // for example a mist effect in the long tunnel on the South America course + // ( https://youtu.be/9rOPkNHTmYA?t=403 6:43 ) + // this is the only course which has this bit set (it is set all the time) and is the only course using blending + // + // the problem here however is that the tilemap used for blending has a lower tilemap priority than the background tilemap?! + // the bit also gets set on the buriki title screen, and how that blends is unclear even with reference footage + //if ((m_tcram[0x0c / 4] & 0x00000004) && (tm == 3)) + // blendmode = 2; + + return blendmode; +} + + +void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm, int flags, int line) +{ + // Useful bits from the global tilemap flags + const int global_dimensions = (m_videoregs[0x00] & 0x03000000) >> 24; #if HNG64_VIDEO_DEBUG if ((global_dimensions != 0) && (global_dimensions != 3)) @@ -512,356 +641,54 @@ void hng64_state::hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, #endif // Determine which tilemap registers and scroll base this tilemap uses - uint16_t tileregs = 0; - uint16_t scrollbase = 0; - if (tm==0) - { - scrollbase = (m_videoregs[0x04]&0x3fff0000)>>16; - tileregs = (m_videoregs[0x02]&0xffff0000)>>16; - } - else if (tm==1) - { - scrollbase = (m_videoregs[0x04]&0x00003fff)>>0; - tileregs = (m_videoregs[0x02]&0x0000ffff)>>0; - } - else if (tm==2) - { - scrollbase = (m_videoregs[0x05]&0x3fff0000)>>16; - tileregs = (m_videoregs[0x03]&0xffff0000)>>16; - } - else if (tm==3) - { - scrollbase = (m_videoregs[0x05]&0x00003fff)>>0; - tileregs = (m_videoregs[0x03]&0x0000ffff)>>0; - } + uint16_t tileregs = get_tileregs(tm); // Useful bits from the tilemap registers - const uint8_t mosaicValueBits = (tileregs & 0xf000) >> 12; (void)mosaicValueBits; - const uint8_t floorModeBit = (tileregs & 0x0800) >> 11; - const uint8_t bppBit = (tileregs & 0x0400) >> 10; - const uint8_t bigTilemapBit = (tileregs & 0x0200) >> 9; - const uint8_t tilemapEnableBit = (tileregs & 0x0040) >> 6; (void)tilemapEnableBit; - - // Tilemap drawing enable (sams64_2 demo mode says this is legit) - //if (!tilemapEnableBit) - //{ - // return; - //} + const uint8_t mosaic = (tileregs & 0xf000) >> 12; + const uint8_t not_line_mode = (tileregs & 0x0800) >> 11; + //const uint8_t bpp = (tileregs & 0x0400) >> 10; // not used? + const uint8_t big = (tileregs & 0x0200) >> 9; + const uint8_t enable = (tileregs & 0x0040) >> 6; + + // Tilemap drawing enable? + // + // Definitely used to disable tilemaps in sams64_2 demo mode + // and is also set on the 'debug layer' of buriki + // however the floor layer of fatfurwa also has it set, and that must be enabled! + // + // Speculate that floormode ignores this flag, because lines can be disabled on + // a per-line basis? + // + // Could also just be another priority bits with some priorities being filtered + if (!enable && not_line_mode) + { + return; + } // Select the proper tilemap size tilemap_t* tilemap = nullptr; if (global_dimensions==0) { - if (bigTilemapBit) tilemap = m_tilemap[tm].m_tilemap_16x16; + if (big) tilemap = m_tilemap[tm].m_tilemap_16x16; else tilemap = m_tilemap[tm].m_tilemap_8x8; } else { - if (bigTilemapBit) tilemap = m_tilemap[tm].m_tilemap_16x16_alt; + if (big) tilemap = m_tilemap[tm].m_tilemap_16x16_alt; else tilemap = m_tilemap[tm].m_tilemap_8x8; // _alt } - // Set the transmask so our manual copy is correct - const int transmask = bppBit ? 0xff : 0xf; - - if (floorModeBit == 0x0000) - { - // floor mode - // life would be easier if the roz we're talking about for complex zoom wasn't setting this as well - - // 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? - - // See how many lines we have in the data region - // DEBUG: Change this to a loop that goes over each line and draws them - it's just for visualization now - //int lineCount = 0; - //for (int ii = 0; ii < 0x2000/4; ii += 4) - //{ - // const int realAddress = floorAddress/4; - // if (m_videoram[realAddress+ii] == 0xffffff00 && m_videoram[realAddress+ii+1] == 0xffffff00) - // continue; - // if (m_videoram[realAddress+ii] == 0x00000000 && m_videoram[realAddress+ii+1] == 0x00000000) - // continue; - // - // 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?) - //if (m_mcu_type == BURIKI_MCU) - // lineCount *= 2; - - // DEBUG - draw a horizontal green line where the uppermost line of the floor is drawn - const rectangle &visarea = screen.visible_area(); - //if (lineCount < visarea.height()) - //{ - // for (int ii = 0; ii < visarea.width(); ii++) - // bitmap.pix((visarea.height()-lineCount), ii) = 0xff00ff00; - //} - - // HACK : Clear RAM - this is "needed" in fatfurwa since it doesn't clear its own ram (buriki does) - // Figure out what the difference between the two programs is. It's possible writing to - // the linescroll ram fills a buffer and it's cleared automatically between frames? - // for (int ii = 0; ii < 0x2000/4; ii++) - //{ - // const int realAddress = floorAddress/4; - // m_videoram[realAddress+ii] = 0x00000000; - // } - - - // Floor mode - per pixel simple / complex modes? -- every other line? - // (there doesn't seem to be enough data in Buriki for every line at least) - rectangle clip = visarea; - - // this was wrong, see below -// if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? -// { - // Logic would dictate that this should be the 'complex' scroll register layout, - // but per-line. That doesn't work however. - // - // You only have line data for the number of lines on the screen, not enough for - // the complex register layout - // - // HOWEVER, using the code below doesn't work either. This might be because - // they have mosaic turned on, and it adopts a new meaning in linescroll modes? - // - // The code below could also be wrong, and rowscroll simply acts the same in all - // modes, this is hard to know because ss64_2 barely uses it. - // - // buriki line data is at 20146000 (physical) - -//#if HNG64_VIDEO_DEBUG -// popmessage("Unhandled rowscroll %02x", tileregs>>12); -//#endif -// } -// else // 'simple' mode with linescroll, used in some ss64_2 levels (assumed to be correct, but doesn't do much with it.. so could be wrong) - { - for (int line=0; line < 448; line++) - { - clip.min_y = clip.max_y = line; - - int32_t xtopleft, xmiddle; - int32_t ytopleft, ymiddle; - - if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) - { - // If this bit is active the scroll registers don't seem valid at all? - // It either disables zooming, or disables use of the scroll registers completely - // - used at startup - - xtopleft = 0; - xmiddle = 256<<16; - - ytopleft = 0; - ymiddle = 256<<16; - } - else - { - xtopleft = (m_videoram[(0x40000+(line*0x10)+(scrollbase<<4))/4]); - xmiddle = (m_videoram[(0x40004+(line*0x10)+(scrollbase<<4))/4]); // middle screen point - ytopleft = (m_videoram[(0x40008+(line*0x10)+(scrollbase<<4))/4]); - ymiddle = (m_videoram[(0x4000c+(line*0x10)+(scrollbase<<4))/4]); // middle screen point - } - - const int xinc = (xmiddle - xtopleft) / 512; - const int yinc = (ymiddle - ytopleft) / 512; - // TODO: if global_alt_scroll_register_format is enabled uses incxy / incyx into calculation somehow ... - - hng64_tilemap_draw_roz(screen, bitmap,clip,tilemap,xtopleft,ytopleft, - xinc<<1,0,0,yinc<<1, - 1, - 0,0, debug_blend_enabled?HNG64_TILEMAP_ADDITIVE:HNG64_TILEMAP_NORMAL); - } - } - } - else - { - // 0x1000 is set up the buriki 2nd title screen with rotating logo and in fatal fury at various times? - - if (global_alt_scroll_register_format) // globally selects alt scroll register layout??? - { - /* complex zoom mode? */ - /* with this scroll register layout rotation effects are possible - the most obvious use of rotation is the Buriki One logo after - attract mode; the text around the outside of the logo is rotated - onto the screen - - see 1:32 in http://www.youtube.com/watch?v=PoYaHOILuGs - - Xtreme Rally seems to have an issue with this mode on the communication check - screen at startup, however during the period in which the values are invalid - it looks like the display shouldn't even be enabled (only gets enabled when - the value starts counting up) - - */ - -#if HNG64_VIDEO_DEBUG - if (0) - if (tm==2) - popmessage("X %08x X %08x X %08x Y %08x Y %08x Y %08x", - m_videoram[(0x40000+(scrollbase<<4))/4], - m_videoram[(0x40004+(scrollbase<<4))/4], - m_videoram[(0x40010+(scrollbase<<4))/4], - /*m_videoram[(0x40014+(scrollbase<<4))/4],*/ // unused? (dupe value on fatfurwa, 00 on rest) - - m_videoram[(0x40008+(scrollbase<<4))/4], - m_videoram[(0x40018+(scrollbase<<4))/4], - m_videoram[(0x4000c+(scrollbase<<4))/4]); - /*m_videoram[(0x4001c+(scrollbase<<4))/4]);*/ // unused? (dupe value on fatfurwa, 00 on rest) -#endif - - int32_t xtopleft = (m_videoram[(0x40000+(scrollbase<<4))/4]); - const int32_t xalt = (m_videoram[(0x40004+(scrollbase<<4))/4]); // middle screen point - const int32_t xmiddle = (m_videoram[(0x40010+(scrollbase<<4))/4]); - - int32_t ytopleft = (m_videoram[(0x40008+(scrollbase<<4))/4]); - const int32_t yalt = (m_videoram[(0x40018+(scrollbase<<4))/4]); // middle screen point - const int32_t ymiddle = (m_videoram[(0x4000c+(scrollbase<<4))/4]); - - const int xinc = (xmiddle - xtopleft) / 512; - const int yinc = (ymiddle - ytopleft) / 512; - const int xinc2 = (xalt-xtopleft) / 512; - const int yinc2 = (yalt-ytopleft) /512; - - /* manual copy = slooow */ - if (BLEND_TEST) - { - const bitmap_ind16 &bm = tilemap->pixmap(); - const int bmheight = bm.height(); - const int bmwidth = bm.width(); - pen_t const *const paldata = m_palette->pens(); - - //logerror("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle); - - for (int yy=0; yy<448; yy++) - { - uint32_t *dstptr = &bitmap.pix(yy); + rectangle clip = cliprect; + clip.min_y = clip.max_y = line; - int tmp = xtopleft; - int tmp2 = ytopleft; - - for (int xx=0; xx<512; xx++) - { - int realsrcx = (xtopleft>>16)&(bmwidth-1); - int realsrcy = (ytopleft>>16)&(bmheight-1); - - uint16_t const *const srcptr = &bm.pix(realsrcy); - - uint16_t pen = srcptr[realsrcx]; - - if (pen&transmask) - *dstptr = paldata[pen]; - - xtopleft+= xinc<<1; - ytopleft+= yinc2<<1; - ++dstptr; - } - - ytopleft = tmp2 + (yinc<<1); - xtopleft = tmp + (xinc2<<1); - } - } - else - { - hng64_tilemap_draw_roz(screen, bitmap,cliprect,tilemap,xtopleft,ytopleft, - xinc<<1,yinc2<<1,xinc2<<1,yinc<<1, - 1, - 0,0, debug_blend_enabled?HNG64_TILEMAP_ADDITIVE:HNG64_TILEMAP_NORMAL); - } - - } - 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 */ - -#if HNG64_VIDEO_DEBUG - if (0) - if (tm==2) - popmessage("%08x %08x %08x %08x", - m_videoram[(0x40010+(scrollbase<<4))/4], - m_videoram[(0x40014+(scrollbase<<4))/4], - m_videoram[(0x40018+(scrollbase<<4))/4], - m_videoram[(0x4001c+(scrollbase<<4))/4]); -#endif - - int32_t xtopleft,xmiddle; - int32_t ytopleft,ymiddle; - - if (global_zoom_disable) // disable all scrolling / zoom (test screen) (maybe) - { - /* If this bit is active the scroll registers don't seem valid at all? - It either disables zooming, or disables use of the scroll registers completely - - used at startup - */ - - xtopleft = 0; - xmiddle = 256<<16; - - ytopleft = 0; - ymiddle = 256<<16; - } - else - { - xtopleft = (m_videoram[(0x40000+(scrollbase<<4))/4]); - 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 - } - - const int xinc = (xmiddle - xtopleft) / 512; - const int yinc = (ymiddle - ytopleft) / 512; - - /* manual copy = slooow */ - if (BLEND_TEST) - { - const bitmap_ind16 &bm = tilemap->pixmap(); - const int bmheight = bm.height(); - const int bmwidth = bm.width(); - pen_t const *const paldata = m_palette->pens(); - - int tmp = xtopleft; - - //logerror("start %08x end %08x start %08x end %08x\n", xtopleft, xmiddle, ytopleft, ymiddle); - - for (int yy=0; yy<448; yy++) - { - int realsrcy = (ytopleft>>16)&(bmheight-1); - - uint32_t *dstptr = &bitmap.pix(yy); - uint16_t const *const srcptr = &bm.pix(realsrcy); - - xtopleft = tmp; - - for (int xx=0; xx<512; xx++) - { - int realsrcx = (xtopleft>>16)&(bmwidth-1); - - uint16_t pen = srcptr[realsrcx]; - - if (pen&transmask) - *dstptr = paldata[pen]; +g_profiler.start(PROFILER_TILEMAP_DRAW_ROZ); + /* get the full pixmap for the tilemap */ + tilemap->pixmap(); - xtopleft+= xinc<<1; - ++dstptr; - } + /* then do the roz copy */ + hng64_tilemap_draw_roz_core_line(screen, bitmap, clip, tilemap, 1, get_blend_mode(tm), 0x80, mosaic, tm); +g_profiler.stop(); - ytopleft+= yinc<<1; - } - } - else - { - hng64_tilemap_draw_roz(screen, bitmap,cliprect,tilemap,xtopleft,ytopleft, - xinc<<1,0,0,yinc<<1, - 1, - 0,0, debug_blend_enabled?HNG64_TILEMAP_ADDITIVE:HNG64_TILEMAP_NORMAL); - } - } - } } @@ -871,7 +698,7 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b // press in sams64_2 attract mode for a nice debug screen from the game // not sure how functional it is, and it doesn't appear to test everything (rowscroll modes etc.) // but it could be useful - if ( machine().input().code_pressed_once(KEYCODE_L) ) + if (machine().input().code_pressed_once(KEYCODE_L)) { address_space &space = m_maincpu->space(AS_PROGRAM); @@ -882,9 +709,12 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } #endif - // Initialize some buffers - bitmap.fill(m_tcram[0x50/4] & 0x10000 ? m_palette->black_pen() : m_palette->pen(0), cliprect); //FIXME: Is the register correct? check with HW tests + if (m_fbcontrol[0] & 0x01) //FIXME: Is the register correct? check with HW tests + bitmap.fill(m_palette->pen(0), cliprect); + else + bitmap.fill(m_palette->black_pen(), cliprect); + screen.priority().fill(0x00, cliprect); // If the screen is disabled, don't draw anything (m_screen_dis is a shady variable at best) @@ -897,21 +727,21 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b if ((m_old_animmask != animmask) || (m_old_animbits != animbits)) { int tile_index; - for (tile_index=0;tile_index<128*128;tile_index++) + for (tile_index = 0; tile_index < 128 * 128; tile_index++) { - if (m_videoram[tile_index+(0x00000/4)] & 0x200000) + if (m_videoram[tile_index + (0x00000 / 4)] & 0x200000) { hng64_mark_tile_dirty(0, tile_index); } - if (m_videoram[tile_index+(0x10000/4)] & 0x200000) + if (m_videoram[tile_index + (0x10000 / 4)] & 0x200000) { hng64_mark_tile_dirty(1, tile_index); } - if (m_videoram[tile_index+(0x20000/4)] & 0x200000) + if (m_videoram[tile_index + (0x20000 / 4)] & 0x200000) { hng64_mark_tile_dirty(2, tile_index); } - if (m_videoram[tile_index+(0x30000/4)] & 0x200000) + if (m_videoram[tile_index + (0x30000 / 4)] & 0x200000) { hng64_mark_tile_dirty(3, tile_index); } @@ -937,14 +767,22 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b } } - // Draw the four tilemaps - hng64_drawtilemap(screen,bitmap,cliprect, 3); - hng64_drawtilemap(screen,bitmap,cliprect, 2); - hng64_drawtilemap(screen,bitmap,cliprect, 1); - hng64_drawtilemap(screen,bitmap,cliprect, 0); + for (int y = cliprect.min_y; y <= cliprect.max_y; y++) + { + for (int i = 0x3f; i >= 0; i--) + { + for (int j = 0; j < 4; j++) + { + uint16_t pri = get_tileregs(j) & 0x3f; + + if (pri == i) + hng64_drawtilemap(screen, bitmap, cliprect, j, 0, y); + } + } + } // 3d gets drawn next - if(!(m_fbcontrol[0] & 0x01)) + if (!(m_fbcontrol[0] & 0x01)) { // Blit the color buffer into the primary bitmap for (int y = cliprect.min_y; y <= cliprect.max_y; y++) @@ -954,7 +792,7 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b for (int x = cliprect.min_x; x <= cliprect.max_x; x++) { - if(*src & 0xff000000) + if (*src & 0xff000000) *dst = *src; dst++; @@ -975,73 +813,62 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b popmessage("%08x %08x %08x %08x %08x", m_spriteregs[0], m_spriteregs[1], m_spriteregs[2], m_spriteregs[3], m_spriteregs[4]); if (1) - popmessage("%08x %08x TR(%04x %04x %04x %04x) SB(%04x %04x %04x %04x) %08x %08x %08x %08x %08x AA(%08x %08x) %08x", - m_videoregs[0x00], - m_videoregs[0x01], - (m_videoregs[0x02]>>16)&0xffff, - (m_videoregs[0x02]>>0)&0xffff, // ss64_2 debug mode indicates that 0x0040 is enable! - (m_videoregs[0x03]>>16)&0xffff, // buriki agrees (debug data on text layer) xrally agress (pink layer) - (m_videoregs[0x03]>>0)&0xffff, // fatal fury doesn't (all backgrounds have it set) joy - (m_videoregs[0x04]>>16)&0xffff, - (m_videoregs[0x04]>>0)&0xffff, - (m_videoregs[0x05]>>16)&0xffff, - (m_videoregs[0x05]>>0)&0xffff, - m_videoregs[0x06], - m_videoregs[0x07], - m_videoregs[0x08], - m_videoregs[0x09], - m_videoregs[0x0a], - m_videoregs[0x0b], - m_videoregs[0x0c], - m_videoregs[0x0d]); + popmessage("%08x %08x TR(%04x %04x %04x %04x) SB(%04x %04x %04x %04x) %08x %08x %08x %08x %08x AA(%08x %08x) %08x", + m_videoregs[0x00], + m_videoregs[0x01], + (m_videoregs[0x02] >> 16) & 0xffff, + (m_videoregs[0x02] >> 0) & 0xffff, // ss64_2 debug mode indicates that 0x0040 is enable! + (m_videoregs[0x03] >> 16) & 0xffff, // buriki agrees (debug data on text layer) xrally agress (pink layer) + (m_videoregs[0x03] >> 0) & 0xffff, // fatal fury doesn't (all backgrounds have it set) joy + (m_videoregs[0x04] >> 16) & 0xffff, + (m_videoregs[0x04] >> 0) & 0xffff, + (m_videoregs[0x05] >> 16) & 0xffff, + (m_videoregs[0x05] >> 0) & 0xffff, + m_videoregs[0x06], + m_videoregs[0x07], + m_videoregs[0x08], + m_videoregs[0x09], + m_videoregs[0x0a], + m_videoregs[0x0b], + m_videoregs[0x0c], + m_videoregs[0x0d]); if (0) popmessage("TC: %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x : %08x %08x %08x %08x", - m_tcram[0x00/4], - m_tcram[0x04/4], - m_tcram[0x08/4], // tilemaps 0/1 ? - m_tcram[0x0c/4], // ss64_2 debug 04000000 = 'half' on tm1 00000004 = 'half' on tm3 (used in transitions?) - m_tcram[0x10/4], - m_tcram[0x14/4], - m_tcram[0x18/4], - m_tcram[0x1c/4], - m_tcram[0x20/4], - m_tcram[0x24/4], - m_tcram[0x28/4], - m_tcram[0x2c/4], - m_tcram[0x30/4], - m_tcram[0x34/4], - m_tcram[0x38/4], - m_tcram[0x3c/4], - m_tcram[0x40/4], - m_tcram[0x44/4], - m_tcram[0x48/4], - m_tcram[0x4c/4], - m_tcram[0x50/4], - m_tcram[0x54/4], - m_tcram[0x58/4], - m_tcram[0x5c/4]); - - if ( machine().input().code_pressed_once(KEYCODE_T) ) - { - m_additive_tilemap_debug ^= 1; - popmessage("blend changed %02x", m_additive_tilemap_debug); - } - if ( machine().input().code_pressed_once(KEYCODE_Y) ) - { - m_additive_tilemap_debug ^= 2; - popmessage("blend changed %02x", m_additive_tilemap_debug); - } - if ( machine().input().code_pressed_once(KEYCODE_U) ) - { - m_additive_tilemap_debug ^= 4; - popmessage("blend changed %02x", m_additive_tilemap_debug); - } - if ( machine().input().code_pressed_once(KEYCODE_I) ) - { - m_additive_tilemap_debug ^= 8; - popmessage("blend changed %02x", m_additive_tilemap_debug); - } + m_tcram[0x00 / 4], + m_tcram[0x04 / 4], + m_tcram[0x08 / 4], // tilemaps 0/1 ? + m_tcram[0x0c / 4], // ss64_2 debug 04000000 = 'half' on tm1 00000004 = 'half' on tm3 (used in transitions?) + m_tcram[0x10 / 4], + m_tcram[0x14 / 4], + m_tcram[0x18 / 4], + m_tcram[0x1c / 4], + m_tcram[0x20 / 4], + m_tcram[0x24 / 4], + m_tcram[0x28 / 4], + m_tcram[0x2c / 4], + m_tcram[0x30 / 4], + m_tcram[0x34 / 4], + m_tcram[0x38 / 4], + m_tcram[0x3c / 4], + m_tcram[0x40 / 4], + m_tcram[0x44 / 4], + m_tcram[0x48 / 4], + m_tcram[0x4c / 4], + m_tcram[0x50 / 4], + m_tcram[0x54 / 4], + m_tcram[0x58 / 4], + m_tcram[0x5c / 4]); + + /* + m_tcram[0x0c/4] + 05002201 blending? + 01002201 + + m_tcram[0x14/4], + 0011057f blending? + 0001057f + */ #endif return 0; @@ -1050,7 +877,7 @@ uint32_t hng64_state::screen_update_hng64(screen_device &screen, bitmap_rgb32 &b WRITE_LINE_MEMBER(hng64_state::screen_vblank_hng64) { // rising edge and buffer swap - if (state && (m_tcram[0x50/4] & 0x10000)) + if (state && (m_tcram[0x50 / 4] & 0x10000)) clear3d(); } @@ -1099,9 +926,9 @@ void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) { uint32_t *hng64_tcram = m_tcram; - COMBINE_DATA (&hng64_tcram[offset]); + COMBINE_DATA(&hng64_tcram[offset]); - if(offset == 0x02) + if (offset == 0x02) { rectangle visarea = m_screen->visible_area(); @@ -1110,7 +937,7 @@ void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) const uint16_t max_x = (hng64_tcram[2] & 0xffff0000) >> 16; const uint16_t max_y = (hng64_tcram[2] & 0x0000ffff) >> 0; - if(max_x == 0 || max_y == 0) // bail out if values are invalid, Fatal Fury WA sets this to disable the screen. + if (max_x == 0 || max_y == 0) // bail out if values are invalid, Fatal Fury WA sets this to disable the screen. { m_screen_dis = 1; return; @@ -1119,7 +946,7 @@ void hng64_state::tcram_w(offs_t offset, uint32_t data, uint32_t mem_mask) m_screen_dis = 0; visarea.set(min_x, min_x + max_x - 1, min_y, min_y + max_y - 1); - m_screen->configure(HTOTAL, VTOTAL, visarea, m_screen->frame_period().attoseconds() ); + m_screen->configure(HTOTAL, VTOTAL, visarea, m_screen->frame_period().attoseconds()); } } @@ -1127,70 +954,63 @@ uint32_t hng64_state::tcram_r(offs_t offset) { /* is this really a port? this seems treated like RAM otherwise, check if there's code anywhere to write the desired value here instead */ - if ((offset*4) == 0x48) - return ioport("VBLANK")->read(); + if ((offset * 4) == 0x48) + return m_vblank->read(); return m_tcram[offset]; } // Very much a work in progress - no hard testing has been done -void hng64_state::transition_control( bitmap_rgb32 &bitmap, const rectangle &cliprect) +void hng64_state::transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect) { -// float colorScaleR, colorScaleG, colorScaleB; - int32_t finR, finG, finB; - - int32_t darkR, darkG, darkB; - int32_t brigR, brigG, brigB; - // If either of the fading memory regions is non-zero... if (m_tcram[0x00000007] != 0x00000000 || m_tcram[0x0000000a] != 0x00000000) { - darkR = (int32_t)( m_tcram[0x00000007] & 0xff); - darkG = (int32_t)((m_tcram[0x00000007] >> 8) & 0xff); - darkB = (int32_t)((m_tcram[0x00000007] >> 16) & 0xff); + const int32_t darkR = int32_t(m_tcram[0x00000007] & 0xff); + const int32_t darkG = int32_t((m_tcram[0x00000007] >> 8) & 0xff); + const int32_t darkB = int32_t((m_tcram[0x00000007] >> 16) & 0xff); - brigR = (int32_t)( m_tcram[0x0000000a] & 0xff); - brigG = (int32_t)((m_tcram[0x0000000a] >> 8) & 0xff); - brigB = (int32_t)((m_tcram[0x0000000a] >> 16) & 0xff); + const int32_t brigR = int32_t(m_tcram[0x0000000a] & 0xff); + const int32_t brigG = int32_t((m_tcram[0x0000000a] >> 8) & 0xff); + const int32_t brigB = int32_t((m_tcram[0x0000000a] >> 16) & 0xff); for (int i = cliprect.min_x; i < cliprect.max_x; i++) { for (int j = cliprect.min_y; j < cliprect.max_y; j++) { - rgb_t* thePixel = reinterpret_cast<rgb_t *>(&bitmap.pix(j, i)); + rgb_t *thePixel = reinterpret_cast<rgb_t *>(&bitmap.pix(j, i)); - finR = (int32_t)thePixel->r(); - finG = (int32_t)thePixel->g(); - finB = (int32_t)thePixel->b(); + int32_t finR = (int32_t)thePixel->r(); + int32_t finG = (int32_t)thePixel->g(); + int32_t finB = (int32_t)thePixel->b(); #if 0 + float colorScaleR, colorScaleG, colorScaleB; + // Apply the darkening pass (0x07)... - colorScaleR = 1.0f - (float)( m_tcram[0x00000007] & 0xff) / 255.0f; - colorScaleG = 1.0f - (float)((m_tcram[0x00000007] >> 8) & 0xff) / 255.0f; + colorScaleR = 1.0f - (float)(m_tcram[0x00000007] & 0xff) / 255.0f; + colorScaleG = 1.0f - (float)((m_tcram[0x00000007] >> 8) & 0xff) / 255.0f; colorScaleB = 1.0f - (float)((m_tcram[0x00000007] >> 16) & 0xff) / 255.0f; - finR = ((float)thePixel->r() * colorScaleR); + finR = ((float)thePixel->r() * colorScaleR); finG = ((float)thePixel->g() * colorScaleG); - finB = ((float)thePixel->b() * colorScaleB); - + finB = ((float)thePixel->b() * colorScaleB); // Apply the lightening pass (0x0a)... - colorScaleR = 1.0f + (float)( m_tcram[0x0000000a] & 0xff) / 255.0f; - colorScaleG = 1.0f + (float)((m_tcram[0x0000000a] >> 8) & 0xff) / 255.0f; + colorScaleR = 1.0f + (float)(m_tcram[0x0000000a] & 0xff) / 255.0f; + colorScaleG = 1.0f + (float)((m_tcram[0x0000000a] >> 8) & 0xff) / 255.0f; colorScaleB = 1.0f + (float)((m_tcram[0x0000000a] >> 16) & 0xff) / 255.0f; finR *= colorScaleR; finG *= colorScaleG; finB *= colorScaleB; - // Clamp if (finR > 255.0f) finR = 255.0f; if (finG > 255.0f) finG = 255.0f; if (finB > 255.0f) finB = 255.0f; #endif - // Subtractive fading if (m_tcram[0x00000007] != 0x00000000) { @@ -1232,32 +1052,29 @@ void hng64_state::video_start() m_old_tileflags[2] = -1; m_old_tileflags[3] = -1; - m_tilemap[0].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[0].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[0].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 + m_tilemap[0].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[0].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[0].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile0_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 - m_tilemap[1].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[1].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[1].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 + m_tilemap[1].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[1].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[1].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile1_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 - m_tilemap[2].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[2].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[2].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 + m_tilemap[2].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[2].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[2].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile2_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 - m_tilemap[3].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[3].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 - m_tilemap[3].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 + m_tilemap[3].m_tilemap_8x8 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_8x8_info)), TILEMAP_SCAN_ROWS, 8, 8, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[3].m_tilemap_16x16 = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128); // 128x128x4 = 0x10000 + m_tilemap[3].m_tilemap_16x16_alt = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(hng64_state::get_hng64_tile3_16x16_info)), TILEMAP_SCAN_ROWS, 16, 16, 256, 64); // 128x128x4 = 0x10000 - for (auto & elem : m_tilemap) + for (auto &elem : m_tilemap) { elem.m_tilemap_8x8->set_transparent_pen(0); elem.m_tilemap_16x16->set_transparent_pen(0); elem.m_tilemap_16x16_alt->set_transparent_pen(0); } - // Debug switch, turn on / off additive blending on a per-tilemap basis - m_additive_tilemap_debug = 0; - // Rasterizer creation m_poly_renderer = std::make_unique<hng64_poly_renderer>(*this); |