#ifndef GBAEXP_TILES_H #define GBAEXP_TILES_H #include #include "common.h" #include "bd-font.c" typedef struct TextEngine { // Currently working on tiled backgrounds only. The X and Y positions // correspond to the tile X and Y starting from the top left of the screen. // For a 240x160 screen, we have 30x20 tiles available. size_t cursor_x; size_t cursor_y; // Pointer to the screenblock being used for writing to the screen. u16 *screenblock; } TextEngine; static TextEngine text_engine = {0}; void txt_putc(char c) { if (c == '\0') { return; } if (c == '\n') { text_engine.cursor_x = 0; text_engine.cursor_y++; } else { text_engine.screenblock[text_engine.cursor_x + 32 * text_engine.cursor_y] = c; text_engine.cursor_x++; if (text_engine.cursor_x >= 30) { text_engine.cursor_x = 0; text_engine.cursor_y++; } } if (text_engine.cursor_y >= 20) { text_engine.cursor_y = 0; } } static inline void txt_puts(char *msg) { while (*msg) { txt_putc(*msg++); } } void txt_init(size_t bg, Color clr, size_t cb_idx) { // The screenblock for the tile map should start after the tile memory // (MEM_VRAM + 0x2000 for 256 characters). Since each screenblock is // composed of 1024 screenblock entries of u16 (2 bytes), we need an // screenblock index offset of 8192 / (1024 * 2) = 4 screen blocks. size_t sb_idx = cb_idx * 8 + 4; // Set the background parameters for the text layer. BG_CTRL(bg) = BG_CHARBLOCK(cb_idx) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(3); // Load font data in video memory. Each character is unpacked into a tile of // 8 32bit values (4bpp), meaning that for the full ASCII set of 256 // characters, we need 8192 bytes of VRAM (8 * 4 * 256). unpack_tiles(&bd_font, &CHARBLOCK_MEM[cb_idx], 256); // Load palette color. PAL_BUFFER_BG[1] = clr; // Update text_engine variables. text_engine.screenblock = SCREENBLOCK_MEM[sb_idx]; } // Print text to the screen with formatting. void txt_printf(char *msg, ...) { va_list arg_list; va_start(arg_list, msg); char c; char prev_c; while ((c = *msg++) != '\0') { if (c != '%') { txt_putc(c); prev_c = c; continue; } c = *msg++; switch (c) { case 's': { txt_puts(va_arg(arg_list, char *)); } break; case 'd': { char buf[32] = {0}; int x = va_arg(arg_list, int); sprintf(buf, "%d", x); txt_puts(buf); } break; case 'u': { char buf[32] = {0}; unsigned int x = va_arg(arg_list, unsigned int); sprintf(buf, "%u", x); txt_puts(buf); } break; case 'x': { char buf[32] = {0}; unsigned int x = va_arg(arg_list, unsigned int); sprintf(buf, "%x", x); txt_puts(buf); } break; default: { txt_putc('%'); txt_putc(c); } break; } } } void txt_clear_line(void) { for (size_t i = 0; i < 30; ++i) { text_engine.screenblock[i + 32 * text_engine.cursor_y] = ' '; } text_engine.cursor_x = 0; } void txt_clear_screen(void) { for (size_t j = 0; j < 20; ++j) { for (size_t i = 0; i < 30; ++i) { text_engine.screenblock[i + 32 * j] = ' '; } } text_engine.cursor_x = 0; text_engine.cursor_y = 0; } void txt_position(size_t tile_x, size_t tile_y) { text_engine.cursor_x = tile_x; text_engine.cursor_y = tile_y; } #endif // GBAEXP_TILES_H