summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-27 21:16:17 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-27 21:16:17 -0400
commit0448ec0a87f8688d93be38e5a92de79cbc672017 (patch)
treebbf98f2519f00239aec3b6e1959a8b0e95fba210
parent3da68a59dffec91cb832d8b2f1d703ed2004f28f (diff)
downloadgb-c-0448ec0a87f8688d93be38e5a92de79cbc672017.tar.bz2
gb-c-0448ec0a87f8688d93be38e5a92de79cbc672017.zip
add gpu_draw_objs()
-rw-r--r--ops.yaml143
1 files changed, 94 insertions, 49 deletions
diff --git a/ops.yaml b/ops.yaml
index a88e9e4..0c50cee 100644
--- a/ops.yaml
+++ b/ops.yaml
@@ -10247,6 +10247,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,
const uint8_t ty,
@@ -10311,41 +10321,97 @@ templates:
}
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
) {
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