mirror of https://github.com/mgba-emu/mgba.git
GB: Implement sprites, SRAM
This commit is contained in:
parent
5cd84799be
commit
8750f78808
|
@ -57,6 +57,9 @@ void GBMemoryDeinit(struct GB* gb) {
|
||||||
if (gb->memory.rom) {
|
if (gb->memory.rom) {
|
||||||
mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
|
mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
|
||||||
}
|
}
|
||||||
|
if (gb->memory.sram) {
|
||||||
|
mappedMemoryFree(gb->memory.sram, 0x8000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBMemoryReset(struct GB* gb) {
|
void GBMemoryReset(struct GB* gb) {
|
||||||
|
@ -67,6 +70,10 @@ void GBMemoryReset(struct GB* gb) {
|
||||||
gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
|
gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
|
||||||
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
|
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
|
||||||
gb->memory.currentBank = 1;
|
gb->memory.currentBank = 1;
|
||||||
|
gb->memory.sram = anonymousMemoryMap(0x8000); // TODO: Persist
|
||||||
|
gb->memory.sramCurrentBank = 0;
|
||||||
|
|
||||||
|
memset(&gb->video.oam, 0, sizeof(gb->video.oam));
|
||||||
|
|
||||||
const struct GBCartridge* cart = &gb->memory.rom[0x100];
|
const struct GBCartridge* cart = &gb->memory.rom[0x100];
|
||||||
switch (cart->type) {
|
switch (cart->type) {
|
||||||
|
@ -138,8 +145,10 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||||
return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
|
return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
|
||||||
case GB_REGION_EXTERNAL_RAM:
|
case GB_REGION_EXTERNAL_RAM:
|
||||||
case GB_REGION_EXTERNAL_RAM + 1:
|
case GB_REGION_EXTERNAL_RAM + 1:
|
||||||
// TODO
|
if (memory->sramAccess) {
|
||||||
return 0;
|
return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
case GB_REGION_WORKING_RAM_BANK0:
|
case GB_REGION_WORKING_RAM_BANK0:
|
||||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||||
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||||
|
@ -149,9 +158,14 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||||
if (address < GB_BASE_OAM) {
|
if (address < GB_BASE_OAM) {
|
||||||
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||||
}
|
}
|
||||||
|
if (address < GB_BASE_UNUSABLE) {
|
||||||
|
if (gb->video.mode < 2) {
|
||||||
|
return gb->video.oam.raw[address & 0xFF];
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
if (address < GB_BASE_IO) {
|
if (address < GB_BASE_IO) {
|
||||||
// TODO
|
return 0xFF;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (address < GB_BASE_HRAM) {
|
if (address < GB_BASE_HRAM) {
|
||||||
return GBIORead(gb, address & (GB_SIZE_IO - 1));
|
return GBIORead(gb, address & (GB_SIZE_IO - 1));
|
||||||
|
@ -185,7 +199,9 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||||
return;
|
return;
|
||||||
case GB_REGION_EXTERNAL_RAM:
|
case GB_REGION_EXTERNAL_RAM:
|
||||||
case GB_REGION_EXTERNAL_RAM + 1:
|
case GB_REGION_EXTERNAL_RAM + 1:
|
||||||
// TODO
|
if (memory->sramAccess) {
|
||||||
|
gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case GB_REGION_WORKING_RAM_BANK0:
|
case GB_REGION_WORKING_RAM_BANK0:
|
||||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||||
|
@ -197,8 +213,13 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||||
default:
|
default:
|
||||||
if (address < GB_BASE_OAM) {
|
if (address < GB_BASE_OAM) {
|
||||||
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
||||||
|
} else if (address < GB_BASE_UNUSABLE) {
|
||||||
|
if (gb->video.mode < 2) {
|
||||||
|
gb->video.oam.raw[address & 0xFF] = value;
|
||||||
|
gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
|
||||||
|
}
|
||||||
} else if (address < GB_BASE_IO) {
|
} else if (address < GB_BASE_IO) {
|
||||||
// TODO
|
// TODO: Log
|
||||||
} else if (address < GB_BASE_HRAM) {
|
} else if (address < GB_BASE_HRAM) {
|
||||||
GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
|
GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
|
||||||
} else if (address < GB_BASE_IE) {
|
} else if (address < GB_BASE_IE) {
|
||||||
|
@ -282,12 +303,30 @@ static void _switchBank(struct GBMemory* memory, int bank) {
|
||||||
memory->currentBank = bank;
|
memory->currentBank = bank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _switchSramBank(struct GBMemory* memory, int bank) {
|
||||||
|
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
|
||||||
|
memory->sramBank = &memory->sram[bankStart];
|
||||||
|
memory->sramCurrentBank = bank;
|
||||||
|
}
|
||||||
|
|
||||||
void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
|
void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
|
||||||
int bank = value & 0x1F;
|
int bank = value & 0x1F;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
memory->sramAccess = false;
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
memory->sramAccess = true;
|
||||||
|
_switchSramBank(memory, memory->sramCurrentBank);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
if (!bank) {
|
if (!bank) {
|
||||||
++bank;
|
++bank;
|
||||||
|
@ -305,14 +344,30 @@ void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
|
||||||
int bank = value & 0x7F;
|
int bank = value & 0x7F;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
memory->sramAccess = false;
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
memory->sramAccess = true;
|
||||||
|
_switchSramBank(memory, memory->sramCurrentBank);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
if (!bank) {
|
if (!bank) {
|
||||||
++bank;
|
++bank;
|
||||||
}
|
}
|
||||||
_switchBank(memory, bank);
|
_switchBank(memory, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0x2:
|
||||||
|
if (value < 4) {
|
||||||
|
_switchSramBank(memory, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +379,20 @@ void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
|
||||||
int bank = value & 0x7F;
|
int bank = value & 0x7F;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
memory->sramAccess = false;
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
memory->sramAccess = true;
|
||||||
|
_switchSramBank(memory, memory->sramCurrentBank);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
_switchBank(memory, bank);
|
_switchBank(memory, bank);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,6 +20,7 @@ enum {
|
||||||
GB_BASE_WORKING_RAM_BANK0 = 0xC000,
|
GB_BASE_WORKING_RAM_BANK0 = 0xC000,
|
||||||
GB_BASE_WORKING_RAM_BANK1 = 0xD000,
|
GB_BASE_WORKING_RAM_BANK1 = 0xD000,
|
||||||
GB_BASE_OAM = 0xFE00,
|
GB_BASE_OAM = 0xFE00,
|
||||||
|
GB_BASE_UNUSABLE = 0xFEA0,
|
||||||
GB_BASE_IO = 0xFF00,
|
GB_BASE_IO = 0xFF00,
|
||||||
GB_BASE_HRAM = 0xFF80,
|
GB_BASE_HRAM = 0xFF80,
|
||||||
GB_BASE_IE = 0xFFFF
|
GB_BASE_IE = 0xFFFF
|
||||||
|
|
|
@ -12,6 +12,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer);
|
||||||
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
|
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
|
||||||
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer);
|
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer);
|
||||||
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
||||||
|
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam);
|
||||||
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||||
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
|
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
|
||||||
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
|
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||||
|
@ -19,6 +20,9 @@ static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, u
|
||||||
static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
|
static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
|
||||||
|
|
||||||
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int x, int y, int sx, int sy);
|
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int x, int y, int sx, int sy);
|
||||||
|
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y);
|
||||||
|
|
||||||
|
static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer);
|
||||||
|
|
||||||
#ifdef COLOR_16_BIT
|
#ifdef COLOR_16_BIT
|
||||||
#ifdef COLOR_5_6_5
|
#ifdef COLOR_5_6_5
|
||||||
|
@ -36,6 +40,7 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
|
||||||
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
|
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
|
||||||
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
|
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
|
||||||
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
|
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
|
||||||
|
renderer->d.writeOAM = GBVideoSoftwareRendererWriteOAM;
|
||||||
renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline;
|
renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline;
|
||||||
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
|
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
|
||||||
renderer->d.getPixels = 0;
|
renderer->d.getPixels = 0;
|
||||||
|
@ -65,6 +70,8 @@ static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer) {
|
||||||
softwareRenderer->scx = 0;
|
softwareRenderer->scx = 0;
|
||||||
softwareRenderer->wy = 0;
|
softwareRenderer->wy = 0;
|
||||||
softwareRenderer->wx = 0;
|
softwareRenderer->wx = 0;
|
||||||
|
softwareRenderer->oamMax = 0;
|
||||||
|
softwareRenderer->oamDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
|
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
|
||||||
|
@ -76,6 +83,13 @@ static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, u
|
||||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam) {
|
||||||
|
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||||
|
UNUSED(oam);
|
||||||
|
softwareRenderer->oamDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
|
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
|
||||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||||
switch (address) {
|
switch (address) {
|
||||||
|
@ -119,7 +133,14 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
|
||||||
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
||||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||||
|
|
||||||
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
size_t x;
|
||||||
|
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||||
|
softwareRenderer->row[x] = GB_PALETTE[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (softwareRenderer->oamDirty) {
|
||||||
|
_cleanOAM(softwareRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||||
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
|
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
|
||||||
|
@ -127,15 +148,27 @@ static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer
|
||||||
}
|
}
|
||||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, softwareRenderer->scx, softwareRenderer->scy);
|
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, softwareRenderer->scx, softwareRenderer->scy);
|
||||||
|
|
||||||
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc)) {
|
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy < GB_VIDEO_VERTICAL_PIXELS) {
|
||||||
maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||||
if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {
|
if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {
|
||||||
maps += GB_SIZE_MAP;
|
maps += GB_SIZE_MAP;
|
||||||
}
|
}
|
||||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, -7, y, softwareRenderer->wx - 7, softwareRenderer->wy);
|
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, 7 - softwareRenderer->wx, -softwareRenderer->wy);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t x;
|
int spriteHeight = 8;
|
||||||
|
if (GBRegisterLCDCIsObjSize(softwareRenderer->lcdc)) {
|
||||||
|
spriteHeight = 16;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < softwareRenderer->oamMax; ++i) {
|
||||||
|
// TODO: Sprite sizes
|
||||||
|
if (y >= softwareRenderer->obj[i]->y - 16 && y < softwareRenderer->obj[i]->y - 16 + spriteHeight) {
|
||||||
|
GBVideoSoftwareRendererDrawObj(softwareRenderer, softwareRenderer->obj[i], y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||||
#ifdef COLOR_16_BIT
|
#ifdef COLOR_16_BIT
|
||||||
#if defined(__ARM_NEON) && !defined(__APPLE__)
|
#if defined(__ARM_NEON) && !defined(__APPLE__)
|
||||||
_to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS);
|
_to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS);
|
||||||
|
@ -149,6 +182,24 @@ static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer) {
|
||||||
|
// TODO: GBC differences
|
||||||
|
renderer->oamMax = 0;
|
||||||
|
int o = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 40; ++i) {
|
||||||
|
uint8_t y = renderer->d.oam->obj[i].y;
|
||||||
|
if (y < 16 || y >= GB_VIDEO_VERTICAL_PIXELS + 16) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO: Sort
|
||||||
|
renderer->obj[o] = &renderer->d.oam->obj[i];
|
||||||
|
++o;
|
||||||
|
}
|
||||||
|
renderer->oamMax = o;
|
||||||
|
renderer->oamDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
|
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
|
||||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||||
|
|
||||||
|
@ -165,9 +216,6 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
||||||
}
|
}
|
||||||
int topY = (((y + sy) >> 3) & 0x1F) * 0x20;
|
int topY = (((y + sy) >> 3) & 0x1F) * 0x20;
|
||||||
int bottomY = (y + sy) & 7;
|
int bottomY = (y + sy) & 7;
|
||||||
if (x < 0) {
|
|
||||||
x = 0;
|
|
||||||
}
|
|
||||||
for (; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
for (; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||||
int topX = ((x + sx) >> 3) & 0x1F;
|
int topX = ((x + sx) >> 3) & 0x1F;
|
||||||
int bottomX = 7 - ((x + sx) & 7);
|
int bottomX = 7 - ((x + sx) & 7);
|
||||||
|
@ -184,3 +232,45 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
||||||
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
|
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y) {
|
||||||
|
uint8_t* data = renderer->d.vram;
|
||||||
|
int tileOffset = 0;
|
||||||
|
int bottomY;
|
||||||
|
if (GBObjAttributesIsYFlip(obj->attr)) {
|
||||||
|
bottomY = 7 - ((y - obj->y - 16) & 7);
|
||||||
|
if (y - obj->y < -8) {
|
||||||
|
++tileOffset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bottomY = (y - obj->y - 16) & 7;
|
||||||
|
if (y - obj->y >= -8) {
|
||||||
|
++tileOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int end = GB_VIDEO_HORIZONTAL_PIXELS;
|
||||||
|
if (obj->x < end) {
|
||||||
|
end = obj->x;
|
||||||
|
}
|
||||||
|
int x = obj->x - 8;
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
for (; x < end; ++x) {
|
||||||
|
int bottomX;
|
||||||
|
if (GBObjAttributesIsXFlip(obj->attr)) {
|
||||||
|
bottomX = (x - obj->x) & 7;
|
||||||
|
} else {
|
||||||
|
bottomX = 7 - ((x - obj->x) & 7);
|
||||||
|
}
|
||||||
|
int objTile = obj->tile + tileOffset;
|
||||||
|
uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2];
|
||||||
|
uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1];
|
||||||
|
tileDataUpper >>= bottomX;
|
||||||
|
tileDataLower >>= bottomX;
|
||||||
|
color_t current = renderer->row[x];
|
||||||
|
if (((tileDataUpper | tileDataLower) & 1) && (!GBObjAttributesIsPriority(obj->attr) || current == GB_PALETTE[0])) {
|
||||||
|
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,10 @@ struct GBVideoSoftwareRenderer {
|
||||||
uint8_t wx;
|
uint8_t wx;
|
||||||
|
|
||||||
GBRegisterLCDC lcdc;
|
GBRegisterLCDC lcdc;
|
||||||
|
|
||||||
|
struct GBObj* obj[40];
|
||||||
|
int oamMax;
|
||||||
|
bool oamDirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
|
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
|
||||||
|
|
|
@ -15,6 +15,7 @@ static void GBVideoDummyRendererReset(struct GBVideoRenderer* renderer);
|
||||||
static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
|
static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
|
||||||
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||||
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
|
||||||
|
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam);
|
||||||
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
|
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
|
||||||
static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
|
static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||||
static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
|
static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
|
||||||
|
@ -25,6 +26,7 @@ static struct GBVideoRenderer dummyRenderer = {
|
||||||
.deinit = GBVideoDummyRendererDeinit,
|
.deinit = GBVideoDummyRendererDeinit,
|
||||||
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
|
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
|
||||||
.writeVRAM = GBVideoDummyRendererWriteVRAM,
|
.writeVRAM = GBVideoDummyRendererWriteVRAM,
|
||||||
|
.writeOAM = GBVideoDummyRendererWriteOAM,
|
||||||
.drawScanline = GBVideoDummyRendererDrawScanline,
|
.drawScanline = GBVideoDummyRendererDrawScanline,
|
||||||
.finishFrame = GBVideoDummyRendererFinishFrame,
|
.finishFrame = GBVideoDummyRendererFinishFrame,
|
||||||
.getPixels = GBVideoDummyRendererGetPixels
|
.getPixels = GBVideoDummyRendererGetPixels
|
||||||
|
@ -53,6 +55,8 @@ void GBVideoReset(struct GBVideo* video) {
|
||||||
}
|
}
|
||||||
video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
|
video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
|
||||||
video->renderer->vram = video->vram;
|
video->renderer->vram = video->vram;
|
||||||
|
memset(&video->oam, 0, sizeof(video->oam));
|
||||||
|
video->renderer->oam = &video->oam;
|
||||||
|
|
||||||
video->renderer->deinit(video->renderer);
|
video->renderer->deinit(video->renderer);
|
||||||
video->renderer->init(video->renderer);
|
video->renderer->init(video->renderer);
|
||||||
|
@ -200,6 +204,12 @@ static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam) {
|
||||||
|
UNUSED(renderer);
|
||||||
|
UNUSED(oam);
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
||||||
UNUSED(renderer);
|
UNUSED(renderer);
|
||||||
UNUSED(y);
|
UNUSED(y);
|
||||||
|
|
|
@ -29,6 +29,24 @@ enum {
|
||||||
GB_SIZE_MAP = 0x0400
|
GB_SIZE_MAP = 0x0400
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DECL_BITFIELD(GBObjAttributes, uint8_t);
|
||||||
|
DECL_BIT(GBObjAttributes, Palette, 4);
|
||||||
|
DECL_BIT(GBObjAttributes, XFlip, 5);
|
||||||
|
DECL_BIT(GBObjAttributes, YFlip, 6);
|
||||||
|
DECL_BIT(GBObjAttributes, Priority, 7);
|
||||||
|
|
||||||
|
struct GBObj {
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t tile;
|
||||||
|
GBObjAttributes attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
union GBOAM {
|
||||||
|
struct GBObj obj[40];
|
||||||
|
uint8_t raw[160];
|
||||||
|
};
|
||||||
|
|
||||||
struct GBVideoRenderer {
|
struct GBVideoRenderer {
|
||||||
void (*init)(struct GBVideoRenderer* renderer);
|
void (*init)(struct GBVideoRenderer* renderer);
|
||||||
void (*reset)(struct GBVideoRenderer* renderer);
|
void (*reset)(struct GBVideoRenderer* renderer);
|
||||||
|
@ -36,6 +54,7 @@ struct GBVideoRenderer {
|
||||||
|
|
||||||
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||||
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
|
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
|
||||||
|
void (*writeOAM)(struct GBVideoRenderer* renderer, uint8_t oam);
|
||||||
void (*drawScanline)(struct GBVideoRenderer* renderer, int y);
|
void (*drawScanline)(struct GBVideoRenderer* renderer, int y);
|
||||||
void (*finishFrame)(struct GBVideoRenderer* renderer);
|
void (*finishFrame)(struct GBVideoRenderer* renderer);
|
||||||
|
|
||||||
|
@ -43,6 +62,7 @@ struct GBVideoRenderer {
|
||||||
void (*putPixels)(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
|
void (*putPixels)(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
|
||||||
|
|
||||||
uint8_t* vram;
|
uint8_t* vram;
|
||||||
|
union GBOAM* oam;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECL_BITFIELD(GBRegisterLCDC, uint8_t);
|
DECL_BITFIELD(GBRegisterLCDC, uint8_t);
|
||||||
|
@ -80,6 +100,8 @@ struct GBVideo {
|
||||||
uint8_t* vram;
|
uint8_t* vram;
|
||||||
uint8_t* vramBank;
|
uint8_t* vramBank;
|
||||||
|
|
||||||
|
union GBOAM oam;
|
||||||
|
|
||||||
int32_t frameCounter;
|
int32_t frameCounter;
|
||||||
int frameskip;
|
int frameskip;
|
||||||
int frameskipCounter;
|
int frameskipCounter;
|
||||||
|
|
Loading…
Reference in New Issue