GB Video: Improved window implementation
Vicki Pfau vi@endrift.com
Tue, 26 Dec 2017 16:35:15 -0500
2 files changed,
36 insertions(+),
2 deletions(-)
M
include/mgba/internal/gb/renderers/software.h
→
include/mgba/internal/gb/renderers/software.h
@@ -31,6 +31,8 @@ uint8_t scx;
uint8_t wy; uint8_t wx; uint8_t currentWy; + int lastY; + bool hasWindow; GBRegisterLCDC lcdc; enum GBModel model;
M
src/gb/renderers/software.c
→
src/gb/renderers/software.c
@@ -38,6 +38,10 @@ }
} } +static bool _inWindow(struct GBVideoSoftwareRenderer* renderer) { + return GBRegisterLCDCIsWindow(renderer->lcdc) && GB_VIDEO_HORIZONTAL_PIXELS + 7 > renderer->wx; +} + void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) { renderer->d.init = GBVideoSoftwareRendererInit; renderer->d.deinit = GBVideoSoftwareRendererDeinit;@@ -65,6 +69,8 @@ softwareRenderer->scy = 0;
softwareRenderer->scx = 0; softwareRenderer->wy = 0; softwareRenderer->currentWy = 0; + softwareRenderer->lastY = 0; + softwareRenderer->hasWindow = false; softwareRenderer->wx = 0; softwareRenderer->model = model; }@@ -74,11 +80,31 @@ struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
UNUSED(softwareRenderer); } +static void GBVideoSoftwareRendererUpdateWindow(struct GBVideoSoftwareRenderer* renderer, bool before, bool after) { + if (renderer->lastY >= GB_VIDEO_VERTICAL_PIXELS || after == before) { + return; + } + if (renderer->lastY >= renderer->wy) { + if (!after) { + renderer->currentWy -= renderer->lastY; + renderer->hasWindow = true; + } else { + if (!renderer->hasWindow) { + renderer->currentWy = renderer->lastY + 1 - renderer->wy; + } else { + renderer->currentWy += renderer->lastY; + } + } + } +} + static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + bool wasWindow = _inWindow(softwareRenderer); switch (address) { case REG_LCDC: softwareRenderer->lcdc = value; + GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer)); break; case REG_SCY: softwareRenderer->scy = value;@@ -88,9 +114,11 @@ softwareRenderer->scx = value;
break; case REG_WY: softwareRenderer->wy = value; + GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer)); break; case REG_WX: softwareRenderer->wx = value; + GBVideoSoftwareRendererUpdateWindow(softwareRenderer, wasWindow, _inWindow(softwareRenderer)); break; } return value;@@ -134,6 +162,7 @@ }
static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + softwareRenderer->lastY = y; uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP]; if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) { maps += GB_SIZE_MAP;@@ -142,7 +171,8 @@ if (softwareRenderer->d.disableBG) {
memset(&softwareRenderer->row[startX], 0, endX - startX); } if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) { - if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && endX >= softwareRenderer->wx - 7) { + int wy = softwareRenderer->wy + softwareRenderer->currentWy; + if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) { if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) { GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx, softwareRenderer->scy + y); }@@ -152,7 +182,7 @@ if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {
maps += GB_SIZE_MAP; } if (!softwareRenderer->d.disableWIN) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx, softwareRenderer->currentWy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx, y - wy); } } else if (!softwareRenderer->d.disableBG) { GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx, softwareRenderer->scy + y);@@ -201,7 +231,9 @@ }
if (!GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { _clearScreen(softwareRenderer); } + softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; softwareRenderer->currentWy = 0; + softwareRenderer->hasWindow = false; } static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy) {