From 7744332b64065acbf97b3429e13a706ec5e9aec4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 31 Mar 2021 23:06:16 -0700 Subject: [PATCH] GBA Video: Fix window start on modes 2-5 with mosaic (fixes #1690) --- CHANGES | 1 + src/gba/renderers/software-bg.c | 46 +++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 2e31592f3..9fc667493 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Emulation fixes: - Core: Fix first event scheduling after loading savestate - GB Serialize: Fix switching speed modes when loading a state (fixes mgba.io/i/2097) - GBA Memory: Fix loading Thumb savestates when in ARM mode + - GBA Video: Fix window start on modes 3-5 with mosaic (fixes mgba.io/i/1690) Other fixes: - GBA: Fix non-USA 1.0 FireRed misdetecting as a ROM hack (fixes mgba.io/i/2100) - GBA: Fix crash when ROM loading fails diff --git a/src/gba/renderers/software-bg.c b/src/gba/renderers/software-bg.c index 60d18a7dc..acaf0bbfa 100644 --- a/src/gba/renderers/software-bg.c +++ b/src/gba/renderers/software-bg.c @@ -13,15 +13,21 @@ int32_t y = background->sy + (renderer->start - 1) * background->dy; \ int mosaicH = 0; \ int mosaicWait = 0; \ - if (background->mosaic) { \ - int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \ - y -= (inY % mosaicV) * background->dmy; \ - x -= (inY % mosaicV) * background->dmx; \ - mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \ - mosaicWait = renderer->start % (mosaicH + 1); \ - } \ int32_t localX; \ int32_t localY; \ + if (background->mosaic) { \ + int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \ + mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \ + mosaicWait = (mosaicH - renderer->start + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \ + int32_t startX = renderer->start - (renderer->start % mosaicH); \ + --mosaicH; \ + localX = -(inY % mosaicV) * background->dmx; \ + localY = -(inY % mosaicV) * background->dmy; \ + x += localX; \ + y += localY; \ + localX += background->sx + startX * background->dx; \ + localY += background->sy + startX * background->dy; \ + } \ \ uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ flags |= FLAG_TARGET_2 * background->target2; \ @@ -55,10 +61,9 @@ \ if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \ continue; \ - } else { \ - localX = x; \ - localY = y; \ - } + } \ + localX = x; \ + localY = y; \ #define MODE_2_COORD_OVERFLOW \ localX = x & (sizeAdjusted - 1); \ @@ -102,12 +107,20 @@ #define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \ if (background->overflow) { \ if (mosaicH > 1) { \ + localX &= sizeAdjusted - 1; \ + localY &= sizeAdjusted - 1; \ + MODE_2_NO_MOSAIC(); \ MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \ } else { \ MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \ } \ } else { \ if (mosaicH > 1) { \ + if (!((x | y) & ~(sizeAdjusted - 1))) { \ + localX &= sizeAdjusted - 1; \ + localY &= sizeAdjusted - 1; \ + MODE_2_NO_MOSAIC(); \ + } \ MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \ } else { \ MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \ @@ -146,6 +159,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer BACKGROUND_BITMAP_INIT; uint32_t color = renderer->normalPalette[0]; + if (mosaicWait && localX >= 0 && localY >= 0) { + LOAD_16(color, ((localX >> 8) + (localY >> 8) * GBA_VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram); + color = mColorFrom555(color); + } int outX; uint32_t* pixel; @@ -185,6 +202,9 @@ void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { offset = 0xA000; } + if (mosaicWait && localX >= 0 && localY >= 0) { + color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * GBA_VIDEO_HORIZONTAL_PIXELS]; + } int outX; uint32_t* pixel; @@ -223,6 +243,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { offset = 0xA000; } + if (mosaicWait && localX >= 0 && localY >= 0) { + LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram); + color = mColorFrom555(color); + } int outX; uint32_t* pixel;