mirror of https://github.com/mgba-emu/mgba.git
DS Video: Add extended BG palettes
This commit is contained in:
parent
242e3c6ec5
commit
a9ca1221f2
|
@ -27,6 +27,11 @@ struct DSVideoSoftwareRenderer {
|
|||
int outputBufferStride;
|
||||
|
||||
uint32_t row[DS_VIDEO_HORIZONTAL_PIXELS];
|
||||
|
||||
color_t extPaletteA[16384];
|
||||
color_t extPaletteB[16384];
|
||||
color_t variantPaletteA[16384];
|
||||
color_t variantPaletteB[16384];
|
||||
};
|
||||
|
||||
void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer);
|
||||
|
|
|
@ -57,11 +57,15 @@ DECL_BITS(DSRegisterDISPCNT, TileBoundary, 20, 2);
|
|||
DECL_BITS(DSRegisterDISPCNT, CharBase, 24, 3);
|
||||
DECL_BITS(DSRegisterDISPCNT, ScreenBase, 27, 3);
|
||||
// TODO
|
||||
DECL_BIT(DSRegisterDISPCNT, BgExtPalette, 30);
|
||||
DECL_BIT(DSRegisterDISPCNT, ObjExtPalette, 31);
|
||||
|
||||
DECL_BITFIELD(DSRegisterPOWCNT1, uint16_t);
|
||||
// TODO
|
||||
DECL_BIT(DSRegisterPOWCNT1, Swap, 15);
|
||||
|
||||
DECL_BIT(GBARegisterBGCNT, ExtPaletteSlot, 13);
|
||||
|
||||
struct DSVideoRenderer {
|
||||
void (*init)(struct DSVideoRenderer* renderer);
|
||||
void (*reset)(struct DSVideoRenderer* renderer);
|
||||
|
@ -70,6 +74,7 @@ struct DSVideoRenderer {
|
|||
uint16_t (*writeVideoRegister)(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*writePalette)(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*writeOAM)(struct DSVideoRenderer* renderer, uint32_t oam);
|
||||
void (*invalidateExtPal)(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot);
|
||||
void (*drawScanline)(struct DSVideoRenderer* renderer, int y);
|
||||
void (*finishFrame)(struct DSVideoRenderer* renderer);
|
||||
|
||||
|
@ -80,8 +85,12 @@ struct DSVideoRenderer {
|
|||
uint16_t* vram;
|
||||
uint16_t* vramABG[32];
|
||||
uint16_t* vramAOBJ[32];
|
||||
uint16_t* vramABGExtPal[4];
|
||||
uint16_t* vramAOBJExtPal[4];
|
||||
uint16_t* vramBBG[32];
|
||||
uint16_t* vramBOBJ[32];
|
||||
uint16_t* vramBBGExtPal[4];
|
||||
uint16_t* vramBOBJExtPal[4];
|
||||
union DSOAM* oam;
|
||||
};
|
||||
|
||||
|
@ -99,8 +108,12 @@ struct DSVideo {
|
|||
uint16_t* vram;
|
||||
uint16_t* vramABG[32];
|
||||
uint16_t* vramAOBJ[32];
|
||||
uint16_t* vramABGExtPal[4];
|
||||
uint16_t* vramAOBJExtPal[4];
|
||||
uint16_t* vramBBG[32];
|
||||
uint16_t* vramBOBJ[32];
|
||||
uint16_t* vramBBGExtPal[4];
|
||||
uint16_t* vramBOBJExtPal[4];
|
||||
union DSOAM oam;
|
||||
|
||||
int32_t frameCounter;
|
||||
|
@ -117,7 +130,7 @@ struct DSCommon;
|
|||
void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value);
|
||||
|
||||
struct DSMemory;
|
||||
void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value);
|
||||
void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldValue);
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ struct GBAVideoSoftwareBackground {
|
|||
int16_t dmy;
|
||||
int32_t sx;
|
||||
int32_t sy;
|
||||
color_t* extPalette;
|
||||
color_t* variantPalette;
|
||||
};
|
||||
|
||||
enum BlendEffect {
|
||||
|
@ -116,7 +118,7 @@ struct GBAVideoSoftwareRenderer {
|
|||
|
||||
uint32_t* temporaryBuffer;
|
||||
|
||||
GBARegisterDISPCNT dispcnt;
|
||||
uint32_t dispcnt;
|
||||
|
||||
uint32_t row[256];
|
||||
uint32_t spriteLayer[256];
|
||||
|
|
14
src/ds/io.c
14
src/ds/io.c
|
@ -424,24 +424,28 @@ void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
|
|||
} else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY) {
|
||||
value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
|
||||
} else {
|
||||
uint16_t oldValue;
|
||||
switch (address) {
|
||||
// VRAM control
|
||||
case DS9_REG_VRAMCNT_A:
|
||||
case DS9_REG_VRAMCNT_C:
|
||||
case DS9_REG_VRAMCNT_E:
|
||||
oldValue = ds->memory.io9[address >> 1];
|
||||
value &= 0x9F9F;
|
||||
DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A, value & 0xFF);
|
||||
DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A + 1, value >> 8);
|
||||
DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A, value & 0xFF, oldValue & 0xFF);
|
||||
DSVideoConfigureVRAM(ds, address - DS9_REG_VRAMCNT_A + 1, value >> 8, oldValue >> 8);
|
||||
break;
|
||||
case DS9_REG_VRAMCNT_G:
|
||||
oldValue = ds->memory.io9[address >> 1];
|
||||
value &= 0x9F03;
|
||||
DSVideoConfigureVRAM(ds, 6, value & 0xFF);
|
||||
DSVideoConfigureVRAM(ds, 6, value & 0xFF, oldValue & 0xFF);
|
||||
DSConfigureWRAM(&ds->memory, value >> 8);
|
||||
break;
|
||||
case DS9_REG_VRAMCNT_H:
|
||||
oldValue = ds->memory.io9[address >> 1];
|
||||
value &= 0x9F9F;
|
||||
DSVideoConfigureVRAM(ds, 7, value & 0xFF);
|
||||
DSVideoConfigureVRAM(ds, 8, value >> 8);
|
||||
DSVideoConfigureVRAM(ds, 7, value & 0xFF, oldValue & 0xFF);
|
||||
DSVideoConfigureVRAM(ds, 8, value >> 8, oldValue >> 8);
|
||||
break;
|
||||
|
||||
case DS9_REG_EXMEMCNT:
|
||||
|
|
|
@ -202,15 +202,15 @@ void DSMemoryReset(struct DS* ds) {
|
|||
DSSPIReset(ds);
|
||||
DSSlot1Reset(ds);
|
||||
|
||||
DSVideoConfigureVRAM(ds, 0, 0);
|
||||
DSVideoConfigureVRAM(ds, 1, 0);
|
||||
DSVideoConfigureVRAM(ds, 2, 0);
|
||||
DSVideoConfigureVRAM(ds, 3, 0);
|
||||
DSVideoConfigureVRAM(ds, 4, 0);
|
||||
DSVideoConfigureVRAM(ds, 5, 0);
|
||||
DSVideoConfigureVRAM(ds, 6, 0);
|
||||
DSVideoConfigureVRAM(ds, 7, 0);
|
||||
DSVideoConfigureVRAM(ds, 8, 0);
|
||||
DSVideoConfigureVRAM(ds, 0, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 1, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 2, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 3, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 4, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 5, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 6, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 7, 0, 1);
|
||||
DSVideoConfigureVRAM(ds, 8, 0, 1);
|
||||
DSConfigureWRAM(&ds->memory, 3);
|
||||
|
||||
if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/ds/renderers/software.h>
|
||||
#include "gba/renderers/software-private.h"
|
||||
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/ds/io.h>
|
||||
|
@ -14,11 +15,61 @@ static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer);
|
|||
static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void DSVideoSoftwareRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void DSVideoSoftwareRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam);
|
||||
static void DSVideoSoftwareRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot);
|
||||
static void DSVideoSoftwareRendererDrawScanline(struct DSVideoRenderer* renderer, int y);
|
||||
static void DSVideoSoftwareRendererFinishFrame(struct DSVideoRenderer* renderer);
|
||||
static void DSVideoSoftwareRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels);
|
||||
static void DSVideoSoftwareRendererPutPixels(struct DSVideoRenderer* renderer, size_t stride, const void* pixels);
|
||||
|
||||
static bool _regenerateExtPalette(struct DSVideoSoftwareRenderer* renderer, bool engB, int slot) {
|
||||
color_t* palette;
|
||||
color_t* variantPalette;
|
||||
struct GBAVideoSoftwareRenderer* softwareRenderer;
|
||||
uint16_t* vram;
|
||||
if (!engB) {
|
||||
palette = &renderer->extPaletteA[slot * 4096];
|
||||
variantPalette = &renderer->variantPaletteA[slot * 4096];
|
||||
softwareRenderer = &renderer->engA;
|
||||
vram = renderer->d.vramABGExtPal[slot];
|
||||
} else {
|
||||
palette = &renderer->extPaletteB[slot * 4096];
|
||||
variantPalette = &renderer->variantPaletteB[slot * 4096];
|
||||
softwareRenderer = &renderer->engB;
|
||||
vram = renderer->d.vramBBGExtPal[slot];
|
||||
}
|
||||
if (!vram) {
|
||||
return false;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < 4096; ++i) {
|
||||
uint16_t value = vram[i];
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
unsigned color = 0;
|
||||
color |= (value & 0x001F) << 11;
|
||||
color |= (value & 0x03E0) << 1;
|
||||
color |= (value & 0x7C00) >> 10;
|
||||
#else
|
||||
unsigned color = value;
|
||||
#endif
|
||||
#else
|
||||
unsigned color = 0;
|
||||
color |= (value << 3) & 0xF8;
|
||||
color |= (value << 6) & 0xF800;
|
||||
color |= (value << 9) & 0xF80000;
|
||||
color |= (color >> 5) & 0x070707;
|
||||
#endif
|
||||
palette[i] = color;
|
||||
if (softwareRenderer->blendEffect == BLEND_BRIGHTEN) {
|
||||
variantPalette[i] = _brighten(color, softwareRenderer->bldy);
|
||||
} else if (softwareRenderer->blendEffect == BLEND_DARKEN) {
|
||||
variantPalette[i] = _darken(color, softwareRenderer->bldy);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) {
|
||||
renderer->d.init = DSVideoSoftwareRendererInit;
|
||||
renderer->d.reset = DSVideoSoftwareRendererReset;
|
||||
|
@ -26,6 +77,7 @@ void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) {
|
|||
renderer->d.writeVideoRegister = DSVideoSoftwareRendererWriteVideoRegister;
|
||||
renderer->d.writePalette = DSVideoSoftwareRendererWritePalette;
|
||||
renderer->d.writeOAM = DSVideoSoftwareRendererWriteOAM;
|
||||
renderer->d.invalidateExtPal = DSVideoSoftwareRendererInvalidateExtPal;
|
||||
renderer->d.drawScanline = DSVideoSoftwareRendererDrawScanline;
|
||||
renderer->d.finishFrame = DSVideoSoftwareRendererFinishFrame;
|
||||
renderer->d.getPixels = DSVideoSoftwareRendererGetPixels;
|
||||
|
@ -75,6 +127,25 @@ static void DSVideoSoftwareRendererUpdateDISPCNTA(struct DSVideoSoftwareRenderer
|
|||
fakeDispcnt = GBARegisterDISPCNTFillObjCharacterMapping(fakeDispcnt);
|
||||
}
|
||||
softwareRenderer->engA.d.writeVideoRegister(&softwareRenderer->engA.d, DS9_REG_A_DISPCNT_LO, fakeDispcnt);
|
||||
softwareRenderer->engA.dispcnt |= softwareRenderer->dispcntA & 0xFFFF000;
|
||||
if (DSRegisterDISPCNTIsBgExtPalette(softwareRenderer->dispcntA)) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
// TODO: Regenerate on change
|
||||
int slot = i;
|
||||
if (i < 2 && GBARegisterBGCNTIsExtPaletteSlot(softwareRenderer->engA.bg[i].control)) {
|
||||
slot += 2;
|
||||
}
|
||||
if (softwareRenderer->engA.bg[i].extPalette != &softwareRenderer->extPaletteA[slot * 4096] && _regenerateExtPalette(softwareRenderer, false, slot)) {
|
||||
softwareRenderer->engA.bg[i].extPalette = &softwareRenderer->extPaletteA[slot * 4096];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
softwareRenderer->engA.bg[0].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[1].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[2].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[3].extPalette = NULL;
|
||||
}
|
||||
uint32_t charBase = DSRegisterDISPCNTGetCharBase(softwareRenderer->dispcntA) << 16;
|
||||
uint32_t screenBase = DSRegisterDISPCNTGetScreenBase(softwareRenderer->dispcntA) << 16;
|
||||
softwareRenderer->engA.d.writeVideoRegister(&softwareRenderer->engA.d, DS9_REG_A_BG0CNT, softwareRenderer->engA.bg[0].control);
|
||||
|
@ -96,6 +167,7 @@ static void DSVideoSoftwareRendererUpdateDISPCNTA(struct DSVideoSoftwareRenderer
|
|||
}
|
||||
|
||||
static void DSVideoSoftwareRendererUpdateDISPCNTB(struct DSVideoSoftwareRenderer* softwareRenderer) {
|
||||
// TODO: Share code with DISPCNTA
|
||||
uint16_t fakeDispcnt = softwareRenderer->dispcntB & 0xFF87;
|
||||
if (!DSRegisterDISPCNTIsTileObjMapping(softwareRenderer->dispcntB)) {
|
||||
softwareRenderer->engB.tileStride = 0x20;
|
||||
|
@ -104,6 +176,25 @@ static void DSVideoSoftwareRendererUpdateDISPCNTB(struct DSVideoSoftwareRenderer
|
|||
fakeDispcnt = GBARegisterDISPCNTFillObjCharacterMapping(fakeDispcnt);
|
||||
}
|
||||
softwareRenderer->engB.d.writeVideoRegister(&softwareRenderer->engB.d, DS9_REG_A_DISPCNT_LO, fakeDispcnt);
|
||||
softwareRenderer->engB.dispcnt |= softwareRenderer->dispcntB & 0xFFFF000;
|
||||
if (DSRegisterDISPCNTIsBgExtPalette(softwareRenderer->dispcntB)) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
// TODO: Regenerate on change
|
||||
int slot = i;
|
||||
if (i < 2 && GBARegisterBGCNTIsExtPaletteSlot(softwareRenderer->engB.bg[i].control)) {
|
||||
slot += 2;
|
||||
}
|
||||
if (softwareRenderer->engB.bg[i].extPalette != &softwareRenderer->extPaletteB[slot * 4096] && _regenerateExtPalette(softwareRenderer, true, slot)) {
|
||||
softwareRenderer->engB.bg[i].extPalette = &softwareRenderer->extPaletteB[slot * 4096];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
softwareRenderer->engA.bg[0].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[1].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[2].extPalette = NULL;
|
||||
softwareRenderer->engA.bg[3].extPalette = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
||||
|
@ -161,6 +252,89 @@ static void DSVideoSoftwareRendererWriteOAM(struct DSVideoRenderer* renderer, ui
|
|||
}
|
||||
}
|
||||
|
||||
static void DSVideoSoftwareRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot) {
|
||||
struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
|
||||
_regenerateExtPalette(softwareRenderer, engB, slot);
|
||||
}
|
||||
|
||||
static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* renderer, int y) {
|
||||
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
||||
|
||||
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||
if (GBARegisterDISPCNTIsForcedBlank(softwareRenderer->dispcnt)) {
|
||||
int x;
|
||||
for (x = 0; x < softwareRenderer->masterEnd; ++x) {
|
||||
row[x] = GBA_COLOR_WHITE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y);
|
||||
int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y);
|
||||
|
||||
int w;
|
||||
unsigned priority;
|
||||
for (priority = 0; priority < 4; ++priority) {
|
||||
softwareRenderer->end = 0;
|
||||
for (w = 0; w < softwareRenderer->nWindows; ++w) {
|
||||
softwareRenderer->start = softwareRenderer->end;
|
||||
softwareRenderer->end = softwareRenderer->windows[w].endX;
|
||||
softwareRenderer->currentWindow = softwareRenderer->windows[w].control;
|
||||
if (spriteLayers & (1 << priority)) {
|
||||
GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority);
|
||||
}
|
||||
if (TEST_LAYER_ENABLED(0)) {
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[0], y);
|
||||
}
|
||||
if (TEST_LAYER_ENABLED(1)) {
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[1], y);
|
||||
}
|
||||
if (TEST_LAYER_ENABLED(2)) {
|
||||
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[2], y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (TEST_LAYER_ENABLED(3)) {
|
||||
switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) {
|
||||
case 0:
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[3], y);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
GBAVideoSoftwareRendererDrawBackgroundMode2(softwareRenderer, &softwareRenderer->bg[3], y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);
|
||||
|
||||
#ifdef COLOR_16_BIT
|
||||
#if defined(__ARM_NEON) && !defined(__APPLE__)
|
||||
_to16Bit(row, softwareRenderer->row, softwareRenderer->masterEnd);
|
||||
#else
|
||||
for (x = 0; x < softwareRenderer->masterEnd; ++x) {
|
||||
row[x] = softwareRenderer->row[x];
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _drawScanlineA(struct DSVideoSoftwareRenderer* softwareRenderer, int y) {
|
||||
memcpy(softwareRenderer->engA.d.vramBG, softwareRenderer->d.vramABG, sizeof(softwareRenderer->engA.d.vramBG));
|
||||
memcpy(softwareRenderer->engA.d.vramOBJ, softwareRenderer->d.vramAOBJ, sizeof(softwareRenderer->engA.d.vramOBJ));
|
||||
|
@ -174,7 +348,7 @@ static void _drawScanlineA(struct DSVideoSoftwareRenderer* softwareRenderer, int
|
|||
}
|
||||
return;
|
||||
case 1:
|
||||
softwareRenderer->engA.d.drawScanline(&softwareRenderer->engA.d, y);
|
||||
DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engA.d, y);
|
||||
return;
|
||||
case 2: {
|
||||
uint16_t* vram = &softwareRenderer->d.vram[0x10000 * DSRegisterDISPCNTGetVRAMBlock(softwareRenderer->dispcntA)];
|
||||
|
@ -229,7 +403,7 @@ static void _drawScanlineB(struct DSVideoSoftwareRenderer* softwareRenderer, int
|
|||
}
|
||||
return;
|
||||
case 1:
|
||||
softwareRenderer->engB.d.drawScanline(&softwareRenderer->engB.d, y);
|
||||
DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engB.d, y);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
203
src/ds/video.c
203
src/ds/video.c
|
@ -20,6 +20,7 @@ static void DSVideoDummyRendererDeinit(struct DSVideoRenderer* renderer);
|
|||
static uint16_t DSVideoDummyRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void DSVideoDummyRendererWritePalette(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void DSVideoDummyRendererWriteOAM(struct DSVideoRenderer* renderer, uint32_t oam);
|
||||
static void DSVideoDummyRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot);
|
||||
static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y);
|
||||
static void DSVideoDummyRendererFinishFrame(struct DSVideoRenderer* renderer);
|
||||
static void DSVideoDummyRendererGetPixels(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels);
|
||||
|
@ -42,60 +43,86 @@ static const uint32_t _vramSize[9] = {
|
|||
0x04000
|
||||
};
|
||||
|
||||
enum DSVRAMBankMode {
|
||||
MODE_A_BG = 0,
|
||||
MODE_B_BG = 1,
|
||||
MODE_A_OBJ = 2,
|
||||
MODE_B_OBJ = 3,
|
||||
MODE_LCDC,
|
||||
MODE_7_VRAM,
|
||||
MODE_A_BG_EXT_PAL,
|
||||
MODE_B_BG_EXT_PAL,
|
||||
MODE_A_OBJ_EXT_PAL,
|
||||
MODE_B_OBJ_EXT_PAL,
|
||||
MODE_3D_TEX,
|
||||
MODE_3D_TEX_PAL,
|
||||
};
|
||||
|
||||
const struct DSVRAMBankInfo {
|
||||
int base;
|
||||
uint32_t mirrorSize;
|
||||
int mode;
|
||||
enum DSVRAMBankMode mode;
|
||||
int offset[4];
|
||||
} _vramInfo[9][8] = {
|
||||
{ // A
|
||||
{ 0x000, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
|
||||
{ 0x000, 0x10, 2, { 0x00, 0x08, 0x80, 0x80 } }, // A-OBJ
|
||||
{ 0x000, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
|
||||
{ 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x08, 0x80, 0x80 } },
|
||||
{ 0x000, 0x10, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
|
||||
},
|
||||
{ // B
|
||||
{ 0x008, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
|
||||
{ 0x000, 0x10, 2, { 0x00, 0x08, 0x80, 0x80 } }, // A-OBJ
|
||||
{ 0x008, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
|
||||
{ 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x08, 0x80, 0x80 } },
|
||||
{ 0x000, 0x10, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
|
||||
},
|
||||
{ // C
|
||||
{ 0x010, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
|
||||
{ 0x000, 0x40, 5, { 0x00, 0x08, 0x80, 0x80 } }, // 7-VRAM
|
||||
{},
|
||||
{ 0x000, 0x08, 1 }, // B-BG
|
||||
{ 0x010, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
|
||||
{ 0x000, 0x40, MODE_7_VRAM, { 0x00, 0x08, 0x80, 0x80 } },
|
||||
{ 0x000, 0x10, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
|
||||
{ 0x000, 0x08, MODE_B_BG },
|
||||
},
|
||||
{ // D
|
||||
{ 0x018, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
|
||||
{ 0x000, 0x40, 8, { 0x00, 0x08, 0x80, 0x80 } }, // 7-VRAM
|
||||
{},
|
||||
{ 0x000, 0x08, 3 }, // B-OBJ
|
||||
{ 0x018, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x08, 0x10, 0x18 } },
|
||||
{ 0x000, 0x40, MODE_7_VRAM, { 0x00, 0x08, 0x80, 0x80 } },
|
||||
{ 0x000, 0x10, MODE_3D_TEX, { 0x00, 0x01, 0x02, 0x03 } },
|
||||
{ 0x000, 0x08, MODE_B_OBJ },
|
||||
},
|
||||
{ // E
|
||||
{ 0x020, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0 }, // A-BG
|
||||
{ 0x000, 0x10, 2 }, // A-OBJ
|
||||
{ 0x020, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG },
|
||||
{ 0x000, 0x10, MODE_A_OBJ },
|
||||
{ 0x000, 0x04, MODE_3D_TEX_PAL },
|
||||
{ 0x000, 0x04, MODE_A_BG_EXT_PAL },
|
||||
},
|
||||
{ // F
|
||||
{ 0x024, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0, { 0x00, 0x01, 0x04, 0x05 } }, // A-BG
|
||||
{ 0x000, 0x10, 2, { 0x00, 0x01, 0x04, 0x05 } }, // A-OBJ
|
||||
{ 0x024, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x01, MODE_3D_TEX_PAL, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x02, MODE_A_BG_EXT_PAL, { 0x00, 0x02, 0x00, 0x02 } },
|
||||
{ 0x000, 0x01, MODE_A_OBJ_EXT_PAL},
|
||||
},
|
||||
{ // G
|
||||
{ 0x025, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x20, 0 }, // A-BG
|
||||
{ 0x000, 0x10, 2 }, // A-OBJ
|
||||
{ 0x025, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x20, MODE_A_BG, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x10, MODE_A_OBJ, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x01, MODE_3D_TEX_PAL, { 0x00, 0x01, 0x04, 0x05 } },
|
||||
{ 0x000, 0x02, MODE_A_BG_EXT_PAL, { 0x00, 0x02, 0x00, 0x02 } },
|
||||
{ 0x000, 0x01, MODE_A_OBJ_EXT_PAL},
|
||||
},
|
||||
{ // H
|
||||
{ 0x026, 0x40, 4 }, // LCDC
|
||||
{ 0x000, 0x04, 1 }, // B-BG
|
||||
{ 0x000, 0x10, 2 }, // A-OBJ
|
||||
{ 0x026, 0x40, MODE_LCDC },
|
||||
{ 0x000, 0x04, MODE_B_BG },
|
||||
{ 0x000, 0x04, MODE_B_BG_EXT_PAL },
|
||||
},
|
||||
{ // I
|
||||
{ 0x028, 0x40, 4 }, // LCDC
|
||||
{ 0x002, 0x04, 1 }, // B-BG
|
||||
{ 0x000, 0x01, 3 }, // B-OBJ
|
||||
{ 0x028, 0x40, MODE_LCDC },
|
||||
{ 0x002, 0x04, MODE_B_BG },
|
||||
{ 0x000, 0x01, MODE_B_OBJ },
|
||||
{ 0x000, 0x01, MODE_B_OBJ_EXT_PAL },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -166,8 +193,12 @@ void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* ren
|
|||
renderer->vram = video->vram;
|
||||
memcpy(renderer->vramABG, video->vramABG, sizeof(renderer->vramABG));
|
||||
memcpy(renderer->vramAOBJ, video->vramAOBJ, sizeof(renderer->vramAOBJ));
|
||||
memcpy(renderer->vramABGExtPal, video->vramABGExtPal, sizeof(renderer->vramABGExtPal));
|
||||
memcpy(renderer->vramAOBJExtPal, video->vramAOBJExtPal, sizeof(renderer->vramAOBJExtPal));
|
||||
memcpy(renderer->vramBBG, video->vramBBG, sizeof(renderer->vramBBG));
|
||||
memcpy(renderer->vramBOBJ, video->vramBOBJ, sizeof(renderer->vramBOBJ));
|
||||
memcpy(renderer->vramBBGExtPal, video->vramBBGExtPal, sizeof(renderer->vramBBGExtPal));
|
||||
memcpy(renderer->vramBOBJExtPal, video->vramBOBJExtPal, sizeof(renderer->vramBOBJExtPal));
|
||||
renderer->oam = &video->oam;
|
||||
video->renderer->init(video->renderer);
|
||||
}
|
||||
|
@ -300,18 +331,83 @@ void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) {
|
|||
// TODO: Does a VCounter IRQ trigger on write?
|
||||
}
|
||||
|
||||
void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value) {
|
||||
void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value, uint8_t oldValue) {
|
||||
struct DSMemory* memory = &ds->memory;
|
||||
if (value == oldValue) {
|
||||
return;
|
||||
}
|
||||
uint32_t i, j;
|
||||
uint32_t size = _vramSize[index] >> DS_VRAM_OFFSET;
|
||||
struct DSVRAMBankInfo oldInfo = _vramInfo[index][oldValue & 0x7];
|
||||
uint32_t offset = oldInfo.base + oldInfo.offset[(oldValue >> 3) & 3];
|
||||
switch (oldInfo.mode) {
|
||||
case MODE_A_BG:
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (ds->video.vramABG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
|
||||
ds->video.vramABG[offset + i] = NULL;
|
||||
ds->video.renderer->vramABG[offset + i] = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_B_BG:
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (ds->video.vramBBG[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
|
||||
ds->video.vramBBG[offset + i] = NULL;
|
||||
ds->video.renderer->vramBBG[offset + i] = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_A_OBJ:
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (ds->video.vramAOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
|
||||
ds->video.vramAOBJ[offset + i] = NULL;
|
||||
ds->video.renderer->vramAOBJ[offset + i] = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_B_OBJ:
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (ds->video.vramBOBJ[offset + i] == &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)]) {
|
||||
ds->video.vramBOBJ[offset + i] = NULL;
|
||||
ds->video.renderer->vramBOBJ[offset + i] = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_A_BG_EXT_PAL:
|
||||
for (i = 0; i < oldInfo.mirrorSize; ++i) {
|
||||
if (ds->video.vramABGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
|
||||
ds->video.vramABGExtPal[offset + i] = NULL;
|
||||
ds->video.renderer->vramABGExtPal[offset + i] = NULL;
|
||||
ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_B_BG_EXT_PAL:
|
||||
for (i = 0; i < oldInfo.mirrorSize; ++i) {
|
||||
if (ds->video.vramBBGExtPal[offset + i] == &memory->vramBank[index][i << 12]) {
|
||||
ds->video.vramBBGExtPal[offset + i] = NULL;
|
||||
ds->video.renderer->vramBBGExtPal[offset + i] = NULL;
|
||||
ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_7_VRAM:
|
||||
for (i = 0; i < size; i += 16) {
|
||||
ds->memory.vram7[(offset + i) >> 4] = NULL;
|
||||
}
|
||||
break;
|
||||
case MODE_LCDC:
|
||||
break;
|
||||
}
|
||||
|
||||
struct DSVRAMBankInfo info = _vramInfo[index][value & 0x7];
|
||||
memset(&memory->vramMirror[index], 0, sizeof(memory->vramMirror[index]));
|
||||
memset(&memory->vramMode[index], 0, sizeof(memory->vramMode[index]));
|
||||
if (!(value & 0x80) || !info.mirrorSize) {
|
||||
return;
|
||||
}
|
||||
uint32_t size = _vramSize[index] >> DS_VRAM_OFFSET;
|
||||
uint32_t i, j;
|
||||
uint32_t offset = info.base + info.offset[(value >> 3) & 3];
|
||||
if (info.mode < 4) {
|
||||
offset = info.base + info.offset[(value >> 3) & 3];
|
||||
if (info.mode <= MODE_LCDC) {
|
||||
memory->vramMode[index][info.mode] = 0xFFFF;
|
||||
for (j = offset; j < 0x40; j += info.mirrorSize) {
|
||||
for (i = 0; i < size; ++i) {
|
||||
|
@ -320,35 +416,51 @@ void DSVideoConfigureVRAM(struct DS* ds, int index, uint8_t value) {
|
|||
}
|
||||
}
|
||||
switch (info.mode) {
|
||||
case 0:
|
||||
case MODE_A_BG:
|
||||
for (i = 0; i < size; ++i) {
|
||||
ds->video.vramABG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
|
||||
ds->video.renderer->vramABG[offset + i] = ds->video.vramABG[offset + i];
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case MODE_B_BG:
|
||||
for (i = 0; i < size; ++i) {
|
||||
ds->video.vramBBG[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
|
||||
ds->video.renderer->vramBBG[offset + i] = ds->video.vramBBG[offset + i];
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case MODE_A_OBJ:
|
||||
for (i = 0; i < size; ++i) {
|
||||
ds->video.vramAOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
|
||||
ds->video.renderer->vramAOBJ[offset + i] = ds->video.vramAOBJ[offset + i];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case MODE_B_OBJ:
|
||||
for (i = 0; i < size; ++i) {
|
||||
ds->video.vramBOBJ[offset + i] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 1)];
|
||||
ds->video.renderer->vramBOBJ[offset + i] = ds->video.vramBOBJ[offset + i];
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case MODE_A_BG_EXT_PAL:
|
||||
for (i = 0; i < info.mirrorSize; ++i) {
|
||||
ds->video.vramABGExtPal[offset + i] = &memory->vramBank[index][i << 12];
|
||||
ds->video.renderer->vramABGExtPal[offset + i] = ds->video.vramABGExtPal[offset + i];
|
||||
ds->video.renderer->invalidateExtPal(ds->video.renderer, false, false, offset + i);
|
||||
}
|
||||
break;
|
||||
case MODE_B_BG_EXT_PAL:
|
||||
for (i = 0; i < info.mirrorSize; ++i) {
|
||||
ds->video.vramBBGExtPal[offset + i] = &memory->vramBank[index][i << 12];
|
||||
ds->video.renderer->vramBBGExtPal[offset + i] = ds->video.vramBBGExtPal[offset + i];
|
||||
ds->video.renderer->invalidateExtPal(ds->video.renderer, false, true, offset + i);
|
||||
}
|
||||
break;
|
||||
case MODE_7_VRAM:
|
||||
for (i = 0; i < size; i += 16) {
|
||||
ds->memory.vram7[(offset + i) >> 4] = &memory->vramBank[index][i << (DS_VRAM_OFFSET - 5)];
|
||||
}
|
||||
break;
|
||||
case MODE_LCDC:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,6 +497,13 @@ static void DSVideoDummyRendererWriteOAM(struct DSVideoRenderer* renderer, uint3
|
|||
// Nothing to do
|
||||
}
|
||||
|
||||
static void DSVideoDummyRendererInvalidateExtPal(struct DSVideoRenderer* renderer, bool obj, bool engB, int slot) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(obj);
|
||||
UNUSED(engB);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
static void DSVideoDummyRendererDrawScanline(struct DSVideoRenderer* renderer, int y) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(y);
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
} \
|
||||
screenBase = background->screenBase + yBase + (xBase >> 2); \
|
||||
uint16_t* screenBlock = renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET]; \
|
||||
if (UNLIKELY(!screenBlock)) { \
|
||||
return; \
|
||||
} \
|
||||
LOAD_16(mapData, screenBase & VRAM_BLOCK_MASK, screenBlock); \
|
||||
localY = inY & 0x7; \
|
||||
if (GBA_TEXT_MAP_VFLIP(mapData)) { \
|
||||
|
@ -361,6 +364,195 @@
|
|||
} \
|
||||
}
|
||||
|
||||
#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256Ext(BLEND, OBJWIN) \
|
||||
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
|
||||
palette = &mainPalette[paletteData]; \
|
||||
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
|
||||
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
|
||||
int end2 = end - 4; \
|
||||
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
|
||||
int shift = inX & 0x3; \
|
||||
if (LIKELY(vram)) { \
|
||||
if (end2 > outX) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= 8 * shift; \
|
||||
shift = 0; \
|
||||
for (; outX < end2; ++outX, ++pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (LIKELY(vram)) { \
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= 8 * shift; \
|
||||
for (; outX < end; ++outX, ++pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
int start = outX; \
|
||||
outX = end - 1; \
|
||||
pixel = &renderer->row[outX]; \
|
||||
if (LIKELY(vram)) { \
|
||||
if (end2 > start) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
for (; outX >= end2; --outX, --pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
charBase += 4; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (LIKELY(vram)) { \
|
||||
LOAD_32(tileData, charBase, vram); \
|
||||
for (; outX >= renderer->start; --outX, --pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
} \
|
||||
outX = end; \
|
||||
pixel = &renderer->row[outX]; \
|
||||
}
|
||||
|
||||
#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256Ext(BLEND, OBJWIN) \
|
||||
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
|
||||
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
|
||||
if (UNLIKELY(!vram)) { \
|
||||
return; \
|
||||
} \
|
||||
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
|
||||
palette = &mainPalette[paletteData]; \
|
||||
int end = mod8 - 4; \
|
||||
pixel = &renderer->row[outX]; \
|
||||
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
|
||||
if (end > 0) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
for (; outX < renderer->end - end; ++outX, ++pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
charBase += 4; \
|
||||
} \
|
||||
\
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
for (; outX < renderer->end; ++outX, ++pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
} else { \
|
||||
int shift = (8 - mod8) & 0x3; \
|
||||
int start = outX; \
|
||||
outX = renderer->end - 1; \
|
||||
pixel = &renderer->row[outX]; \
|
||||
if (end > 0) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= 8 * shift; \
|
||||
for (; outX >= start + 4; --outX, --pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
shift = 0; \
|
||||
} \
|
||||
\
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= 8 * shift; \
|
||||
for (; outX >= start; --outX, --pixel) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
/* Needed for consistency checks */ \
|
||||
if (VIDEO_CHECKS) { \
|
||||
outX = renderer->end; \
|
||||
pixel = &renderer->row[outX]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DRAW_BACKGROUND_MODE_0_TILES_256Ext(BLEND, OBJWIN) \
|
||||
for (; tileX < tileEnd; ++tileX) { \
|
||||
BACKGROUND_TEXT_SELECT_CHARACTER; \
|
||||
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
|
||||
palette = &mainPalette[paletteData]; \
|
||||
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
|
||||
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
|
||||
if (UNLIKELY(!vram)) { \
|
||||
pixel += 8; \
|
||||
continue; \
|
||||
} \
|
||||
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
if (tileData) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
|
||||
} \
|
||||
pixel += 4; \
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
if (tileData) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
|
||||
} \
|
||||
pixel += 4; \
|
||||
} else { \
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
if (tileData) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
pixel += 4; \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
if (tileData) { \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
} \
|
||||
pixel += 4; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DRAW_BACKGROUND_MODE_0_MOSAIC_256Ext(BLEND, OBJWIN) \
|
||||
for (; tileX < tileEnd; ++tileX) { \
|
||||
BACKGROUND_TEXT_SELECT_CHARACTER; \
|
||||
charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
|
||||
vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
|
||||
tileData = carryData; \
|
||||
for (x = 0; x < 8; ++x) { \
|
||||
if (!mosaicWait) { \
|
||||
if (UNLIKELY(!vram)) { \
|
||||
carryData = 0; \
|
||||
} else { \
|
||||
paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
|
||||
palette = &mainPalette[paletteData]; \
|
||||
if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
|
||||
if (x >= 4) { \
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= (x - 4) * 8; \
|
||||
} else { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= x * 8; \
|
||||
} \
|
||||
} else { \
|
||||
if (x >= 4) { \
|
||||
LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= (7 - x) * 8; \
|
||||
} else { \
|
||||
LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
|
||||
tileData >>= (3 - x) * 8; \
|
||||
} \
|
||||
} \
|
||||
tileData &= 0xFF; \
|
||||
carryData = tileData; \
|
||||
} \
|
||||
mosaicWait = mosaicH; \
|
||||
} \
|
||||
tileData |= tileData << 8; \
|
||||
--mosaicWait; \
|
||||
BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
|
||||
++pixel; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DRAW_BACKGROUND_MODE_0(BPP, BLEND, OBJWIN) \
|
||||
uint32_t* pixel = &renderer->row[outX]; \
|
||||
if (background->mosaic && GBAMosaicControlGetBgH(renderer->mosaic)) { \
|
||||
|
@ -460,9 +652,18 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer
|
|||
uint32_t screenBase;
|
||||
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 (variant) {
|
||||
mainPalette = renderer->variantPalette;
|
||||
color_t* mainPalette;
|
||||
if (background->multipalette && background->extPalette) {
|
||||
mainPalette = background->extPalette;
|
||||
// TODO
|
||||
/*if (variant) {
|
||||
mainPalette = background->variantPalette;
|
||||
}*/
|
||||
} else {
|
||||
mainPalette = renderer->normalPalette;
|
||||
if (variant) {
|
||||
mainPalette = renderer->variantPalette;
|
||||
}
|
||||
}
|
||||
color_t* palette = mainPalette;
|
||||
PREPARE_OBJWIN;
|
||||
|
@ -481,28 +682,36 @@ void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer
|
|||
if (!(flags & FLAG_TARGET_2)) {
|
||||
if (!background->multipalette) {
|
||||
DRAW_BACKGROUND_MODE_0(16, NoBlend, NO_OBJWIN);
|
||||
} else {
|
||||
} else if (!background->extPalette) {
|
||||
DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN);
|
||||
} else {
|
||||
DRAW_BACKGROUND_MODE_0(256Ext, NoBlend, NO_OBJWIN);
|
||||
}
|
||||
} else {
|
||||
if (!background->multipalette) {
|
||||
DRAW_BACKGROUND_MODE_0(16, Blend, NO_OBJWIN);
|
||||
} else {
|
||||
} else if (!background->extPalette) {
|
||||
DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN);
|
||||
} else {
|
||||
DRAW_BACKGROUND_MODE_0(256Ext, Blend, NO_OBJWIN);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(flags & FLAG_TARGET_2)) {
|
||||
if (!background->multipalette) {
|
||||
DRAW_BACKGROUND_MODE_0(16, NoBlend, OBJWIN);
|
||||
} else {
|
||||
} else if (!background->extPalette) {
|
||||
DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN);
|
||||
} else {
|
||||
DRAW_BACKGROUND_MODE_0(256Ext, NoBlend, OBJWIN);
|
||||
}
|
||||
} else {
|
||||
if (!background->multipalette) {
|
||||
DRAW_BACKGROUND_MODE_0(16, Blend, OBJWIN);
|
||||
} else {
|
||||
} else if (!background->extPalette) {
|
||||
DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN);
|
||||
} else {
|
||||
DRAW_BACKGROUND_MODE_0(256Ext, Blend, OBJWIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,8 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) {
|
|||
bg->dmy = 256;
|
||||
bg->sx = 0;
|
||||
bg->sy = 0;
|
||||
bg->extPalette = NULL;
|
||||
bg->variantPalette = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue