lcd window support

This commit is contained in:
Matthew Laux 2022-08-04 01:31:59 -05:00
parent d6b6988742
commit af18bb9a39
3 changed files with 42 additions and 28 deletions

View File

@ -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);

View File

@ -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];
}
}
}

View File

@ -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);