aboutsummaryrefslogtreecommitdiffstats
path: root/src/bitmap.h
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-18 16:40:24 +0200
committerBad Diode <bd@badd10de.dev>2021-05-18 16:40:24 +0200
commit0c7265cf0de9d4ec95d28c5e103c00a63f4a1697 (patch)
tree4a1145e849e078395430a8d718c4bd69a06fb29f /src/bitmap.h
downloaduxngba-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.h209
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.
8static void
9draw_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
71static inline void
72draw_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
97static inline void
98draw_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.
127static inline void
128put_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
141static inline void
142put_pixel_m3(int x, int y, u16 color, Scanline *buffer) {
143 buffer[y][x] = color;
144}
145
146static inline void
147clear_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
155static inline void
156clear_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
164static inline void
165draw_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
174void
175draw_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