GBA Video: Implement sprite mosaic on transformed sprites

This commit is contained in:
Vicki Pfau 2019-05-21 15:32:20 -07:00
parent 6c1bc5548c
commit 2781a2a9f9
4 changed files with 46 additions and 2 deletions

View File

@ -27,6 +27,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)

View File

@ -215,7 +215,6 @@ Footnotes
<a name="missing">[1]</a> 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))
<a name="flashdetect">[2]</a> 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.

View File

@ -215,7 +215,6 @@ Fußnoten
<a name="missing">[1]</a> 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))
<a name="flashdetect">[2]</a> 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.

View File

@ -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 {