summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/mame/snk/hng64.h40
-rw-r--r--src/mame/snk/hng64_3d.ipp6
-rw-r--r--src/mame/snk/hng64_v.cpp1151
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);