diff --git a/Core/display.c b/Core/display.c index fa5a40c..f227724 100755 --- a/Core/display.c +++ b/Core/display.c @@ -419,14 +419,37 @@ static void render_pixel_if_possible(GB_gameboy_t *gb) gb->position_in_line++; return; } - if (gb->fifo_paused) return; - uint8_t pixel = ((gb->io_registers[GB_IO_BGP] >> (fifo_item->pixel << 1)) & 3); - gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[pixel]; + /* Mixing */ + bool bg_enabled = true, bg_behind = false; + + if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) { + if (gb->cgb_mode) { + bg_behind = true; + } + else { + bg_enabled = false; + } + } + if (!bg_enabled) { + gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); + } + else { + uint8_t pixel = fifo_item->pixel; + if (!gb->cgb_mode) { + pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3); + } + gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[pixel]; + } gb->position_in_line++; } +static inline uint8_t scrolled_y(GB_gameboy_t *gb) +{ + return gb->current_line + (gb->in_window? - gb->io_registers[GB_IO_WY] - gb->wy_diff : gb->io_registers[GB_IO_SCY]); +} + void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) { @@ -546,16 +569,31 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->fetcher_divisor = false; gb->fetcher_state = GB_FETCHER_GET_TILE; gb->fifo_paused = true; + gb->in_window = false; while (true) { + /* Handle window */ + /* Todo: Timing not verified by test ROM */ + if (!gb->in_window && window_enabled(gb) && + gb->current_line >= gb->io_registers[GB_IO_WY] + gb->wy_diff && + gb->position_in_line + 7 == gb->io_registers[GB_IO_WX]) { + gb->in_window = true; + fifo_clear(&gb->bg_fifo); + gb->fifo_paused = true; + gb->fetcher_x = 0; + gb->fetcher_state = GB_FETCHER_GET_TILE; + } + if (gb->fetcher_divisor) { switch (gb->fetcher_state) { case GB_FETCHER_GET_TILE: { uint16_t map = 0x1800; - if (gb->io_registers[GB_IO_LCDC] & 0x08) { + if (gb->io_registers[GB_IO_LCDC] & 0x08 && !gb->in_window) { map = 0x1C00; } - uint8_t y = gb->current_line + gb->io_registers[GB_IO_SCY]; - gb->current_tile = gb->vram[map + gb->fetcher_x + y / 8 * 32]; + else if (gb->io_registers[GB_IO_LCDC] & 0x40 && gb->in_window) { + map = 0x1C00; + } + gb->current_tile = gb->vram[map + gb->fetcher_x + scrolled_y(gb) / 8 * 32]; gb->fetcher_x++; gb->fetcher_x &= 0x1f; } @@ -569,13 +607,13 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) gb->current_tile_address = (int8_t)gb->current_tile * 0x10 + 0x1000; } gb->current_tile_data[0] = - gb->vram[gb->current_tile_address + ((gb->current_line + gb->io_registers[GB_IO_SCY]) & 7) * 2]; + gb->vram[gb->current_tile_address + (scrolled_y(gb) & 7) * 2]; } break; case GB_FETCHER_GET_TILE_DATA_HIGH: { gb->current_tile_data[1] = - gb->vram[gb->current_tile_address + ((gb->current_line + gb->io_registers[GB_IO_SCY]) & 7) * 2 + 1]; + gb->vram[gb->current_tile_address + (scrolled_y(gb) & 7) * 2 + 1]; } break; diff --git a/Core/gb.h b/Core/gb.h index 68c7c0d..b4ff2ab 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -419,7 +419,7 @@ struct GB_gameboy_internal_s { } fetcher_state:8; bool fetcher_divisor; // The fetcher runs at 2MHz bool fifo_paused; - + bool in_window; ); /* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */