// 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); }