mirror of https://github.com/mgba-emu/mgba.git
GB Video: Change to dot-based renderer
This commit is contained in:
parent
32f0bb9f1f
commit
2290dd6781
|
@ -203,7 +203,6 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
|||
case GB_REGION_VRAM + 1:
|
||||
// TODO: Block access in wrong modes
|
||||
gb->video.vram[address & (GB_SIZE_VRAM - 1)] = value;
|
||||
gb->video.renderer->writeVRAM(gb->video.renderer, address & (GB_SIZE_VRAM - 1));
|
||||
return;
|
||||
case GB_REGION_EXTERNAL_RAM:
|
||||
case GB_REGION_EXTERNAL_RAM + 1:
|
||||
|
@ -224,7 +223,6 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t 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) {
|
||||
mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value);
|
||||
|
@ -268,7 +266,6 @@ void _GBMemoryDMAService(struct GB* gb) {
|
|||
uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
|
||||
// TODO: Can DMA write OAM during modes 2-3?
|
||||
gb->video.oam.raw[gb->memory.dmaDest] = b;
|
||||
gb->video.renderer->writeOAM(gb->video.renderer, gb->memory.dmaDest);
|
||||
++gb->memory.dmaSource;
|
||||
++gb->memory.dmaDest;
|
||||
--gb->memory.dmaRemaining;
|
||||
|
|
|
@ -11,18 +11,14 @@
|
|||
static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer);
|
||||
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 void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
|
||||
static void GBVideoSoftwareRendererDrawDot(struct GBVideoRenderer* renderer, int x, int y, struct GBObj** obj, size_t oamMax);
|
||||
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const 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 GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y);
|
||||
|
||||
static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer);
|
||||
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int x, int y);
|
||||
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
|
@ -39,9 +35,7 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
|
|||
renderer->d.reset = GBVideoSoftwareRendererReset;
|
||||
renderer->d.deinit = GBVideoSoftwareRendererDeinit;
|
||||
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
|
||||
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
|
||||
renderer->d.writeOAM = GBVideoSoftwareRendererWriteOAM;
|
||||
renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline;
|
||||
renderer->d.drawDot = GBVideoSoftwareRendererDrawDot;
|
||||
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
|
||||
renderer->d.getPixels = 0;
|
||||
renderer->d.putPixels = 0;
|
||||
|
@ -70,8 +64,6 @@ static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer) {
|
|||
softwareRenderer->scx = 0;
|
||||
softwareRenderer->wy = 0;
|
||||
softwareRenderer->wx = 0;
|
||||
softwareRenderer->oamMax = 0;
|
||||
softwareRenderer->oamDirty = false;
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
|
||||
|
@ -79,17 +71,6 @@ static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
|
|||
UNUSED(softwareRenderer);
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
// 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) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
switch (address) {
|
||||
|
@ -130,70 +111,37 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
|
|||
return value;
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
||||
static void GBVideoSoftwareRendererDrawDot(struct GBVideoRenderer* renderer, int x, int y, struct GBObj** obj, size_t oamMax) {
|
||||
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
|
||||
|
||||
if (softwareRenderer->oamDirty) {
|
||||
_cleanOAM(softwareRenderer);
|
||||
}
|
||||
|
||||
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
|
||||
maps += GB_SIZE_MAP;
|
||||
}
|
||||
size_t x;
|
||||
if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc)) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, softwareRenderer->scx, softwareRenderer->scy);
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, x, y, softwareRenderer->scx, softwareRenderer->scy);
|
||||
|
||||
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y) {
|
||||
maps = &softwareRenderer->d.vram[GB_BASE_MAP];
|
||||
if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {
|
||||
maps += GB_SIZE_MAP;
|
||||
}
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, y, 7 - softwareRenderer->wx, -softwareRenderer->wy);
|
||||
if (x >= softwareRenderer->wx - 7) {
|
||||
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, x, y, 7 - softwareRenderer->wx, -softwareRenderer->wy);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||
softwareRenderer->row[x] = 0;
|
||||
}
|
||||
softwareRenderer->row[x] = 0;
|
||||
}
|
||||
|
||||
if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc)) {
|
||||
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);
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < oamMax; ++i) {
|
||||
GBVideoSoftwareRendererDrawObj(softwareRenderer, obj[i], x, y);
|
||||
}
|
||||
}
|
||||
|
||||
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||
row[x] = softwareRenderer->palette[softwareRenderer->row[x]];
|
||||
}
|
||||
}
|
||||
|
||||
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 == 0 || y >= GB_VIDEO_VERTICAL_PIXELS + 16) {
|
||||
continue;
|
||||
}
|
||||
// TODO: Sort
|
||||
renderer->obj[o] = &renderer->d.oam->obj[i];
|
||||
++o;
|
||||
}
|
||||
renderer->oamMax = o;
|
||||
renderer->oamDirty = false;
|
||||
row[x] = softwareRenderer->palette[softwareRenderer->row[x]];
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
|
||||
|
@ -212,27 +160,22 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
|||
}
|
||||
int topY = (((y + sy) >> 3) & 0x1F) * 0x20;
|
||||
int bottomY = (y + sy) & 7;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
for (; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||
int topX = ((x + sx) >> 3) & 0x1F;
|
||||
int bottomX = 7 - ((x + sx) & 7);
|
||||
int bgTile;
|
||||
if (GBRegisterLCDCIsTileData(renderer->lcdc)) {
|
||||
bgTile = maps[topX + topY];
|
||||
} else {
|
||||
bgTile = ((int8_t*) maps)[topX + topY];
|
||||
}
|
||||
uint8_t tileDataLower = data[(bgTile * 8 + bottomY) * 2];
|
||||
uint8_t tileDataUpper = data[(bgTile * 8 + bottomY) * 2 + 1];
|
||||
tileDataUpper >>= bottomX;
|
||||
tileDataLower >>= bottomX;
|
||||
renderer->row[x] = ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
|
||||
int topX = ((x + sx) >> 3) & 0x1F;
|
||||
int bottomX = 7 - ((x + sx) & 7);
|
||||
int bgTile;
|
||||
if (GBRegisterLCDCIsTileData(renderer->lcdc)) {
|
||||
bgTile = maps[topX + topY];
|
||||
} else {
|
||||
bgTile = ((int8_t*) maps)[topX + topY];
|
||||
}
|
||||
uint8_t tileDataLower = data[(bgTile * 8 + bottomY) * 2];
|
||||
uint8_t tileDataUpper = data[(bgTile * 8 + bottomY) * 2 + 1];
|
||||
tileDataUpper >>= bottomX;
|
||||
tileDataLower >>= bottomX;
|
||||
renderer->row[x] = ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
|
||||
}
|
||||
|
||||
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y) {
|
||||
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int x, int y) {
|
||||
uint8_t* data = renderer->d.vram;
|
||||
int tileOffset = 0;
|
||||
int bottomY;
|
||||
|
@ -251,27 +194,25 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
|
|||
if (obj->x < end) {
|
||||
end = obj->x;
|
||||
}
|
||||
int x = obj->x - 8;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
int ix = obj->x - 8;
|
||||
if (x < ix || x >= ix + 8) {
|
||||
return;
|
||||
}
|
||||
uint8_t mask = GBObjAttributesIsPriority(obj->attr) ? 0 : 0x20;
|
||||
int p = (GBObjAttributesGetPalette(obj->attr) + 8) * 4;
|
||||
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) && current <= mask) {
|
||||
renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
|
||||
}
|
||||
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) && current <= mask) {
|
||||
renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,6 @@ struct GBVideoSoftwareRenderer {
|
|||
uint8_t wx;
|
||||
|
||||
GBRegisterLCDC lcdc;
|
||||
|
||||
struct GBObj* obj[40];
|
||||
int oamMax;
|
||||
bool oamDirty;
|
||||
};
|
||||
|
||||
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
|
||||
|
|
|
@ -14,20 +14,18 @@ static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer);
|
|||
static void GBVideoDummyRendererReset(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
|
||||
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
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 GBVideoDummyRendererDrawDot(struct GBVideoRenderer* renderer, int x, int y, struct GBObj** obj, size_t oamMax);
|
||||
static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
|
||||
static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
|
||||
|
||||
static void _cleanOAM(struct GBVideo* video, int y);
|
||||
|
||||
static struct GBVideoRenderer dummyRenderer = {
|
||||
.init = GBVideoDummyRendererInit,
|
||||
.reset = GBVideoDummyRendererReset,
|
||||
.deinit = GBVideoDummyRendererDeinit,
|
||||
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
|
||||
.writeVRAM = GBVideoDummyRendererWriteVRAM,
|
||||
.writeOAM = GBVideoDummyRendererWriteOAM,
|
||||
.drawScanline = GBVideoDummyRendererDrawScanline,
|
||||
.drawDot = GBVideoDummyRendererDrawDot,
|
||||
.finishFrame = GBVideoDummyRendererFinishFrame,
|
||||
.getPixels = GBVideoDummyRendererGetPixels
|
||||
};
|
||||
|
@ -47,6 +45,7 @@ void GBVideoReset(struct GBVideo* video) {
|
|||
video->eventDiff = 0;
|
||||
|
||||
video->nextMode = INT_MAX;
|
||||
video->nextDot = INT_MAX;
|
||||
|
||||
video->frameCounter = 0;
|
||||
video->frameskipCounter = 0;
|
||||
|
@ -83,6 +82,17 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
if (video->nextEvent <= 0) {
|
||||
if (video->nextEvent != INT_MAX) {
|
||||
video->nextMode -= video->eventDiff;
|
||||
video->nextDot -= video->eventDiff;
|
||||
}
|
||||
video->nextEvent = INT_MAX;
|
||||
if (video->nextDot <= 0) {
|
||||
video->renderer->drawDot(video->renderer, video->x, video->ly, video->objThisLine, video->objMax);
|
||||
++video->x;
|
||||
if (video->x < GB_VIDEO_HORIZONTAL_PIXELS) {
|
||||
video->nextDot = 1;
|
||||
} else {
|
||||
video->nextDot = INT_MAX;
|
||||
}
|
||||
}
|
||||
if (video->nextMode <= 0) {
|
||||
int lyc = video->p->memory.io[REG_LYC];
|
||||
|
@ -91,11 +101,7 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
++video->ly;
|
||||
video->p->memory.io[REG_LY] = video->ly;
|
||||
video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly);
|
||||
if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
}
|
||||
if (video->ly < GB_VIDEO_VERTICAL_PIXELS) {
|
||||
video->renderer->drawScanline(video->renderer, video->ly);
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
if (GBRegisterSTATIsOAMIRQ(video->stat)) {
|
||||
|
@ -111,6 +117,9 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
}
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK);
|
||||
}
|
||||
if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
}
|
||||
GBUpdateIRQs(video->p);
|
||||
break;
|
||||
case 1:
|
||||
|
@ -121,7 +130,6 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
}
|
||||
if (video->ly >= GB_VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||
video->ly = 0;
|
||||
video->renderer->drawScanline(video->renderer, video->ly);
|
||||
video->nextMode = GB_VIDEO_MODE_2_LENGTH;
|
||||
video->mode = 2;
|
||||
if (GBRegisterSTATIsOAMIRQ(video->stat)) {
|
||||
|
@ -134,11 +142,15 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
video->p->memory.io[REG_LY] = video->ly;
|
||||
break;
|
||||
case 2:
|
||||
video->nextMode = GB_VIDEO_MODE_3_LENGTH;
|
||||
_cleanOAM(video, video->ly);
|
||||
video->nextDot = 1;
|
||||
video->nextEvent = video->nextDot;
|
||||
video->x = 0;
|
||||
video->nextMode = GB_VIDEO_MODE_3_LENGTH_BASE + video->objMax * 8;
|
||||
video->mode = 3;
|
||||
break;
|
||||
case 3:
|
||||
video->nextMode = GB_VIDEO_MODE_0_LENGTH;
|
||||
video->nextMode = GB_VIDEO_MODE_0_LENGTH_BASE - video->objMax * 8;
|
||||
video->mode = 0;
|
||||
if (GBRegisterSTATIsHblankIRQ(video->stat)) {
|
||||
video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT);
|
||||
|
@ -149,13 +161,42 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
video->stat = GBRegisterSTATSetMode(video->stat, video->mode);
|
||||
video->p->memory.io[REG_STAT] = video->stat;
|
||||
}
|
||||
|
||||
video->nextEvent = video->nextMode;
|
||||
if (video->nextDot < video->nextEvent) {
|
||||
video->nextEvent = video->nextDot;
|
||||
}
|
||||
if (video->nextMode < video->nextEvent) {
|
||||
video->nextEvent = video->nextMode;
|
||||
}
|
||||
video->eventDiff = 0;
|
||||
}
|
||||
return video->nextEvent;
|
||||
}
|
||||
|
||||
static void _cleanOAM(struct GBVideo* video, int y) {
|
||||
// TODO: GBC differences
|
||||
// TODO: Optimize
|
||||
video->objMax = 0;
|
||||
int spriteHeight = 8;
|
||||
if (GBRegisterLCDCIsObjSize(video->p->memory.io[REG_LCDC])) {
|
||||
spriteHeight = 16;
|
||||
}
|
||||
int o = 0;
|
||||
int i;
|
||||
for (i = 0; i < 40; ++i) {
|
||||
uint8_t oy = video->oam.obj[i].y;
|
||||
if (y < oy - 16 || y >= oy - 16 + spriteHeight) {
|
||||
continue;
|
||||
}
|
||||
// TODO: Sort
|
||||
video->objThisLine[o] = &video->oam.obj[i];
|
||||
++o;
|
||||
if (o == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
video->objMax = o;
|
||||
}
|
||||
|
||||
void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) {
|
||||
if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && GBRegisterLCDCIsEnable(value)) {
|
||||
// TODO: Does enabling the LCD start in vblank?
|
||||
|
@ -219,9 +260,12 @@ static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint8
|
|||
// Nothing to do
|
||||
}
|
||||
|
||||
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
|
||||
static void GBVideoDummyRendererDrawDot(struct GBVideoRenderer* renderer, int x, int y, struct GBObj** obj, size_t oamMax) {
|
||||
UNUSED(renderer);
|
||||
UNUSED(x);
|
||||
UNUSED(y);
|
||||
UNUSED(obj);
|
||||
UNUSED(oamMax);
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,12 @@ enum {
|
|||
GB_VIDEO_VBLANK_PIXELS = 10,
|
||||
GB_VIDEO_VERTICAL_TOTAL_PIXELS = GB_VIDEO_VERTICAL_PIXELS + GB_VIDEO_VBLANK_PIXELS,
|
||||
|
||||
GB_VIDEO_MODE_0_LENGTH = 203, // Estimates, figure out with more precision
|
||||
GB_VIDEO_MODE_2_LENGTH = 81,
|
||||
GB_VIDEO_MODE_3_LENGTH = 172,
|
||||
// TODO: Figure out exact lengths
|
||||
GB_VIDEO_MODE_2_LENGTH = 84,
|
||||
GB_VIDEO_MODE_3_LENGTH_BASE = 168,
|
||||
GB_VIDEO_MODE_0_LENGTH_BASE = 204,
|
||||
|
||||
GB_VIDEO_HORIZONTAL_LENGTH = GB_VIDEO_MODE_0_LENGTH + GB_VIDEO_MODE_2_LENGTH + GB_VIDEO_MODE_3_LENGTH,
|
||||
GB_VIDEO_HORIZONTAL_LENGTH = GB_VIDEO_MODE_0_LENGTH_BASE + GB_VIDEO_MODE_2_LENGTH + GB_VIDEO_MODE_3_LENGTH_BASE,
|
||||
|
||||
GB_VIDEO_MODE_1_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VBLANK_PIXELS,
|
||||
GB_VIDEO_TOTAL_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VERTICAL_TOTAL_PIXELS,
|
||||
|
@ -53,9 +54,7 @@ struct GBVideoRenderer {
|
|||
void (*deinit)(struct GBVideoRenderer* renderer);
|
||||
|
||||
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
|
||||
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
|
||||
void (*writeOAM)(struct GBVideoRenderer* renderer, uint8_t oam);
|
||||
void (*drawScanline)(struct GBVideoRenderer* renderer, int y);
|
||||
void (*drawDot)(struct GBVideoRenderer* renderer, int x, int y, struct GBObj** objOnLine, size_t nObj);
|
||||
void (*finishFrame)(struct GBVideoRenderer* renderer);
|
||||
|
||||
void (*getPixels)(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
|
||||
|
@ -87,6 +86,7 @@ struct GBVideo {
|
|||
struct GB* p;
|
||||
struct GBVideoRenderer* renderer;
|
||||
|
||||
int x;
|
||||
int ly;
|
||||
GBRegisterSTAT stat;
|
||||
|
||||
|
@ -96,11 +96,14 @@ struct GBVideo {
|
|||
int32_t eventDiff;
|
||||
|
||||
int32_t nextMode;
|
||||
int32_t nextDot;
|
||||
|
||||
uint8_t* vram;
|
||||
uint8_t* vramBank;
|
||||
|
||||
union GBOAM oam;
|
||||
struct GBObj* objThisLine[10];
|
||||
int objMax;
|
||||
|
||||
int32_t frameCounter;
|
||||
int frameskip;
|
||||
|
|
Loading…
Reference in New Issue