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