diff options
-rw-r--r-- | gb.h | 3 | ||||
-rw-r--r-- | ops.yaml | 118 |
2 files changed, 103 insertions, 18 deletions
@@ -124,7 +124,8 @@ struct gb_t_ { uint32_t frame; struct { - uint8_t x, y, tile; + int16_t x, y; + uint8_t tile; bool priority, y_flip, x_flip, @@ -8088,6 +8088,7 @@ templates: #define UNUSED(a) ((void) (a)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) + #define BETWEEN(v, a, b) (((v) >= (a)) && ((v) <= (b))) // cpu flags #define FLAG(ctx, f) (cpu_rb(ctx, RB_F) & (F_##f)) @@ -10211,10 +10212,10 @@ templates: return; } - // decode oam + // decode and cache oam for (uint8_t i = 0; i < 40; i++) { - ctx->gpu.oam_cache[i].y = (ctx->mmu.oam[4 * i + 0] + 16) & 0xFF; - ctx->gpu.oam_cache[i].x = (ctx->mmu.oam[4 * i + 1] + 8) & 0xFF; + ctx->gpu.oam_cache[i].y = ctx->mmu.oam[4 * i + 0] - 10; + ctx->gpu.oam_cache[i].x = ctx->mmu.oam[4 * i + 1] - 8; ctx->gpu.oam_cache[i].tile = ctx->mmu.oam[4 * i + 2]; const uint8_t flags = ctx->mmu.oam[4 * i + 3]; @@ -10228,6 +10229,87 @@ templates: ctx->gpu.oam_dirty = false; } + static uint8_t + bg_get_tile( + gb_t * const ctx, + const uint8_t ty, + const uint8_t tx + ) { + // calculate tile offset + return mmu_rb(ctx, ( + // get bg tile map base + // (lcdc & (1 << 3)) + ((ctx->gpu.lcdc & (1 << 3)) ? 0x9C00 : 0x9800) + + + // calculate tile offset + ty * 32 + tx + )); + } + + static uint16_t + bg_get_tile_addr( + gb_t * const ctx, + const uint8_t ty, + const uint8_t tx + ) { + // get tile + const uint8_t tile = bg_get_tile(ctx, ty, tx); + + if (ctx->gpu.lcdc & (1 << 4)) { + // base: 0x8000, tile is unsigned + return 0x8000 + 16 * tile; + } else { + // base: 0x9000, tile is signed + return 0x9000 + 16 * ((int8_t) tile); + } + } + + static uint8_t + bg_get_color( + gb_t * const ctx, + const uint8_t sy, + const uint8_t sx + ) { + // TODO: draw background + const uint8_t y = (ctx->gpu.scy + sy) & 0xFF, + ty = y >> 3, + py = y - (ty << 3); + + const uint8_t x = (ctx->gpu.scx + sx) & 0xFF, + tx = x >> 3, + px = x - (tx << 3); + + // get tile data address + const uint16_t addr = bg_get_tile_addr(ctx, ty, tx); + + // get tile data + const uint16_t data = mmu_rw(ctx, addr + (2 * py)); + + // get bg palette entry + const uint8_t p_ofs = ( + ((data >> (8 + (7 - px)) & 0x01) << 1) | + ((data >> (7 - px)) & 0x01) + ); + + // get pixel color + const uint8_t pc = (ctx->gpu.bgp >> (2 * p_ofs)) & 0x03; + + // convert from 0-3 to RGB + switch (pc) { + case 0: + return 0xFF; + case 1: + return 0xC0; + case 2: + return 0x40; + case 3: + return 0x00; + } + + // never reached + return 0xA0; + } + static void gpu_draw_line( gb_t * const ctx @@ -10242,12 +10324,11 @@ templates: ctx->gpu.oam_cache[i].priority && // sprite is on screen - ctx->gpu.oam_cache[i].y < 144 && - ctx->gpu.oam_cache[i].x < 160 && + BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && + BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && // sprite is on current line - ctx->gpu.line >= ctx->gpu.oam_cache[i].y && - ctx->gpu.line <= ctx->gpu.oam_cache[i].y + BETWEEN(ctx->gpu.line, ctx->gpu.oam_cache[i].y, ctx->gpu.oam_cache[i].y + 8) ) { const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x); @@ -10262,12 +10343,16 @@ templates: } } - // TODO: draw background - for (uint8_t i = 0; i < 160; i++) { - // interim: set line to red - ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = 0xff; - ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = 0x00; - ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = 0x00; + if (ctx->gpu.lcdc & 1) { + for (uint8_t i = 0; i < 160; i++) { + // get pixel color + const uint8_t c = bg_get_color(ctx, ctx->gpu.line, i); + + // populate framebuffer + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = c; + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = c; + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = c; + } } // draw foreground sprites @@ -10277,12 +10362,11 @@ templates: !ctx->gpu.oam_cache[i].priority && // sprite is on screen - ctx->gpu.oam_cache[i].y < 144 && - ctx->gpu.oam_cache[i].x < 160 && + BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && + BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && // sprite is on current line - ctx->gpu.line >= ctx->gpu.oam_cache[i].y && - ctx->gpu.line <= ctx->gpu.oam_cache[i].y + BETWEEN(ctx->gpu.line, ctx->gpu.oam_cache[i].y, ctx->gpu.oam_cache[i].y + 8) ) { const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x); |