diff options
Diffstat (limited to 'src/text.h')
-rw-r--r-- | src/text.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/text.h b/src/text.h new file mode 100644 index 0000000..e38c220 --- /dev/null +++ b/src/text.h | |||
@@ -0,0 +1,142 @@ | |||
1 | #ifndef GBAEXP_TILES_H | ||
2 | #define GBAEXP_TILES_H | ||
3 | |||
4 | #include <stdarg.h> | ||
5 | |||
6 | #include "common.h" | ||
7 | #include "bd-font.c" | ||
8 | |||
9 | typedef struct TextEngine { | ||
10 | // Currently working on tiled backgrounds only. The X and Y positions | ||
11 | // correspond to the tile X and Y starting from the top left of the screen. | ||
12 | // For a 240x160 screen, we have 30x20 tiles available. | ||
13 | size_t cursor_x; | ||
14 | size_t cursor_y; | ||
15 | // Pointer to the screenblock being used for writing to the screen. | ||
16 | u16 *screenblock; | ||
17 | } TextEngine; | ||
18 | |||
19 | static TextEngine text_engine = {0}; | ||
20 | |||
21 | void | ||
22 | txt_putc(char c) { | ||
23 | if (c == '\0') { | ||
24 | return; | ||
25 | } | ||
26 | if (c == '\n') { | ||
27 | text_engine.cursor_x = 0; | ||
28 | text_engine.cursor_y++; | ||
29 | } else { | ||
30 | text_engine.screenblock[text_engine.cursor_x + 32 * text_engine.cursor_y] = c; | ||
31 | text_engine.cursor_x++; | ||
32 | if (text_engine.cursor_x >= 30) { | ||
33 | text_engine.cursor_x = 0; | ||
34 | text_engine.cursor_y++; | ||
35 | } | ||
36 | } | ||
37 | if (text_engine.cursor_y >= 20) { | ||
38 | text_engine.cursor_y = 0; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static inline void | ||
43 | txt_puts(char *msg) { | ||
44 | while (*msg) { | ||
45 | txt_putc(*msg++); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | void | ||
50 | txt_init(size_t bg, Color clr, size_t cb_idx) { | ||
51 | // The screenblock for the tile map should start after the tile memory | ||
52 | // (MEM_VRAM + 0x2000 for 256 characters). Since each screenblock is | ||
53 | // composed of 1024 screenblock entries of u16 (2 bytes), we need an | ||
54 | // screenblock index offset of 8192 / (1024 * 2) = 4 screen blocks. | ||
55 | size_t sb_idx = cb_idx * 8 + 4; | ||
56 | |||
57 | // Set the background parameters for the text layer. | ||
58 | BG_CTRL(bg) = BG_CHARBLOCK(cb_idx) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(3); | ||
59 | |||
60 | // Load font data in video memory. Each character is unpacked into a tile of | ||
61 | // 8 32bit values (4bpp), meaning that for the full ASCII set of 256 | ||
62 | // characters, we need 8192 bytes of VRAM (8 * 4 * 256). | ||
63 | unpack_tiles(&bd_font, &CHARBLOCK_MEM[cb_idx], 256); | ||
64 | |||
65 | // Load palette color. | ||
66 | PAL_BUFFER_BG[1] = clr; | ||
67 | |||
68 | // Update text_engine variables. | ||
69 | text_engine.screenblock = SCREENBLOCK_MEM[sb_idx]; | ||
70 | } | ||
71 | |||
72 | // Print text to the screen with formatting. | ||
73 | void | ||
74 | txt_printf(char *msg, ...) { | ||
75 | va_list arg_list; | ||
76 | va_start(arg_list, msg); | ||
77 | char c; | ||
78 | char prev_c; | ||
79 | while ((c = *msg++) != '\0') { | ||
80 | if (c != '%') { | ||
81 | txt_putc(c); | ||
82 | prev_c = c; | ||
83 | continue; | ||
84 | } | ||
85 | c = *msg++; | ||
86 | switch (c) { | ||
87 | case 's': { | ||
88 | txt_puts(va_arg(arg_list, char *)); | ||
89 | } break; | ||
90 | case 'd': { | ||
91 | char buf[32] = {0}; | ||
92 | int x = va_arg(arg_list, int); | ||
93 | sprintf(buf, "%d", x); | ||
94 | txt_puts(buf); | ||
95 | } break; | ||
96 | case 'u': { | ||
97 | char buf[32] = {0}; | ||
98 | unsigned int x = va_arg(arg_list, unsigned int); | ||
99 | sprintf(buf, "%u", x); | ||
100 | txt_puts(buf); | ||
101 | } break; | ||
102 | case 'x': { | ||
103 | char buf[32] = {0}; | ||
104 | unsigned int x = va_arg(arg_list, unsigned int); | ||
105 | sprintf(buf, "%x", x); | ||
106 | txt_puts(buf); | ||
107 | } break; | ||
108 | default: { | ||
109 | txt_putc('%'); | ||
110 | txt_putc(c); | ||
111 | } break; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void | ||
117 | txt_clear_line(void) { | ||
118 | for (size_t i = 0; i < 30; ++i) { | ||
119 | text_engine.screenblock[i + 32 * text_engine.cursor_y] = ' '; | ||
120 | } | ||
121 | text_engine.cursor_x = 0; | ||
122 | } | ||
123 | |||
124 | void | ||
125 | txt_clear_screen(void) { | ||
126 | for (size_t j = 0; j < 20; ++j) { | ||
127 | for (size_t i = 0; i < 30; ++i) { | ||
128 | text_engine.screenblock[i + 32 * j] = ' '; | ||
129 | } | ||
130 | } | ||
131 | text_engine.cursor_x = 0; | ||
132 | text_engine.cursor_y = 0; | ||
133 | } | ||
134 | |||
135 | void | ||
136 | txt_position(size_t tile_x, size_t tile_y) { | ||
137 | text_engine.cursor_x = tile_x; | ||
138 | text_engine.cursor_y = tile_y; | ||
139 | } | ||
140 | |||
141 | #endif // GBAEXP_TILES_H | ||
142 | |||