mirror of https://github.com/bsnes-emu/bsnes.git
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -128,7 +129,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||
|
||||
if (in_window) {
|
||||
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 {
|
||||
x += gb->effective_scx;
|
||||
|
@ -282,7 +283,8 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||
}
|
||||
|
||||
/* Reset window rendering state */
|
||||
gb->current_window_line = 0xFF;
|
||||
gb->wy_diff = 0;
|
||||
gb->window_disabled_while_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -330,7 +332,8 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||
|
||||
|
||||
/* 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 */
|
||||
|
@ -418,9 +421,6 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
|
|||
if (position_in_line == stat_delay) {
|
||||
gb->io_registers[GB_IO_STAT] &= ~3;
|
||||
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) {
|
||||
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->effective_scx = gb->io_registers[GB_IO_SCX];
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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_window_related_write(GB_gameboy_t *gb, uint8_t addr, uint8_t value);
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -367,7 +367,7 @@ struct GB_gameboy_internal_s {
|
|||
int16_t previous_lcdc_x;
|
||||
bool stat_interrupt_line;
|
||||
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.
|
||||
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/ */
|
||||
|
@ -383,6 +383,7 @@ struct GB_gameboy_internal_s {
|
|||
bool vram_read_blocked;
|
||||
bool oam_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 */
|
||||
|
|
|
@ -408,10 +408,14 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||
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) {
|
||||
/* Hardware registers */
|
||||
switch (addr & 0xFF) {
|
||||
|
||||
case GB_IO_WX:
|
||||
GB_window_related_write(gb, addr & 0xFF, value);
|
||||
break;
|
||||
case GB_IO_SCX:
|
||||
case GB_IO_IF:
|
||||
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_OBP1:
|
||||
case GB_IO_WY:
|
||||
case GB_IO_WX:
|
||||
case GB_IO_SB:
|
||||
case GB_IO_DMG_EMULATION_INDICATION:
|
||||
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 */
|
||||
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;
|
||||
|
||||
case GB_IO_STAT:
|
||||
|
|
Loading…
Reference in New Issue