summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-06-04 15:36:18 +0200
committerBad Diode <bd@badd10de.dev>2021-06-04 15:36:18 +0200
commit8feaf2dc269dd0cb81de87be90d2b2c7f28bcbea (patch)
tree70c679876c0e74ec029bda2f3e6c00d46024fb71
parentef15a89a8cf161241c3c382e0e332427e46be8a9 (diff)
downloadgba-sequencer-8feaf2dc269dd0cb81de87be90d2b2c7f28bcbea.tar.gz
gba-sequencer-8feaf2dc269dd0cb81de87be90d2b2c7f28bcbea.zip
Add line drawing func for horz/vert lines
-rw-r--r--src/main.c1
-rw-r--r--src/renderer.c207
2 files changed, 178 insertions, 30 deletions
diff --git a/src/main.c b/src/main.c
index 8df466f..048824e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -55,6 +55,7 @@ test_rects() {
55 for (size_t i = 0; i < 100; i++) { 55 for (size_t i = 0; i < 100; i++) {
56 draw_rect(30, 30, 45, 45, 1); 56 draw_rect(30, 30, 45, 45, 1);
57 draw_rect(35, 35, 60, 40, 2); 57 draw_rect(35, 35, 60, 40, 2);
58 draw_rect(10, 10, 200, 130, 2);
58 draw_rect(1, 1, 6, 6, 3); 59 draw_rect(1, 1, 6, 6, 3);
59 } 60 }
60} 61}
diff --git a/src/renderer.c b/src/renderer.c
index c66b87b..d247d06 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -46,6 +46,145 @@ draw_pixel(size_t x, size_t y, u8 color) {
46 46
47IWRAM_CODE 47IWRAM_CODE
48void 48void
49draw_line(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) {
50 // Pointer to the initial position of the screen buffer where we will start
51 // writing our data.
52 // vu16 *destination = (u16*)(SCREEN_BUFFER + y0 * SCREEN_WIDTH + x0);
53
54// // Adjust the step direction and calculate deltas.
55// size_t x_step;
56// size_t y_step;
57// size_t dx;
58// size_t dy;
59// if (x0 > x1) {
60// x_step = -1;
61// dx = x0 - x1;
62// } else {
63// x_step = 1;
64// dx = x1 - x0;
65// }
66// if (y0 > y1) {
67// y_step = -SCREEN_WIDTH;
68// dy = y0 - y1;
69// } else {
70// y_step = +SCREEN_WIDTH;
71// dy = y1 - y0;
72// }
73
74// if(dy == 0) {
75// // Horizontal line.
76// for(int i = 0; i <= dx; i++) {
77// draw_pixel(x0 + i, y0, clr);
78// }
79// } else if(dx == 0) {
80// // Vertical line.
81// for(int i = 0; i <= dy; i++) {
82// draw_pixel(x0, y0 + i, clr);
83// }
84// } else if (dx >= dy){
85// // Positive slope.
86// int diff = 2 * dy - dx;
87// for (int i = 0; i <= dx; ++i) {
88// // *destination = clr;
89// if (diff >= 0) {
90// // destination += y_step;
91// diff -= 2 * dx;
92// }
93// // destination += x_step;
94// diff += 2 * dy;
95// }
96// } else {
97// // Negative slope.
98// int diff = 2 * dx - dy;
99// for (int i = 0; i <= dy; ++i) {
100// // *destination = clr;
101// if (diff >= 0) {
102// // destination += x_step;
103// diff -= 2 * dy;
104// }
105// // destination += y_step;
106// diff += 2 * dx;
107// }
108// }
109 BOUNDCHECK_SCREEN(x0, y0);
110 BOUNDCHECK_SCREEN(x1, y1);
111
112 // Find row positions for the given x/y coordinates.
113 size_t tile_x0 = x0 / 8;
114 size_t tile_y0 = y0 / 8;
115 size_t tile_x1 = x1 / 8;
116 size_t tile_y1 = y1 / 8;
117 size_t start_col0 = x0 % 8;
118 size_t start_col1 = x1 % 8;
119 size_t start_row0 = y0 % 8;
120 size_t start_row1 = y1 % 8;
121
122 // Get a pointer to the backbuffer and the tile row.
123 u32 *backbuffer = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8];
124
125 size_t dx = tile_x1 - tile_x0;
126 size_t dy = tile_y1 - tile_y0;
127
128 if (y0 == y1) {
129 // There are 3 cases:
130 // 1. Lines fit on a single tile.
131 // 2. Lines go through 2 tiles, both require partial row updates.
132 // 3. Lines go through 3 or more tiles, first and last tiles use
133 // partial row updates, rows in the middle can write the.
134 if (dx < 1) {
135 u32 row_mask = 0xFFFFFFFF;
136 row_mask >>= (7 - start_col1 - dx) * 4;
137 row_mask &= 0xFFFFFFFF << start_col0 * 4;
138 u32 row = (0x11111111 * clr) & row_mask;
139 backbuffer[0] = (backbuffer[0] & ~row_mask) | row;
140 dirty_tiles[tile_y0] |= 1 << tile_x0;
141 } else {
142 size_t shift_left = start_col0 * 4;
143 size_t shift_right = (7 - start_col1) * 4;
144 u32 row_mask = 0xFFFFFFFF;
145 u32 row = 0x11111111 * clr;
146 backbuffer[0] = backbuffer[0] & ~(row_mask << shift_left);
147 backbuffer[0] |= row << shift_left;
148 dirty_tiles[tile_y0] |= 1 << tile_x0;
149 for (size_t i = 1; i < dx; i++) {
150 backbuffer[i * 8] = row;
151 dirty_tiles[tile_y0] |= 1 << (tile_x0 + i);
152 }
153 backbuffer[dx * 8] = backbuffer[dx * 8] & ~(row_mask >> shift_right);
154 backbuffer[dx * 8] |= row >> shift_right;
155 dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx);
156 }
157 } else if (x0 == x1) {
158 //The vertical line cases are analogous to the horizontal ones.
159 u32 row_mask = 0xF << start_col0 * 4;
160 u32 row_left = (0x11111111 * clr) & row_mask;
161 if (dy < 1) {
162 for (size_t i = 0; i <= y1 - y0; i++, backbuffer++) {
163 backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left;
164 }
165 } else {
166 for (size_t i = 0; i < (8 - start_row0); i++, backbuffer++) {
167 backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left;
168 }
169 backbuffer += 8 * 31;
170 for (size_t j = 1; j < dy; j++) {
171 for (size_t i = 0; i < 8; i++, backbuffer++) {
172 backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left;
173 }
174 backbuffer += 8 * 31;
175 dirty_tiles[tile_y0 + j] |= 1 << tile_x0;
176 }
177 for (size_t i = 0; i <= start_row1; i++, backbuffer++) {
178 backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left;
179 }
180 }
181 }
182
183 // TODO: Add slope line drawing.
184}
185
186IWRAM_CODE
187void
49draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { 188draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) {
50 BOUNDCHECK_SCREEN(x0, y0); 189 BOUNDCHECK_SCREEN(x0, y0);
51 BOUNDCHECK_SCREEN(x1, y1); 190 BOUNDCHECK_SCREEN(x1, y1);
@@ -61,24 +200,21 @@ draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) {
61 size_t start_row1 = y1 % 8; 200 size_t start_row1 = y1 % 8;
62 201
63 // Get a pointer to the backbuffer and the tile row. 202 // Get a pointer to the backbuffer and the tile row.
64 u32 *backbuffer0 = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8]; 203 u32 *buf_top = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8];
65 u32 *backbuffer1 = &BACKBUF[start_row1 + (tile_x0 + tile_y1 * 32) * 8]; 204 u32 *buf_bot = &BACKBUF[start_row1 + (tile_x0 + tile_y1 * 32) * 8];
66 205
67 size_t dx = tile_x1 - tile_x0; 206 size_t dx = tile_x1 - tile_x0;
68 size_t dy = tile_y1 - tile_y0; 207 size_t dy = tile_y1 - tile_y0;
69 208
70 // There are 3 cases: 209 // We can update two lines at a time, which is faster than calling draw_line
71 // 1. Lines fit on a single tile. 210 // four times.
72 // 2. Lines go through 2 tiles, both require partial row updates.
73 // 3. Lines go through 3 or more tiles, first and last tiles use partial
74 // row updates, rows in the middle can write the.
75 if (dx < 1) { 211 if (dx < 1) {
76 u32 row_mask = 0xFFFFFFFF; 212 u32 row_mask = 0xFFFFFFFF;
77 row_mask >>= (7 - start_col1 - dx) * 4; 213 row_mask >>= (7 - start_col1 - dx) * 4;
78 row_mask &= 0xFFFFFFFF << start_col0 * 4; 214 row_mask &= 0xFFFFFFFF << start_col0 * 4;
79 u32 row = (0x11111111 * clr) & row_mask; 215 u32 row = (0x11111111 * clr) & row_mask;
80 backbuffer0[0] = (backbuffer0[0] & ~row_mask) | row; 216 buf_top[0] = (buf_top[0] & ~row_mask) | row;
81 backbuffer1[0] = (backbuffer1[0] & ~row_mask) | row; 217 buf_bot[0] = (buf_bot[0] & ~row_mask) | row;
82 dirty_tiles[tile_y0] |= 1 << tile_x0; 218 dirty_tiles[tile_y0] |= 1 << tile_x0;
83 dirty_tiles[tile_y1] |= 1 << tile_x0; 219 dirty_tiles[tile_y1] |= 1 << tile_x0;
84 } else { 220 } else {
@@ -86,49 +222,60 @@ draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) {
86 size_t shift_right = (7 - start_col1) * 4; 222 size_t shift_right = (7 - start_col1) * 4;
87 u32 row_mask = 0xFFFFFFFF; 223 u32 row_mask = 0xFFFFFFFF;
88 u32 row = 0x11111111 * clr; 224 u32 row = 0x11111111 * clr;
89 backbuffer0[0] = (backbuffer0[0] & ~(row_mask << shift_left)) | (row << shift_left); 225 buf_top[0] = buf_top[0] & ~(row_mask << shift_left);
90 backbuffer1[0] = (backbuffer1[0] & ~(row_mask << shift_left)) | (row << shift_left); 226 buf_top[0] |= row << shift_left;
227 buf_bot[0] = buf_bot[0] & ~(row_mask << shift_left);
228 buf_bot[0] |= row << shift_left;
91 dirty_tiles[tile_y0] |= 1 << tile_x0; 229 dirty_tiles[tile_y0] |= 1 << tile_x0;
92 dirty_tiles[tile_y1] |= 1 << tile_x0; 230 dirty_tiles[tile_y1] |= 1 << tile_x0;
93 for (size_t i = 1; i < dx; i++) { 231 for (size_t i = 1; i < dx; i++) {
94 backbuffer0[i * 8] = row; 232 buf_top[i * 8] = row;
95 backbuffer1[i * 8] = row; 233 buf_bot[i * 8] = row;
96 dirty_tiles[tile_y0] |= 1 << (tile_x0 + i); 234 dirty_tiles[tile_y0] |= 1 << (tile_x0 + i);
97 dirty_tiles[tile_y1] |= 1 << (tile_x0 + i); 235 dirty_tiles[tile_y1] |= 1 << (tile_x0 + i);
98 } 236 }
99 backbuffer0[dx * 8] = (backbuffer0[dx * 8] & ~(row_mask >> shift_right)) | (row >> shift_right); 237 buf_top[dx * 8] = buf_top[dx * 8] & ~(row_mask >> shift_right);
100 backbuffer1[dx * 8] = (backbuffer1[dx * 8] & ~(row_mask >> shift_right)) | (row >> shift_right); 238 buf_top[dx * 8] |= row >> shift_right;
239 buf_bot[dx * 8] = buf_bot[dx * 8] & ~(row_mask >> shift_right);
240 buf_bot[dx * 8] |= row >> shift_right;
101 dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx); 241 dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx);
102 dirty_tiles[tile_y1] |= 1 << (tile_x0 + dx); 242 dirty_tiles[tile_y1] |= 1 << (tile_x0 + dx);
103 } 243 }
104 // The vertical line cases are analogous to the horizontal ones.
105 u32 row_mask_left = 0xF << start_col0 * 4; 244 u32 row_mask_left = 0xF << start_col0 * 4;
106 u32 row_mask_right = 0xF << start_col1 * 4; 245 u32 row_mask_right = 0xF << start_col1 * 4;
107 u32 row_left = (0x11111111 * clr) & row_mask_left; 246 u32 row_left = (0x11111111 * clr) & row_mask_left;
108 u32 row_right = (0x11111111 * clr) & row_mask_right; 247 u32 row_right = (0x11111111 * clr) & row_mask_right;
109 if (dy < 1) { 248 if (dy < 1) {
110 for (size_t i = 1; i < y1 - y0; i++, backbuffer0++) { 249 for (size_t i = 1; i < y1 - y0; i++, buf_top++) {
111 backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; 250 buf_top[1] = buf_top[1] & ~row_mask_left;
112 backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; 251 buf_top[1] |= row_left;
252 buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right;
253 buf_top[1 + 8 * dx] |= row_right;
113 } 254 }
114 } else { 255 } else {
115 for (size_t i = 1; i < (8 - start_row0); i++, backbuffer0++) { 256 for (size_t i = 1; i < (8 - start_row0); i++, buf_top++) {
116 backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; 257 buf_top[1] = buf_top[1] & ~row_mask_left;
117 backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; 258 buf_top[1] |= row_left;
259 buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right;
260 buf_top[1 + 8 * dx] |= row_right;
118 } 261 }
119 backbuffer0 += 8 * 31; 262 buf_top += 8 * 31;
120 for (size_t j = 1; j < dy; j++) { 263 for (size_t j = 1; j < dy; j++) {
121 for (size_t i = 0; i < 8; i++, backbuffer0++) { 264 for (size_t i = 0; i < 8; i++, buf_top++) {
122 backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; 265 buf_top[1] = buf_top[1] & ~row_mask_left;
123 backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; 266 buf_top[1] |= row_left;
267 buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right;
268 buf_top[1 + 8 * dx] |= row_right;
124 } 269 }
125 backbuffer0 += 8 * 31; 270 buf_top += 8 * 31;
126 dirty_tiles[tile_y0 + j] |= 1 << tile_x0; 271 dirty_tiles[tile_y0 + j] |= 1 << tile_x0;
127 dirty_tiles[tile_y0 + j] |= 1 << (tile_x0 + dx); 272 dirty_tiles[tile_y0 + j] |= 1 << (tile_x0 + dx);
128 } 273 }
129 for (size_t i = 0; i < start_row1; i++, backbuffer0++) { 274 for (size_t i = 0; i < start_row1; i++, buf_top++) {
130 backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; 275 buf_top[1] = buf_top[1] & ~row_mask_left;
131 backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; 276 buf_top[1] |= row_left;
277 buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right;
278 buf_top[1 + 8 * dx] |= row_right;
132 } 279 }
133 } 280 }
134} 281}