diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 34 | ||||
-rw-r--r-- | src/profiling.c | 106 | ||||
-rw-r--r-- | src/renderer.h | 45 | ||||
-rw-r--r-- | src/renderer_m0.c | 811 | ||||
-rw-r--r-- | src/sequencer.c | 94 | ||||
-rw-r--r-- | src/text/font.h | 131 | ||||
-rw-r--r-- | src/text/text.h | 115 |
7 files changed, 1122 insertions, 214 deletions
@@ -12,17 +12,33 @@ WITH REGARD TO THIS SOFTWARE. | |||
12 | #include "gba/gba.h" | 12 | #include "gba/gba.h" |
13 | 13 | ||
14 | #include "filesystem.c" | 14 | #include "filesystem.c" |
15 | #include "renderer.c" | 15 | #include "renderer_m0.c" |
16 | #include "sequencer.c" | 16 | #include "sequencer.c" |
17 | 17 | ||
18 | #define PROF_ENABLE 0 | 18 | #define PROF_ENABLE 1 |
19 | #include "profiling.c" | 19 | #include "profiling.c" |
20 | 20 | ||
21 | // | ||
22 | // Config parameters. | ||
23 | // | ||
24 | 21 | ||
25 | int main(void) { | 22 | void |
23 | render(void) { | ||
24 | PROF(screen_fill(0), clear_cycles); | ||
25 | PROF(draw_triggers(), draw_trigs_cycles); | ||
26 | PROF(draw_channels(), draw_btn_cycles); | ||
27 | PROF(draw_pattern_buttons(), draw_btn_cycles); | ||
28 | PROF(draw_bank_buttons(), draw_btn_cycles); | ||
29 | PROF(draw_bpm(), draw_btn_cycles); | ||
30 | PROF(draw_play(), draw_btn_cycles); | ||
31 | PROF(draw_stop(), draw_btn_cycles); | ||
32 | PROF(draw_piano(), draw_piano_cycles); | ||
33 | PROF(draw_parameters(), draw_param_cycles); | ||
34 | PROF(draw_trig_cursor(trig_selection_loc, COL_CURSOR), draw_cursor_cycles); | ||
35 | PROF(draw_channel_cursor(channel_selection_loc, COL_GREY), draw_cursor_cycles); | ||
36 | PROF(draw_pattern_cursor(pattern_selection_loc, COL_GREY), draw_cursor_cycles); | ||
37 | PROF(draw_current_step(COL_RED), draw_cursor_cycles); | ||
38 | } | ||
39 | |||
40 | int | ||
41 | main(void) { | ||
26 | // Adjust system wait times. | 42 | // Adjust system wait times. |
27 | SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE; | 43 | SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE; |
28 | 44 | ||
@@ -38,15 +54,17 @@ int main(void) { | |||
38 | 54 | ||
39 | // Initialize sequencer. | 55 | // Initialize sequencer. |
40 | sequencer_init(); | 56 | sequencer_init(); |
57 | txt_spacing(6); | ||
41 | 58 | ||
42 | // Main loop. | 59 | // Main loop. |
43 | while (true) { | 60 | while (true) { |
44 | poll_keys(); | 61 | poll_keys(); |
45 | bios_vblank_wait(); | 62 | bios_vblank_wait(); |
46 | FRAME_START(); | ||
47 | PROF(handle_sequencer_input(), input_cycles); | ||
48 | PROF_SHOW(); | 63 | PROF_SHOW(); |
64 | FRAME_START(); | ||
49 | PROF(flip_buffer(), flip_cycles); | 65 | PROF(flip_buffer(), flip_cycles); |
66 | PROF(handle_sequencer_input(), input_cycles); | ||
67 | PROF(render(), render_cycles); | ||
50 | FRAME_END(); | 68 | FRAME_END(); |
51 | } | 69 | } |
52 | 70 | ||
diff --git a/src/profiling.c b/src/profiling.c index de969d2..7a4f4ad 100644 --- a/src/profiling.c +++ b/src/profiling.c | |||
@@ -52,22 +52,23 @@ static bool profile_bg_show = true; | |||
52 | profile_bg_show ^= 1;\ | 52 | profile_bg_show ^= 1;\ |
53 | }\ | 53 | }\ |
54 | if (profile_show) {\ | 54 | if (profile_show) {\ |
55 | txt_color(1);\ | ||
55 | txt_position((PROF_SHOW_X), (PROF_SHOW_Y));\ | 56 | txt_position((PROF_SHOW_X), (PROF_SHOW_Y));\ |
56 | draw_filled_rect((PROF_SHOW_X), (PROF_SHOW_X), 8 * 18, 8 * 16, 0);\ | 57 | if (profile_bg_show) {\ |
58 | draw_filled_rect((PROF_SHOW_X), (PROF_SHOW_X), 8 * 18, 8 * 14, 0);\ | ||
59 | }\ | ||
57 | txt_printf("VIDEO\n");\ | 60 | txt_printf("VIDEO\n");\ |
58 | txt_printf(">CLEAR %.8lu\n", avg_clear_cycles);\ | 61 | txt_printf(">CLEAR %.8lu\n", avg_clear_cycles);\ |
59 | txt_printf(">LINES %.8lu\n", avg_line_cycles);\ | ||
60 | txt_printf(">RECT %.8lu\n", avg_rect_cycles);\ | ||
61 | txt_printf(">FRECT %.8lu\n", avg_fill_rect_cycles);\ | ||
62 | txt_printf(">1BPP %.8lu\n", avg_icn_cycles);\ | ||
63 | txt_printf(">2BPP %.8lu\n", avg_chr_cycles);\ | ||
64 | txt_printf(">FLIP %.8lu\n", avg_flip_cycles);\ | 62 | txt_printf(">FLIP %.8lu\n", avg_flip_cycles);\ |
65 | txt_printf("TEXT\n");\ | 63 | txt_printf("SEQUENCER RENDER\n");\ |
66 | txt_printf(">DRAWF %.8lu\n", avg_txt_drawf_cycles);\ | 64 | txt_printf(">TRIGS %.8lu\n", avg_draw_trigs_cycles);\ |
67 | txt_printf(">PRINTF %.8lu\n", avg_txt_printf_cycles);\ | 65 | txt_printf(">BTNS %.8lu\n", avg_draw_btns_cycles);\ |
68 | txt_printf(">RENDER %.8lu\n", avg_txt_render_cycles);\ | 66 | txt_printf(">PARAM %.8lu\n", avg_draw_param_cycles);\ |
69 | txt_printf(">CLEAR %.8lu\n", avg_txt_clear_cycles);\ | 67 | txt_printf(">PIANO %.8lu\n", avg_draw_piano_cycles);\ |
68 | txt_printf(">CURSOR %.8lu\n", avg_draw_cursor_cycles);\ | ||
69 | txt_printf(">RENDER %.8lu\n", avg_render_cycles);\ | ||
70 | txt_printf("TOTAL %.8lu\n", avg_frame_cycles);\ | 70 | txt_printf("TOTAL %.8lu\n", avg_frame_cycles);\ |
71 | txt_render();\ | ||
71 | }\ | 72 | }\ |
72 | if (profile_bg_show) {\ | 73 | if (profile_bg_show) {\ |
73 | u32 frame_time =\ | 74 | u32 frame_time =\ |
@@ -80,40 +81,35 @@ static bool profile_bg_show = true; | |||
80 | FP_NUM(280896 * 60, 2),\ | 81 | FP_NUM(280896 * 60, 2),\ |
81 | FP_NUM(avg_frame_cycles + 1, 2),\ | 82 | FP_NUM(avg_frame_cycles + 1, 2),\ |
82 | 2);\ | 83 | 2);\ |
83 | txt_printf("TIME %.8lu\n", frame_time >> 2);\ | 84 | draw_filled_rect(8 * 18, 0, 239, 16, 0);\ |
84 | txt_printf("FPS %.8lu\n", (fps >> 2) + 1);\ | 85 | txt_drawf("TIME: %.6lu", 8 * 18, 0, 1, frame_time >> 2);\ |
86 | txt_drawf("MAX FPS:%.4lu", 8 * 18, 8, 1, (fps >> 2) + 1);\ | ||
85 | }\ | 87 | }\ |
86 | } while (0) | 88 | } while (0) |
87 | 89 | ||
88 | static u32 prof_frame_counter = 0; | 90 | static u32 prof_frame_counter = 0; |
89 | 91 | ||
90 | static u32 frame_cycles = 0; | 92 | static u32 frame_cycles = 0; |
91 | static u32 flip_cycles = 0; | 93 | static u32 flip_cycles = 0; |
92 | static u32 clear_cycles = 0; | 94 | static u32 clear_cycles = 0; |
93 | static u32 line_cycles = 0; | 95 | static u32 input_cycles = 0; |
94 | static u32 rect_cycles = 0; | 96 | static u32 draw_trigs_cycles = 0; |
95 | static u32 fill_rect_cycles = 0; | 97 | static u32 draw_btn_cycles = 0; |
96 | static u32 chr_cycles = 0; | 98 | static u32 draw_piano_cycles = 0; |
97 | static u32 icn_cycles = 0; | 99 | static u32 draw_param_cycles = 0; |
98 | static u32 txt_drawf_cycles = 0; | 100 | static u32 draw_cursor_cycles = 0; |
99 | static u32 txt_printf_cycles = 0; | 101 | static u32 render_cycles = 0; |
100 | static u32 txt_render_cycles = 0; | ||
101 | static u32 txt_clear_cycles = 0; | ||
102 | static u32 input_cycles = 0; | ||
103 | 102 | ||
104 | static u32 avg_frame_cycles = 0; | 103 | static u32 avg_frame_cycles = 0; |
105 | static u32 avg_flip_cycles = 0; | 104 | static u32 avg_flip_cycles = 0; |
106 | static u32 avg_clear_cycles = 0; | 105 | static u32 avg_clear_cycles = 0; |
107 | static u32 avg_line_cycles = 0; | 106 | static u32 avg_input_cycles = 0; |
108 | static u32 avg_rect_cycles = 0; | 107 | static u32 avg_draw_trigs_cycles = 0; |
109 | static u32 avg_fill_rect_cycles = 0; | 108 | static u32 avg_draw_btns_cycles = 0; |
110 | static u32 avg_chr_cycles = 0; | 109 | static u32 avg_draw_piano_cycles = 0; |
111 | static u32 avg_icn_cycles = 0; | 110 | static u32 avg_draw_param_cycles = 0; |
112 | static u32 avg_txt_drawf_cycles = 0; | 111 | static u32 avg_draw_cursor_cycles = 0; |
113 | static u32 avg_txt_printf_cycles = 0; | 112 | static u32 avg_render_cycles = 0; |
114 | static u32 avg_txt_render_cycles = 0; | ||
115 | static u32 avg_txt_clear_cycles = 0; | ||
116 | static u32 avg_input_cycles = 0; | ||
117 | 113 | ||
118 | #if PROF_ENABLE == 1 | 114 | #if PROF_ENABLE == 1 |
119 | #define FRAME_START()\ | 115 | #define FRAME_START()\ |
@@ -122,29 +118,23 @@ static u32 avg_input_cycles = 0; | |||
122 | avg_frame_cycles = frame_cycles / prof_frame_counter;\ | 118 | avg_frame_cycles = frame_cycles / prof_frame_counter;\ |
123 | avg_flip_cycles = flip_cycles / prof_frame_counter;\ | 119 | avg_flip_cycles = flip_cycles / prof_frame_counter;\ |
124 | avg_clear_cycles = clear_cycles / prof_frame_counter;\ | 120 | avg_clear_cycles = clear_cycles / prof_frame_counter;\ |
125 | avg_line_cycles = line_cycles / prof_frame_counter;\ | 121 | avg_draw_trigs_cycles = draw_trigs_cycles / prof_frame_counter;\ |
126 | avg_rect_cycles = rect_cycles / prof_frame_counter;\ | 122 | avg_draw_btns_cycles = draw_btn_cycles / prof_frame_counter;\ |
127 | avg_fill_rect_cycles = fill_rect_cycles / prof_frame_counter;\ | 123 | avg_draw_piano_cycles = draw_piano_cycles / prof_frame_counter;\ |
128 | avg_chr_cycles = chr_cycles / prof_frame_counter;\ | 124 | avg_draw_param_cycles = draw_param_cycles / prof_frame_counter;\ |
129 | avg_icn_cycles = icn_cycles / prof_frame_counter;\ | 125 | avg_draw_cursor_cycles = draw_cursor_cycles / prof_frame_counter;\ |
130 | avg_txt_drawf_cycles = txt_drawf_cycles / prof_frame_counter;\ | 126 | avg_input_cycles = input_cycles / prof_frame_counter;\ |
131 | avg_txt_printf_cycles = txt_printf_cycles / prof_frame_counter;\ | 127 | avg_render_cycles = render_cycles / prof_frame_counter;\ |
132 | avg_txt_render_cycles = txt_render_cycles / prof_frame_counter;\ | ||
133 | avg_txt_clear_cycles = txt_clear_cycles / prof_frame_counter;\ | ||
134 | avg_input_cycles = input_cycles / prof_frame_counter;\ | ||
135 | frame_cycles = 0;\ | 128 | frame_cycles = 0;\ |
136 | flip_cycles = 0;\ | 129 | flip_cycles = 0;\ |
137 | clear_cycles = 0;\ | 130 | clear_cycles = 0;\ |
138 | line_cycles = 0;\ | ||
139 | rect_cycles = 0;\ | ||
140 | fill_rect_cycles = 0;\ | ||
141 | chr_cycles = 0;\ | ||
142 | icn_cycles = 0;\ | ||
143 | txt_drawf_cycles = 0;\ | ||
144 | txt_printf_cycles = 0;\ | ||
145 | txt_render_cycles = 0;\ | ||
146 | txt_clear_cycles = 0;\ | ||
147 | input_cycles = 0;\ | 131 | input_cycles = 0;\ |
132 | render_cycles = 0;\ | ||
133 | draw_trigs_cycles = 0;\ | ||
134 | draw_param_cycles = 0;\ | ||
135 | draw_cursor_cycles = 0;\ | ||
136 | draw_btn_cycles = 0;\ | ||
137 | draw_piano_cycles = 0;\ | ||
148 | prof_frame_counter = 0;\ | 138 | prof_frame_counter = 0;\ |
149 | }\ | 139 | }\ |
150 | profile_start();\ | 140 | profile_start();\ |
diff --git a/src/renderer.h b/src/renderer.h index 4620c27..e6637ef 100644 --- a/src/renderer.h +++ b/src/renderer.h | |||
@@ -3,31 +3,6 @@ | |||
3 | 3 | ||
4 | #include "gba/gba.h" | 4 | #include "gba/gba.h" |
5 | 5 | ||
6 | // The frontbuffer is located at the beginning of the VRAM, and requires 20KB of | ||
7 | // video memory for 32 * 20 tiles at 4bpp. | ||
8 | #define FRONTBUF ((u32*)(MEM_VRAM)) | ||
9 | |||
10 | // Adjust both of these if the location of the map changes. Each screnblock | ||
11 | // requires less than 2KB. | ||
12 | #define FRONTBUF_TILEMAP ((u16*)(MEM_VRAM + KB(20))) | ||
13 | #define FRONTBUF_SB 10 | ||
14 | |||
15 | // The backbuffer is located at the end of the VRAM. This can allow us to use | ||
16 | // more backgrounds but eats into the available memory for sprites. This should | ||
17 | // be fine for non sprite intensive applications. If more sprite memory is | ||
18 | // needed, the backbuffer can be located at the end of the background memory | ||
19 | // instead (64KB - 20KB). | ||
20 | #define BACKBUF ((u32*)(MEM_VRAM + KB(96) - KB(20))) | ||
21 | |||
22 | // The font data is located at the end of the frontbuffer memory, after the tile | ||
23 | // map and requires 8KB for 256 8x8 characters at 4bpp. This, along with the | ||
24 | // tilemap information allow us to store the frontbuffer and font for a text | ||
25 | // background in the first 2 charblocks (32KB). | ||
26 | #define FONT_DATA ((u32*)(MEM_VRAM + KB(22))) | ||
27 | #define FONT_TILEMAP ((u16*)(MEM_VRAM + KB(30))) | ||
28 | #define FONT_SB 15 | ||
29 | #define FONT_OFFSET 192 | ||
30 | |||
31 | // Draws a pixel to the given (x, y) position on the framebuffer. All drawing | 6 | // Draws a pixel to the given (x, y) position on the framebuffer. All drawing |
32 | // functions use paletted colors (clr: 0-15). | 7 | // functions use paletted colors (clr: 0-15). |
33 | void draw_pixel(size_t x, size_t y, u8 clr); | 8 | void draw_pixel(size_t x, size_t y, u8 clr); |
@@ -41,17 +16,19 @@ void draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr); | |||
41 | // Draw a filled rectangle between (x0, y0) and (x1, y1) (x0 <= x1 and y0 <= y1). | 16 | // Draw a filled rectangle between (x0, y0) and (x1, y1) (x0 <= x1 and y0 <= y1). |
42 | void draw_filled_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr); | 17 | void draw_filled_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr); |
43 | 18 | ||
44 | // Draw a 8x8 tile starting at the (x, y) position. If the merge parameter is | 19 | // Fills the framebuffer with the given color. |
45 | // set, colors will be added together instead of replaced. This could lead to | 20 | void screen_fill(u8 clr); |
46 | // some merging issues if we are not careful with the chosen colors. The tile | 21 | |
47 | // color will be multiplied by the given clr parameter, which is useful to | 22 | // Draws a chr sprite (16 * u8). The first 8 bytes correspond to ch0 and the |
48 | // change the color of flat tiles. | 23 | // last 8 to ch1. If clr is 0 the regular 4bit color will be used, from clr 1-14 |
49 | void draw_tile(size_t x, size_t y, Tile *tile, u8 clr, bool merge); | 24 | // the given color will overwrite the existing one. Color 15 will "clear" the |
25 | // sprite instead. | ||
26 | void draw_chr(size_t x, size_t y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y); | ||
50 | 27 | ||
51 | // Fills the framebuffer with color 0. | 28 | // Draws a 1bpp icn sprite in the given color. |
52 | void clear_screen(void); | 29 | void draw_icn(size_t x, size_t y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y); |
53 | 30 | ||
54 | // Copies the content of dirty tiles from the backbuffer into the frontbuffer. | 31 | // Copies data and performs page flipping if needed. |
55 | // To be called exactly once at the beginning of the VBlank. | 32 | // To be called exactly once at the beginning of the VBlank. |
56 | void flip_buffer(void); | 33 | void flip_buffer(void); |
57 | 34 | ||
diff --git a/src/renderer_m0.c b/src/renderer_m0.c new file mode 100644 index 0000000..8bd4263 --- /dev/null +++ b/src/renderer_m0.c | |||
@@ -0,0 +1,811 @@ | |||
1 | // | ||
2 | // This Mode 0 renderer provides a way of drawing directly to a framebuffer | ||
3 | // (similar to Mode 3 and 4) while retaining the flexibility of using other | ||
4 | // backgrounds if needed. It also performs double buffering to avoid tearing | ||
5 | // artifacts and tries to only draw tiles that changed on each frame. | ||
6 | // | ||
7 | |||
8 | #include "renderer.h" | ||
9 | #include "text.h" | ||
10 | |||
11 | // | ||
12 | // Parameters. | ||
13 | // | ||
14 | |||
15 | #define SUBPIXEL_LINES 1 | ||
16 | #define DEC_BIG_LUT 1 | ||
17 | #define FLIP_TYPE 3 | ||
18 | |||
19 | // Front/back buffers for double buffering. | ||
20 | #define BUF_0 ((u32*)(MEM_VRAM)) | ||
21 | #define BUF_1 ((u32*)(MEM_VRAM + KB(20))) | ||
22 | |||
23 | // Pointer to the backbuffer. | ||
24 | static u32 *backbuf = BUF_1; | ||
25 | |||
26 | // Tracking which tiles are "dirty" and need refreshing. | ||
27 | static u32 dirty_tiles[21] = {0}; | ||
28 | |||
29 | // Position of the tilemap. | ||
30 | #define TILE_MAP ((u32*)(MEM_VRAM + KB(40))) | ||
31 | |||
32 | // Charblock and screenblock for both render buffers. | ||
33 | #define CB_0 0 | ||
34 | #define CB_1 1 | ||
35 | #define SB_0 20 | ||
36 | #define SB_1 22 | ||
37 | |||
38 | // Boundchecks can be disable at compile time but this will not always improve | ||
39 | // the performance and can in fact make it worse. It is possible that this is | ||
40 | // due to some aliasing optimizations but not sure at this moment. | ||
41 | #ifdef DISABLE_BOUNDCHECK_SCREEN | ||
42 | #define BOUNDCHECK_SCREEN(X,Y) | ||
43 | #else | ||
44 | #define BOUNDCHECK_SCREEN(X,Y) if ((X) >= SCREEN_WIDTH || (Y) >= SCREEN_HEIGHT) return; | ||
45 | #endif | ||
46 | |||
47 | // Swap A and B values without a tmp variable. | ||
48 | #define SWAP(A, B) (((A) ^= (B)), ((B) ^= (A)), ((A) ^= (B))) | ||
49 | |||
50 | // Swap A and B values to make sure A <= B. | ||
51 | #define MAYBE_SWAP(A,B) if ((A) > (B)) { SWAP(A,B); } | ||
52 | |||
53 | // | ||
54 | // Basic primitives. | ||
55 | // | ||
56 | |||
57 | static inline | ||
58 | void | ||
59 | redraw(void) { | ||
60 | for (size_t i = 0; i < 21; i++) { | ||
61 | dirty_tiles[i] = 0xFFFFFFFF; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | IWRAM_CODE | ||
66 | void screen_fill(u8 clr) { | ||
67 | // We have to make sure we leave the last tile blank to use as alpha channel | ||
68 | // when moving the BG during double buffering. | ||
69 | dma_fill(backbuf, 0x11111111 * clr, KB(20) - 32, 3); | ||
70 | redraw(); | ||
71 | } | ||
72 | |||
73 | IWRAM_CODE | ||
74 | void | ||
75 | draw_pixel(size_t x, size_t y, u8 clr) { | ||
76 | BOUNDCHECK_SCREEN(x, y); | ||
77 | |||
78 | // Find row position for the given x/y coordinates. | ||
79 | size_t tile_x = x / 8; | ||
80 | size_t tile_y = y / 8; | ||
81 | size_t start_col = x % 8; | ||
82 | size_t start_row = y % 8; | ||
83 | u32 *dst = &backbuf[start_row + (tile_x + tile_y * 32) * 8]; | ||
84 | |||
85 | // Update backbuffer. | ||
86 | size_t shift = start_col * sizeof(u32); | ||
87 | u32 mask = 0xF << shift; | ||
88 | u32 row = clr << shift; | ||
89 | *dst = (*dst & ~mask) | row; | ||
90 | dirty_tiles[tile_y] |= 1 << tile_x; | ||
91 | } | ||
92 | |||
93 | IWRAM_CODE | ||
94 | static inline | ||
95 | void | ||
96 | draw_hline(size_t x0, size_t x1, size_t y0, u8 clr) { | ||
97 | BOUNDCHECK_SCREEN(x0, y0); | ||
98 | BOUNDCHECK_SCREEN(x1, y0); | ||
99 | // Find row positions for the given x/y coordinates. | ||
100 | size_t tile_x0 = x0 / 8; | ||
101 | size_t tile_x1 = x1 / 8; | ||
102 | size_t tile_y = y0 / 8; | ||
103 | size_t start_col = x0 % 8; | ||
104 | size_t end_col = x1 % 8; | ||
105 | size_t start_row = y0 % 8; | ||
106 | u32 dirty = (1 << tile_x0) | (1 << tile_x1); | ||
107 | |||
108 | // Horizontal line. There are 3 cases: | ||
109 | // 1. Lines fit on a single tile. | ||
110 | // 2. Lines go through 2 tiles, both require partial row updates. | ||
111 | // 3. Lines go through 3 or more tiles, first and last tiles use | ||
112 | // partial row updates, rows in the middle can write the entire | ||
113 | // row. | ||
114 | size_t dtx = tile_x1 - tile_x0; | ||
115 | u32 *dst = &backbuf[start_row + (tile_x0 + tile_y * 32) * 8]; | ||
116 | if (dtx < 1) { | ||
117 | size_t shift_left = start_col * 4; | ||
118 | size_t shift_right = (7 - end_col) * 4; | ||
119 | u32 mask = (0xFFFFFFFF >> shift_right) & (0xFFFFFFFF << shift_left); | ||
120 | u32 row = (0x11111111 * clr) & mask; | ||
121 | *dst = (*dst & ~mask) | row; | ||
122 | } else { | ||
123 | size_t shift_left = start_col * 4; | ||
124 | size_t shift_right = (7 - end_col) * 4; | ||
125 | u32 mask = 0xFFFFFFFF; | ||
126 | u32 row = 0x11111111 * clr; | ||
127 | *dst = (*dst & ~(mask << shift_left)) | (row << shift_left); | ||
128 | dst += 8; | ||
129 | for (size_t i = 1; i < dtx; i++) { | ||
130 | dirty |= (1 << (tile_x0 + i)); | ||
131 | *dst = row; | ||
132 | dst += 8; | ||
133 | } | ||
134 | *dst = (*dst & ~(mask >> shift_right)) | (row >> shift_right); | ||
135 | } | ||
136 | dirty_tiles[tile_y] |= dirty; | ||
137 | } | ||
138 | |||
139 | IWRAM_CODE | ||
140 | UNROLL_LOOPS | ||
141 | static inline | ||
142 | void | ||
143 | draw_vline(size_t x0, size_t y0, size_t y1, u8 clr) { | ||
144 | BOUNDCHECK_SCREEN(x0, y0); | ||
145 | BOUNDCHECK_SCREEN(x0, y1); | ||
146 | size_t tile_x = x0 / 8; | ||
147 | size_t tile_y = y0 / 8; | ||
148 | size_t tile_y0 = y0 / 8; | ||
149 | size_t tile_y1 = y1 / 8; | ||
150 | size_t start_col = x0 % 8; | ||
151 | size_t start_row0 = y0 % 8; | ||
152 | size_t start_row1 = y1 % 8; | ||
153 | |||
154 | size_t shift_left = start_col * 4; | ||
155 | u32 dirty = (1 << tile_x); | ||
156 | |||
157 | u32 *dst = &backbuf[start_row0 + (tile_x + tile_y * 32) * 8]; | ||
158 | u32 mask = 0x0000000F << shift_left; | ||
159 | u32 row = (0x11111111 * clr) & mask; | ||
160 | u32 dty = tile_y1 - tile_y0; | ||
161 | if (dty < 1) { | ||
162 | for (size_t i = 0; i <= (y1 - y0); i++, dst++) { | ||
163 | dst[0] = (dst[0] & ~mask) | row; | ||
164 | } | ||
165 | } else { | ||
166 | for (size_t i = 0; i < (8 - start_row0); i++, dst++) { | ||
167 | dst[0] = (dst[0] & ~mask) | row; | ||
168 | } | ||
169 | dst += 8 * 31; | ||
170 | for (size_t j = 1; j < dty; j++) { | ||
171 | dirty_tiles[tile_y0 + j] |= dirty; | ||
172 | for (size_t i = 0; i < 8; i++, dst++) { | ||
173 | dst[0] = (dst[0] & ~mask) | row; | ||
174 | } | ||
175 | dst += 8 * 31; | ||
176 | } | ||
177 | for (size_t i = 0; i <= start_row1; i++, dst++) { | ||
178 | dst[0] = (dst[0] & ~mask) | row; | ||
179 | } | ||
180 | } | ||
181 | dirty_tiles[tile_y0] |= dirty; | ||
182 | dirty_tiles[tile_y1] |= dirty; | ||
183 | } | ||
184 | |||
185 | IWRAM_CODE | ||
186 | void | ||
187 | draw_line(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { | ||
188 | BOUNDCHECK_SCREEN(x0, y0); | ||
189 | BOUNDCHECK_SCREEN(x1, y1); | ||
190 | if (y0 == y1) { | ||
191 | MAYBE_SWAP(x0, x1); | ||
192 | draw_hline(x0, x1, y0, clr); | ||
193 | } else if (x0 == x1) { | ||
194 | MAYBE_SWAP(y0, y1); | ||
195 | draw_vline(x0, y0, y1, clr); | ||
196 | } else { | ||
197 | // Fixed Precision constants. | ||
198 | const int fp_bit = 6; | ||
199 | const int fp_one = FP_NUM(1, fp_bit); | ||
200 | const int fp_half = fp_one >> 1; | ||
201 | |||
202 | int dx = x0 > x1 ? x0 - x1 : x1 - x0; | ||
203 | int dy = y0 > y1 ? y0 - y1 : y1 - y0; | ||
204 | |||
205 | if ((dx >= dy && x0 > x1) || (dx < dy && y0 > y1)) { | ||
206 | SWAP(x0, x1); | ||
207 | SWAP(y0, y1); | ||
208 | } | ||
209 | |||
210 | #if SUBPIXEL_LINES == 1 | ||
211 | int dxf = (dx << fp_bit); | ||
212 | int dyf = (dy << fp_bit); | ||
213 | int frac_x = x0 > x1 ? FP_NUM(x0 - x1, fp_bit) : FP_NUM(x1 - x0, fp_bit); | ||
214 | int frac_y = y0 > y1 ? FP_NUM(y0 - y1, fp_bit) : FP_NUM(y1 - y0, fp_bit); | ||
215 | int x_step = x0 > x1 ? -1 : 1; | ||
216 | int y_step = y0 > y1 ? -1 : 1; | ||
217 | int distance = (frac_y - fp_one) * dx - (frac_x - fp_half) * dy; | ||
218 | if (dx >= dy) { | ||
219 | int step = dxf / dyf; | ||
220 | int remaining = dx; | ||
221 | while (remaining > (step - 1)) { | ||
222 | distance += step * 2 * dyf; | ||
223 | if (distance >= 0) { | ||
224 | draw_hline(x0, x0 + step - 1, y0, clr); | ||
225 | x0 += x_step * step; | ||
226 | remaining -= step; | ||
227 | } else { | ||
228 | if (remaining < step) { | ||
229 | break; | ||
230 | } | ||
231 | draw_hline(x0, x0 + step, y0, clr); | ||
232 | distance += 2 * dyf; | ||
233 | x0 += x_step * (step + 1); | ||
234 | remaining -= step + 1; | ||
235 | } | ||
236 | distance -= 2 * dxf; | ||
237 | y0 += y_step; | ||
238 | } | ||
239 | if (remaining >= 0) { | ||
240 | draw_hline(x0, x0 + remaining, y0, clr); | ||
241 | } | ||
242 | } else { | ||
243 | int step = dyf / dxf; | ||
244 | int remaining = dy; | ||
245 | while (remaining > (step - 1)) { | ||
246 | distance += step * 2 * dxf; | ||
247 | if (distance >= 0) { | ||
248 | draw_vline(x0, y0, y0 + step - 1, clr); | ||
249 | y0 += y_step * step; | ||
250 | remaining -= step; | ||
251 | } else { | ||
252 | draw_vline(x0, y0, y0 + step, clr); | ||
253 | distance += 2 * dxf; | ||
254 | y0 += y_step * (step + 1); | ||
255 | remaining -= step + 1; | ||
256 | } | ||
257 | distance -= 2 * dyf; | ||
258 | x0 += x_step; | ||
259 | } | ||
260 | if (remaining >= 0) { | ||
261 | draw_vline(x0, y0, y0 + remaining, clr); | ||
262 | } | ||
263 | } | ||
264 | #else | ||
265 | int x_step = x0 > x1 ? -1 : 1; | ||
266 | int y_step = y0 > y1 ? -1 : 1; | ||
267 | if (dx >= dy) { | ||
268 | int diff = 2 * dy - dx; | ||
269 | for (int i = 0; i < dx + 1; i++) { | ||
270 | draw_pixel(x0, y0, clr); | ||
271 | if (diff >= 0) { | ||
272 | diff -= 2 * dx; | ||
273 | y0 += y_step; | ||
274 | } | ||
275 | diff += 2 * dy; | ||
276 | x0 += x_step; | ||
277 | } | ||
278 | } else { | ||
279 | int diff = 2 * dx - dy; | ||
280 | for (int i = 0; i < dy + 1; i++) { | ||
281 | draw_pixel(x0, y0, clr); | ||
282 | if (diff >= 0) { | ||
283 | diff -= 2 * dy; | ||
284 | x0 += x_step; | ||
285 | } | ||
286 | diff += 2 * dx; | ||
287 | y0 += y_step; | ||
288 | } | ||
289 | } | ||
290 | #endif | ||
291 | } | ||
292 | } | ||
293 | |||
294 | IWRAM_CODE | ||
295 | void | ||
296 | draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { | ||
297 | BOUNDCHECK_SCREEN(x0, y0); | ||
298 | BOUNDCHECK_SCREEN(x1, y1); | ||
299 | MAYBE_SWAP(x0, x1); | ||
300 | MAYBE_SWAP(y0, y1); | ||
301 | |||
302 | draw_hline(x0, x1, y0, clr); | ||
303 | draw_hline(x0, x1, y1, clr); | ||
304 | draw_vline(x0, y0, y1, clr); | ||
305 | draw_vline(x1, y0, y1, clr); | ||
306 | } | ||
307 | |||
308 | IWRAM_CODE | ||
309 | void | ||
310 | draw_filled_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { | ||
311 | BOUNDCHECK_SCREEN(x0, y0); | ||
312 | BOUNDCHECK_SCREEN(x1, y1); | ||
313 | MAYBE_SWAP(x0, x1); | ||
314 | MAYBE_SWAP(y0, y1); | ||
315 | |||
316 | // Special condition. If the screen is to be completely filled, use the DMA | ||
317 | // instead. | ||
318 | if (x0 == 0 && x1 >= (SCREEN_WIDTH - 1) && y0 == 0 && y1 >= (SCREEN_HEIGHT - 1)) { | ||
319 | screen_fill(clr); | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | for (size_t y = y0; y <= y1; y++) { | ||
324 | draw_hline(x0, x1, y, clr); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | // | ||
329 | // Sprites (chr/icn). | ||
330 | // | ||
331 | |||
332 | #if DEC_BIG_LUT == 1 | ||
333 | static u32 dec_byte_flip_x[256] = { | ||
334 | 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, | ||
335 | 0x00000101, 0x00000110, 0x00000111, 0x00001000, 0x00001001, | ||
336 | 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, | ||
337 | 0x00001111, 0x00010000, 0x00010001, 0x00010010, 0x00010011, | ||
338 | 0x00010100, 0x00010101, 0x00010110, 0x00010111, 0x00011000, | ||
339 | 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, | ||
340 | 0x00011110, 0x00011111, 0x00100000, 0x00100001, 0x00100010, | ||
341 | 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, | ||
342 | 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, | ||
343 | 0x00101101, 0x00101110, 0x00101111, 0x00110000, 0x00110001, | ||
344 | 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, | ||
345 | 0x00110111, 0x00111000, 0x00111001, 0x00111010, 0x00111011, | ||
346 | 0x00111100, 0x00111101, 0x00111110, 0x00111111, 0x01000000, | ||
347 | 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, | ||
348 | 0x01000110, 0x01000111, 0x01001000, 0x01001001, 0x01001010, | ||
349 | 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, | ||
350 | 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, | ||
351 | 0x01010101, 0x01010110, 0x01010111, 0x01011000, 0x01011001, | ||
352 | 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, | ||
353 | 0x01011111, 0x01100000, 0x01100001, 0x01100010, 0x01100011, | ||
354 | 0x01100100, 0x01100101, 0x01100110, 0x01100111, 0x01101000, | ||
355 | 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, | ||
356 | 0x01101110, 0x01101111, 0x01110000, 0x01110001, 0x01110010, | ||
357 | 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, | ||
358 | 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, | ||
359 | 0x01111101, 0x01111110, 0x01111111, 0x10000000, 0x10000001, | ||
360 | 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, | ||
361 | 0x10000111, 0x10001000, 0x10001001, 0x10001010, 0x10001011, | ||
362 | 0x10001100, 0x10001101, 0x10001110, 0x10001111, 0x10010000, | ||
363 | 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, | ||
364 | 0x10010110, 0x10010111, 0x10011000, 0x10011001, 0x10011010, | ||
365 | 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, | ||
366 | 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, | ||
367 | 0x10100101, 0x10100110, 0x10100111, 0x10101000, 0x10101001, | ||
368 | 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, | ||
369 | 0x10101111, 0x10110000, 0x10110001, 0x10110010, 0x10110011, | ||
370 | 0x10110100, 0x10110101, 0x10110110, 0x10110111, 0x10111000, | ||
371 | 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, | ||
372 | 0x10111110, 0x10111111, 0x11000000, 0x11000001, 0x11000010, | ||
373 | 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, | ||
374 | 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, | ||
375 | 0x11001101, 0x11001110, 0x11001111, 0x11010000, 0x11010001, | ||
376 | 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, | ||
377 | 0x11010111, 0x11011000, 0x11011001, 0x11011010, 0x11011011, | ||
378 | 0x11011100, 0x11011101, 0x11011110, 0x11011111, 0x11100000, | ||
379 | 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, | ||
380 | 0x11100110, 0x11100111, 0x11101000, 0x11101001, 0x11101010, | ||
381 | 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, | ||
382 | 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, | ||
383 | 0x11110101, 0x11110110, 0x11110111, 0x11111000, 0x11111001, | ||
384 | 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, | ||
385 | 0x11111111 | ||
386 | }; | ||
387 | |||
388 | static u32 dec_byte[256] = { | ||
389 | 0x00000000, 0x10000000, 0x01000000, 0x11000000, 0x00100000, | ||
390 | 0x10100000, 0x01100000, 0x11100000, 0x00010000, 0x10010000, | ||
391 | 0x01010000, 0x11010000, 0x00110000, 0x10110000, 0x01110000, | ||
392 | 0x11110000, 0x00001000, 0x10001000, 0x01001000, 0x11001000, | ||
393 | 0x00101000, 0x10101000, 0x01101000, 0x11101000, 0x00011000, | ||
394 | 0x10011000, 0x01011000, 0x11011000, 0x00111000, 0x10111000, | ||
395 | 0x01111000, 0x11111000, 0x00000100, 0x10000100, 0x01000100, | ||
396 | 0x11000100, 0x00100100, 0x10100100, 0x01100100, 0x11100100, | ||
397 | 0x00010100, 0x10010100, 0x01010100, 0x11010100, 0x00110100, | ||
398 | 0x10110100, 0x01110100, 0x11110100, 0x00001100, 0x10001100, | ||
399 | 0x01001100, 0x11001100, 0x00101100, 0x10101100, 0x01101100, | ||
400 | 0x11101100, 0x00011100, 0x10011100, 0x01011100, 0x11011100, | ||
401 | 0x00111100, 0x10111100, 0x01111100, 0x11111100, 0x00000010, | ||
402 | 0x10000010, 0x01000010, 0x11000010, 0x00100010, 0x10100010, | ||
403 | 0x01100010, 0x11100010, 0x00010010, 0x10010010, 0x01010010, | ||
404 | 0x11010010, 0x00110010, 0x10110010, 0x01110010, 0x11110010, | ||
405 | 0x00001010, 0x10001010, 0x01001010, 0x11001010, 0x00101010, | ||
406 | 0x10101010, 0x01101010, 0x11101010, 0x00011010, 0x10011010, | ||
407 | 0x01011010, 0x11011010, 0x00111010, 0x10111010, 0x01111010, | ||
408 | 0x11111010, 0x00000110, 0x10000110, 0x01000110, 0x11000110, | ||
409 | 0x00100110, 0x10100110, 0x01100110, 0x11100110, 0x00010110, | ||
410 | 0x10010110, 0x01010110, 0x11010110, 0x00110110, 0x10110110, | ||
411 | 0x01110110, 0x11110110, 0x00001110, 0x10001110, 0x01001110, | ||
412 | 0x11001110, 0x00101110, 0x10101110, 0x01101110, 0x11101110, | ||
413 | 0x00011110, 0x10011110, 0x01011110, 0x11011110, 0x00111110, | ||
414 | 0x10111110, 0x01111110, 0x11111110, 0x00000001, 0x10000001, | ||
415 | 0x01000001, 0x11000001, 0x00100001, 0x10100001, 0x01100001, | ||
416 | 0x11100001, 0x00010001, 0x10010001, 0x01010001, 0x11010001, | ||
417 | 0x00110001, 0x10110001, 0x01110001, 0x11110001, 0x00001001, | ||
418 | 0x10001001, 0x01001001, 0x11001001, 0x00101001, 0x10101001, | ||
419 | 0x01101001, 0x11101001, 0x00011001, 0x10011001, 0x01011001, | ||
420 | 0x11011001, 0x00111001, 0x10111001, 0x01111001, 0x11111001, | ||
421 | 0x00000101, 0x10000101, 0x01000101, 0x11000101, 0x00100101, | ||
422 | 0x10100101, 0x01100101, 0x11100101, 0x00010101, 0x10010101, | ||
423 | 0x01010101, 0x11010101, 0x00110101, 0x10110101, 0x01110101, | ||
424 | 0x11110101, 0x00001101, 0x10001101, 0x01001101, 0x11001101, | ||
425 | 0x00101101, 0x10101101, 0x01101101, 0x11101101, 0x00011101, | ||
426 | 0x10011101, 0x01011101, 0x11011101, 0x00111101, 0x10111101, | ||
427 | 0x01111101, 0x11111101, 0x00000011, 0x10000011, 0x01000011, | ||
428 | 0x11000011, 0x00100011, 0x10100011, 0x01100011, 0x11100011, | ||
429 | 0x00010011, 0x10010011, 0x01010011, 0x11010011, 0x00110011, | ||
430 | 0x10110011, 0x01110011, 0x11110011, 0x00001011, 0x10001011, | ||
431 | 0x01001011, 0x11001011, 0x00101011, 0x10101011, 0x01101011, | ||
432 | 0x11101011, 0x00011011, 0x10011011, 0x01011011, 0x11011011, | ||
433 | 0x00111011, 0x10111011, 0x01111011, 0x11111011, 0x00000111, | ||
434 | 0x10000111, 0x01000111, 0x11000111, 0x00100111, 0x10100111, | ||
435 | 0x01100111, 0x11100111, 0x00010111, 0x10010111, 0x01010111, | ||
436 | 0x11010111, 0x00110111, 0x10110111, 0x01110111, 0x11110111, | ||
437 | 0x00001111, 0x10001111, 0x01001111, 0x11001111, 0x00101111, | ||
438 | 0x10101111, 0x01101111, 0x11101111, 0x00011111, 0x10011111, | ||
439 | 0x01011111, 0x11011111, 0x00111111, 0x10111111, 0x01111111, | ||
440 | 0x11111111 | ||
441 | }; | ||
442 | |||
443 | IWRAM_CODE | ||
444 | static inline | ||
445 | u32 | ||
446 | decode_1bpp(u8 row, u8 flip_x) { | ||
447 | if (flip_x) { | ||
448 | return dec_byte_flip_x[row]; | ||
449 | } | ||
450 | return dec_byte[row]; | ||
451 | } | ||
452 | #else | ||
453 | static u16 dec_nibble[] = { | ||
454 | 0x0000, 0x1000, 0x0100, 0x1100, | ||
455 | 0x0010, 0x1010, 0x0110, 0x1110, | ||
456 | 0x0001, 0x1001, 0x0101, 0x1101, | ||
457 | 0x0011, 0x1011, 0x0111, 0x1111, | ||
458 | }; | ||
459 | |||
460 | static u16 dec_nibble_flip_x[] = { | ||
461 | 0x0000, 0x0001, 0x0010, 0x0011, | ||
462 | 0x0100, 0x0101, 0x0110, 0x0111, | ||
463 | 0x1000, 0x1001, 0x1010, 0x1011, | ||
464 | 0x1100, 0x1101, 0x1110, 0x1111, | ||
465 | }; | ||
466 | |||
467 | IWRAM_CODE | ||
468 | static inline | ||
469 | u32 | ||
470 | decode_1bpp(u8 row, u8 flip_x) { | ||
471 | if (flip_x) { | ||
472 | u16 *lut = dec_nibble_flip_x; | ||
473 | return (u32)lut[(row >> 4) & 0xF] << 16 | (u32)lut[(row >> 0) & 0xF]; | ||
474 | } | ||
475 | u16 *lut = dec_nibble; | ||
476 | return (u32)lut[(row >> 0) & 0xF] << 16 | (u32)lut[(row >> 4) & 0xF]; | ||
477 | } | ||
478 | #endif | ||
479 | |||
480 | IWRAM_CODE | ||
481 | UNROLL_LOOPS | ||
482 | void | ||
483 | draw_chr(size_t x, size_t y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { | ||
484 | BOUNDCHECK_SCREEN(x, y); | ||
485 | size_t tile_x0 = x / 8; | ||
486 | size_t tile_x1 = (x + 7) / 8; | ||
487 | size_t tile_y = y / 8; | ||
488 | size_t start_col = x % 8; | ||
489 | size_t start_row = y % 8; | ||
490 | size_t shift_left = start_col * 4; | ||
491 | size_t shift_right = (8 - start_col) * 4; | ||
492 | u32 dirty = (1 << tile_x0) | (1 << tile_x1); | ||
493 | u32 *dst = &backbuf[start_row + (tile_x0 + tile_y * 32) * 8]; | ||
494 | #if DEC_BIG_LUT | ||
495 | u32 *lut = flip_x ? dec_byte_flip_x : dec_byte; | ||
496 | #endif | ||
497 | if (!flip_y) { | ||
498 | for(size_t v = 0; v < 8; v++, dst++) { | ||
499 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
500 | u8 ch1 = sprite[v + 0]; | ||
501 | u8 ch2 = sprite[v + 8]; | ||
502 | #if DEC_BIG_LUT | ||
503 | u32 clr_a = lut[ch1]; | ||
504 | u32 clr_b = lut[ch2]; | ||
505 | #else | ||
506 | u32 clr_a = decode_1bpp(ch1, flip_x); | ||
507 | u32 clr_b = decode_1bpp(ch2, flip_x); | ||
508 | #endif | ||
509 | u32 mask_a = (clr_a * 0xF); | ||
510 | u32 mask_b = (clr_b * 0xF); | ||
511 | u32 mask = (mask_a | mask_b); | ||
512 | u32 color; | ||
513 | if (clr == 0) { | ||
514 | color = clr_a + (clr_b << 1); | ||
515 | } else if (clr == 15) { | ||
516 | color = 0; | ||
517 | } else { | ||
518 | color = (clr_a | clr_b) * clr; | ||
519 | } | ||
520 | dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); | ||
521 | dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); | ||
522 | if ((start_row + v) == 7) { | ||
523 | dirty_tiles[tile_y + 1] |= dirty; | ||
524 | dst += (32 - 1) * 8; | ||
525 | } | ||
526 | } | ||
527 | } else { | ||
528 | for(size_t v = 0; v < 8; v++, dst++) { | ||
529 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
530 | u8 ch1 = sprite[(7 - v) + 0]; | ||
531 | u8 ch2 = sprite[(7 - v) + 8]; | ||
532 | #if DEC_BIG_LUT | ||
533 | u32 clr_a = lut[ch1]; | ||
534 | u32 clr_b = lut[ch2]; | ||
535 | #else | ||
536 | u32 clr_a = decode_1bpp(ch1, flip_x); | ||
537 | u32 clr_b = decode_1bpp(ch2, flip_x); | ||
538 | #endif | ||
539 | u32 mask_a = (clr_a * 0xF); | ||
540 | u32 mask_b = (clr_b * 0xF); | ||
541 | u32 mask = (mask_a | mask_b); | ||
542 | u32 color; | ||
543 | if (clr == 0) { | ||
544 | color = clr_a + (clr_b << 1); | ||
545 | } else if (clr == 15) { | ||
546 | color = 0; | ||
547 | } else { | ||
548 | color = (clr_a | clr_b) * clr; | ||
549 | } | ||
550 | dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); | ||
551 | dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); | ||
552 | if ((start_row + v) == 7) { | ||
553 | dirty_tiles[tile_y + 1] |= dirty; | ||
554 | dst += (32 - 1) * 8; | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | dirty_tiles[tile_y] |= dirty; | ||
559 | } | ||
560 | |||
561 | IWRAM_CODE | ||
562 | UNROLL_LOOPS | ||
563 | void | ||
564 | draw_icn(size_t x, size_t y, u8 *sprite, u8 clr, u8 flip_x, u8 flip_y) { | ||
565 | BOUNDCHECK_SCREEN(x, y); | ||
566 | size_t tile_x0 = x / 8; | ||
567 | size_t tile_x1 = (x + 7) / 8; | ||
568 | size_t tile_y = y / 8; | ||
569 | size_t start_col = x % 8; | ||
570 | size_t start_row = y % 8; | ||
571 | size_t shift_left = start_col * 4; | ||
572 | size_t shift_right = (8 - start_col) * 4; | ||
573 | u32 dirty = (1 << tile_x0) | (1 << tile_x1); | ||
574 | u32 *dst = &backbuf[start_row + (tile_x0 + tile_y * 32) * 8]; | ||
575 | #if DEC_BIG_LUT | ||
576 | u32 *lut = flip_x ? dec_byte_flip_x : dec_byte; | ||
577 | #endif | ||
578 | if (!flip_y) { | ||
579 | for(size_t v = 0; v < 8; v++, dst++) { | ||
580 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
581 | u8 ch1 = sprite[v + 0]; | ||
582 | #if DEC_BIG_LUT | ||
583 | u32 color = lut[ch1]; | ||
584 | #else | ||
585 | u32 color = decode_1bpp(ch1, flip_x); | ||
586 | #endif | ||
587 | u32 mask = (color * 0xF); | ||
588 | color *= clr; | ||
589 | dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); | ||
590 | dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); | ||
591 | if ((start_row + v) == 7) { | ||
592 | dirty_tiles[tile_y + 1] |= dirty; | ||
593 | dst += (32 - 1) * 8; | ||
594 | } | ||
595 | } | ||
596 | } else { | ||
597 | for(size_t v = 0; v < 8; v++, dst++) { | ||
598 | if ((y + v) >= SCREEN_HEIGHT) break; | ||
599 | u8 ch1 = sprite[(7 - v) + 0]; | ||
600 | #if DEC_BIG_LUT | ||
601 | u32 color = lut[ch1]; | ||
602 | #else | ||
603 | u32 color = decode_1bpp(ch1, flip_x); | ||
604 | #endif | ||
605 | u32 mask = (color * 0xF); | ||
606 | color *= clr; | ||
607 | dst[0] = (dst[0] & ~(mask << shift_left)) | (color << shift_left); | ||
608 | dst[8] = (dst[8] & ~(mask >> shift_right)) | (color >> shift_right); | ||
609 | if ((start_row + v) == 7) { | ||
610 | dirty_tiles[tile_y + 1] |= dirty; | ||
611 | dst += (32 - 1) * 8; | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | dirty_tiles[tile_y] |= dirty; | ||
616 | } | ||
617 | |||
618 | // | ||
619 | // Flipping buffers/copying memory. | ||
620 | // | ||
621 | |||
622 | IWRAM_CODE | ||
623 | void | ||
624 | flip_buffer(void) { | ||
625 | // Mode 0: double buffering without dirty tiles. | ||
626 | #if FLIP_TYPE == 0 | ||
627 | if (backbuf == BUF_0) { | ||
628 | backbuf = BUF_1; | ||
629 | BG_H_SCROLL_0 = 0; | ||
630 | BG_H_SCROLL_1 = -240; | ||
631 | } else { | ||
632 | backbuf = BUF_0; | ||
633 | BG_H_SCROLL_0 = -240; | ||
634 | BG_H_SCROLL_1 = 0; | ||
635 | } | ||
636 | |||
637 | // Mode 1: single buffer, copy the dirty lines from backbuffer (BUF_1) to | ||
638 | // frontbuffer (BUF_0) using the DMA. | ||
639 | #elif FLIP_TYPE == 1 | ||
640 | u32 *front = BUF_0; | ||
641 | u32 *back = BUF_1; | ||
642 | BG_H_SCROLL_0 = 0; | ||
643 | BG_H_SCROLL_1 = -240; | ||
644 | for (size_t j = 0; j < 20; ++j) { | ||
645 | if (dirty_tiles[j] == 0) { | ||
646 | continue; | ||
647 | } | ||
648 | u32 offset = j * 32 * 8; | ||
649 | dma_copy(front + offset, back + offset, (30 * 8 * 4), 3); | ||
650 | dirty_tiles[j] = 0; | ||
651 | } | ||
652 | |||
653 | // Mode 2: single buffer, copy the dirty tiles from backbuffer (BUF_1) to | ||
654 | // frontbuffer (BUF_0). | ||
655 | #elif FLIP_TYPE == 2 | ||
656 | u32 *front = BUF_0; | ||
657 | u32 *back = BUF_1; | ||
658 | BG_H_SCROLL_0 = 0; | ||
659 | BG_H_SCROLL_1 = -240; | ||
660 | for (size_t j = 0; j < 20; ++j) { | ||
661 | if (dirty_tiles[j] == 0) { | ||
662 | continue; | ||
663 | } | ||
664 | size_t k = 1; | ||
665 | for (size_t i = 0; i < 30; ++i, k <<= 1) { | ||
666 | if (dirty_tiles[j] & k) { | ||
667 | Tile *mem_front = front; | ||
668 | Tile *mem_back = back; | ||
669 | mem_front[i + j * 32] = mem_back[i + j * 32]; | ||
670 | } | ||
671 | } | ||
672 | dirty_tiles[j] = 0; | ||
673 | } | ||
674 | |||
675 | // Mode 3: Double buffering with dirty line, copying the dirty lines if needed | ||
676 | // after flipping buffers with the DMA. | ||
677 | #elif FLIP_TYPE == 3 | ||
678 | bool should_flip = false; | ||
679 | for (size_t j = 0; j < 20; ++j) { | ||
680 | if (dirty_tiles[j] == 0) { | ||
681 | continue; | ||
682 | } | ||
683 | should_flip = true; | ||
684 | break; | ||
685 | } | ||
686 | if (!should_flip) { | ||
687 | return; | ||
688 | } | ||
689 | u32 *frontbuf = backbuf; | ||
690 | if (backbuf == BUF_0) { | ||
691 | backbuf = BUF_1; | ||
692 | BG_H_SCROLL_0 = 0; | ||
693 | BG_H_SCROLL_1 = -240; | ||
694 | } else { | ||
695 | backbuf = BUF_0; | ||
696 | BG_H_SCROLL_0 = -240; | ||
697 | BG_H_SCROLL_1 = 0; | ||
698 | } | ||
699 | for (size_t j = 0; j < 20; ++j) { | ||
700 | if (dirty_tiles[j] == 0) { | ||
701 | continue; | ||
702 | } | ||
703 | u32 offset = j * 32 * 8; | ||
704 | dma_copy(backbuf + offset, frontbuf + offset, (30 * 8 * 4), 3); | ||
705 | dirty_tiles[j] = 0; | ||
706 | } | ||
707 | |||
708 | // Mode 4: Double buffering with dirty tiles, copying the dirty tiles if needed | ||
709 | // after flipping buffers. | ||
710 | #elif FLIP_TYPE == 4 | ||
711 | bool should_flip = false; | ||
712 | for (size_t j = 0; j < 20; ++j) { | ||
713 | if (dirty_tiles[j] == 0) { | ||
714 | continue; | ||
715 | } | ||
716 | should_flip = true; | ||
717 | break; | ||
718 | } | ||
719 | if (!should_flip) { | ||
720 | return; | ||
721 | } | ||
722 | u32 *frontbuf = backbuf; | ||
723 | if (backbuf == BUF_0) { | ||
724 | backbuf = BUF_1; | ||
725 | BG_H_SCROLL_0 = 0; | ||
726 | BG_H_SCROLL_1 = -240; | ||
727 | } else { | ||
728 | backbuf = BUF_0; | ||
729 | BG_H_SCROLL_0 = -240; | ||
730 | BG_H_SCROLL_1 = 0; | ||
731 | } | ||
732 | for (size_t j = 0; j < 20; ++j) { | ||
733 | if (dirty_tiles[j] == 0) { | ||
734 | continue; | ||
735 | } | ||
736 | size_t k = 1; | ||
737 | for (size_t i = 0; i < 30; ++i, k <<= 1) { | ||
738 | if (dirty_tiles[j] & k) { | ||
739 | Tile *mem_front = frontbuf; | ||
740 | Tile *mem_back = backbuf; | ||
741 | mem_back[i + j * 32] = mem_front[i + j * 32]; | ||
742 | } | ||
743 | } | ||
744 | dirty_tiles[j] = 0; | ||
745 | } | ||
746 | #endif | ||
747 | } | ||
748 | |||
749 | // | ||
750 | // Text rendering. | ||
751 | // | ||
752 | |||
753 | #include "font.h" | ||
754 | |||
755 | // Font rendering function for the text engine. | ||
756 | void | ||
757 | txt_drawc(char c, size_t x, size_t y, u8 clr) { | ||
758 | u8 *tile = font_icn; | ||
759 | draw_icn(x, y, tile + 8 * c, clr, 1, 0); | ||
760 | } | ||
761 | |||
762 | // | ||
763 | // Initialization. | ||
764 | // | ||
765 | |||
766 | void | ||
767 | renderer_init(void) { | ||
768 | // Initialize display mode and bg palette. | ||
769 | DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_BG_1; | ||
770 | |||
771 | // Clear VRAM. | ||
772 | dma_fill((u32*)MEM_VRAM, 0, KB(96), 3); | ||
773 | |||
774 | // Initialize backgrounds. | ||
775 | BG_CTRL(0) = BG_CHARBLOCK(CB_0) | BG_SCREENBLOCK(SB_0) | BG_PRIORITY(0) | BG_SIZE(1); | ||
776 | BG_CTRL(1) = BG_CHARBLOCK(CB_1) | BG_SCREENBLOCK(SB_1) | BG_PRIORITY(1) | BG_SIZE(1); | ||
777 | |||
778 | // Initialize background memory map for the render buffers. The backgrounds | ||
779 | // are 64x32 each, with the second screenblock pointing to a zeroed tile. | ||
780 | // This makes it so while scrolling the backgrounds to the second screen we | ||
781 | // effectively disabling them. Thanks to this we can perform double | ||
782 | // buffering with mode 0 rendering. | ||
783 | u16 *mem_map_fg = SCREENBLOCK_MEM[SB_0]; | ||
784 | u16 *mem_map_fg_blank = SCREENBLOCK_MEM[SB_0 + 1]; | ||
785 | u16 *mem_map_bg = SCREENBLOCK_MEM[SB_1]; | ||
786 | u16 *mem_map_bg_blank = SCREENBLOCK_MEM[SB_1 + 1]; | ||
787 | for (size_t i = 0; i < 32 * 20; ++i) { | ||
788 | mem_map_fg[i] = i; | ||
789 | mem_map_fg_blank[i] = 32 * 20 - 1; | ||
790 | mem_map_bg[i] = i + 32 * 4; | ||
791 | mem_map_bg_blank[i] = (32 * 20 - 1) + 32 * 4; | ||
792 | } | ||
793 | |||
794 | // Setup initial background state. | ||
795 | BG_H_SCROLL_0 = -240; | ||
796 | BG_H_SCROLL_1 = -240; | ||
797 | |||
798 | // Initialize default palette. | ||
799 | PAL_BUFFER_BG[0] = COLOR_BLACK; | ||
800 | PAL_BUFFER_BG[1] = COLOR_WHITE; | ||
801 | PAL_BUFFER_BG[2] = COLOR_RED; | ||
802 | PAL_BUFFER_BG[3] = COLOR_BLUE; | ||
803 | PAL_BUFFER_BG[4] = COLOR_CYAN; | ||
804 | PAL_BUFFER_BG[5] = COLOR_GREY; | ||
805 | PAL_BUFFER_BG[6] = COLOR_WHITE; | ||
806 | PAL_BUFFER_BG[7] = COLOR_GREEN; | ||
807 | PAL_BUFFER_BG[8] = COLOR_PURPLE; | ||
808 | |||
809 | // Initialize text engine. | ||
810 | txt_init(txt_drawc); | ||
811 | } | ||
diff --git a/src/sequencer.c b/src/sequencer.c index b582cf4..ff3904d 100644 --- a/src/sequencer.c +++ b/src/sequencer.c | |||
@@ -527,9 +527,9 @@ draw_channels(void) { | |||
527 | } | 527 | } |
528 | u8 clr = active ? COL_FG : COL_GREY; | 528 | u8 clr = active ? COL_FG : COL_GREY; |
529 | size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y; | 529 | size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y; |
530 | draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false); | 530 | // draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false); |
531 | draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false); | 531 | // draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false); |
532 | draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false); | 532 | // draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false); |
533 | } | 533 | } |
534 | } | 534 | } |
535 | 535 | ||
@@ -582,8 +582,8 @@ draw_trigger(size_t chan, size_t i) { | |||
582 | size_t y = TRIG_START_Y + offset_y; | 582 | size_t y = TRIG_START_Y + offset_y; |
583 | Tile *tiles = ASSETS_NOTE_NAMES; | 583 | Tile *tiles = ASSETS_NOTE_NAMES; |
584 | tiles += 2 * trig.note; | 584 | tiles += 2 * trig.note; |
585 | draw_tile(x, y, tiles, COL_FG, true); | 585 | // draw_tile(x, y, tiles, COL_FG, true); |
586 | draw_tile(x + 8, y, tiles + 1, COL_FG, true); | 586 | // draw_tile(x + 8, y, tiles + 1, COL_FG, true); |
587 | } else { | 587 | } else { |
588 | clear_trigger(i); | 588 | clear_trigger(i); |
589 | } | 589 | } |
@@ -658,7 +658,7 @@ void | |||
658 | draw_bank_buttons() { | 658 | draw_bank_buttons() { |
659 | size_t x = BANK_START_X; | 659 | size_t x = BANK_START_X; |
660 | size_t y = BANK_START_Y; | 660 | size_t y = BANK_START_Y; |
661 | txt_drawf_small("BANK", x - 2, y - 10, 4, COL_FG); | 661 | // txt_drawf_small("BANK", x - 2, y - 10, 4, COL_FG); |
662 | char bank_names[] = { | 662 | char bank_names[] = { |
663 | 'A', 'B', 'C', 'D', | 663 | 'A', 'B', 'C', 'D', |
664 | }; | 664 | }; |
@@ -669,7 +669,7 @@ draw_bank_buttons() { | |||
669 | } | 669 | } |
670 | draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG); | 670 | draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG); |
671 | draw_rect(x, y, x + PAT_W, y + PAT_H, color); | 671 | draw_rect(x, y, x + PAT_W, y + PAT_H, color); |
672 | txt_drawc(bank_names[i], x + 4, y + 2, 6, color); | 672 | // txt_drawc(bank_names[i], x + 4, y + 2, 6, color); |
673 | y += PAT_OFFSET_Y; | 673 | y += PAT_OFFSET_Y; |
674 | } | 674 | } |
675 | } | 675 | } |
@@ -678,7 +678,7 @@ void | |||
678 | draw_pattern_buttons() { | 678 | draw_pattern_buttons() { |
679 | size_t x = PAT_START_X; | 679 | size_t x = PAT_START_X; |
680 | size_t y = PAT_START_Y; | 680 | size_t y = PAT_START_Y; |
681 | txt_drawf_small("PAT", x, y - 10, 4, COL_FG); | 681 | // txt_drawf_small("PAT", x, y - 10, 4, COL_FG); |
682 | char pat_names[] = { | 682 | char pat_names[] = { |
683 | 'A', 'B', 'C', 'D', | 683 | 'A', 'B', 'C', 'D', |
684 | 'E', 'F', 'G', 'H', | 684 | 'E', 'F', 'G', 'H', |
@@ -693,7 +693,7 @@ draw_pattern_buttons() { | |||
693 | } | 693 | } |
694 | draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG); | 694 | draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG); |
695 | draw_rect(x, y, x + PAT_W, y + PAT_H, color); | 695 | draw_rect(x, y, x + PAT_W, y + PAT_H, color); |
696 | txt_drawc(pat_names[i], x + 4, y + 2, 6, color); | 696 | // txt_drawc(pat_names[i], x + 4, y + 2, 6, color); |
697 | y += PAT_OFFSET_Y; | 697 | y += PAT_OFFSET_Y; |
698 | } | 698 | } |
699 | } | 699 | } |
@@ -745,7 +745,7 @@ draw_bpm() { | |||
745 | draw_filled_rect(x, y, x + R_COL_W, y + BPM_H, COL_BG); | 745 | draw_filled_rect(x, y, x + R_COL_W, y + BPM_H, COL_BG); |
746 | draw_rect(x, y, x + R_COL_W, y + BPM_H, COL_FG); | 746 | draw_rect(x, y, x + R_COL_W, y + BPM_H, COL_FG); |
747 | draw_line(x + 5, y, x + 19, y, COL_BG); | 747 | draw_line(x + 5, y, x + 19, y, COL_BG); |
748 | txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG); | 748 | // txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG); |
749 | 749 | ||
750 | // Make sure its horizontally centered if only 2 digits | 750 | // Make sure its horizontally centered if only 2 digits |
751 | int bpm = patterns[pattern_selection_loc].bpm; | 751 | int bpm = patterns[pattern_selection_loc].bpm; |
@@ -1069,24 +1069,24 @@ draw_parameters_wave(void) { | |||
1069 | 1069 | ||
1070 | // Wave text. | 1070 | // Wave text. |
1071 | x -= 2; | 1071 | x -= 2; |
1072 | txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG, | 1072 | // txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG, |
1073 | wave_a[0], wave_a[1], wave_a[2], wave_a[3]); | 1073 | // wave_a[0], wave_a[1], wave_a[2], wave_a[3]); |
1074 | txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG, | 1074 | // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG, |
1075 | wave_a[4], wave_a[5], wave_a[6], wave_a[7]); | 1075 | // wave_a[4], wave_a[5], wave_a[6], wave_a[7]); |
1076 | txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG, | 1076 | // txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG, |
1077 | wave_a[8], wave_a[9], wave_a[10], wave_a[11]); | 1077 | // wave_a[8], wave_a[9], wave_a[10], wave_a[11]); |
1078 | txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG, | 1078 | // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG, |
1079 | wave_a[12], wave_a[13], wave_a[14], wave_a[15]); | 1079 | // wave_a[12], wave_a[13], wave_a[14], wave_a[15]); |
1080 | 1080 | ||
1081 | x += 70; | 1081 | x += 70; |
1082 | txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG, | 1082 | // txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG, |
1083 | wave_b[0], wave_b[1], wave_b[2], wave_b[3]); | 1083 | // wave_b[0], wave_b[1], wave_b[2], wave_b[3]); |
1084 | txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG, | 1084 | // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG, |
1085 | wave_b[4], wave_b[5], wave_b[6], wave_b[7]); | 1085 | // wave_b[4], wave_b[5], wave_b[6], wave_b[7]); |
1086 | txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG, | 1086 | // txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG, |
1087 | wave_b[8], wave_b[9], wave_b[10], wave_b[11]); | 1087 | // wave_b[8], wave_b[9], wave_b[10], wave_b[11]); |
1088 | txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG, | 1088 | // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG, |
1089 | wave_b[12], wave_b[13], wave_b[14], wave_b[15]); | 1089 | // wave_b[12], wave_b[13], wave_b[14], wave_b[15]); |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | // Draw default wave buttons. | 1092 | // Draw default wave buttons. |
@@ -1095,12 +1095,12 @@ draw_parameters_wave(void) { | |||
1095 | size_t x = PARAMS_START_X; | 1095 | size_t x = PARAMS_START_X; |
1096 | size_t y = PARAMS_START_Y + PARAMS_H - 12; | 1096 | size_t y = PARAMS_START_Y + PARAMS_H - 12; |
1097 | for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) { | 1097 | for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) { |
1098 | draw_tile(x + 17 * k, y, wave_tiles + i, COL_FG, true); | 1098 | // draw_tile(x + 17 * k, y, wave_tiles + i, COL_FG, true); |
1099 | draw_tile(x + 17 * k + 8, y, wave_tiles + i + 1, COL_FG, true); | 1099 | // draw_tile(x + 17 * k + 8, y, wave_tiles + i + 1, COL_FG, true); |
1100 | } | 1100 | } |
1101 | for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) { | 1101 | for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) { |
1102 | draw_tile(x + 17 * k + 70, y, wave_tiles + i, COL_FG, true); | 1102 | // draw_tile(x + 17 * k + 70, y, wave_tiles + i, COL_FG, true); |
1103 | draw_tile(x + 17 * k + 8 + 70, y, wave_tiles + i + 1, COL_FG, true); | 1103 | // draw_tile(x + 17 * k + 8 + 70, y, wave_tiles + i + 1, COL_FG, true); |
1104 | } | 1104 | } |
1105 | } | 1105 | } |
1106 | 1106 | ||
@@ -1113,7 +1113,7 @@ draw_parameters_wave(void) { | |||
1113 | draw_line(x, y + 5, x, y + 16, COL_FG); | 1113 | draw_line(x, y + 5, x, y + 16, COL_FG); |
1114 | draw_line(x + 30, y + 5, x + 30, y + 17, COL_FG); | 1114 | draw_line(x + 30, y + 5, x + 30, y + 17, COL_FG); |
1115 | draw_line(x, y + 17, x + 30, y + 17, COL_FG); | 1115 | draw_line(x, y + 17, x + 30, y + 17, COL_FG); |
1116 | txt_drawf_small("mode", x + 6, y, 4, COL_FG); | 1116 | // txt_drawf_small("mode", x + 6, y, 4, COL_FG); |
1117 | 1117 | ||
1118 | switch (pat->ch3.params[trig_selection_loc].wave_mode) { | 1118 | switch (pat->ch3.params[trig_selection_loc].wave_mode) { |
1119 | case 0: { | 1119 | case 0: { |
@@ -1137,7 +1137,7 @@ draw_parameters_wave(void) { | |||
1137 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1137 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1138 | draw_line(x + 30, y + 8, x + 30, y + 19, COL_FG); | 1138 | draw_line(x + 30, y + 8, x + 30, y + 19, COL_FG); |
1139 | draw_line(x, y + 20, x + 30, y + 20, COL_FG); | 1139 | draw_line(x, y + 20, x + 30, y + 20, COL_FG); |
1140 | txt_drawf_small("vol", x + 8, y + 3, 4, COL_FG); | 1140 | // txt_drawf_small("vol", x + 8, y + 3, 4, COL_FG); |
1141 | 1141 | ||
1142 | switch (pat->ch3.params[trig_selection_loc].wave_volume) { | 1142 | switch (pat->ch3.params[trig_selection_loc].wave_volume) { |
1143 | case 0: { | 1143 | case 0: { |
@@ -1232,7 +1232,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1232 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1232 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1233 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1233 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1234 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1234 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1235 | txt_drawf_small("duty", x + 3, y + 3, 4, COL_FG); | 1235 | // txt_drawf_small("duty", x + 3, y + 3, 4, COL_FG); |
1236 | 1236 | ||
1237 | switch (params->duty_cycle) { | 1237 | switch (params->duty_cycle) { |
1238 | case 0: { | 1238 | case 0: { |
@@ -1291,7 +1291,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1291 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1291 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1292 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1292 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1293 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1293 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1294 | txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG); | 1294 | // txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG); |
1295 | 1295 | ||
1296 | switch (params->env_volume) { | 1296 | switch (params->env_volume) { |
1297 | case 0: { | 1297 | case 0: { |
@@ -1354,7 +1354,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1354 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1354 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1355 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1355 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1356 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1356 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1357 | txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); | 1357 | // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); |
1358 | 1358 | ||
1359 | char arr_up[2] = { 0x19, 0 }; | 1359 | char arr_up[2] = { 0x19, 0 }; |
1360 | char arr_down[2] = { 0x18, 0 }; | 1360 | char arr_down[2] = { 0x18, 0 }; |
@@ -1377,7 +1377,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1377 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1377 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1378 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1378 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1379 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1379 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1380 | txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); | 1380 | // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); |
1381 | 1381 | ||
1382 | switch (params->env_time) { | 1382 | switch (params->env_time) { |
1383 | case 0: { | 1383 | case 0: { |
@@ -1417,7 +1417,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1417 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1417 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1418 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1418 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1419 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1419 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1420 | txt_drawf_small("num", x + 5, y + 3, 4, COL_FG); | 1420 | // txt_drawf_small("num", x + 5, y + 3, 4, COL_FG); |
1421 | 1421 | ||
1422 | switch (params->sweep_number) { | 1422 | switch (params->sweep_number) { |
1423 | case 0: { | 1423 | case 0: { |
@@ -1456,7 +1456,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1456 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1456 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1457 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1457 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1458 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1458 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1459 | txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); | 1459 | // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); |
1460 | 1460 | ||
1461 | switch (params->sweep_time) { | 1461 | switch (params->sweep_time) { |
1462 | case 0: { | 1462 | case 0: { |
@@ -1495,7 +1495,7 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1495 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1495 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1496 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1496 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1497 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1497 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1498 | txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); | 1498 | // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); |
1499 | 1499 | ||
1500 | char arr_up[2] = { 0x19, 0 }; | 1500 | char arr_up[2] = { 0x19, 0 }; |
1501 | char arr_down[2] = { 0x18, 0 }; | 1501 | char arr_down[2] = { 0x18, 0 }; |
@@ -1513,10 +1513,10 @@ draw_parameters_square(ChannelSquareParams *params, bool sweep) { | |||
1513 | { | 1513 | { |
1514 | size_t x = PARAMS_START_X + x_offset; | 1514 | size_t x = PARAMS_START_X + x_offset; |
1515 | size_t y = PARAMS_START_Y + PARAMS_H - 45; | 1515 | size_t y = PARAMS_START_Y + PARAMS_H - 45; |
1516 | txt_drawf_small("shape", x + 1, y - 12, 4, COL_FG); | 1516 | // txt_drawf_small("shape", x + 1, y - 12, 4, COL_FG); |
1517 | txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG); | 1517 | // txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG); |
1518 | if (sweep) { | 1518 | if (sweep) { |
1519 | txt_drawf_small("sweep", x + 133, y - 12, 4, COL_FG); | 1519 | // txt_drawf_small("sweep", x + 133, y - 12, 4, COL_FG); |
1520 | } | 1520 | } |
1521 | } | 1521 | } |
1522 | } | 1522 | } |
@@ -1538,7 +1538,7 @@ draw_parameters_noise(void) { | |||
1538 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1538 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1539 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1539 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1540 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1540 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1541 | txt_drawf_small("mode", x + 3, y + 3, 4, COL_FG); | 1541 | // txt_drawf_small("mode", x + 3, y + 3, 4, COL_FG); |
1542 | 1542 | ||
1543 | switch (params->bit_mode) { | 1543 | switch (params->bit_mode) { |
1544 | case 0: { | 1544 | case 0: { |
@@ -1591,7 +1591,7 @@ draw_parameters_noise(void) { | |||
1591 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1591 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1592 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1592 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1593 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1593 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1594 | txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG); | 1594 | // txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG); |
1595 | 1595 | ||
1596 | switch (params->env_volume) { | 1596 | switch (params->env_volume) { |
1597 | case 0: { | 1597 | case 0: { |
@@ -1654,7 +1654,7 @@ draw_parameters_noise(void) { | |||
1654 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1654 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1655 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1655 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1656 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1656 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1657 | txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); | 1657 | // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG); |
1658 | 1658 | ||
1659 | char arr_up[2] = { 0x19, 0 }; | 1659 | char arr_up[2] = { 0x19, 0 }; |
1660 | char arr_down[2] = { 0x18, 0 }; | 1660 | char arr_down[2] = { 0x18, 0 }; |
@@ -1677,7 +1677,7 @@ draw_parameters_noise(void) { | |||
1677 | draw_line(x, y + 8, x, y + 19, COL_FG); | 1677 | draw_line(x, y + 8, x, y + 19, COL_FG); |
1678 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); | 1678 | draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG); |
1679 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); | 1679 | draw_line(x, y + 20, x + 24, y + 20, COL_FG); |
1680 | txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); | 1680 | // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG); |
1681 | 1681 | ||
1682 | switch (params->env_time) { | 1682 | switch (params->env_time) { |
1683 | case 0: { | 1683 | case 0: { |
@@ -1712,7 +1712,7 @@ draw_parameters_noise(void) { | |||
1712 | { | 1712 | { |
1713 | size_t x = PARAMS_START_X + x_offset; | 1713 | size_t x = PARAMS_START_X + x_offset; |
1714 | size_t y = PARAMS_START_Y + PARAMS_H - 45; | 1714 | size_t y = PARAMS_START_Y + PARAMS_H - 45; |
1715 | txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG); | 1715 | // txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG); |
1716 | } | 1716 | } |
1717 | } | 1717 | } |
1718 | 1718 | ||
diff --git a/src/text/font.h b/src/text/font.h index daf0c24..e4b089c 100644 --- a/src/text/font.h +++ b/src/text/font.h | |||
@@ -128,3 +128,134 @@ static const u32 font[] = { | |||
128 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 128 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
129 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 129 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
130 | }; | 130 | }; |
131 | |||
132 | u32 font_icn[] = { | ||
133 | 0x00000000, 0x00000000, 0x00240000, 0x00003c42, | ||
134 | 0x00240000, 0x0000423c, 0x3e360000, 0x00081c3e, | ||
135 | 0x3e1c0800, 0x00081c3e, 0x3e1c1c00, 0x1c083e36, | ||
136 | 0x3e1c0800, 0x1c083e3e, 0x18000000, 0x00000018, | ||
137 | 0x667e7e7e, 0x7e7e7e66, 0x24180000, 0x00001824, | ||
138 | 0x5a667e7e, 0x7e7e665a, 0x3e1c0800, 0x1c221c08, | ||
139 | 0x1c221c00, 0x083e0808, 0x28381800, 0x0c0c0808, | ||
140 | 0x24243c00, 0x06363424, 0x08220800, 0x0822081c, | ||
141 | 0x3c1c0c04, 0x00040c1c, 0x3c383020, 0x00203038, | ||
142 | 0x083e1c08, 0x081c3e08, 0x14141400, 0x00140014, | ||
143 | 0x2a2a3c00, 0x2828282c, 0x3c043800, 0x1e203c42, | ||
144 | 0x00000000, 0x0000007e, 0x083e1c08, 0x3e081c3e, | ||
145 | 0x3e1c0800, 0x00080808, 0x08080800, 0x00081c3e, | ||
146 | 0x30100000, 0x0010307e, 0x0c080000, 0x00080c7e, | ||
147 | 0x00000000, 0x3e020200, 0x36140000, 0x0014367f, | ||
148 | 0x1c080800, 0x003e3e1c, 0x1c3e3e00, 0x0008081c, | ||
149 | 0x00000000, 0x00000000, 0x08080800, 0x00080008, | ||
150 | 0x14141400, 0x00000000, 0x3e140000, 0x00143e14, | ||
151 | 0x021c0800, 0x081e201c, 0x16260000, 0x00323408, | ||
152 | 0x08140800, 0x002c1234, 0x08080800, 0x00000000, | ||
153 | 0x04080000, 0x00080404, 0x10080000, 0x00081010, | ||
154 | 0x08140000, 0x0014083e, 0x08080000, 0x0008083e, | ||
155 | 0x00000000, 0x04080c00, 0x00000000, 0x0000003e, | ||
156 | 0x00000000, 0x000c0c00, 0x18302000, 0x0002060c, | ||
157 | 0x221c0000, 0x001c222a, 0x0a0c0000, 0x003e0808, | ||
158 | 0x201c0000, 0x003e021c, 0x221c0000, 0x001c2218, | ||
159 | 0x12120000, 0x00103e12, 0x023e0000, 0x001e201e, | ||
160 | 0x021c0000, 0x001c221e, 0x203e0000, 0x00040810, | ||
161 | 0x221c0000, 0x001c221c, 0x221c0000, 0x001c203c, | ||
162 | 0x0c0c0000, 0x000c0c00, 0x0c0c0000, 0x04080c00, | ||
163 | 0x08100000, 0x00100804, 0x3e000000, 0x00003e00, | ||
164 | 0x08040000, 0x00040810, 0x10221c00, 0x00080008, | ||
165 | 0x2a1c0000, 0x001c023a, 0x221c0000, 0x00223e22, | ||
166 | 0x221e0000, 0x001e221e, 0x221c0000, 0x001c2202, | ||
167 | 0x221e0000, 0x001e2222, 0x023e0000, 0x003e021e, | ||
168 | 0x023e0000, 0x0002021e, 0x021c0000, 0x001c2232, | ||
169 | 0x22220000, 0x0022223e, 0x083e0000, 0x003e0808, | ||
170 | 0x20200000, 0x001c2220, 0x12220000, 0x0022120e, | ||
171 | 0x02020000, 0x003e0202, 0x36220000, 0x0022222a, | ||
172 | 0x2a260000, 0x00222232, 0x221c0000, 0x001c2222, | ||
173 | 0x221e0000, 0x00021e22, 0x221c0000, 0x002c1222, | ||
174 | 0x221e0000, 0x00221e22, 0x021c0000, 0x001e201c, | ||
175 | 0x083e0000, 0x00080808, 0x22220000, 0x001c2222, | ||
176 | 0x22220000, 0x00081422, 0x2a220000, 0x00142a2a, | ||
177 | 0x14220000, 0x00221408, 0x22220000, 0x00080814, | ||
178 | 0x103e0000, 0x003e0408, 0x041c0000, 0x001c0404, | ||
179 | 0x0c060200, 0x00203018, 0x101c0000, 0x001c1010, | ||
180 | 0x22140800, 0x00000000, 0x00000000, 0x003e0000, | ||
181 | 0x10080400, 0x00000000, 0x201c0000, 0x003c223c, | ||
182 | 0x1e020200, 0x001e2222, 0x021c0000, 0x001c0202, | ||
183 | 0x3c202000, 0x003c2222, 0x221c0000, 0x001c021e, | ||
184 | 0x023c0000, 0x0002021e, 0x223c0000, 0x1c203c22, | ||
185 | 0x1e020200, 0x00222222, 0x0c000800, 0x003e0808, | ||
186 | 0x20002000, 0x1c222020, 0x0a120200, 0x00320a06, | ||
187 | 0x08080c00, 0x003e0808, 0x2a160000, 0x002a2a2a, | ||
188 | 0x320e0000, 0x00222222, 0x221c0000, 0x001c2222, | ||
189 | 0x221e0000, 0x02021e22, 0x223c0000, 0x70203c22, | ||
190 | 0x261a0000, 0x00020202, 0x021c0000, 0x001e201c, | ||
191 | 0x043e0400, 0x00180404, 0x22220000, 0x001c2222, | ||
192 | 0x22220000, 0x00081422, 0x22220000, 0x00142a2a, | ||
193 | 0x14220000, 0x00221408, 0x22220000, 0x1c203c22, | ||
194 | 0x103e0000, 0x003e0408, 0x041c0000, 0x001c0406, | ||
195 | 0x08080000, 0x00080808, 0x101c0000, 0x001c1030, | ||
196 | 0x1a2c0000, 0x00000000, 0x14080000, 0x003e2222, | ||
197 | 0x00000000, 0x00000000, 0x08080000, 0x00080008, | ||
198 | 0x14140000, 0x00000000, 0x3e140000, 0x00143e14, | ||
199 | 0x041c0800, 0x081c101c, 0x10040000, 0x00100408, | ||
200 | 0x14080000, 0x00381438, 0x08080000, 0x00000000, | ||
201 | 0x04080000, 0x00080404, 0x10080000, 0x00081010, | ||
202 | 0x08140000, 0x0014081c, 0x08000000, 0x0000081c, | ||
203 | 0x00000000, 0x04080000, 0x00000000, 0x0000001c, | ||
204 | 0x00000000, 0x00080000, 0x18100000, 0x00040c08, | ||
205 | 0x141c0000, 0x001c1414, 0x0c080000, 0x001c0808, | ||
206 | 0x101c0000, 0x001c041c, 0x101c0000, 0x001c1018, | ||
207 | 0x14140000, 0x0010101c, 0x041c0000, 0x001c101c, | ||
208 | 0x041c0000, 0x001c141c, 0x101c0000, 0x00040408, | ||
209 | 0x141c0000, 0x001c141c, 0x141c0000, 0x0010101c, | ||
210 | 0x08000000, 0x00080000, 0x08000000, 0x04080000, | ||
211 | 0x08100000, 0x00100804, 0x1c000000, 0x00001c00, | ||
212 | 0x08040000, 0x00040810, 0x101c0000, 0x00080008, | ||
213 | 0x141c0000, 0x001c0414, 0x141c0000, 0x00141c14, | ||
214 | 0x141c0000, 0x001c140c, 0x041c0000, 0x001c0404, | ||
215 | 0x140c0000, 0x000c1414, 0x041c0000, 0x001c040c, | ||
216 | 0x041c0000, 0x0004040c, 0x041c0000, 0x001c1414, | ||
217 | 0x14140000, 0x0014141c, 0x081c0000, 0x001c0808, | ||
218 | 0x10100000, 0x001c1410, 0x14140000, 0x0014140c, | ||
219 | 0x04040000, 0x001c0404, 0x1c140000, 0x00141414, | ||
220 | 0x140c0000, 0x00141414, 0x140c0000, 0x001c1414, | ||
221 | 0x141c0000, 0x0004041c, 0x141c0000, 0x00101c14, | ||
222 | 0x141c0000, 0x0014140c, 0x04180000, 0x000c101c, | ||
223 | 0x081c0000, 0x00080808, 0x14140000, 0x001c1414, | ||
224 | 0x14140000, 0x00181414, 0x14140000, 0x00141c14, | ||
225 | 0x14140000, 0x00141408, 0x14140000, 0x0008081c, | ||
226 | 0x101c0000, 0x001c0408, 0x041c0000, 0x001c0404, | ||
227 | 0x0c040000, 0x00101808, 0x101c0000, 0x001c1010, | ||
228 | 0x14080000, 0x00000000, 0x00000000, 0x001c0000, | ||
229 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
230 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
231 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
232 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
233 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
234 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
235 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
236 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
237 | 0x3232323e, 0x003e3232, 0x18181818, 0x00181818, | ||
238 | 0x3e30303e, 0x003e0606, 0x3c30303e, 0x003e3030, | ||
239 | 0x32323232, 0x0030303e, 0x3e06063e, 0x003e3030, | ||
240 | 0x3e06063e, 0x003e2626, 0x1830303e, 0x0006060c, | ||
241 | 0x3e32323e, 0x003e3232, 0x3e32323e, 0x003e3030, | ||
242 | 0x00000000, 0x00060600, 0x18362600, 0x0032360c, | ||
243 | 0x32323e1c, 0x0032323e, 0x1e26261e, 0x001e2626, | ||
244 | 0x0606063c, 0x003c0606, 0x3232321e, 0x001e3232, | ||
245 | 0x1e06063e, 0x003e0606, 0x1e06063e, 0x00060606, | ||
246 | 0x3606063c, 0x001c2626, 0x3e323232, 0x00323232, | ||
247 | 0x0c0c0c1e, 0x001e0c0c, 0x30303030, 0x003e3232, | ||
248 | 0x0e162626, 0x00262616, 0x06060606, 0x003e0606, | ||
249 | 0x6a7e7662, 0x00626262, 0x323a3e36, 0x00323232, | ||
250 | 0x3232321c, 0x001c3232, 0x3e32323e, 0x00020202, | ||
251 | 0x3232321c, 0x002c1a3a, 0x1e26261e, 0x00262626, | ||
252 | 0x1e06063c, 0x001e3030, 0x1818187e, 0x00181818, | ||
253 | 0x32323232, 0x003e3232, 0x32323232, 0x00183432, | ||
254 | 0x32323232, 0x00143a32, 0x0c323232, 0x00323232, | ||
255 | 0x32323232, 0x001e203c, 0x1c30303e, 0x003e0606, | ||
256 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
257 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
258 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
259 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
260 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||
261 | }; | ||
diff --git a/src/text/text.h b/src/text/text.h index 0bcf090..ab525d4 100644 --- a/src/text/text.h +++ b/src/text/text.h | |||
@@ -2,10 +2,8 @@ | |||
2 | #define TEXT_H | 2 | #define TEXT_H |
3 | 3 | ||
4 | #include "posprintf.h" | 4 | #include "posprintf.h" |
5 | #include "renderer.h" | ||
6 | |||
7 | #include "font.h" | ||
8 | 5 | ||
6 | typedef void (*TxtDrawc)(char c, size_t x, size_t y, u8 clr); | ||
9 | typedef struct TextEngine { | 7 | typedef struct TextEngine { |
10 | // Cursor for tiled text mode The X and Y positions correspond to the tile | 8 | // Cursor for tiled text mode The X and Y positions correspond to the tile |
11 | // X and Y starting from the top left of the screen. For a 240x160 screen, | 9 | // X and Y starting from the top left of the screen. For a 240x160 screen, |
@@ -13,14 +11,10 @@ typedef struct TextEngine { | |||
13 | size_t cursor_x; | 11 | size_t cursor_x; |
14 | size_t cursor_y; | 12 | size_t cursor_y; |
15 | 13 | ||
16 | // Memory location of font tile data and tilemap. Likely located on the | 14 | u8 buffer[30 * 20]; |
17 | // VRAM. | 15 | u8 spacing; |
18 | u32 *font_data; | 16 | u8 color; |
19 | u16 *font_tilemap; | 17 | TxtDrawc drawc; |
20 | |||
21 | // The font map for tiled text. Writing the character stored in this | ||
22 | // position on the tilemap will show a character on the screen. | ||
23 | u16 font_map[256]; | ||
24 | } TextEngine; | 18 | } TextEngine; |
25 | 19 | ||
26 | static TextEngine text_engine = {0}; | 20 | static TextEngine text_engine = {0}; |
@@ -28,20 +22,11 @@ static TextEngine text_engine = {0}; | |||
28 | // Initializes the text engine. | 22 | // Initializes the text engine. |
29 | static inline | 23 | static inline |
30 | void | 24 | void |
31 | txt_init(u32 *font_data, u16 *font_tilemap, u16 font_offset) { | 25 | txt_init(TxtDrawc drawc) { |
32 | // Load font data into VRAM. | ||
33 | unpack_tiles(&font, font_data, 256); | ||
34 | |||
35 | // Initialize the font map translation table. That way we can write | ||
36 | // a character on the text background layer with: | ||
37 | // FONT_TILEMAP[tile_x + 32 * tile_y] = font_map['A']; | ||
38 | for (size_t i = 0; i < 256; ++i) { | ||
39 | text_engine.font_map[i] = font_offset + i; | ||
40 | } | ||
41 | |||
42 | // Initialize remaining variables. | 26 | // Initialize remaining variables. |
43 | text_engine.font_data = font_data; | 27 | text_engine.spacing = 8; |
44 | text_engine.font_tilemap = font_tilemap; | 28 | text_engine.color = 1; |
29 | text_engine.drawc = drawc; | ||
45 | } | 30 | } |
46 | 31 | ||
47 | // Writes a message to the tile text background. | 32 | // Writes a message to the tile text background. |
@@ -59,7 +44,7 @@ txt_puts(char *msg) { | |||
59 | } else { | 44 | } else { |
60 | int x = text_engine.cursor_x; | 45 | int x = text_engine.cursor_x; |
61 | int y = text_engine.cursor_y; | 46 | int y = text_engine.cursor_y; |
62 | text_engine.font_tilemap[x + 32 * y] = text_engine.font_map[(u16)c]; | 47 | text_engine.buffer[x + 30 * y] = c; |
63 | text_engine.cursor_x += 1; | 48 | text_engine.cursor_x += 1; |
64 | if (text_engine.cursor_x >= 30) { | 49 | if (text_engine.cursor_x >= 30) { |
65 | text_engine.cursor_x = 0; | 50 | text_engine.cursor_x = 0; |
@@ -76,18 +61,15 @@ txt_puts(char *msg) { | |||
76 | static inline | 61 | static inline |
77 | void | 62 | void |
78 | txt_clear_line(void) { | 63 | txt_clear_line(void) { |
79 | for (size_t i = 0; i < 30; ++i) { | 64 | dma_fill(text_engine.buffer, 0, sizeof(text_engine.buffer), 3); |
80 | int x = text_engine.cursor_x; | ||
81 | int y = text_engine.cursor_y; | ||
82 | text_engine.font_tilemap[x + 32 * y] = text_engine.font_map[0]; | ||
83 | } | ||
84 | text_engine.cursor_x = 0; | 65 | text_engine.cursor_x = 0; |
66 | text_engine.cursor_y = 0; | ||
85 | } | 67 | } |
86 | 68 | ||
87 | // Clears the screen on the tile text mode. | 69 | // Clears the screen on the tile text mode. |
88 | static inline | 70 | static inline |
89 | void | 71 | void |
90 | txt_clear_screen(void) { | 72 | txt_clear(void) { |
91 | for (size_t j = 0; j < 20; ++j) { | 73 | for (size_t j = 0; j < 20; ++j) { |
92 | text_engine.cursor_y = j; | 74 | text_engine.cursor_y = j; |
93 | txt_clear_line(); | 75 | txt_clear_line(); |
@@ -104,30 +86,49 @@ txt_position(size_t tile_x, size_t tile_y) { | |||
104 | text_engine.cursor_y = tile_y; | 86 | text_engine.cursor_y = tile_y; |
105 | } | 87 | } |
106 | 88 | ||
89 | static inline | ||
90 | void | ||
91 | txt_color(u8 clr) { | ||
92 | text_engine.color = clr; | ||
93 | } | ||
94 | |||
95 | static inline | ||
96 | void | ||
97 | txt_spacing(u8 spacing) { | ||
98 | text_engine.spacing = spacing; | ||
99 | } | ||
100 | |||
101 | // Renders the contents of the scrollback buffer to the screen. | ||
102 | void | ||
103 | txt_render(void) { | ||
104 | for (size_t y = 0; y < 20; y++) { | ||
105 | for (size_t x = 0; x < 30; x++) { | ||
106 | size_t pos = x + y * 30; | ||
107 | if (text_engine.buffer[pos] == 0) { | ||
108 | continue; | ||
109 | } | ||
110 | text_engine.drawc( | ||
111 | text_engine.buffer[pos], | ||
112 | x * text_engine.spacing, | ||
113 | y * text_engine.spacing, | ||
114 | text_engine.color); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
107 | // Draws a message where the first character's top-left corner begins at the | 119 | // Draws a message where the first character's top-left corner begins at the |
108 | // given x and y position. The character spacing can be adjusted, but beware of | 120 | // given x and y position. The character spacing can be adjusted, but beware of |
109 | // color merging issues. | 121 | // color merging issues. |
110 | static inline | 122 | static inline |
111 | void | 123 | void |
112 | txt_draws(char *msg, size_t x, size_t y, size_t spacing, u8 clr) { | 124 | txt_draws(char *msg, size_t x, size_t y, u8 clr) { |
125 | size_t i = 0; | ||
113 | while (*msg) { | 126 | while (*msg) { |
114 | char c = *msg++; | 127 | char c = *msg++; |
115 | Tile *tile = FONT_DATA; | 128 | text_engine.drawc(c, x + i++ * text_engine.spacing, y, clr); |
116 | tile += c; | ||
117 | draw_tile(x, y, tile, clr, true); | ||
118 | x += spacing; | ||
119 | } | 129 | } |
120 | } | 130 | } |
121 | 131 | ||
122 | static inline | ||
123 | void | ||
124 | txt_drawc(char c, size_t x, size_t y, size_t spacing, u8 clr) { | ||
125 | Tile *tile = FONT_DATA; | ||
126 | tile += c; | ||
127 | draw_tile(x, y, tile, clr, true); | ||
128 | x += spacing; | ||
129 | } | ||
130 | |||
131 | // Print text to the screen with formatting. | 132 | // Print text to the screen with formatting. |
132 | #define txt_printf(msg, ...) \ | 133 | #define txt_printf(msg, ...) \ |
133 | { \ | 134 | { \ |
@@ -138,31 +139,11 @@ txt_drawc(char c, size_t x, size_t y, size_t spacing, u8 clr) { | |||
138 | 139 | ||
139 | // Draws text to the screen with formatting starting on the x and y position and | 140 | // Draws text to the screen with formatting starting on the x and y position and |
140 | // with custom character spacing. | 141 | // with custom character spacing. |
141 | #define txt_drawf(msg, x, y, s, c, ...) \ | 142 | #define txt_drawf(msg, x, y, c, ...) \ |
142 | { \ | ||
143 | char buf[256] = {0}; \ | ||
144 | posprintf(buf, msg, ##__VA_ARGS__); \ | ||
145 | txt_draws(buf, x, y, s, c); \ | ||
146 | } | ||
147 | |||
148 | // Small font is located after the initial ASCII characters, and only supports | ||
149 | // lowercase characters. | ||
150 | // NOTE: Slow, we should do this with a LUT. | ||
151 | #define txt_drawf_small(msg, x, y, s, c, ...) \ | ||
152 | { \ | 143 | { \ |
153 | char buf[256] = {0}; \ | 144 | char buf[256] = {0}; \ |
154 | posprintf(buf, msg, ##__VA_ARGS__); \ | 145 | posprintf(buf, msg, ##__VA_ARGS__); \ |
155 | for (size_t i = 0; i < 256; i++) { \ | 146 | txt_draws(buf, x, y, c); \ |
156 | if (buf[i] == 0) { \ | ||
157 | break; \ | ||
158 | } \ | ||
159 | if (buf[i] < 'a') { \ | ||
160 | buf[i] += 16 * 6; \ | ||
161 | } else { \ | ||
162 | buf[i] += 16 * 4; \ | ||
163 | }\ | ||
164 | } \ | ||
165 | txt_draws(buf, x, y, s, c); \ | ||
166 | } | 147 | } |
167 | 148 | ||
168 | #endif // TEXT_H | 149 | #endif // TEXT_H |