#include "bd-font.c" // The frontbuffer is located at the beginning of the VRAM, and requires 20KB of // video memory for 32 * 20 tiles at 4bpp. #define FRONTBUF ((u32*)(MEM_VRAM)) // Adjust both of these if the location of the map changes. Each screnblock // requires less than 2KB. #define FRONTBUF_TILEMAP ((u16*)(MEM_VRAM + KB(20))) #define FRONTBUF_SB 10 // The backbuffer is located at the end of the VRAM. This can allow us to use // more backgrounds but eats into the available memory for sprites. This should // be fine for non sprite intensive applications. If more sprite memory is // needed, the backbuffer can be located at the end of the background memory // instead (64KB - 20KB). #define BACKBUF ((u32*)(MEM_VRAM + KB(96) - KB(20))) // The font data is located at the end of the frontbuffer memory, after the tile // map and requires 8KB for 256 8x8 characters at 4bpp. This, along with the // tilemap information allow us to store the frontbuffer and font for a text // background in the first 2 charblocks (32KB). #define FONT_DATA ((u32*)(MEM_VRAM + KB(22))) #define FONT_TILEMAP ((u16*)(MEM_VRAM + KB(30))) #define FONT_SB 15 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); BACKBUF[pos] = (BACKBUF[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 = FRONTBUF; Tile *src = BACKBUF; 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; } } static u16 font_map[256] = {0}; void renderer_init(void) { // Initialize display mode and bg palette. DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_BG_1 | DISP_OBJ; // Initialize backgrounds. BG_CTRL(0) = BG_CHARBLOCK(0) | BG_SCREENBLOCK(FRONTBUF_SB) | BG_PRIORITY(1); BG_CTRL(1) = BG_CHARBLOCK(1) | BG_SCREENBLOCK(FONT_SB) | BG_PRIORITY(0); // Use DMA to clear front and back buffers as well as the font memory map. dma_fill(FRONTBUF, 0, KB(20), 3); dma_fill(FRONTBUF_TILEMAP, 0, KB(2), 3); dma_fill(FONT_DATA, 0, KB(8), 3); dma_fill(FONT_TILEMAP, 0, KB(2), 3); dma_fill(BACKBUF, 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 frontbuffer and font backgorund. for (size_t i = 0; i < 32 * 20; ++i) { FRONTBUF_TILEMAP[i] = i; } // Load font data into VRAM. unpack_tiles(&bd_font, FONT_DATA, 256); // Initialize the font map translation table. That way we can write // a character on the text background layer with: // FONT_TILEMAP[tile_x + 32 * tile_y] = font_map['A']; for (size_t i = 0; i < 256; ++i) { font_map[i] = 192 + i; } }