mirror of https://github.com/mgba-emu/mgba.git
GB Video: Draw SGB border pieces that overlap GB graphics (fixes #1339)
This commit is contained in:
parent
ca0cfa077e
commit
70f75bba49
1
CHANGES
1
CHANGES
|
@ -14,6 +14,7 @@ Features:
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- ARM7: Fix unsigned multiply timing
|
- ARM7: Fix unsigned multiply timing
|
||||||
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
|
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
|
||||||
|
- GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339)
|
||||||
- GBA: Improve timing when not booting from BIOS
|
- GBA: Improve timing when not booting from BIOS
|
||||||
- GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059)
|
- GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059)
|
||||||
- GBA I/O: Redo internal key input, enabling edge-based key IRQs
|
- GBA I/O: Redo internal key input, enabling edge-based key IRQs
|
||||||
|
|
|
@ -60,6 +60,7 @@ struct GBVideoSoftwareRenderer {
|
||||||
uint8_t sgbPacket[128];
|
uint8_t sgbPacket[128];
|
||||||
uint8_t sgbCommandHeader;
|
uint8_t sgbCommandHeader;
|
||||||
bool sgbBorders;
|
bool sgbBorders;
|
||||||
|
uint32_t sgbBorderMask[18];
|
||||||
|
|
||||||
uint8_t lastHighlightAmount;
|
uint8_t lastHighlightAmount;
|
||||||
};
|
};
|
||||||
|
|
|
@ -64,37 +64,58 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
|
||||||
}
|
}
|
||||||
int x, y;
|
int x, y;
|
||||||
for (y = 0; y < 224; ++y) {
|
for (y = 0; y < 224; ++y) {
|
||||||
|
int localY = y & 0x7;
|
||||||
|
if (!localY && y >= 40 && y < 184) {
|
||||||
|
renderer->sgbBorderMask[(y - 40) >> 3] = 0;
|
||||||
|
}
|
||||||
for (x = 0; x < 256; x += 8) {
|
for (x = 0; x < 256; x += 8) {
|
||||||
if (x >= 48 && x < 208 && y >= 40 && y < 184) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint16_t mapData;
|
uint16_t mapData;
|
||||||
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
|
LOAD_16LE(mapData, (x >> 2) + (y & ~7) * 8, renderer->d.sgbMapRam);
|
||||||
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
|
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int localY = y & 0x7;
|
if (x >= 48 && x < 208 && y >= 40 && y < 184) {
|
||||||
if (SGBBgAttributesIsYFlip(mapData)) {
|
if (!localY) {
|
||||||
localY = 7 - localY;
|
unsigned tileBase = SGBBgAttributesGetTile(mapData) * 8;
|
||||||
|
uint32_t bits = 0;
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 0];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 1];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 2];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 3];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 4];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 5];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 6];
|
||||||
|
bits |= ((uint32_t*) renderer->d.sgbCharRam)[tileBase + 7];
|
||||||
|
if (bits) {
|
||||||
|
renderer->sgbBorderMask[(y - 40) >> 3] |= 1 << ((x - 48) >> 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int yFlip = 0;
|
||||||
|
if (SGBBgAttributesIsYFlip(mapData)) {
|
||||||
|
yFlip = 7;
|
||||||
|
}
|
||||||
|
unsigned tileBase = (SGBBgAttributesGetTile(mapData) * 16 + (localY ^ yFlip)) * 2;
|
||||||
uint8_t tileData[4];
|
uint8_t tileData[4];
|
||||||
tileData[0] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x00];
|
tileData[0] = renderer->d.sgbCharRam[tileBase + 0x00];
|
||||||
tileData[1] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x01];
|
tileData[1] = renderer->d.sgbCharRam[tileBase + 0x01];
|
||||||
tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10];
|
tileData[2] = renderer->d.sgbCharRam[tileBase + 0x10];
|
||||||
tileData[3] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x11];
|
tileData[3] = renderer->d.sgbCharRam[tileBase + 0x11];
|
||||||
|
|
||||||
size_t base = y * renderer->outputBufferStride + x;
|
size_t base = y * renderer->outputBufferStride + x;
|
||||||
int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10;
|
int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10;
|
||||||
int colorSelector;
|
int colorSelector;
|
||||||
|
|
||||||
int flip = 0;
|
int xFlip = 0;
|
||||||
if (SGBBgAttributesIsXFlip(mapData)) {
|
if (SGBBgAttributesIsXFlip(mapData)) {
|
||||||
flip = 7;
|
xFlip = 7;
|
||||||
}
|
}
|
||||||
for (i = 7; i >= 0; --i) {
|
for (i = 7; i >= 0; --i) {
|
||||||
colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3;
|
colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3;
|
||||||
renderer->outputBuffer[(base + 7 - i) ^ flip] = renderer->palette[paletteBase | colorSelector];
|
renderer->outputBuffer[(base + 7 - i) ^ xFlip] = renderer->palette[paletteBase | colorSelector];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,6 +254,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(softwareRenderer->palette, 0, sizeof(softwareRenderer->palette));
|
memset(softwareRenderer->palette, 0, sizeof(softwareRenderer->palette));
|
||||||
|
memset(softwareRenderer->sgbBorderMask, 0, sizeof(softwareRenderer->sgbBorderMask));
|
||||||
|
|
||||||
softwareRenderer->lastHighlightAmount = 0;
|
softwareRenderer->lastHighlightAmount = 0;
|
||||||
}
|
}
|
||||||
|
@ -667,6 +689,46 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
||||||
for (; x < endX; ++x) {
|
for (; x < endX; ++x) {
|
||||||
row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]];
|
row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]];
|
||||||
}
|
}
|
||||||
|
if (softwareRenderer->sgbBorderMask[y >> 3]) {
|
||||||
|
uint32_t borderMask = softwareRenderer->sgbBorderMask[y >> 3];
|
||||||
|
int localY = y & 0x7;
|
||||||
|
for (x = startX; x < endX; x += 8) {
|
||||||
|
if (!(borderMask & (1 << (x >> 3)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint16_t mapData;
|
||||||
|
LOAD_16LE(mapData, (x >> 2) + 12 + (y & ~7) * 8 + 320, softwareRenderer->d.sgbMapRam);
|
||||||
|
if (UNLIKELY(SGBBgAttributesGetTile(mapData) >= 0x100)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yFlip = 0;
|
||||||
|
if (SGBBgAttributesIsYFlip(mapData)) {
|
||||||
|
yFlip = 7;
|
||||||
|
}
|
||||||
|
unsigned tileBase = (SGBBgAttributesGetTile(mapData) * 16 + (localY ^ yFlip)) * 2;
|
||||||
|
uint8_t tileData[4];
|
||||||
|
tileData[0] = softwareRenderer->d.sgbCharRam[tileBase + 0x00];
|
||||||
|
tileData[1] = softwareRenderer->d.sgbCharRam[tileBase + 0x01];
|
||||||
|
tileData[2] = softwareRenderer->d.sgbCharRam[tileBase + 0x10];
|
||||||
|
tileData[3] = softwareRenderer->d.sgbCharRam[tileBase + 0x11];
|
||||||
|
|
||||||
|
int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10;
|
||||||
|
int colorSelector;
|
||||||
|
|
||||||
|
int flip = 0;
|
||||||
|
if (SGBBgAttributesIsXFlip(mapData)) {
|
||||||
|
flip = 7;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
for (i = 7; i >= 0; --i) {
|
||||||
|
colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3;
|
||||||
|
if (colorSelector) {
|
||||||
|
row[(x + 7 - i) ^ flip] = softwareRenderer->palette[paletteBase | colorSelector];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue