summaryrefslogtreecommitdiffstats
path: root/src/bitmap.h
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-04-26 11:11:36 +0200
committerBad Diode <bd@badd10de.dev>2021-04-26 11:11:36 +0200
commit24887f28c3eb6d67a7c1a0803520b3fb728ee4f3 (patch)
tree3816d8f7f4e1d3d6c4bb6caf084cbb06d93e941c /src/bitmap.h
parent0f16e5bfb1738330a33b300067f86d363fd250bf (diff)
downloadgba-experiments-24887f28c3eb6d67a7c1a0803520b3fb728ee4f3.tar.gz
gba-experiments-24887f28c3eb6d67a7c1a0803520b3fb728ee4f3.zip
Move code to relevant files for organization
Diffstat (limited to 'src/bitmap.h')
-rw-r--r--src/bitmap.h228
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.
8static void
9put_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
19static void
20put_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.
30static void
31draw_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
93static inline void
94draw_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
119static inline void
120draw_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.
149static void
150put_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
163static void
164draw_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
173void
174draw_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
208void
209copy_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