From 0d7657e845987841ada3f4490e7d2f3181dbc189 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 24 Apr 2013 00:34:50 -0700 Subject: [PATCH] Implement BLDCNT (partially) and BLDY --- src/gba/gba-video.h | 9 +++ src/gba/renderers/video-software.c | 103 ++++++++++++++++++++++++++++- src/gba/renderers/video-software.h | 19 ++++++ 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/gba/gba-video.h b/src/gba/gba-video.h index 5f4d52629..d198b4374 100644 --- a/src/gba/gba-video.h +++ b/src/gba/gba-video.h @@ -35,6 +35,15 @@ enum ObjShape { OBJ_SHAPE_VERTICAL = 2 }; +union GBAColor { + struct { + unsigned r : 5; + unsigned g : 5; + unsigned b : 5; + }; + uint16_t packed; +}; + union GBAOAM { struct { int y : 8; diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index e4cfe9fcf..89224f034 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -14,9 +14,14 @@ static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* rendere static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer); static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value); +static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value); static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, uint16_t* output, int y); +static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer); +static inline uint16_t _brighten(uint16_t color, int y); +static inline uint16_t _darken(uint16_t color, int y); + static void _sortBackgrounds(struct GBAVideoSoftwareRenderer* renderer); static int _backgroundComparator(const void* a, const void* b); @@ -49,6 +54,15 @@ static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) { softwareRenderer->dispcnt.packed = 0x0080; + softwareRenderer->target1Obj = 0; + softwareRenderer->target1Bd = 0; + softwareRenderer->target2Obj = 0; + softwareRenderer->target2Bd = 0; + softwareRenderer->blendEffect = BLEND_NONE; + memset(softwareRenderer->variantPalette, 0, sizeof(softwareRenderer->variantPalette)); + + softwareRenderer->bldy = 0; + for (i = 0; i < 4; ++i) { struct GBAVideoSoftwareBackground* bg = &softwareRenderer->bg[i]; bg->index = i; @@ -60,6 +74,8 @@ static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) { bg->screenBase = 0; bg->overflow = 0; bg->size = 0; + bg->target1 = 0; + bg->target2 = 0; bg->x = 0; bg->y = 0; bg->refx = 0; @@ -139,6 +155,16 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender value &= 0x01FF; softwareRenderer->bg[3].y = value; break; + case REG_BLDCNT: + GBAVideoSoftwareRendererWriteBLDCNT(softwareRenderer, value); + break; + case REG_BLDY: + softwareRenderer->bldy = value & 0x1F; + if (softwareRenderer->bldy > 0x10) { + softwareRenderer->bldy = 0x10; + } + _updatePalettes(softwareRenderer); + break; default: GBALog(GBA_LOG_STUB, "Stub video register write: %03x", address); } @@ -195,6 +221,49 @@ static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* _sortBackgrounds(renderer); } +static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value) { + union { + struct { + unsigned target1Bg0 : 1; + unsigned target1Bg1 : 1; + unsigned target1Bg2 : 1; + unsigned target1Bg3 : 1; + unsigned target1Obj : 1; + unsigned target1Bd : 1; + enum BlendEffect effect : 2; + unsigned target2Bg0 : 1; + unsigned target2Bg1 : 1; + unsigned target2Bg2 : 1; + unsigned target2Bg3 : 1; + unsigned target2Obj : 1; + unsigned target2Bd : 1; + }; + uint16_t packed; + } bldcnt = { .packed = value }; + + enum BlendEffect oldEffect = renderer->blendEffect; + + renderer->bg[0].target1 = bldcnt.target1Bg0; + renderer->bg[1].target1 = bldcnt.target1Bg1; + renderer->bg[2].target1 = bldcnt.target1Bg2; + renderer->bg[3].target1 = bldcnt.target1Bg3; + renderer->bg[0].target2 = bldcnt.target2Bg0; + renderer->bg[1].target2 = bldcnt.target2Bg1; + renderer->bg[2].target2 = bldcnt.target2Bg2; + renderer->bg[3].target2 = bldcnt.target2Bg3; + + renderer->blendEffect = bldcnt.effect; + renderer->target1Obj = bldcnt.target1Obj; + renderer->target1Bd = bldcnt.target1Bd; + renderer->target2Obj = bldcnt.target2Obj; + renderer->target2Bd = bldcnt.target2Bd; + + if (oldEffect != renderer->blendEffect) { + _updatePalettes(renderer); + } +} + + static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, uint16_t* output, int y) { int start = 0; int end = VIDEO_HORIZONTAL_PIXELS; @@ -228,12 +297,44 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru uint16_t tileData = renderer->d.vram[charBase]; tileData >>= ((outX + inX) & 0x3) << 2; if (tileData & 0xF) { - output[outX] = renderer->d.palette[(tileData & 0xF) | (mapData.palette << 4)]; + if (renderer->blendEffect == BLEND_NONE || !background->target1) { + output[outX] = renderer->d.palette[(tileData & 0xF) | (mapData.palette << 4)]; + } else if (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN) { + output[outX] = renderer->variantPalette[(tileData & 0xF) | (mapData.palette << 4)]; + } renderer->flags[outX].finalized = 1; } } } +static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) { + if (renderer->blendEffect == BLEND_BRIGHTEN) { + for (int i = 0; i < 512; ++i) { + renderer->variantPalette[i] = _brighten(renderer->d.palette[i], renderer->bldy); + } + } else if (renderer->blendEffect == BLEND_DARKEN) { + for (int i = 0; i < 512; ++i) { + renderer->variantPalette[i] = _darken(renderer->d.palette[i], renderer->bldy); + } + } +} + +static inline uint16_t _brighten(uint16_t c, int y) { + union GBAColor color = { .packed = c }; + color.r = color.r + ((31 - color.r) * y) / 16; + color.g = color.g + ((31 - color.g) * y) / 16; + color.b = color.b + ((31 - color.b) * y) / 16; + return color.packed; +} + +static inline uint16_t _darken(uint16_t c, int y) { + union GBAColor color = { .packed = c }; + color.r = color.r - (color.r * y) / 16; + color.g = color.g - (color.g * y) / 16; + color.b = color.b - (color.b * y) / 16; + return color.packed; +} + static void _sortBackgrounds(struct GBAVideoSoftwareRenderer* renderer) { qsort(renderer->sortedBg, 4, sizeof(struct GBAVideoSoftwareBackground*), _backgroundComparator); } diff --git a/src/gba/renderers/video-software.h b/src/gba/renderers/video-software.h index 284657bb3..421d28829 100644 --- a/src/gba/renderers/video-software.h +++ b/src/gba/renderers/video-software.h @@ -15,6 +15,8 @@ struct GBAVideoSoftwareBackground { uint32_t screenBase; int overflow; int size; + int target1; + int target2; uint16_t x; uint16_t y; uint32_t refx; @@ -27,6 +29,13 @@ struct GBAVideoSoftwareBackground { uint32_t sy; }; +enum BlendEffect { + BLEND_NONE = 0, + BLEND_ALPHA = 1, + BLEND_BRIGHTEN = 2, + BLEND_DARKEN = 3 +}; + struct PixelFlags { unsigned finalized : 1; }; @@ -41,6 +50,16 @@ struct GBAVideoSoftwareRenderer { struct PixelFlags flags[VIDEO_HORIZONTAL_PIXELS]; + // BLDCNT + unsigned target1Obj; + unsigned target1Bd; + unsigned target2Obj; + unsigned target2Bd; + enum BlendEffect blendEffect; + uint16_t variantPalette[512]; + + uint16_t bldy; + struct GBAVideoSoftwareBackground bg[4]; struct GBAVideoSoftwareBackground* sortedBg[4];