From 5ca4491aa46b7090189685fecf422ee7316de724 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 3 Jun 2021 15:07:53 +0200 Subject: Add tile drawing function for the framebuffer --- src/renderer.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) (limited to 'src/renderer.c') diff --git a/src/renderer.c b/src/renderer.c index bd2c023..500cc78 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -46,12 +46,12 @@ static u32 dirty_tiles[21] = {0}; // TODO: Allow disable bound checking at compile time. -#define BOUNDCHECK_SCREEN() if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; +#define BOUNDCHECK_SCREEN(X,Y) if ((X) >= SCREEN_WIDTH || (Y) >= SCREEN_HEIGHT) return; IWRAM_CODE void draw_pixel(u16 x, u16 y, u8 color) { - BOUNDCHECK_SCREEN(); + BOUNDCHECK_SCREEN(x, y); // Find row position for the given x/y coordinates. size_t tile_x = x / 8; @@ -68,6 +68,78 @@ draw_pixel(u16 x, u16 y, u8 color) { dirty_tiles[tile_y] |= 1 << tile_x; } +IWRAM_CODE +void +draw_tile(u16 x, u16 y, Tile *tile, bool merge) { + BOUNDCHECK_SCREEN(x, y); + + // Find row position for the given x/y coordinates. + size_t tile_x = x / 8; + size_t tile_y = y / 8; + size_t start_col = x % 8; + size_t start_row = y % 8; + + // Get a pointer to the backbuffer and the tile row. + size_t pos = start_row + (tile_x + tile_y * 32) * 8; + u32 *backbuffer = &BACKBUF[pos]; + u32 *row = tile; + + // This will blend all colors weirdly if using tiles that contain colors + // higher than 1. + size_t shift_left = start_col * 4; + size_t shift_right = (8 - start_col) * 4; + u32 row_mask = merge ? 0 : 0xFFFFFFFF << shift_left; + + // Draw the tiles. There are 4 possible cases: + // 1. The tile is exactly at the tile boundary. + // 2. The tile spans 2 tiles horizontally. + // 3. The tile spans 2 tiles vertically. + // 4. The tile spans 4 tiles. + if (start_col == 0 && start_row == 0) { + for (size_t i = 0; i < (8 - start_row); i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | row[i]; + } + dirty_tiles[tile_y] |= 1 << tile_x; + } else if (start_row == 0) { + for (size_t i = 0; i < 8; i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | (row[i] << shift_left); + backbuffer[8] = (backbuffer[8] & row_mask) | (row[i] >> shift_right); + } + dirty_tiles[tile_y] |= 1 << tile_x; + dirty_tiles[tile_y] |= 1 << (tile_x + 1); + } else if (start_col == 0) { + for (size_t i = 0; i < (8 - start_row); i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | row[i]; + } + backbuffer += 8 * 31; + for (size_t i = (8 - start_row); i < 8; i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | row[i]; + } + dirty_tiles[tile_y] |= 1 << tile_x; + dirty_tiles[tile_y + 1] |= 1 << tile_x; + } else { + for (size_t i = 0; i < (8 - start_row); i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | (row[i] << shift_left); + backbuffer[8] = (backbuffer[8] & row_mask) | (row[i] >> shift_right); + } + backbuffer += 8 * 31; + for (size_t i = (8 - start_row); i < 8; i++, backbuffer++) { + BOUNDCHECK_SCREEN(x, y + i); + backbuffer[0] = (backbuffer[0] & ~row_mask) | (row[i] << shift_left); + backbuffer[8] = (backbuffer[8] & row_mask) | (row[i] >> shift_right); + } + dirty_tiles[tile_y] |= 1 << tile_x; + dirty_tiles[tile_y] |= 1 << (tile_x + 1); + dirty_tiles[tile_y + 1] |= 1 << tile_x; + dirty_tiles[tile_y + 1] |= 1 << (tile_x + 1); + } +} + IWRAM_CODE void flip_buffer(void) { -- cgit v1.2.1