diff --git a/include/mgba/internal/gba/renderers/common.h b/include/mgba/internal/gba/renderers/common.h index e90b1f350..ba368edc9 100644 --- a/include/mgba/internal/gba/renderers/common.h +++ b/include/mgba/internal/gba/renderers/common.h @@ -16,6 +16,7 @@ struct GBAVideoRendererSprite { struct GBAObj obj; int16_t y; int16_t endY; + int8_t index; }; int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites, int offsetY); diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index 47b8ddfb6..b15dc47b4 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -42,6 +42,7 @@ struct GBAVideoSoftwareBackground { uint16_t mapCache[64]; int32_t offsetX; int32_t offsetY; + bool highlight; }; enum { @@ -105,6 +106,8 @@ struct GBAVideoSoftwareRenderer { enum GBAVideoBlendEffect blendEffect; color_t normalPalette[512]; color_t variantPalette[512]; + color_t highlightPalette[512]; + color_t highlightVariantPalette[512]; uint16_t blda; uint16_t bldb; @@ -144,6 +147,8 @@ struct GBAVideoSoftwareRenderer { int start; int end; + + uint8_t lastHighlightAmount; }; void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer); diff --git a/include/mgba/internal/gba/video.h b/include/mgba/internal/gba/video.h index ba8048ffd..908954aaf 100644 --- a/include/mgba/internal/gba/video.h +++ b/include/mgba/internal/gba/video.h @@ -12,6 +12,7 @@ CXX_GUARD_START #include #include +#include mLOG_DECLARE_CATEGORY(GBA_VIDEO); @@ -192,6 +193,11 @@ struct GBAVideoRenderer { bool disableBG[4]; bool disableOBJ; + + bool highlightBG[4]; + bool highlightOBJ[128]; + color_t highlightColor; + uint8_t highlightAmount; }; struct GBAVideo { diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index 52a0047b4..6121f4f99 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -191,6 +191,12 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD proxyRenderer->backend->disableBG[2] = proxyRenderer->d.disableBG[2]; proxyRenderer->backend->disableBG[3] = proxyRenderer->d.disableBG[3]; proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ; + proxyRenderer->backend->highlightBG[0] = proxyRenderer->d.highlightBG[0]; + proxyRenderer->backend->highlightBG[1] = proxyRenderer->d.highlightBG[1]; + proxyRenderer->backend->highlightBG[2] = proxyRenderer->d.highlightBG[2]; + proxyRenderer->backend->highlightBG[3] = proxyRenderer->d.highlightBG[3]; + memcpy(proxyRenderer->backend->highlightOBJ, proxyRenderer->d.highlightOBJ, sizeof(proxyRenderer->backend->highlightOBJ)); + proxyRenderer->backend->highlightAmount = proxyRenderer->d.highlightAmount; if (item->address < GBA_VIDEO_VERTICAL_PIXELS) { proxyRenderer->backend->drawScanline(proxyRenderer->backend, item->address); } diff --git a/src/gba/renderers/common.c b/src/gba/renderers/common.c index 9065a6267..2ec71b3f7 100644 --- a/src/gba/renderers/common.c +++ b/src/gba/renderers/common.c @@ -25,6 +25,7 @@ int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* sprites[oamMax].y = y; sprites[oamMax].endY = y + height; sprites[oamMax].obj = obj; + sprites[oamMax].index = i; ++oamMax; } } diff --git a/src/gba/renderers/software-mode0.c b/src/gba/renderers/software-mode0.c index df5626c4b..9c5697e6c 100644 --- a/src/gba/renderers/software-mode0.c +++ b/src/gba/renderers/software-mode0.c @@ -482,8 +482,14 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer uint32_t charBase; int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); color_t* mainPalette = renderer->normalPalette; + if (renderer->d.highlightAmount && background->highlight) { + mainPalette = renderer->highlightPalette; + } if (variant) { mainPalette = renderer->variantPalette; + if (renderer->d.highlightAmount && background->highlight) { + mainPalette = renderer->highlightVariantPalette; + } } color_t* palette = mainPalette; PREPARE_OBJWIN; diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 8e3e677e1..6f0c1bb9e 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -127,7 +127,7 @@ renderer->row[outX] |= FLAG_OBJWIN; \ } -int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y) { +int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int index, int y) { int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0]; int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1]; int start = renderer->start; @@ -167,10 +167,16 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re } color_t* palette = &renderer->normalPalette[0x100]; + if (renderer->d.highlightAmount && renderer->d.highlightOBJ[index]) { + palette = &renderer->highlightPalette[0x100]; + } color_t* objwinPalette = palette; if (variant) { palette = &renderer->variantPalette[0x100]; + if (renderer->d.highlightAmount && renderer->d.highlightOBJ[index]) { + palette = &renderer->highlightVariantPalette[0x100]; + } if (GBAWindowControlIsBlendEnable(renderer->objwin.packed)) { objwinPalette = palette; } diff --git a/src/gba/renderers/software-private.h b/src/gba/renderers/software-private.h index 4e4e19166..07e588439 100644 --- a/src/gba/renderers/software-private.h +++ b/src/gba/renderers/software-private.h @@ -26,7 +26,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); -int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y); +int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int index, int y); void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority); static inline unsigned _brighten(unsigned color, int y); @@ -141,11 +141,17 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re int objwinForceEnable = 0; \ UNUSED(objwinForceEnable); \ color_t* objwinPalette = renderer->normalPalette; \ + if (renderer->d.highlightAmount && background->highlight) { \ + objwinPalette = renderer->highlightPalette; \ + } \ UNUSED(objwinPalette); \ if (objwinSlowPath) { \ if (background->target1 && GBAWindowControlIsBlendEnable(renderer->objwin.packed) && \ (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN)) { \ objwinPalette = renderer->variantPalette; \ + if (renderer->d.highlightAmount && background->highlight) { \ + palette = renderer->highlightVariantPalette; \ + } \ } \ switch (background->index) { \ case 0: \ @@ -200,8 +206,14 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && \ (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \ color_t* palette = renderer->normalPalette; \ + if (renderer->d.highlightAmount && background->highlight) { \ + palette = renderer->highlightPalette; \ + } \ if (variant) { \ palette = renderer->variantPalette; \ + if (renderer->d.highlightAmount && background->highlight) { \ + palette = renderer->highlightVariantPalette; \ + } \ } \ UNUSED(palette); \ PREPARE_OBJWIN; diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 86c3bc409..565b7a452 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -62,6 +62,17 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) { renderer->d.disableBG[3] = false; renderer->d.disableOBJ = false; + renderer->d.highlightBG[0] = false; + renderer->d.highlightBG[1] = false; + renderer->d.highlightBG[2] = false; + renderer->d.highlightBG[3] = false; + int i; + for (i = 0; i < 128; ++i) { + renderer->d.highlightOBJ[i] = false; + } + renderer->d.highlightColor = GBA_COLOR_WHITE; + renderer->d.highlightAmount = 0; + renderer->temporaryBuffer = 0; } @@ -568,6 +579,13 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render softwareRenderer->windows[0].control.packed = 0xFF; } + if (softwareRenderer->lastHighlightAmount != softwareRenderer->d.highlightAmount) { + softwareRenderer->lastHighlightAmount = softwareRenderer->d.highlightAmount; + if (softwareRenderer->lastHighlightAmount) { + softwareRenderer->blendDirty = true; + } + } + if (softwareRenderer->blendDirty) { _updatePalettes(softwareRenderer); softwareRenderer->blendDirty = false; @@ -595,6 +613,11 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render } } + softwareRenderer->bg[0].highlight = softwareRenderer->d.highlightBG[0]; + softwareRenderer->bg[1].highlight = softwareRenderer->d.highlightBG[1]; + softwareRenderer->bg[2].highlight = softwareRenderer->d.highlightBG[2]; + softwareRenderer->bg[3].highlight = softwareRenderer->d.highlightBG[3]; + _drawScanline(softwareRenderer, y); if (softwareRenderer->target2Bd) { @@ -828,7 +851,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { continue; } - int drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY); + int drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, sprite->index, localY); spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c); } if (renderer->spriteCyclesRemaining <= 0) { @@ -925,4 +948,12 @@ static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) { renderer->variantPalette[i] = renderer->normalPalette[i]; } } + unsigned highlightAmount = renderer->d.highlightAmount >> 4; + + if (highlightAmount) { + for (i = 0; i < 512; ++i) { + renderer->highlightPalette[i] = _mix(0x10 - highlightAmount, renderer->normalPalette[i], highlightAmount, renderer->d.highlightColor); + renderer->highlightVariantPalette[i] = _mix(0x10 - highlightAmount, renderer->variantPalette[i], highlightAmount, renderer->d.highlightColor); + } + } }