diff options
Diffstat (limited to 'src/bitmap.h')
-rw-r--r-- | src/bitmap.h | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/src/bitmap.h b/src/bitmap.h new file mode 100644 index 0000000..0befe5d --- /dev/null +++ b/src/bitmap.h | |||
@@ -0,0 +1,228 @@ | |||
1 | #ifndef GBAEXP_BITMAP_H | ||
2 | #define GBAEXP_BITMAP_H | ||
3 | |||
4 | #include "bd-font.c" | ||
5 | #include "common.c" | ||
6 | |||
7 | // Using bd-font, an 8x8 bitmap font. | ||
8 | static void | ||
9 | put_char(int x, int y, Color clr, u8 chr) { | ||
10 | for (size_t i = 0; i < 8; ++i) { | ||
11 | for (size_t j = 0; j < 8; ++j) { | ||
12 | if ((font[chr][i] >> (7 - j)) & 0x1) { | ||
13 | FRAMEBUFFER[y + i][x + j] = clr; | ||
14 | } | ||
15 | } | ||
16 | } | ||
17 | } | ||
18 | |||
19 | static void | ||
20 | put_text(int x, int y, Color clr, char *msg) { | ||
21 | int count = 0; | ||
22 | while (*msg) { | ||
23 | put_char(x + count, y, clr, *msg++); | ||
24 | count += 8; | ||
25 | } | ||
26 | } | ||
27 | |||
28 | // Draws a line with the given color between (x0,y0) and (x1,y1) using the | ||
29 | // Bresenham's line drawing algorithm using exclusively integer arithmetic. | ||
30 | static void | ||
31 | draw_line(int x0, int y0, int x1, int y1, Color clr) { | ||
32 | // Pointer to the initial position of the screen buffer where we will start | ||
33 | // writing our data. | ||
34 | vu16 *destination = (u16*)(SCREEN_BUFFER + y0 * SCREEN_WIDTH + x0); | ||
35 | |||
36 | // Adjust the step direction and calculate deltas. | ||
37 | int x_step; | ||
38 | int y_step; | ||
39 | int dx; | ||
40 | int dy; | ||
41 | if (x0 > x1) { | ||
42 | x_step = -1; | ||
43 | dx = x0 - x1; | ||
44 | } else { | ||
45 | x_step = 1; | ||
46 | dx = x1 - x0; | ||
47 | } | ||
48 | if (y0 > y1) { | ||
49 | y_step = -SCREEN_WIDTH; | ||
50 | dy = y0 - y1; | ||
51 | } else { | ||
52 | y_step = +SCREEN_WIDTH; | ||
53 | dy = y1 - y0; | ||
54 | } | ||
55 | |||
56 | if(dy == 0) { | ||
57 | // Horizontal line. | ||
58 | for(int i = 0; i <= dx; i++) { | ||
59 | destination[i * x_step] = clr; | ||
60 | } | ||
61 | } else if(dx == 0) { | ||
62 | // Vertical line. | ||
63 | for(int i = 0; i <= dy; i++) { | ||
64 | destination[i * y_step] = clr; | ||
65 | } | ||
66 | } else if (dx >= dy){ | ||
67 | // Positive slope. | ||
68 | int diff = 2 * dy - dx; | ||
69 | for (int i = 0; i <= dx; ++i) { | ||
70 | *destination = clr; | ||
71 | if (diff >= 0) { | ||
72 | destination += y_step; | ||
73 | diff -= 2 * dx; | ||
74 | } | ||
75 | destination += x_step; | ||
76 | diff += 2 * dy; | ||
77 | } | ||
78 | } else { | ||
79 | // Negative slope. | ||
80 | int diff = 2 * dx - dy; | ||
81 | for (int i = 0; i <= dy; ++i) { | ||
82 | *destination = clr; | ||
83 | if (diff >= 0) { | ||
84 | destination += x_step; | ||
85 | diff -= 2 * dy; | ||
86 | } | ||
87 | destination += y_step; | ||
88 | diff += 2 * dx; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static inline void | ||
94 | draw_rect(int x0, int y0, int x1, int y1, Color clr) { | ||
95 | if (x0 > x1) { | ||
96 | int tmp = x0; | ||
97 | x0 = x1; | ||
98 | x1 = tmp; | ||
99 | } | ||
100 | if (y0 > y1) { | ||
101 | int tmp = y0; | ||
102 | y0 = y1; | ||
103 | y1 = tmp; | ||
104 | } | ||
105 | int dx = x1 - x0; | ||
106 | int dy = y1 - y0; | ||
107 | for (int i = 0; i <= dx; ++i) { | ||
108 | int x = x0 + i; | ||
109 | FRAMEBUFFER[y0][x] = clr; | ||
110 | FRAMEBUFFER[y1][x] = clr; | ||
111 | } | ||
112 | for (int j = 0; j <= dy; ++j) { | ||
113 | int y = y0 + j; | ||
114 | FRAMEBUFFER[y][x0] = clr; | ||
115 | FRAMEBUFFER[y][x1] = clr; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static inline void | ||
120 | draw_fill_rect(int x0, int y0, int x1, int y1, Color clr) { | ||
121 | if (x0 > x1) { | ||
122 | int tmp = x0; | ||
123 | x0 = x1; | ||
124 | x1 = tmp; | ||
125 | } | ||
126 | if (y0 > y1) { | ||
127 | int tmp = y0; | ||
128 | y0 = y1; | ||
129 | y1 = tmp; | ||
130 | } | ||
131 | int dx = x1 - x0; | ||
132 | int dy = y1 - y0; | ||
133 | for (int i = 0; i <= dx; ++i) { | ||
134 | for (int j = 0; j <= dy; ++j) { | ||
135 | int x = x0 + i; | ||
136 | int y = y0 + j; | ||
137 | FRAMEBUFFER[y][x] = clr; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // In Mode4 the buffer is of 8 bytes per pixel instead of 16. We can't write the | ||
143 | // color directly, instead the color is stored in the palette memory at | ||
144 | // `MEM_PAL`. Note that in this mode MEM_PAL[0] is the background color. This | ||
145 | // plotter takes an index to a color stored in MEM_PAL[col_index]. Because the | ||
146 | // GBA needs to meet memory alignment requirements, we can't write a u8 into | ||
147 | // memory, instead we need to read a u16 word, mask and or the corresponding | ||
148 | // bits and wave the updated u16. | ||
149 | static void | ||
150 | put_pixel_m4(int x, int y, u8 col_index, vu16 *buffer) { | ||
151 | int buffer_index = (y * SCREEN_WIDTH + x) / 2; | ||
152 | vu16 *destination = &buffer[buffer_index]; | ||
153 | // Odd pixels will go to the top 8 bits of the destination. Even pixels to | ||
154 | // the lower 8 bits. | ||
155 | int odd = x & 0x1; | ||
156 | if(odd) { | ||
157 | *destination= (*destination & 0xFF) | (col_index << 8); | ||
158 | } else { | ||
159 | *destination= (*destination & ~0xFF) | col_index; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static void | ||
164 | draw_fill_rect_m4(int x0, int y0, int x1, int y1, u8 col_index, vu16 *buffer) { | ||
165 | int ix, iy; | ||
166 | for(iy = y0; iy < y1; iy++) { | ||
167 | for(ix = x0; ix < x1; ix++) { | ||
168 | put_pixel_m4(ix, iy, col_index, buffer); | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | void | ||
174 | draw_logo(void) { | ||
175 | int side = 60; | ||
176 | int line = 35; | ||
177 | int height = side * 0.5; | ||
178 | int x = SCREEN_WIDTH / 2 - height / 2; | ||
179 | int y = SCREEN_HEIGHT / 2; | ||
180 | |||
181 | // Draw red triangle. | ||
182 | draw_line(x + height - 1, y - side / 2, x, y - 1, COLOR_RED); | ||
183 | draw_line(x + height - 1, y + side / 2, x, y + 1, COLOR_RED); | ||
184 | draw_line(x + height - 1, y - side / 2 + 1, x, y, COLOR_RED); | ||
185 | draw_line(x + height - 1, y + side / 2 - 1, x, y, COLOR_RED); | ||
186 | |||
187 | // Draw white triangle. | ||
188 | draw_line(x, y - side / 2, x, y + side / 2, COLOR_WHITE); | ||
189 | draw_line(x + 1, y - side / 2, x + height, y - 1, COLOR_WHITE); | ||
190 | draw_line(x + 1, y + side / 2, x + height, y + 1, COLOR_WHITE); | ||
191 | |||
192 | // Draw white line at triangle tip. | ||
193 | draw_line(x + height, y - side / 2, x + height, y + side / 2, COLOR_WHITE); | ||
194 | draw_line(x + height + 1, y - side / 2, x + height + 1, y + side / 2, COLOR_WHITE); | ||
195 | |||
196 | // Double triangle line. | ||
197 | draw_line(x - 1, y - side / 2, x - 1, y + side / 2, COLOR_WHITE); | ||
198 | draw_line(x + 1, y - side / 2 + 1, x + height, y, COLOR_WHITE); | ||
199 | draw_line(x + 1, y + side / 2 - 1, x + height, y, COLOR_WHITE); | ||
200 | |||
201 | // Draw white lines. | ||
202 | draw_line(x - line, y, x, y, COLOR_WHITE); | ||
203 | draw_line(x + height, y, x + height + line, y, COLOR_WHITE); | ||
204 | draw_line(x - line, y + 1, x, y + 1, COLOR_WHITE); | ||
205 | draw_line(x + height, y + 1, x + height + line, y + 1, COLOR_WHITE); | ||
206 | } | ||
207 | |||
208 | void | ||
209 | copy_font_to_tile_memory(Tile *tile) { | ||
210 | // Hex to bits translation table. | ||
211 | const u32 conversion_u32[16] = { | ||
212 | 0x00000000, 0x00001000, 0x00000100, 0x00001100, | ||
213 | 0x00000010, 0x00001010, 0x00000110, 0x00001110, | ||
214 | 0x00000001, 0x00001001, 0x00000101, 0x00001101, | ||
215 | 0x00000011, 0x00001011, 0x00000111, 0x00001111, | ||
216 | }; | ||
217 | for (size_t i = 0; i < 250; ++i) { | ||
218 | for (size_t j = 0; j < 8; ++j) { | ||
219 | u8 row = font[i][j]; | ||
220 | u32 tile_idx = 0x00000000; | ||
221 | tile_idx = conversion_u32[row & 0xF] << 16; | ||
222 | tile_idx |= conversion_u32[(row >> 4) & 0xF]; | ||
223 | (tile + i)->data[j] = tile_idx; | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | #endif // GBAEXP_BITMAP_H | ||