From f6686f1e86927f038086023362251ebe78ce5ad6 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 2 Jun 2021 17:26:08 +0200 Subject: Init repo with basic BG framebuffer renderer --- src/renderer.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/renderer.c (limited to 'src/renderer.c') diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..9fe55b2 --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,86 @@ +// TODO: For now we pack front/backbuffers together but this make it so that we +// can only use 2 backgrounds. Instead we can move the backbuffer to the end of +// the VRAM. This will give us 3 backgrounds but eats into the available memory +// for sprites but should be fine for non sprite intensive applications. +#define FRONTBUFFER ((u32*)(MEM_VRAM)) +#define BACKBUFFER ((u32*)(MEM_VRAM + KB(96) - KB(20))) + +// Adjust both of these if the location of the map changes. Each screnblock +// requires 2K. +#define FRONTBUFFER_TILEMAP ((u16*)(MEM_VRAM + KB(20))) +#define FRONTBUFFER_SCREENBLOCK 10 + +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; + +IWRAM_CODE +void +draw_pixel(u16 x, u16 y, u8 color) { + BOUNDCHECK_SCREEN(); + + // 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; + size_t pos = start_row + (tile_x + tile_y * 32) * 8; + + // Update backbuffer. + size_t shift = start_col * sizeof(u32); + BACKBUFFER[pos] = (BACKBUFFER[pos] & ~(0xF << shift)) | color << shift; + + // Mark tile as dirty. + dirty_tiles[tile_y] |= 1 << tile_x; +} + +IWRAM_CODE +void +flip_buffer(void) { + // Copy dirty tiles from the backbuffer to the frontbuffer. + Tile *dst = FRONTBUFFER; + Tile *src = BACKBUFFER; + for (size_t j = 0; j < 20; ++j) { + if (dirty_tiles[j] == 0) { + continue; + } + for (size_t i = 0, k = 1; i < 30; ++i, k <<= 1) { + if (dirty_tiles[j] & k) { + dst[i + j * 32] = src[i + j * 32]; + } + } + dirty_tiles[j] = 0; + } +} + +void +renderer_init(void) { + // Initialize display mode and bg palette. + DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_OBJ; + + // Initialize backgrounds. + BG_CTRL(0) = BG_CHARBLOCK(0) | BG_SCREENBLOCK(FRONTBUFFER_SCREENBLOCK); + + // TODO: Initialize other backgrounds if needed. + + // Use DMA to clear front and back buffers. + dma_fill(FRONTBUFFER, 0, KB(20), 3); + dma_fill(BACKBUFFER, 0, KB(20), 3); + + // Initialize default palette. + PAL_BUFFER_BG[0] = COLOR_BLACK; + PAL_BUFFER_BG[1] = COLOR_WHITE; + PAL_BUFFER_BG[2] = COLOR_RED; + PAL_BUFFER_BG[3] = COLOR_BLUE; + PAL_BUFFER_BG[4] = COLOR_CYAN; + PAL_BUFFER_BG[5] = COLOR_GREY; + + // Initialize background memory map. + for (size_t i = 0; i < 32 * 20; ++i) { + FRONTBUFFER_TILEMAP[i] = i; + } + +// // Load font data into VRAM. +// unpack_tiles(&bd_font, FONT_DATA, 256); +} -- cgit v1.2.1