From af18bb9a39b13615bfc0edd9c9dae4290cb5374f Mon Sep 17 00:00:00 2001 From: Matthew Laux Date: Thu, 4 Aug 2022 01:31:59 -0500 Subject: [PATCH] lcd window support --- src/dmg.c | 48 +++++++++++++++++++++++++----------------------- src/lcd.c | 19 +++++++++++++++---- src/lcd.h | 3 ++- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/dmg.c b/src/dmg.c index b87bb73..026f759 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -145,36 +145,37 @@ void dmg_request_interrupt(struct dmg *dmg, int nr) } // TODO move to lcd.c, it needs to be able to access dmg_read though -static void render_background(struct dmg *dmg, int lcdc) +static void render_background(struct dmg *dmg, int lcdc, int is_window) { - int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800; - int window_base = (lcdc & LCDC_WINDOW_TILE_MAP) ? 0x9c00 : 0x9800; - int use_unsigned = lcdc & LCDC_BG_TILE_DATA; + int bg_map = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800; + int window_map = (lcdc & LCDC_WINDOW_TILE_MAP) ? 0x9c00 : 0x9800; + int map_base_addr = is_window ? window_map : bg_map; + int unsigned_mode = lcdc & LCDC_BG_TILE_DATA; + int tile_base_addr = unsigned_mode ? 0x8000 : 0x9000; int palette = lcd_read(dmg->lcd, REG_BGP); - int tilebase = use_unsigned ? 0x8000 : 0x9000; + u8 *dest = is_window ? dmg->lcd->window : dmg->lcd->buf; - //printf("%04x %04x %04x\n", bg_base, window_base, tilebase); - - int k = 0, off = 0; - int tile_y = 0, tile_x = 0; + int tile_y, tile_x; for (tile_y = 0; tile_y < 32; tile_y++) { for (tile_x = 0; tile_x < 32; tile_x++) { - off = 256 * 8 * tile_y + 8 * tile_x; - int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x)); - int eff_addr; - if (use_unsigned) { - eff_addr = tilebase + 16 * tile; + int eff_addr, b, i; + + int off = 256 * 8 * tile_y + 8 * tile_x; + int tile_index = dmg_read(dmg, map_base_addr + (tile_y * 32 + tile_x)); + + if (unsigned_mode) { + eff_addr = tile_base_addr + 16 * tile_index; } else { - eff_addr = tilebase + 16 * (signed char) tile; + eff_addr = tile_base_addr + 16 * (signed char) tile_index; } - int b, i, col_index; + for (b = 0; b < 16; b += 2) { int data1 = dmg_read(dmg, eff_addr + b); int data2 = dmg_read(dmg, eff_addr + b + 1); for (i = 7; i >= 0; i--) { - col_index = (data1 & (1 << i)) ? 1 : 0; + int col_index = (data1 & (1 << i)) ? 1 : 0; col_index |= ((data2 & (1 << i)) ? 1 : 0) << 1; - dmg->lcd->buf[off] = (palette >> (col_index << 1)) & 3; + dest[off] = (palette >> (col_index << 1)) & 3; off++; } off += 248; @@ -193,8 +194,8 @@ struct oam_entry { // TODO: only ten per scanline, priority, attributes, move to lcd.c static void render_objs(struct dmg *dmg) { - struct oam_entry *oam = (struct oam_entry *) dmg->lcd->oam; int k, lcd_x, lcd_y, off; + struct oam_entry *oam = (struct oam_entry *) dmg->lcd->oam; int tall = lcd_isset(dmg->lcd, REG_LCDC, LCDC_OBJ_SIZE); for (k = 0; k < 40; k++, oam++) { @@ -285,14 +286,15 @@ void dmg_step(void *_dmg) int lcdc = lcd_read(dmg->lcd, REG_LCDC); if (lcdc & LCDC_ENABLE_BG) { - render_background(dmg, lcdc); + render_background(dmg, lcdc, 0); } - if (lcdc & LCDC_ENABLE_WINDOW) { - // printf("window\n"); + int window_enabled = lcdc & LCDC_ENABLE_WINDOW; + if (window_enabled) { + render_background(dmg, lcdc, 1); } - lcd_apply_scroll(dmg->lcd); + lcd_apply_scroll(dmg->lcd, window_enabled); if (lcdc & LCDC_ENABLE_OBJ) { render_objs(dmg); diff --git a/src/lcd.c b/src/lcd.c index 7c7d3eb..c9874fd 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -29,8 +29,11 @@ void lcd_set_mode(struct lcd *lcd, int mode) void lcd_new(struct lcd *lcd) { - lcd->buf = malloc(256 * 256); - memset(lcd->buf, 0, 256 * 256); + const size_t size = 256 * 256; + lcd->buf = malloc(size); + lcd->window = malloc(size); + memset(lcd->buf, 0, size); + memset(lcd->window, 0, size); // todo < 8 bpp lcd->pixels = malloc(LCD_WIDTH * LCD_HEIGHT); } @@ -66,18 +69,26 @@ void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value) lcd->pixels[y * LCD_WIDTH + x] = value; } -void lcd_apply_scroll(struct lcd *lcd) +void lcd_apply_scroll(struct lcd *lcd, int use_window) { int scroll_y = lcd_read(lcd, REG_SCY); int scroll_x = lcd_read(lcd, REG_SCX); + int win_x = lcd_read(lcd, REG_WX) - 7; + int win_y = lcd_read(lcd, REG_WY); + int lines; for (lines = 0; lines < 144; lines++) { int src_y = (scroll_y + lines) & 0xff; int cols; for (cols = 0; cols < 160; cols++) { int src_off = (src_y << 8) + ((scroll_x + cols) & 0xff); - lcd->pixels[lines * 160 + cols] = lcd->buf[src_off]; + u8 *src = lcd->buf; + if (use_window && cols >= win_x && lines >= win_y) { + src_off = (((lines - win_y) & 0xff) << 8) + ((cols - win_x) & 0xff); + src = lcd->window; + } + lcd->pixels[lines * 160 + cols] = src[src_off]; } } } diff --git a/src/lcd.h b/src/lcd.h index 50cb854..00e80cf 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -48,6 +48,7 @@ struct lcd { u8 oam[0xa0]; u8 regs[0x0c]; u8 *buf; // 256x256 + u8 *window; u8 *pixels; // the actual 160x144 visible area }; @@ -64,7 +65,7 @@ int lcd_isset(struct lcd *lcd, u16 addr, u8 bit); void lcd_set_mode(struct lcd *lcd, int mode); int lcd_step(struct lcd *lcd); -void lcd_apply_scroll(struct lcd *lcd); +void lcd_apply_scroll(struct lcd *lcd, int use_window); // output the pixels to the screen void lcd_draw(struct lcd *lcd);