diff options
-rw-r--r-- | src/main.c | 14 | ||||
-rw-r--r-- | src/sequencer.c | 23 | ||||
-rw-r--r-- | src/text.h | 177 |
3 files changed, 153 insertions, 61 deletions
@@ -6,6 +6,7 @@ | |||
6 | #include "sprites.h" | 6 | #include "sprites.h" |
7 | #include "text.h" | 7 | #include "text.h" |
8 | #include "sequencer.c" | 8 | #include "sequencer.c" |
9 | #include "bd-font.c" | ||
9 | 10 | ||
10 | // | 11 | // |
11 | // Main functions. | 12 | // Main functions. |
@@ -14,14 +15,13 @@ | |||
14 | // TODO: Cleanup OBJ/OAM memory copying and access. | 15 | // TODO: Cleanup OBJ/OAM memory copying and access. |
15 | // | 16 | // |
16 | 17 | ||
17 | |||
18 | int main(void) { | 18 | int main(void) { |
19 | // Configure the display in mode 0 to show OBJs, where tile memory is | 19 | // Configure the display in mode 0 to show OBJs, where tile memory is |
20 | // sequential. | 20 | // sequential. |
21 | DISP_CTRL = DISP_ENABLE_SPRITES | DISP_MODE_3 | DISP_BG_2; | 21 | DISP_CTRL = DISP_ENABLE_SPRITES | DISP_MODE_3 | DISP_BG_2; |
22 | 22 | ||
23 | // Initialize text engine. | 23 | // Initialize text engine. |
24 | // txt_init(0, COLOR_RED, 0); | 24 | txt_init_bitmap(TXT_MODE_MODE3, (Font){.data = bd_font, .char_width = 6}); |
25 | 25 | ||
26 | // Register interrupts. | 26 | // Register interrupts. |
27 | irq_init(); | 27 | irq_init(); |
@@ -37,16 +37,6 @@ int main(void) { | |||
37 | handle_sequencer_input(); | 37 | handle_sequencer_input(); |
38 | update_sequencer_sprites(); | 38 | update_sequencer_sprites(); |
39 | render_sequencer_sprites(); | 39 | render_sequencer_sprites(); |
40 | |||
41 | // DEBUG: Output | ||
42 | // txt_position(1,0); | ||
43 | // txt_clear_line(); | ||
44 | // txt_printf(" BPM: %d\n\n", bpm); | ||
45 | |||
46 | // txt_clear_line(); | ||
47 | // txt_printf(" Step: %d\n", step_counter); | ||
48 | // txt_clear_line(); | ||
49 | // txt_printf(" Note: %s\n", note_names[active_note]); | ||
50 | }; | 40 | }; |
51 | 41 | ||
52 | return 0; | 42 | return 0; |
diff --git a/src/sequencer.c b/src/sequencer.c index c83fa5a..6f7dd21 100644 --- a/src/sequencer.c +++ b/src/sequencer.c | |||
@@ -537,7 +537,6 @@ typedef struct SeqSprite { | |||
537 | u16 obj_attr_2; | 537 | u16 obj_attr_2; |
538 | } SeqSprite; | 538 | } SeqSprite; |
539 | 539 | ||
540 | |||
541 | typedef enum { | 540 | typedef enum { |
542 | SEQ_SELECT_TRIGGER, | 541 | SEQ_SELECT_TRIGGER, |
543 | SEQ_SELECT_CHANNEL, | 542 | SEQ_SELECT_CHANNEL, |
@@ -1058,12 +1057,30 @@ update_sequencer_sprites(void) { | |||
1058 | int x = SEQ_ENV_POS_X + 8; | 1057 | int x = SEQ_ENV_POS_X + 8; |
1059 | int y = SEQ_ENV_POS_Y; | 1058 | int y = SEQ_ENV_POS_Y; |
1060 | 1059 | ||
1060 | draw_fill_rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_BLACK); | ||
1061 | |||
1061 | // Clear wave A and draw. | 1062 | // Clear wave A and draw. |
1062 | draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK); | 1063 | // draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK); |
1063 | draw_wave_pattern(wave_a, x, y, COLOR_RED); | 1064 | draw_wave_pattern(wave_a, x, y, COLOR_RED); |
1064 | 1065 | ||
1066 | // Write wave text. | ||
1067 | txt_position(x, y + 20); | ||
1068 | txt_printf("%02x%02x%02x%02x %02x%02x%02x%02x", | ||
1069 | wave_a[0], wave_a[1], wave_a[2], wave_a[3], | ||
1070 | wave_a[4], wave_a[5], wave_a[6], wave_a[7]); | ||
1071 | txt_position(x, y + 20 + 8); | ||
1072 | txt_printf("%02x%02x%02x%02x %02x%02x%02x%02x", | ||
1073 | wave_a[8], wave_a[9], wave_a[10], wave_a[11], | ||
1074 | wave_a[12], wave_a[13], wave_a[14], wave_a[15]); | ||
1075 | // txt_position(0,y + 20 + 8); | ||
1076 | // txt_printf("%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n", | ||
1077 | // wave_b[0], wave_b[1], wave_b[2], wave_b[3], | ||
1078 | // wave_b[4], wave_b[5], wave_b[6], wave_b[7], | ||
1079 | // wave_b[8], wave_b[9], wave_b[10], wave_b[11], | ||
1080 | // wave_b[12], wave_b[13], wave_b[14], wave_b[15]); | ||
1081 | |||
1065 | // Clear wave B and draw. | 1082 | // Clear wave B and draw. |
1066 | draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK); | 1083 | // draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK); |
1067 | draw_wave_pattern(wave_b, x + 64 + 16, y, COLOR_CYAN); | 1084 | draw_wave_pattern(wave_b, x + 64 + 16, y, COLOR_CYAN); |
1068 | } else if ((current_selection == SEQ_SELECT_TRIGGER | 1085 | } else if ((current_selection == SEQ_SELECT_TRIGGER |
1069 | || current_selection == SEQ_SELECT_PARAMETER) | 1086 | || current_selection == SEQ_SELECT_PARAMETER) |
@@ -5,7 +5,29 @@ | |||
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | 6 | ||
7 | #include "common.h" | 7 | #include "common.h" |
8 | #include "bd-font.c" | 8 | |
9 | typedef enum { | ||
10 | TXT_MODE_TILED_BG, | ||
11 | TXT_MODE_MODE3, | ||
12 | } TextMode; | ||
13 | |||
14 | typedef struct Font { | ||
15 | // A pointer to an area of memory containing font data. | ||
16 | // TODO: Should we unpack each char everytime or unpack everything into RAM? | ||
17 | // Maybe this should be optional? | ||
18 | u32 *data; | ||
19 | // The char_map stores the index to the character position within the font | ||
20 | // array depending on the ascii number we want to render. This allows | ||
21 | // the usage reduced font sets, for example just uppercase letters and | ||
22 | // numbers. | ||
23 | u8 *char_map; | ||
24 | // Width and height of each font character. Only monospaced fonts are | ||
25 | // currently supported. | ||
26 | u8 char_width; | ||
27 | u8 char_height; | ||
28 | // The color of this font. | ||
29 | Color color; | ||
30 | } Font; | ||
9 | 31 | ||
10 | typedef struct TextEngine { | 32 | typedef struct TextEngine { |
11 | // Currently working on tiled backgrounds only. The X and Y positions | 33 | // Currently working on tiled backgrounds only. The X and Y positions |
@@ -13,14 +35,26 @@ typedef struct TextEngine { | |||
13 | // For a 240x160 screen, we have 30x20 tiles available. | 35 | // For a 240x160 screen, we have 30x20 tiles available. |
14 | size_t cursor_x; | 36 | size_t cursor_x; |
15 | size_t cursor_y; | 37 | size_t cursor_y; |
16 | // Pointer to the screenblock being used for writing to the screen. | 38 | // Pointer to the memory being used for writing to the screen. |
17 | u16 *screenblock; | 39 | u16 *memory; |
40 | // TODO: Support other modes and monospaced fonts should be simple but we | ||
41 | // need to keep track of a couple of other variables, which may not be | ||
42 | // available for all modes. For example, tile modes can't have a font width | ||
43 | // smaller than the tile size, although bigger fonts (For example fonts | ||
44 | // composed of multiple tiles) should still be possible. This may not be | ||
45 | // a good time investment, but can be done in the future if needed. | ||
46 | // The mode controls how the text is rendered and how the memory is managed. | ||
47 | TextMode mode; | ||
48 | // The font used to render the text. | ||
49 | Font font; | ||
18 | } TextEngine; | 50 | } TextEngine; |
19 | 51 | ||
20 | static TextEngine text_engine = {0}; | 52 | static TextEngine text_engine = {0}; |
21 | 53 | ||
54 | static u8 default_char_map[256] = {0}; | ||
55 | |||
22 | void | 56 | void |
23 | txt_putc(char c) { | 57 | txt_putc_tile(char c) { |
24 | if (c == '\0') { | 58 | if (c == '\0') { |
25 | return; | 59 | return; |
26 | } | 60 | } |
@@ -28,7 +62,7 @@ txt_putc(char c) { | |||
28 | text_engine.cursor_x = 0; | 62 | text_engine.cursor_x = 0; |
29 | text_engine.cursor_y++; | 63 | text_engine.cursor_y++; |
30 | } else { | 64 | } else { |
31 | text_engine.screenblock[text_engine.cursor_x + 32 * text_engine.cursor_y] = c; | 65 | text_engine.memory[text_engine.cursor_x + 32 * text_engine.cursor_y] = c; |
32 | text_engine.cursor_x++; | 66 | text_engine.cursor_x++; |
33 | if (text_engine.cursor_x >= 30) { | 67 | if (text_engine.cursor_x >= 30) { |
34 | text_engine.cursor_x = 0; | 68 | text_engine.cursor_x = 0; |
@@ -40,6 +74,52 @@ txt_putc(char c) { | |||
40 | } | 74 | } |
41 | } | 75 | } |
42 | 76 | ||
77 | void | ||
78 | txt_putc_m3(char c) { | ||
79 | if (c == '\0') { | ||
80 | return; | ||
81 | } | ||
82 | if (c == '\n') { | ||
83 | text_engine.cursor_x = 0; | ||
84 | text_engine.cursor_y += text_engine.font.char_height; | ||
85 | } else { | ||
86 | u8 idx = text_engine.font.char_map[c] * 2; | ||
87 | u32 *packed_char = text_engine.font.data; | ||
88 | packed_char += idx; | ||
89 | Tile tile = {0}; | ||
90 | unpack_tiles(packed_char, &tile, 1); | ||
91 | int x = text_engine.cursor_x; | ||
92 | int y = text_engine.cursor_y; | ||
93 | for (size_t i = 0; i < text_engine.font.char_height; ++i) { | ||
94 | for (size_t j = 0; j < text_engine.font.char_width; ++j) { | ||
95 | if ((tile.row[i] >> 4 * j) & 0x1) { | ||
96 | FRAMEBUFFER[y + i][x + j] = text_engine.font.color; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | text_engine.cursor_x += text_engine.font.char_width; | ||
101 | if (text_engine.cursor_x >= SCREEN_WIDTH) { | ||
102 | text_engine.cursor_x = 0; | ||
103 | text_engine.cursor_y += text_engine.font.char_height; | ||
104 | } | ||
105 | } | ||
106 | if (text_engine.cursor_y >= SCREEN_HEIGHT) { | ||
107 | text_engine.cursor_y = 0; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void | ||
112 | txt_putc(char c) { | ||
113 | switch (text_engine.mode) { | ||
114 | case TXT_MODE_TILED_BG: { | ||
115 | txt_putc_tile(c); | ||
116 | } break; | ||
117 | case TXT_MODE_MODE3: { | ||
118 | txt_putc_m3(c); | ||
119 | } break; | ||
120 | } | ||
121 | } | ||
122 | |||
43 | static inline void | 123 | static inline void |
44 | txt_puts(char *msg) { | 124 | txt_puts(char *msg) { |
45 | while (*msg) { | 125 | while (*msg) { |
@@ -48,7 +128,7 @@ txt_puts(char *msg) { | |||
48 | } | 128 | } |
49 | 129 | ||
50 | void | 130 | void |
51 | txt_init(size_t bg, Color clr, size_t cb_idx) { | 131 | txt_init_tile(size_t bg, Font font, size_t cb_idx) { |
52 | // The screenblock for the tile map should start after the tile memory | 132 | // The screenblock for the tile map should start after the tile memory |
53 | // (MEM_VRAM + 0x2000 for 256 characters). Since each screenblock is | 133 | // (MEM_VRAM + 0x2000 for 256 characters). Since each screenblock is |
54 | // composed of 1024 screenblock entries of u16 (2 bytes), we need an | 134 | // composed of 1024 screenblock entries of u16 (2 bytes), we need an |
@@ -61,13 +141,48 @@ txt_init(size_t bg, Color clr, size_t cb_idx) { | |||
61 | // Load font data in video memory. Each character is unpacked into a tile of | 141 | // Load font data in video memory. Each character is unpacked into a tile of |
62 | // 8 32bit values (4bpp), meaning that for the full ASCII set of 256 | 142 | // 8 32bit values (4bpp), meaning that for the full ASCII set of 256 |
63 | // characters, we need 8192 bytes of VRAM (8 * 4 * 256). | 143 | // characters, we need 8192 bytes of VRAM (8 * 4 * 256). |
64 | unpack_tiles(&bd_font, &TILE_MEM[cb_idx], 256); | 144 | text_engine.font = font; |
145 | unpack_tiles(font.data, &TILE_MEM[cb_idx], 256); | ||
146 | |||
147 | // Initialize default values. | ||
148 | if (font.color == 0) { | ||
149 | font.color = COLOR_WHITE; | ||
150 | } | ||
65 | 151 | ||
66 | // Load palette color. | 152 | // Load palette color. |
67 | PAL_BUFFER_BG[1] = clr; | 153 | PAL_BUFFER_BG[1] = font.color; |
68 | 154 | ||
69 | // Update text_engine variables. | 155 | // Update text_engine variables. |
70 | text_engine.screenblock = SCREENBLOCK_MEM[sb_idx]; | 156 | text_engine.memory = SCREENBLOCK_MEM[sb_idx]; |
157 | } | ||
158 | |||
159 | void | ||
160 | txt_init_bitmap(TextMode mode, Font font) { | ||
161 | // NOTE: Only mode 3 is currently supported | ||
162 | assert(mode == TXT_MODE_MODE3); | ||
163 | |||
164 | // If font_map is NULL, initialize the standard 0-255 character map. | ||
165 | if (font.char_map == NULL) { | ||
166 | for (size_t i = 0; i < 256; ++i) { | ||
167 | default_char_map[i] = i; | ||
168 | } | ||
169 | font.char_map = &default_char_map; | ||
170 | } | ||
171 | |||
172 | // Initialize default values if set to zero. | ||
173 | if (font.char_width == 0) { | ||
174 | font.char_width = 8; | ||
175 | } | ||
176 | if (font.char_height == 0) { | ||
177 | font.char_height = 8; | ||
178 | } | ||
179 | if (font.color == 0) { | ||
180 | font.color = COLOR_WHITE; | ||
181 | } | ||
182 | |||
183 | // Prepare text engine. | ||
184 | text_engine.font = font; | ||
185 | text_engine.mode = mode; | ||
71 | } | 186 | } |
72 | 187 | ||
73 | // Print text to the screen with formatting. | 188 | // Print text to the screen with formatting. |
@@ -75,56 +190,26 @@ void | |||
75 | txt_printf(char *msg, ...) { | 190 | txt_printf(char *msg, ...) { |
76 | va_list arg_list; | 191 | va_list arg_list; |
77 | va_start(arg_list, msg); | 192 | va_start(arg_list, msg); |
78 | char c; | 193 | char buf[512] = {0}; |
79 | while ((c = *msg++) != '\0') { | 194 | vsprintf(buf, msg, arg_list); |
80 | if (c != '%') { | 195 | txt_puts(buf); |
81 | txt_putc(c); | ||
82 | continue; | ||
83 | } | ||
84 | c = *msg++; | ||
85 | switch (c) { | ||
86 | case 's': { | ||
87 | txt_puts(va_arg(arg_list, char *)); | ||
88 | } break; | ||
89 | case 'd': { | ||
90 | char buf[12] = {0}; | ||
91 | int x = va_arg(arg_list, int); | ||
92 | sprintf(buf, "%d", x); | ||
93 | txt_puts(buf); | ||
94 | } break; | ||
95 | case 'u': { | ||
96 | char buf[12] = {0}; | ||
97 | unsigned int x = va_arg(arg_list, unsigned int); | ||
98 | sprintf(buf, "%u", x); | ||
99 | txt_puts(buf); | ||
100 | } break; | ||
101 | case 'x': { | ||
102 | char buf[12] = {0}; | ||
103 | unsigned int x = va_arg(arg_list, unsigned int); | ||
104 | sprintf(buf, "%x", x); | ||
105 | txt_puts(buf); | ||
106 | } break; | ||
107 | default: { | ||
108 | txt_putc('%'); | ||
109 | txt_putc(c); | ||
110 | } break; | ||
111 | } | ||
112 | } | ||
113 | } | 196 | } |
114 | 197 | ||
198 | // TODO: Update for working on bitmap modes. | ||
115 | void | 199 | void |
116 | txt_clear_line(void) { | 200 | txt_clear_line(void) { |
117 | for (size_t i = 0; i < 30; ++i) { | 201 | for (size_t i = 0; i < 30; ++i) { |
118 | text_engine.screenblock[i + 32 * text_engine.cursor_y] = ' '; | 202 | text_engine.memory[i + 32 * text_engine.cursor_y] = ' '; |
119 | } | 203 | } |
120 | text_engine.cursor_x = 0; | 204 | text_engine.cursor_x = 0; |
121 | } | 205 | } |
122 | 206 | ||
207 | // TODO: Update for working on bitmap modes. | ||
123 | void | 208 | void |
124 | txt_clear_screen(void) { | 209 | txt_clear_screen(void) { |
125 | for (size_t j = 0; j < 20; ++j) { | 210 | for (size_t j = 0; j < 20; ++j) { |
126 | for (size_t i = 0; i < 30; ++i) { | 211 | for (size_t i = 0; i < 30; ++i) { |
127 | text_engine.screenblock[i + 32 * j] = ' '; | 212 | text_engine.memory[i + 32 * j] = ' '; |
128 | } | 213 | } |
129 | } | 214 | } |
130 | text_engine.cursor_x = 0; | 215 | text_engine.cursor_x = 0; |