diff --git a/src/dmg.c b/src/dmg.c index 823746b..f7f91ea 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -189,11 +189,11 @@ struct oam_entry { }; // TODO: only ten per scanline, priority, attributes, move to lcd.c -static void render_objs(struct dmg *dmg) +static void render_objs(struct dmg *dmg, int scanline) { struct oam_entry *oam = (struct oam_entry *) dmg->lcd->oam; int k, lcd_x, lcd_y, off; - int tall = lcd_isset(dmg->lcd, REG_LCDC, LCDC_OBJ_SIZE); + int height = lcd_isset(dmg->lcd, REG_LCDC, LCDC_OBJ_SIZE) ? 16 : 8; for (k = 0; k < 40; k++, oam++) { if (oam->pos_y == 0 || oam->pos_y >= 160) { @@ -206,33 +206,31 @@ static void render_objs(struct dmg *dmg) lcd_x = oam->pos_x - 8; lcd_y = oam->pos_y - 16; - off = 160 * lcd_y + lcd_x; - int eff_addr = 0x8000 + 16 * oam->tile; - int b, i, limit = 16; - if (tall) { - limit = 32; + if (scanline < lcd_y || scanline >= lcd_y + height) { + continue; } - for (b = 0; b < limit; b += 2) { - int use_tile = b; - if (oam->attrs & OAM_ATTR_MIRROR_Y) { - use_tile = (limit - 2) - b; + + off = 160 * scanline + lcd_x; + int eff_addr = 0x8000 + 16 * oam->tile; + int use_tile = 2 * (scanline - lcd_y); + if (oam->attrs & OAM_ATTR_MIRROR_Y) { + use_tile = (height - 2) - use_tile; + } + int data1 = dmg_read(dmg, eff_addr + use_tile); + int data2 = dmg_read(dmg, eff_addr + use_tile + 1); + int i; + for (i = 7; i >= 0; i--) { + if (off < 0 || off >= 160 * 144) { + // terrible clipping. need to not have an if per-pixel + continue; } - int data1 = dmg_read(dmg, eff_addr + use_tile); - int data2 = dmg_read(dmg, eff_addr + use_tile + 1); - for (i = 7; i >= 0; i--) { - if (off < 0 || off >= 160 * 144) { - // terrible clipping. need to not have an if per-pixel - continue; - } - int use_index = i; - if (oam->attrs & OAM_ATTR_MIRROR_X) { - use_index = 7 - i; - } - dmg->lcd->pixels[off] = ((data1 & (1 << use_index)) ? 1 : 0) << 1; - dmg->lcd->pixels[off] |= (data2 & (1 << use_index)) ? 1 : 0; - off++; + int use_index = i; + if (oam->attrs & OAM_ATTR_MIRROR_X) { + use_index = 7 - i; } - off += 152; + dmg->lcd->pixels[off] = ((data1 & (1 << use_index)) ? 1 : 0) << 1; + dmg->lcd->pixels[off] |= (data2 & (1 << use_index)) ? 1 : 0; + off++; } } } @@ -263,23 +261,23 @@ void dmg_step(void *_dmg) lcd_clear_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH); } + int lcdc = lcd_read(dmg->lcd, REG_LCDC); if (next_scanline >= 144 && next_scanline < 154) { lcd_set_mode(dmg->lcd, 1); - } - // TODO: do all of this per-scanline instead of everything in vblank - if (next_scanline == 144) { - // vblank has started, draw all the stuff from ram into the lcd - dmg_request_interrupt(dmg, INT_VBLANK); - if (lcd_isset(dmg->lcd, REG_STAT, STAT_INTR_SOURCE_VBLANK)) { - dmg_request_interrupt(dmg, INT_LCDSTAT); + if (next_scanline == 144) { + // vblank has started, draw all the stuff from ram into the lcd + dmg_request_interrupt(dmg, INT_VBLANK); + if (lcd_isset(dmg->lcd, REG_STAT, STAT_INTR_SOURCE_VBLANK)) { + dmg_request_interrupt(dmg, INT_LCDSTAT); + } + + if (lcdc & LCDC_ENABLE_BG) { + render_background(dmg, lcdc); + } } - - int lcdc = lcd_read(dmg->lcd, REG_LCDC); - if (lcdc & LCDC_ENABLE_BG) { - render_background(dmg, lcdc); - } - + } else { + // not vblank if (lcdc & LCDC_ENABLE_WINDOW) { // printf("window\n"); } @@ -287,7 +285,7 @@ void dmg_step(void *_dmg) lcd_apply_scroll(dmg->lcd); if (lcdc & LCDC_ENABLE_OBJ) { - render_objs(dmg); + render_objs(dmg, next_scanline); } lcd_draw(dmg->lcd); diff --git a/src/lcd.c b/src/lcd.c index 6021606..7c7d3eb 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -7,18 +7,18 @@ void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit) { - lcd_write(lcd, addr, lcd_read(lcd, addr) | (1 << bit)); + lcd_write(lcd, addr, lcd_read(lcd, addr) | bit); } void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit) { - lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit)); + lcd_write(lcd, addr, lcd_read(lcd, addr) & ~bit); } int lcd_isset(struct lcd *lcd, u16 addr, u8 bit) { u8 val = lcd_read(lcd, addr); - return val & (1 << bit); + return val & bit; } void lcd_set_mode(struct lcd *lcd, int mode) diff --git a/src/lcd.h b/src/lcd.h index a3923bd..50cb854 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -23,11 +23,11 @@ #define REG_LCD_LAST REG_WX -#define STAT_FLAG_MATCH 2 -#define STAT_INTR_SOURCE_HBLANK 3 -#define STAT_INTR_SOURCE_VBLANK 4 -#define STAT_INTR_SOURCE_MODE2 5 -#define STAT_INTR_SOURCE_MATCH 6 +#define STAT_FLAG_MATCH (1 << 2) +#define STAT_INTR_SOURCE_HBLANK (1 << 3) +#define STAT_INTR_SOURCE_VBLANK (1 << 4) +#define STAT_INTR_SOURCE_MODE2 (1 << 5) +#define STAT_INTR_SOURCE_MATCH (1 << 6) #define LCDC_ENABLE_BG (1 << 0)