diff options
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/renderer.c | 207 |
2 files changed, 178 insertions, 30 deletions
@@ -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 | ||
47 | IWRAM_CODE | 47 | IWRAM_CODE |
48 | void | 48 | void |
49 | draw_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 | |||
186 | IWRAM_CODE | ||
187 | void | ||
49 | draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { | 188 | draw_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 | } |