From 0448ec0a87f8688d93be38e5a92de79cbc672017 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Wed, 27 Jun 2018 21:16:17 -0400 Subject: add gpu_draw_objs() --- ops.yaml | 143 +++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 94 insertions(+), 49 deletions(-) diff --git a/ops.yaml b/ops.yaml index a88e9e4..0c50cee 100644 --- a/ops.yaml +++ b/ops.yaml @@ -10246,6 +10246,16 @@ templates: )); } + static uint16_t + obj_get_tile_addr( + gb_t * const ctx, + const uint8_t tile + ) { + UNUSED(ctx); + // base: 0x8000, tile is unsigned + return 0x8000 + 16 * tile; + } + static uint16_t bg_get_tile_addr( gb_t * const ctx, @@ -10310,6 +10320,82 @@ templates: return 0xA0; } + static void + gpu_draw_objs( + gb_t * const ctx, + const bool priority + ) { + for (uint8_t i = 0; i < 40; i++) { + if ( + // sprite has correct priority + (ctx->gpu.oam_cache[i].priority == priority) && + + // sprite is on screen and visible + BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && + BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && + + // sprite is on current line + BETWEEN(ctx->gpu.line, ctx->gpu.oam_cache[i].y, ctx->gpu.oam_cache[i].y + 8) + ) { + // get tile row data + const uint16_t row = mmu_rw(ctx, ( + // get tile data address + obj_get_tile_addr(ctx, ctx->gpu.oam_cache[i].tile) + + + // calculate row offset within tile data + (2 * (ctx->gpu.line - ctx->gpu.oam_cache[i].y)) + )); + + for (uint8_t j = 0; j < 8; j++) { + const int16_t sx = ctx->gpu.oam_cache[i].x + j; + + if (BETWEEN(sx, 0, 160)) { + // get palette offset for pixel + const uint8_t p_ofs = ( + ((row >> (8 + (7 - j)) & 0x01) << 1) | + ((row >> (7 - j)) & 0x01) + ); + + // get pixel color + if (p_ofs > 0) { + // get object palette + const uint8_t obp = ((ctx->gpu.oam_cache[i].palette) ? ctx->gpu.obp1 : ctx->gpu.obp0); + // get pixel color + const uint8_t pc = (obp >> (2 * p_ofs)) & 0x03; + + // calculate framebuffer offset + const uint16_t fb_ofs = 3 * (160 * ctx->gpu.line + sx); + + // convert from 0-3 to RGB + switch (pc) { + case 0: + ctx->gpu.fb[fb_ofs + 0] = 0xFF; + ctx->gpu.fb[fb_ofs + 1] = 0xFF; + ctx->gpu.fb[fb_ofs + 2] = 0xFF; + break; + case 1: + ctx->gpu.fb[fb_ofs + 0] = 0xC0; + ctx->gpu.fb[fb_ofs + 1] = 0xC0; + ctx->gpu.fb[fb_ofs + 2] = 0xC0; + break; + case 2: + ctx->gpu.fb[fb_ofs + 0] = 0x40; + ctx->gpu.fb[fb_ofs + 1] = 0x40; + ctx->gpu.fb[fb_ofs + 2] = 0x40; + break; + case 3: + ctx->gpu.fb[fb_ofs + 0] = 0x00; + ctx->gpu.fb[fb_ofs + 1] = 0x00; + ctx->gpu.fb[fb_ofs + 2] = 0x00; + break; + } + } + } + } + } + } + } + static void gpu_draw_line( gb_t * const ctx @@ -10317,35 +10403,15 @@ templates: if (gpu_is_active(ctx)) { gpu_oam_cache(ctx); - // draw sprites behind bg - for (uint8_t i = 0; i < 40; i++) { - if ( - // sprite is below bg - ctx->gpu.oam_cache[i].priority && - - // sprite is on screen - BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && - BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && - - // sprite is on current line - 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); - - for (uint8_t j = 0; j < max_j; j++) { - const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j); - - // TODO: draw sprite scanline - ctx->gpu.fb[ofs + 0] = 0xff; - ctx->gpu.fb[ofs + 1] = 0xff; - ctx->gpu.fb[ofs + 2] = 0xff; - } - } + if (ctx->gpu.lcdc & (1 << 1)) { + // obj display is on, draw bg sprites + gpu_draw_objs(ctx, true); } if (ctx->gpu.lcdc & 1) { + // draw backgrond for (uint8_t i = 0; i < 160; i++) { - // get pixel color + // get bg pixel color const uint8_t c = bg_get_color(ctx, ctx->gpu.line, i); // populate framebuffer @@ -10355,30 +10421,9 @@ templates: } } - // draw foreground sprites - for (uint8_t i = 0; i < 40; i++) { - if ( - // sprite is above bg - !ctx->gpu.oam_cache[i].priority && - - // sprite is on screen - BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && - BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && - - // sprite is on current line - 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); - - for (int j = 0; j < max_j; j++) { - const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j); - - // TODO: draw sprite scanline - ctx->gpu.fb[ofs + 0] = 0xff; - ctx->gpu.fb[ofs + 1] = 0xff; - ctx->gpu.fb[ofs + 2] = 0xff; - } - } + if (ctx->gpu.lcdc & (1 << 1)) { + // obj display is on, draw fg sprites + gpu_draw_objs(ctx, false); } } else { // write blank line -- cgit v1.2.3