#ifndef TEXT_H #define TEXT_H #include "posprintf.h" typedef void (*TxtDrawc)(char c, size_t x, size_t y, u8 clr); typedef struct TextEngine { // Cursor for tiled text mode 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; u8 buffer[30 * 20]; u8 spacing; u8 color; TxtDrawc drawc; } TextEngine; static TextEngine text_engine = {0}; // Initializes the text engine. static inline void txt_init(TxtDrawc drawc) { // Initialize remaining variables. text_engine.spacing = 8; text_engine.color = 1; text_engine.drawc = drawc; } // Writes a message to the tile text background. static inline void txt_puts(char *msg) { while (*msg) { char c = *msg++; if (c == '\0') { continue; } if (c == '\n') { text_engine.cursor_x = 0; text_engine.cursor_y++; } else { int x = text_engine.cursor_x; int y = text_engine.cursor_y; text_engine.buffer[x + 30 * y] = c; text_engine.cursor_x += 1; 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; } } } // Clears the current line on the tile text mode. static inline void txt_clear_line(void) { dma_fill(text_engine.buffer, 0, sizeof(text_engine.buffer), 3); text_engine.cursor_x = 0; text_engine.cursor_y = 0; } // Clears the screen on the tile text mode. static inline void txt_clear(void) { for (size_t j = 0; j < 20; ++j) { text_engine.cursor_y = j; txt_clear_line(); } text_engine.cursor_x = 0; text_engine.cursor_y = 0; } // Moves the tile mode cursor to the specified position. static inline void txt_position(size_t tile_x, size_t tile_y) { text_engine.cursor_x = tile_x; text_engine.cursor_y = tile_y; } static inline void txt_color(u8 clr) { text_engine.color = clr; } static inline void txt_spacing(u8 spacing) { text_engine.spacing = spacing; } // Renders the contents of the scrollback buffer to the screen. void txt_render(void) { for (size_t y = 0; y < 20; y++) { for (size_t x = 0; x < 30; x++) { size_t pos = x + y * 30; if (text_engine.buffer[pos] == 0) { continue; } text_engine.drawc( text_engine.buffer[pos], x * text_engine.spacing, y * text_engine.spacing, text_engine.color); } } } // Draws a message where the first character's top-left corner begins at the // given x and y position. The character spacing can be adjusted, but beware of // color merging issues. static inline void txt_draws(char *msg, size_t x, size_t y, u8 clr) { size_t i = 0; while (*msg) { char c = *msg++; text_engine.drawc(c, x + i++ * text_engine.spacing, y, clr); } } // Print text to the screen with formatting. #define txt_printf(msg, ...) \ { \ char buf[256] = {0}; \ posprintf(buf, msg, ##__VA_ARGS__); \ txt_puts(buf); \ } // Draws text to the screen with formatting starting on the x and y position and // with custom character spacing. #define txt_drawf(msg, x, y, c, ...) \ { \ char buf[256] = {0}; \ posprintf(buf, msg, ##__VA_ARGS__); \ txt_draws(buf, x, y, c); \ } #endif // TEXT_H