From f5085dfc819fcce1aaa7bbeef8da6543c064dca8 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 May 2019 15:32:20 -0700 Subject: [PATCH] GBA Video: Implement sprite mosaic on transformed sprites --- CHANGES | 1 + README.md | 1 - README_DE.md | 1 - src/gba/renderers/software-obj.c | 45 ++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index e7ae8a925..72a06e3b0 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,7 @@ Emulation fixes: - GBA Memory: Prevent writing to mirrored BG VRAM (fixes mgba.io/i/743) - GBA Video: Fix sprite mosaic clamping (fixes mgba.io/i/1008) - GB: Fix HALT when IE and IF unused bits are set (fixes mgba.io/i/1349) + - GBA Video: Implement mosaic on transformed sprites (fixes mgba.io/b/9) Other fixes: - Qt: More app metadata fixes - Qt: Fix load recent from archive (fixes mgba.io/i/1325) diff --git a/README.md b/README.md index 501ff37f1..cf3cc29aa 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,6 @@ Footnotes [1] Currently missing features are - OBJ window for modes 3, 4 and 5 ([Bug #5](http://mgba.io/b/5)) -- Mosaic for transformed OBJs ([Bug #9](http://mgba.io/b/9)) [2] Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered. diff --git a/README_DE.md b/README_DE.md index f8a2a01d5..3f0b43ecf 100644 --- a/README_DE.md +++ b/README_DE.md @@ -215,7 +215,6 @@ Fußnoten [1] Zurzeit fehlende Features sind - OBJ-Fenster für die Modi 3, 4 und 5 ([Bug #5](http://mgba.io/b/5)) -- Mosaik-Effekt für umgewandelte OBJs ([Bug #9](http://mgba.io/b/9)) [2] In manchen Fällen ist es nicht möglich, die Größe des Flash-Speichers automatisch zu ermitteln. Diese kann dann zur Laufzeit konfiguriert werden, es wird jedoch empfohlen, den Fehler zu melden. diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 8d6ea3768..bd8a29a71 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -48,6 +48,31 @@ SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ } +#define SPRITE_TRANSFORMED_MOSAIC_LOOP(DEPTH, TYPE) \ + unsigned tileData; \ + unsigned widthMask = ~(width - 1); \ + unsigned heightMask = ~(height - 1); \ + int localX = xAccum >> 8; \ + int localY = yAccum >> 8; \ + for (; outX < condition; ++outX, ++inX) { \ + renderer->spriteCyclesRemaining -= 2; \ + xAccum += mat.a; \ + yAccum += mat.c; \ + \ + if (outX % mosaicH == 0) { \ + localX = xAccum >> 8; \ + localY = yAccum >> 8; \ + } \ + \ + if (localX & widthMask || localY & heightMask) { \ + continue; \ + } \ + \ + SPRITE_YBASE_ ## DEPTH(localY); \ + SPRITE_XBASE_ ## DEPTH(localX); \ + SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ + } + #define SPRITE_XBASE_16(localX) unsigned xBase = (localX & ~0x7) * 4 + ((localX >> 1) & 2); #define SPRITE_YBASE_16(localY) unsigned yBase = (localY & ~0x7) * stride + (localY & 0x7) * 4; @@ -173,6 +198,13 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re if (end < condition) { condition = end; } + int mosaicH = 1; + if (GBAObjAttributesAIsMosaic(sprite->a)) { + mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1; + if (condition % mosaicH) { + condition += mosaicH - (condition % mosaicH); + } + } int xAccum = mat.a * (inX - 1 - (totalWidth >> 1)) + mat.b * (inY - (totalHeight >> 1)) + (width << 7); int yAccum = mat.c * (inX - 1 - (totalWidth >> 1)) + mat.d * (inY - (totalHeight >> 1)) + (height << 7); @@ -223,6 +255,13 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; if (flags & FLAG_OBJWIN) { SPRITE_TRANSFORMED_LOOP(16, OBJWIN); + } else if (mosaicH > 1) { + if (objwinSlowPath) { + objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4]; + SPRITE_TRANSFORMED_MOSAIC_LOOP(16, NORMAL_OBJWIN); + } else { + SPRITE_TRANSFORMED_MOSAIC_LOOP(16, NORMAL); + } } else if (objwinSlowPath) { objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4]; SPRITE_TRANSFORMED_LOOP(16, NORMAL_OBJWIN); @@ -232,6 +271,12 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re } else { if (flags & FLAG_OBJWIN) { SPRITE_TRANSFORMED_LOOP(256, OBJWIN); + } else if (mosaicH > 1) { + if (objwinSlowPath) { + SPRITE_TRANSFORMED_MOSAIC_LOOP(256, NORMAL_OBJWIN); + } else { + SPRITE_TRANSFORMED_MOSAIC_LOOP(256, NORMAL); + } } else if (objwinSlowPath) { SPRITE_TRANSFORMED_LOOP(256, NORMAL_OBJWIN); } else {