mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Backport many rendering changes from medusa
This commit is contained in:
parent
de16ea49c7
commit
0352125cad
|
@ -8,53 +8,6 @@
|
||||||
#include <mgba/core/interface.h>
|
#include <mgba/core/interface.h>
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
|
|
||||||
#define BACKGROUND_BITMAP_INIT \
|
|
||||||
int32_t x = background->sx + (renderer->start - 1) * background->dx; \
|
|
||||||
int32_t y = background->sy + (renderer->start - 1) * background->dy; \
|
|
||||||
int mosaicH = 0; \
|
|
||||||
int mosaicWait = 0; \
|
|
||||||
int32_t localX; \
|
|
||||||
int32_t localY; \
|
|
||||||
if (background->mosaic) { \
|
|
||||||
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
|
|
||||||
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
|
|
||||||
mosaicWait = (mosaicH - renderer->start + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \
|
|
||||||
int32_t startX = renderer->start - (renderer->start % mosaicH); \
|
|
||||||
--mosaicH; \
|
|
||||||
localX = -(inY % mosaicV) * background->dmx; \
|
|
||||||
localY = -(inY % mosaicV) * background->dmy; \
|
|
||||||
x += localX; \
|
|
||||||
y += localY; \
|
|
||||||
localX += background->sx + startX * background->dx; \
|
|
||||||
localY += background->sy + startX * background->dy; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
|
|
||||||
flags |= FLAG_TARGET_2 * background->target2; \
|
|
||||||
int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
|
||||||
GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \
|
|
||||||
objwinFlags |= flags; \
|
|
||||||
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
|
||||||
GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \
|
|
||||||
if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) { \
|
|
||||||
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
|
||||||
objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
|
||||||
} \
|
|
||||||
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;
|
|
||||||
|
|
||||||
#define BACKGROUND_BITMAP_ITERATE(W, H) \
|
#define BACKGROUND_BITMAP_ITERATE(W, H) \
|
||||||
x += background->dx; \
|
x += background->dx; \
|
||||||
y += background->dy; \
|
y += background->dy; \
|
||||||
|
@ -75,22 +28,19 @@
|
||||||
localX = x; \
|
localX = x; \
|
||||||
localY = y;
|
localY = y;
|
||||||
|
|
||||||
#define MODE_2_MOSAIC(COORD) \
|
|
||||||
if (!mosaicWait) { \
|
|
||||||
COORD \
|
|
||||||
mapData = screenBase[(localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; \
|
|
||||||
pixelData = charBase[(mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)]; \
|
|
||||||
\
|
|
||||||
mosaicWait = mosaicH; \
|
|
||||||
} else { \
|
|
||||||
--mosaicWait; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MODE_2_NO_MOSAIC(COORD) \
|
#define MODE_2_NO_MOSAIC(COORD) \
|
||||||
COORD \
|
COORD \
|
||||||
mapData = screenBase[(localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; \
|
mapData = screenBase[(localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; \
|
||||||
pixelData = charBase[(mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)];
|
pixelData = charBase[(mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)];
|
||||||
|
|
||||||
|
#define MODE_2_MOSAIC(COORD) \
|
||||||
|
if (!mosaicWait) { \
|
||||||
|
MODE_2_NO_MOSAIC(COORD) \
|
||||||
|
mosaicWait = mosaicH; \
|
||||||
|
} else { \
|
||||||
|
--mosaicWait; \
|
||||||
|
}
|
||||||
|
|
||||||
#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
|
#define MODE_2_LOOP(MOSAIC, COORD, BLEND, OBJWIN) \
|
||||||
for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { \
|
for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { \
|
||||||
x += background->dx; \
|
x += background->dx; \
|
||||||
|
|
|
@ -166,6 +166,60 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BACKGROUND_BITMAP_INIT \
|
||||||
|
int32_t x = background->sx + (renderer->start - 1) * background->dx; \
|
||||||
|
int32_t y = background->sy + (renderer->start - 1) * background->dy; \
|
||||||
|
int mosaicH = 0; \
|
||||||
|
int mosaicWait = 0; \
|
||||||
|
int32_t localX; \
|
||||||
|
int32_t localY; \
|
||||||
|
if (background->mosaic) { \
|
||||||
|
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
|
||||||
|
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
|
||||||
|
mosaicWait = (mosaicH - renderer->start + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \
|
||||||
|
int32_t startX = renderer->start - (renderer->start % mosaicH); \
|
||||||
|
--mosaicH; \
|
||||||
|
localX = -(inY % mosaicV) * background->dmx; \
|
||||||
|
localY = -(inY % mosaicV) * background->dmy; \
|
||||||
|
x += localX; \
|
||||||
|
y += localY; \
|
||||||
|
localX += background->sx + startX * background->dx; \
|
||||||
|
localY += background->sy + startX * background->dy; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
|
||||||
|
flags |= FLAG_TARGET_2 * background->target2; \
|
||||||
|
int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
||||||
|
GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \
|
||||||
|
objwinFlags |= flags; \
|
||||||
|
flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \
|
||||||
|
GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \
|
||||||
|
if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) { \
|
||||||
|
flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
||||||
|
objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \
|
||||||
|
} \
|
||||||
|
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;
|
||||||
|
|
||||||
|
#define TEST_LAYER_ENABLED(X) \
|
||||||
|
!softwareRenderer->d.disableBG[X] && \
|
||||||
|
(softwareRenderer->bg[X].enabled == 4 && \
|
||||||
|
(GBAWindowControlIsBg ## X ## Enable(softwareRenderer->currentWindow.packed) || \
|
||||||
|
(GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (softwareRenderer->objwin.packed))) && \
|
||||||
|
softwareRenderer->bg[X].priority == priority)
|
||||||
|
|
||||||
static inline unsigned _brighten(unsigned color, int y) {
|
static inline unsigned _brighten(unsigned color, int y) {
|
||||||
unsigned c = 0;
|
unsigned c = 0;
|
||||||
unsigned a;
|
unsigned a;
|
||||||
|
|
|
@ -35,7 +35,9 @@ static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackgroun
|
||||||
static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value);
|
static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value);
|
||||||
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
|
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
|
||||||
|
|
||||||
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y);
|
static void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||||
|
static void GBAVideoSoftwareRendererPostprocessBuffer(struct GBAVideoSoftwareRenderer* renderer);
|
||||||
|
static int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||||
|
|
||||||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
|
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
|
||||||
|
|
||||||
|
@ -562,123 +564,87 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x;
|
GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y);
|
||||||
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
|
softwareRenderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(softwareRenderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
|
||||||
softwareRenderer->spriteLayer[x] = FLAG_UNWRITTEN;
|
int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y);
|
||||||
softwareRenderer->spriteLayer[x + 1] = FLAG_UNWRITTEN;
|
|
||||||
softwareRenderer->spriteLayer[x + 2] = FLAG_UNWRITTEN;
|
|
||||||
softwareRenderer->spriteLayer[x + 3] = FLAG_UNWRITTEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
softwareRenderer->windows[0].endX = GBA_VIDEO_HORIZONTAL_PIXELS;
|
|
||||||
softwareRenderer->nWindows = 1;
|
|
||||||
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
|
|
||||||
softwareRenderer->windows[0].control = softwareRenderer->winout;
|
|
||||||
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) && !renderer->disableWIN[1]) {
|
|
||||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[1], y);
|
|
||||||
}
|
|
||||||
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) && !renderer->disableWIN[0]) {
|
|
||||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[0], y);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
softwareRenderer->forceTarget1 = false;
|
|
||||||
|
|
||||||
int w;
|
int w;
|
||||||
x = 0;
|
unsigned priority;
|
||||||
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
for (priority = 0; priority < 4; ++priority) {
|
||||||
// TOOD: handle objwin on backdrop
|
softwareRenderer->end = 0;
|
||||||
uint32_t backdrop = FLAG_UNWRITTEN | FLAG_PRIORITY | FLAG_IS_BACKGROUND;
|
|
||||||
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
|
|
||||||
backdrop |= softwareRenderer->normalPalette[0];
|
|
||||||
} else {
|
|
||||||
backdrop |= softwareRenderer->variantPalette[0];
|
|
||||||
}
|
|
||||||
int end = softwareRenderer->windows[w].endX;
|
|
||||||
for (; x < end - 3; x += 4) {
|
|
||||||
softwareRenderer->row[x] = backdrop;
|
|
||||||
softwareRenderer->row[x + 1] = backdrop;
|
|
||||||
softwareRenderer->row[x + 2] = backdrop;
|
|
||||||
softwareRenderer->row[x + 3] = backdrop;
|
|
||||||
}
|
|
||||||
for (; x < end; ++x) {
|
|
||||||
softwareRenderer->row[x] = backdrop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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->forceTarget1 || softwareRenderer->bg[0].target1 || softwareRenderer->bg[1].target1 || softwareRenderer->bg[2].target1 || softwareRenderer->bg[3].target1) && softwareRenderer->target2Bd) {
|
|
||||||
x = 0;
|
|
||||||
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
||||||
uint32_t backdrop = 0;
|
softwareRenderer->start = softwareRenderer->end;
|
||||||
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
|
softwareRenderer->end = softwareRenderer->windows[w].endX;
|
||||||
backdrop |= softwareRenderer->normalPalette[0];
|
softwareRenderer->currentWindow = softwareRenderer->windows[w].control;
|
||||||
} else {
|
if (spriteLayers & (1 << priority)) {
|
||||||
backdrop |= softwareRenderer->variantPalette[0];
|
GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority);
|
||||||
}
|
}
|
||||||
int end = softwareRenderer->windows[w].endX;
|
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) < 2) {
|
||||||
for (; x < end; ++x) {
|
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[0], y);
|
||||||
uint32_t color = softwareRenderer->row[x];
|
}
|
||||||
if (color & FLAG_TARGET_1) {
|
if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) < 2) {
|
||||||
softwareRenderer->row[x] = mColorMix5Bit(softwareRenderer->bldb, backdrop, softwareRenderer->blda, color);
|
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[1], y);
|
||||||
|
}
|
||||||
|
if (TEST_LAYER_ENABLED(2)) {
|
||||||
|
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
|
||||||
|
case 0:
|
||||||
|
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
GBAVideoSoftwareRendererDrawBackgroundMode3(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
GBAVideoSoftwareRendererDrawBackgroundMode4(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
GBAVideoSoftwareRendererDrawBackgroundMode5(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (TEST_LAYER_ENABLED(3)) {
|
||||||
}
|
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
|
||||||
if (softwareRenderer->forceTarget1 && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
|
case 0:
|
||||||
x = 0;
|
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[3], y);
|
||||||
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
break;
|
||||||
int end = softwareRenderer->windows[w].endX;
|
case 2:
|
||||||
uint32_t mask = FLAG_REBLEND | FLAG_IS_BACKGROUND;
|
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[3], y);
|
||||||
uint32_t match = FLAG_REBLEND;
|
break;
|
||||||
bool objBlend = GBAWindowControlIsBlendEnable(softwareRenderer->objwin.packed);
|
|
||||||
bool winBlend = GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed);
|
|
||||||
if (GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && objBlend != winBlend) {
|
|
||||||
mask |= FLAG_OBJWIN;
|
|
||||||
if (objBlend) {
|
|
||||||
match |= FLAG_OBJWIN;
|
|
||||||
}
|
|
||||||
} else if (!winBlend) {
|
|
||||||
x = end;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (softwareRenderer->blendEffect == BLEND_DARKEN) {
|
|
||||||
for (; x < end; ++x) {
|
|
||||||
uint32_t color = softwareRenderer->row[x];
|
|
||||||
if ((color & mask) == match) {
|
|
||||||
softwareRenderer->row[x] = _darken(color, softwareRenderer->bldy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
|
|
||||||
for (; x < end; ++x) {
|
|
||||||
uint32_t color = softwareRenderer->row[x];
|
|
||||||
if ((color & mask) == match) {
|
|
||||||
softwareRenderer->row[x] = _brighten(color, softwareRenderer->bldy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
|
||||||
|
|
||||||
|
if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
|
||||||
|
softwareRenderer->bg[2].sx += softwareRenderer->bg[2].dmx;
|
||||||
|
softwareRenderer->bg[2].sy += softwareRenderer->bg[2].dmy;
|
||||||
|
softwareRenderer->bg[3].sx += softwareRenderer->bg[3].dmx;
|
||||||
|
softwareRenderer->bg[3].sy += softwareRenderer->bg[3].dmy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (softwareRenderer->bg[0].enabled > 0 && softwareRenderer->bg[0].enabled < 4) {
|
||||||
|
++softwareRenderer->bg[0].enabled;
|
||||||
|
DIRTY_SCANLINE(softwareRenderer, y);
|
||||||
|
}
|
||||||
|
if (softwareRenderer->bg[1].enabled > 0 && softwareRenderer->bg[1].enabled < 4) {
|
||||||
|
++softwareRenderer->bg[1].enabled;
|
||||||
|
DIRTY_SCANLINE(softwareRenderer, y);
|
||||||
|
}
|
||||||
|
if (softwareRenderer->bg[2].enabled > 0 && softwareRenderer->bg[2].enabled < 4) {
|
||||||
|
++softwareRenderer->bg[2].enabled;
|
||||||
|
DIRTY_SCANLINE(softwareRenderer, y);
|
||||||
|
}
|
||||||
|
if (softwareRenderer->bg[3].enabled > 0 && softwareRenderer->bg[3].enabled < 4) {
|
||||||
|
++softwareRenderer->bg[3].enabled;
|
||||||
|
DIRTY_SCANLINE(softwareRenderer, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x;
|
||||||
if (softwareRenderer->greenswap) {
|
if (softwareRenderer->greenswap) {
|
||||||
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
|
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
|
||||||
row[x] = softwareRenderer->row[x] & (M_COLOR_RED | M_COLOR_BLUE);
|
row[x] = softwareRenderer->row[x] & (M_COLOR_RED | M_COLOR_BLUE);
|
||||||
|
@ -828,14 +794,132 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST_LAYER_ENABLED(X) \
|
void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer, int y) {
|
||||||
!renderer->d.disableBG[X] && \
|
int x;
|
||||||
(renderer->bg[X].enabled == 4 && \
|
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
|
||||||
(GBAWindowControlIsBg ## X ## Enable(renderer->currentWindow.packed) || \
|
softwareRenderer->spriteLayer[x] = FLAG_UNWRITTEN;
|
||||||
(GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (renderer->objwin.packed))) && \
|
softwareRenderer->spriteLayer[x + 1] = FLAG_UNWRITTEN;
|
||||||
renderer->bg[X].priority == priority)
|
softwareRenderer->spriteLayer[x + 2] = FLAG_UNWRITTEN;
|
||||||
|
softwareRenderer->spriteLayer[x + 3] = FLAG_UNWRITTEN;
|
||||||
|
}
|
||||||
|
|
||||||
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
softwareRenderer->windows[0].endX = GBA_VIDEO_HORIZONTAL_PIXELS;
|
||||||
|
softwareRenderer->nWindows = 1;
|
||||||
|
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
|
||||||
|
softwareRenderer->windows[0].control = softwareRenderer->winout;
|
||||||
|
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[1]) {
|
||||||
|
_breakWindow(softwareRenderer, &softwareRenderer->winN[1], y);
|
||||||
|
}
|
||||||
|
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[0]) {
|
||||||
|
_breakWindow(softwareRenderer, &softwareRenderer->winN[0], y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
softwareRenderer->windows[0].control.packed = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
softwareRenderer->forceTarget1 = false;
|
||||||
|
|
||||||
|
int w;
|
||||||
|
x = 0;
|
||||||
|
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
||||||
|
// TOOD: handle objwin on backdrop
|
||||||
|
uint32_t backdrop = FLAG_UNWRITTEN | FLAG_PRIORITY | FLAG_IS_BACKGROUND;
|
||||||
|
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
|
||||||
|
backdrop |= softwareRenderer->normalPalette[0];
|
||||||
|
} else {
|
||||||
|
backdrop |= softwareRenderer->variantPalette[0];
|
||||||
|
}
|
||||||
|
int end = softwareRenderer->windows[w].endX;
|
||||||
|
for (; x & 3; ++x) {
|
||||||
|
softwareRenderer->row[x] = backdrop;
|
||||||
|
}
|
||||||
|
for (; x < end - 3; x += 4) {
|
||||||
|
softwareRenderer->row[x] = backdrop;
|
||||||
|
softwareRenderer->row[x + 1] = backdrop;
|
||||||
|
softwareRenderer->row[x + 2] = backdrop;
|
||||||
|
softwareRenderer->row[x + 3] = backdrop;
|
||||||
|
}
|
||||||
|
for (; x < end; ++x) {
|
||||||
|
softwareRenderer->row[x] = backdrop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAVideoSoftwareRendererPostprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer) {
|
||||||
|
int x, w;
|
||||||
|
if ((softwareRenderer->forceTarget1 || softwareRenderer->bg[0].target1 || softwareRenderer->bg[1].target1 || softwareRenderer->bg[2].target1 || softwareRenderer->bg[3].target1) && softwareRenderer->target2Bd) {
|
||||||
|
x = 0;
|
||||||
|
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
||||||
|
uint32_t backdrop = 0;
|
||||||
|
if (!softwareRenderer->target1Bd || softwareRenderer->blendEffect == BLEND_NONE || softwareRenderer->blendEffect == BLEND_ALPHA || !GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed)) {
|
||||||
|
backdrop |= softwareRenderer->normalPalette[0];
|
||||||
|
} else {
|
||||||
|
backdrop |= softwareRenderer->variantPalette[0];
|
||||||
|
}
|
||||||
|
int end = softwareRenderer->windows[w].endX;
|
||||||
|
for (; x < end; ++x) {
|
||||||
|
uint32_t color = softwareRenderer->row[x];
|
||||||
|
if (color & FLAG_TARGET_1) {
|
||||||
|
softwareRenderer->row[x] = mColorMix5Bit(softwareRenderer->bldb, backdrop, softwareRenderer->blda, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (softwareRenderer->forceTarget1 && (softwareRenderer->blendEffect == BLEND_DARKEN || softwareRenderer->blendEffect == BLEND_BRIGHTEN)) {
|
||||||
|
x = 0;
|
||||||
|
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
||||||
|
int end = softwareRenderer->windows[w].endX;
|
||||||
|
uint32_t mask = FLAG_REBLEND | FLAG_IS_BACKGROUND;
|
||||||
|
uint32_t match = FLAG_REBLEND;
|
||||||
|
bool objBlend = GBAWindowControlIsBlendEnable(softwareRenderer->objwin.packed);
|
||||||
|
bool winBlend = GBAWindowControlIsBlendEnable(softwareRenderer->windows[w].control.packed);
|
||||||
|
if (GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt) && objBlend != winBlend) {
|
||||||
|
mask |= FLAG_OBJWIN;
|
||||||
|
if (objBlend) {
|
||||||
|
match |= FLAG_OBJWIN;
|
||||||
|
}
|
||||||
|
} else if (!winBlend) {
|
||||||
|
x = end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (softwareRenderer->blendEffect == BLEND_DARKEN) {
|
||||||
|
for (; x < end; ++x) {
|
||||||
|
uint32_t color = softwareRenderer->row[x];
|
||||||
|
if ((color & mask) == match) {
|
||||||
|
softwareRenderer->row[x] = _darken(color, softwareRenderer->bldy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
|
||||||
|
for (; x < end; ++x) {
|
||||||
|
uint32_t color = softwareRenderer->row[x];
|
||||||
|
if ((color & mask) == match) {
|
||||||
|
softwareRenderer->row[x] = _brighten(color, softwareRenderer->bldy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
||||||
int w;
|
int w;
|
||||||
int spriteLayers = 0;
|
int spriteLayers = 0;
|
||||||
if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) {
|
if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) {
|
||||||
|
@ -843,7 +927,6 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
||||||
renderer->oamMax = GBAVideoRendererCleanOAM(renderer->d.oam->obj, renderer->sprites, renderer->objOffsetY);
|
renderer->oamMax = GBAVideoRendererCleanOAM(renderer->d.oam->obj, renderer->sprites, renderer->objOffsetY);
|
||||||
renderer->oamDirty = false;
|
renderer->oamDirty = false;
|
||||||
}
|
}
|
||||||
renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
|
|
||||||
int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1;
|
int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1;
|
||||||
int mosaicY = y - (y % mosaicV);
|
int mosaicY = y - (y % mosaicV);
|
||||||
int i;
|
int i;
|
||||||
|
@ -881,78 +964,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return spriteLayers;
|
||||||
unsigned priority;
|
|
||||||
for (priority = 0; priority < 4; ++priority) {
|
|
||||||
renderer->end = 0;
|
|
||||||
for (w = 0; w < renderer->nWindows; ++w) {
|
|
||||||
renderer->start = renderer->end;
|
|
||||||
renderer->end = renderer->windows[w].endX;
|
|
||||||
renderer->currentWindow = renderer->windows[w].control;
|
|
||||||
if (spriteLayers & (1 << priority)) {
|
|
||||||
GBAVideoSoftwareRendererPostprocessSprite(renderer, priority);
|
|
||||||
}
|
|
||||||
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) {
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[0], y);
|
|
||||||
}
|
|
||||||
if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) {
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[1], y);
|
|
||||||
}
|
|
||||||
if (TEST_LAYER_ENABLED(2)) {
|
|
||||||
switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) {
|
|
||||||
case 0:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[2], y);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[2], y);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode3(renderer, &renderer->bg[2], y);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode4(renderer, &renderer->bg[2], y);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode5(renderer, &renderer->bg[2], y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TEST_LAYER_ENABLED(3)) {
|
|
||||||
switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) {
|
|
||||||
case 0:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[3], y);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[3], y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GBARegisterDISPCNTGetMode(renderer->dispcnt) != 0) {
|
|
||||||
renderer->bg[2].sx += renderer->bg[2].dmx;
|
|
||||||
renderer->bg[2].sy += renderer->bg[2].dmy;
|
|
||||||
renderer->bg[3].sx += renderer->bg[3].dmx;
|
|
||||||
renderer->bg[3].sy += renderer->bg[3].dmy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderer->bg[0].enabled > 0 && renderer->bg[0].enabled < 4) {
|
|
||||||
++renderer->bg[0].enabled;
|
|
||||||
DIRTY_SCANLINE(renderer, y);
|
|
||||||
}
|
|
||||||
if (renderer->bg[1].enabled > 0 && renderer->bg[1].enabled < 4) {
|
|
||||||
++renderer->bg[1].enabled;
|
|
||||||
DIRTY_SCANLINE(renderer, y);
|
|
||||||
}
|
|
||||||
if (renderer->bg[2].enabled > 0 && renderer->bg[2].enabled < 4) {
|
|
||||||
++renderer->bg[2].enabled;
|
|
||||||
DIRTY_SCANLINE(renderer, y);
|
|
||||||
}
|
|
||||||
if (renderer->bg[3].enabled > 0 && renderer->bg[3].enabled < 4) {
|
|
||||||
++renderer->bg[3].enabled;
|
|
||||||
DIRTY_SCANLINE(renderer, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {
|
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {
|
||||||
|
|
Loading…
Reference in New Issue