Refined Window behavior once more, Fixes #12 (While not breaking Donkey Kong or 007)
This commit is contained in:
parent
7df4e56454
commit
cbbaf2ee84
@ -75,7 +75,8 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||||||
bg_enabled = false;
|
bg_enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (window_enabled(gb) && y >= gb->io_registers[GB_IO_WY] && x + 7 >= gb->io_registers[GB_IO_WX] && gb->current_window_line != 0xFF) {
|
|
||||||
|
if (window_enabled(gb) && y >= gb->io_registers[GB_IO_WY] + gb->wy_diff && x + 7 >= gb->io_registers[GB_IO_WX]) {
|
||||||
in_window = true;
|
in_window = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||||||
|
|
||||||
if (in_window) {
|
if (in_window) {
|
||||||
x -= gb->io_registers[GB_IO_WX] - 7; // Todo: This value is probably latched
|
x -= gb->io_registers[GB_IO_WX] - 7; // Todo: This value is probably latched
|
||||||
y = gb->current_window_line;
|
y -= gb->io_registers[GB_IO_WY] + gb->wy_diff;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
x += gb->effective_scx;
|
x += gb->effective_scx;
|
||||||
@ -282,7 +283,8 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Reset window rendering state */
|
/* Reset window rendering state */
|
||||||
gb->current_window_line = 0xFF;
|
gb->wy_diff = 0;
|
||||||
|
gb->window_disabled_while_active = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +332,8 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
|
|
||||||
|
|
||||||
/* Reset window rendering state */
|
/* Reset window rendering state */
|
||||||
gb->current_window_line = 0xFF;
|
gb->wy_diff = 0;
|
||||||
|
gb->window_disabled_while_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entered VBlank state, update STAT and IF */
|
/* Entered VBlank state, update STAT and IF */
|
||||||
@ -418,9 +421,6 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
if (position_in_line == stat_delay) {
|
if (position_in_line == stat_delay) {
|
||||||
gb->io_registers[GB_IO_STAT] &= ~3;
|
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||||
gb->io_registers[GB_IO_STAT] |= 2;
|
gb->io_registers[GB_IO_STAT] |= 2;
|
||||||
if (window_enabled(gb) && gb->display_cycles / LINE_LENGTH >= gb->io_registers[GB_IO_WY]) {
|
|
||||||
gb->current_window_line++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (position_in_line == 0 && gb->display_cycles != 0) {
|
else if (position_in_line == 0 && gb->display_cycles != 0) {
|
||||||
should_compare_ly = gb->is_cgb;
|
should_compare_ly = gb->is_cgb;
|
||||||
@ -431,11 +431,6 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||||||
gb->io_registers[GB_IO_STAT] |= 3;
|
gb->io_registers[GB_IO_STAT] |= 3;
|
||||||
gb->effective_scx = gb->io_registers[GB_IO_SCX];
|
gb->effective_scx = gb->io_registers[GB_IO_SCX];
|
||||||
gb->previous_lcdc_x = - (gb->effective_scx & 0x7);
|
gb->previous_lcdc_x = - (gb->effective_scx & 0x7);
|
||||||
|
|
||||||
/* Todo: This works on both 007 - The World Is Not Enough and Donkey Kong 94, but should be verified better */
|
|
||||||
if (window_enabled(gb) && gb->display_cycles / LINE_LENGTH == gb->io_registers[GB_IO_WY] && gb->current_window_line == 0xFF) {
|
|
||||||
gb->current_window_line = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (position_in_line == MODE2_LENGTH + MODE3_LENGTH + stat_delay + scx_delay) {
|
else if (position_in_line == MODE2_LENGTH + MODE3_LENGTH + stat_delay + scx_delay) {
|
||||||
gb->io_registers[GB_IO_STAT] &= ~3;
|
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||||
@ -800,3 +795,32 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h
|
|||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called when a write might enable or disable the window */
|
||||||
|
void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
bool before = window_enabled(gb);
|
||||||
|
gb->io_registers[addr] = value;
|
||||||
|
bool after = window_enabled(gb);
|
||||||
|
|
||||||
|
if (before != after && gb->display_cycles < LINES * LINE_LENGTH) {
|
||||||
|
/* Window was disabled or enabled outside of vblank */
|
||||||
|
uint8_t current_line = gb->display_cycles / LINE_LENGTH;
|
||||||
|
if (current_line >= gb->io_registers[GB_IO_WY]) {
|
||||||
|
if (after) {
|
||||||
|
if (!gb->window_disabled_while_active) {
|
||||||
|
/* Window was turned on for the first time this frame while LY > WY,
|
||||||
|
should start window in the next line */
|
||||||
|
gb->wy_diff = current_line + 1 - gb->io_registers[GB_IO_WY];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->wy_diff += current_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->wy_diff -= current_line;
|
||||||
|
gb->window_disabled_while_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifdef GB_INTERNAL
|
#ifdef GB_INTERNAL
|
||||||
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles);
|
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles);
|
||||||
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
|
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
|
||||||
|
void GB_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -367,7 +367,7 @@ struct GB_gameboy_internal_s {
|
|||||||
int16_t previous_lcdc_x;
|
int16_t previous_lcdc_x;
|
||||||
bool stat_interrupt_line;
|
bool stat_interrupt_line;
|
||||||
uint8_t effective_scx;
|
uint8_t effective_scx;
|
||||||
uint8_t current_window_line;
|
uint8_t wy_diff;
|
||||||
/* The LCDC will skip the first frame it renders after turning it on.
|
/* The LCDC will skip the first frame it renders after turning it on.
|
||||||
On the CGB, a frame is not skipped if the previous frame was skipped as well.
|
On the CGB, a frame is not skipped if the previous frame was skipped as well.
|
||||||
See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */
|
See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */
|
||||||
@ -383,6 +383,7 @@ struct GB_gameboy_internal_s {
|
|||||||
bool vram_read_blocked;
|
bool vram_read_blocked;
|
||||||
bool oam_write_blocked;
|
bool oam_write_blocked;
|
||||||
bool vram_write_blocked;
|
bool vram_write_blocked;
|
||||||
|
bool window_disabled_while_active;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||||
|
@ -408,10 +408,14 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Todo: Clean this code up: use a function table and move relevant code to display.c and timing.c
|
||||||
|
(APU read and writes are already at apu.c) */
|
||||||
if (addr < 0xFF80) {
|
if (addr < 0xFF80) {
|
||||||
/* Hardware registers */
|
/* Hardware registers */
|
||||||
switch (addr & 0xFF) {
|
switch (addr & 0xFF) {
|
||||||
|
case GB_IO_WX:
|
||||||
|
GB_window_related_write(gb, addr & 0xFF, value);
|
||||||
|
break;
|
||||||
case GB_IO_SCX:
|
case GB_IO_SCX:
|
||||||
case GB_IO_IF:
|
case GB_IO_IF:
|
||||||
case GB_IO_SCY:
|
case GB_IO_SCY:
|
||||||
@ -420,7 +424,6 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
case GB_IO_OBP0:
|
case GB_IO_OBP0:
|
||||||
case GB_IO_OBP1:
|
case GB_IO_OBP1:
|
||||||
case GB_IO_WY:
|
case GB_IO_WY:
|
||||||
case GB_IO_WX:
|
|
||||||
case GB_IO_SB:
|
case GB_IO_SB:
|
||||||
case GB_IO_DMG_EMULATION_INDICATION:
|
case GB_IO_DMG_EMULATION_INDICATION:
|
||||||
case GB_IO_UNKNOWN2:
|
case GB_IO_UNKNOWN2:
|
||||||
@ -463,7 +466,8 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
/* Sync after turning off LCD */
|
/* Sync after turning off LCD */
|
||||||
GB_timing_sync(gb);
|
GB_timing_sync(gb);
|
||||||
}
|
}
|
||||||
gb->io_registers[GB_IO_LCDC] = value;
|
/* Writing to LCDC might enable to disable the window, so we write it via GB_window_related_write */
|
||||||
|
GB_window_related_write(gb, addr & 0xFF, value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case GB_IO_STAT:
|
case GB_IO_STAT:
|
||||||
|
Loading…
Reference in New Issue
Block a user