Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | Copyright 2023 - 2025 Benjamin Vedder benjamin@vedder.se | ||
3 | Copyright 2023 - 2025 Joel Svensson svenssonjoel@yahoo.se | ||
4 | Copyright 2023 Rasmus Söderhielm rasmus.soderhielm@gmail.com | ||
5 | Copyright 2025 Joakim Lundborg joakim.lundborg@gmail.com | ||
6 | |||
7 | This file is part of LispBM. (Originally a part of the vesc_express FW) | ||
8 | |||
9 | LispBM is free software: you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation, either version 3 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | LispBM is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include "sys/types.h" | ||
24 | #include "tjpgd.h" | ||
25 | |||
26 | #include <math.h> | ||
27 | |||
28 | #include <extensions/display_extensions.h> | ||
29 | #include <lbm_utils.h> | ||
30 | #include <lbm_defrag_mem.h> | ||
31 | |||
32 | #ifdef LBM_OPT_DISPLAY_EXTENSIONS_SIZE | ||
33 | #pragma GCC optimize ("-Os") | ||
34 | #endif | ||
35 | #ifdef LBM_OPT_DISPLAY_EXTENSIONS_SIZE_AGGRESSIVE | ||
36 | #pragma GCC optimize ("-Oz") | ||
37 | #endif | ||
38 | |||
39 | |||
40 | #define MAX_WIDTH 32000 | ||
41 | #define MAX_HEIGHT 32000 | ||
42 | |||
43 | // a single quadrant... | ||
44 | static const uint8_t cos_tab_128[] = | ||
45 | { | ||
46 | 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, // 0 - 9 | ||
47 | 251, 250, 250, 249, 248, 246, 245, 244, 243, 241, //10 - 19 | ||
48 | 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, //20 - 29 | ||
49 | 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, //30 - 39 | ||
50 | 198, 196, 193, 190, 188, 185, 182, 179, 176, 173, //40 - 49 | ||
51 | 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, //50 - 59 | ||
52 | 140, 137, 134, 131, 127, 124, 121, 118, 115, 112, //60 - 69 | ||
53 | 109, 106, 103, 100, 97, 93, 90, 88, 85, 82, //70 - 79 | ||
54 | 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, //80 - 89 | ||
55 | 52, 49, 47, 44, 42, 40, 37, 35, 33, 31, //90 - 99 | ||
56 | 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, //100 - 109 | ||
57 | 12, 11, 10, 9, 7, 6, 5, 5, 4, 3, //110 - 119 | ||
58 | 2, 2, 1, 1, 1, 0, 0, 0 //120 - 127 | ||
59 | }; | ||
60 | |||
61 | 1124 | uint32_t lbm_display_rgb888_from_color(color_t color, int x, int y) { | |
62 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
✗ Branch 2 not taken.
|
1124 | switch (color.type) { |
63 | ✗ | case COLOR_REGULAR: | |
64 | ✗ | return (uint32_t)color.color1; | |
65 | |||
66 | 1124 | case COLOR_GRADIENT_X: | |
67 | case COLOR_GRADIENT_Y: { | ||
68 | uint32_t res; | ||
69 | 1124 | uint32_t r1 = (uint32_t)color.color1 >> 16; | |
70 | 1124 | uint32_t g1 = (uint32_t)color.color1 >> 8 & 0xFF; | |
71 | 1124 | uint32_t b1 = (uint32_t)color.color1 & 0xff; | |
72 | |||
73 | 1124 | uint32_t r2 = (uint32_t)color.color2 >> 16; | |
74 | 1124 | uint32_t g2 = (uint32_t)color.color2 >> 8 & 0xFF; | |
75 | 1124 | uint32_t b2 = (uint32_t)color.color2 & 0xff; | |
76 | |||
77 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1074 times.
|
1124 | int used_len = color.mirrored ? 256 : 128; |
78 | |||
79 |
2/2✓ Branch 0 taken 1094 times.
✓ Branch 1 taken 30 times.
|
1124 | int pos = color.type == COLOR_GRADIENT_X ? x : y; |
80 | // int tab_pos = ((pos * 256) / color.param1 + color.param2) % 256; | ||
81 | 1124 | int tab_pos = (((pos - color.param2) * 256) / color.param1 / 2) % used_len; | |
82 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
|
1124 | if (tab_pos < 0) { |
83 | ✗ | tab_pos += used_len; | |
84 | } | ||
85 | |||
86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
|
1124 | uint32_t tab_val = (uint32_t)cos_tab_128[tab_pos <= 127 ? tab_pos : 128 - (tab_pos - 127)]; |
87 | |||
88 | 1124 | uint32_t r = (r1 * tab_val + r2 * (255 - tab_val)) / 255; | |
89 | 1124 | uint32_t g = (g1 * tab_val + g2 * (255 - tab_val)) / 255; | |
90 | 1124 | uint32_t b = (b1 * tab_val + b2 * (255 - tab_val)) / 255; | |
91 | |||
92 | 1124 | res = r << 16 | g << 8 | b; | |
93 | 1124 | return res; | |
94 | } | ||
95 | |||
96 | ✗ | default: | |
97 | ✗ | return 0; | |
98 | } | ||
99 | } | ||
100 | |||
101 | static lbm_uint symbol_indexed2 = 0; | ||
102 | static lbm_uint symbol_indexed4 = 0; | ||
103 | static lbm_uint symbol_indexed16 = 0; | ||
104 | static lbm_uint symbol_rgb332 = 0; | ||
105 | static lbm_uint symbol_rgb565 = 0; | ||
106 | static lbm_uint symbol_rgb888 = 0; | ||
107 | |||
108 | static lbm_uint symbol_thickness = 0; | ||
109 | static lbm_uint symbol_filled = 0; | ||
110 | static lbm_uint symbol_rounded = 0; | ||
111 | static lbm_uint symbol_dotted = 0; | ||
112 | static lbm_uint symbol_scale = 0; | ||
113 | static lbm_uint symbol_rotate = 0; | ||
114 | static lbm_uint symbol_resolution = 0; | ||
115 | static lbm_uint symbol_tile = 0; | ||
116 | static lbm_uint symbol_clip = 0; | ||
117 | |||
118 | |||
119 | static lbm_uint symbol_regular = 0; | ||
120 | static lbm_uint symbol_gradient_x = 0; | ||
121 | static lbm_uint symbol_gradient_y = 0; | ||
122 | static lbm_uint symbol_gradient_x_pre = 0; | ||
123 | static lbm_uint symbol_gradient_y_pre = 0; | ||
124 | static lbm_uint symbol_repeat = 0; | ||
125 | static lbm_uint symbol_mirrored = 0; | ||
126 | |||
127 | static lbm_uint symbol_color_0 = 0; | ||
128 | static lbm_uint symbol_color_1 = 0; | ||
129 | static lbm_uint symbol_width = 0; | ||
130 | static lbm_uint symbol_offset = 0; | ||
131 | static lbm_uint symbol_repeat_type = 0; | ||
132 | |||
133 | static lbm_uint symbol_down = 0; | ||
134 | static lbm_uint symbol_up = 0; | ||
135 | |||
136 | 24 | bool display_is_symbol_up(lbm_value v) { | |
137 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | if (lbm_is_symbol(v)) { |
138 | 24 | lbm_uint s = lbm_dec_sym(v); | |
139 | 24 | return (s == symbol_up); | |
140 | } | ||
141 | ✗ | return false; | |
142 | } | ||
143 | |||
144 | 24 | bool display_is_symbol_down(lbm_value v) { | |
145 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | if (lbm_is_symbol(v)) { |
146 | 24 | lbm_uint s = lbm_dec_sym(v); | |
147 | 24 | return (s == symbol_down); | |
148 | } | ||
149 | ✗ | return false; | |
150 | } | ||
151 | |||
152 | 91 | color_format_t sym_to_color_format(lbm_value v) { | |
153 | 91 | lbm_uint s = lbm_dec_sym(v); | |
154 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 65 times.
|
91 | if (s == symbol_indexed2) return indexed2; |
155 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 34 times.
|
65 | if (s == symbol_indexed4) return indexed4; |
156 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 19 times.
|
34 | if (s == symbol_indexed16) return indexed16; |
157 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
|
19 | if (s == symbol_rgb332) return rgb332; |
158 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
|
15 | if (s == symbol_rgb565) return rgb565; |
159 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | if (s == symbol_rgb888) return rgb888; |
160 | 3 | return format_not_supported; | |
161 | } | ||
162 | |||
163 | 2808 | uint32_t image_dims_to_size_bytes(color_format_t fmt, uint16_t width, uint16_t height) { | |
164 | 2808 | uint32_t num_pix = (uint32_t)width * (uint32_t)height; | |
165 |
7/7✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2627 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 4 times.
|
2808 | switch(fmt) { |
166 | 111 | case indexed2: | |
167 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 54 times.
|
111 | if (num_pix % 8 != 0) return (num_pix / 8) + 1; |
168 | 54 | else return (num_pix / 8); | |
169 | break; | ||
170 | 2627 | case indexed4: | |
171 |
2/2✓ Branch 0 taken 733 times.
✓ Branch 1 taken 1894 times.
|
2627 | if (num_pix % 4 != 0) return (num_pix / 4) + 1; |
172 | 1894 | else return (num_pix / 4); | |
173 | break; | ||
174 | 28 | case indexed16: // Two pixels per byte | |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (num_pix % 2 != 0) return (num_pix / 2) + 1; |
176 | 28 | else return (num_pix / 2); | |
177 | 8 | case rgb332: | |
178 | 8 | return num_pix; | |
179 | break; | ||
180 | 6 | case rgb565: | |
181 | 6 | return num_pix * 2; | |
182 | break; | ||
183 | 24 | case rgb888: | |
184 | 24 | return num_pix * 3; | |
185 | 4 | default: | |
186 | 4 | return 0; | |
187 | } | ||
188 | } | ||
189 | |||
190 | 70 | static lbm_value image_buffer_lift(uint8_t *buf, color_format_t fmt, uint16_t width, uint16_t height) { | |
191 | 70 | lbm_value res = ENC_SYM_MERROR; | |
192 | 70 | lbm_uint size = image_dims_to_size_bytes(fmt, width, height); | |
193 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | if ( lbm_lift_array(&res, (char*)buf, IMAGE_BUFFER_HEADER_SIZE + size)) { |
194 | 70 | buf[0] = (uint8_t)(width >> 8); | |
195 | 70 | buf[1] = (uint8_t)width; | |
196 | 70 | buf[2] = (uint8_t)(height >> 8); | |
197 | 70 | buf[3] = (uint8_t)height; | |
198 | 70 | buf[4] = color_format_to_byte(fmt); | |
199 | } | ||
200 | 70 | return res; | |
201 | } | ||
202 | |||
203 | 147 | static inline bool is_color_sized(lbm_uint size) { | |
204 | 147 | size_t color_size = sizeof(color_t); | |
205 | 147 | return (size == color_size); | |
206 | } | ||
207 | |||
208 | 71 | static inline bool is_color(uint8_t *data, lbm_uint size) { | |
209 | 71 | bool res = false; | |
210 |
1/2✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
|
71 | if (is_color_sized(size)) { |
211 | 71 | color_t *color = (color_t*)data; | |
212 | 71 | res = (color->magic == COLOR_MAGIC); | |
213 | } | ||
214 | 71 | return res; | |
215 | } | ||
216 | |||
217 | |||
218 | 26 | static lbm_value color_allocate(COLOR_TYPE type, int32_t color1, int32_t color2, uint16_t param1, uint16_t param2, bool mirrored) { | |
219 | 26 | color_t *color = lbm_malloc(sizeof(color_t)); | |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (!color) { |
221 | ✗ | return ENC_SYM_MERROR; | |
222 | } | ||
223 | |||
224 | 26 | uint32_t *pre = 0; | |
225 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 21 times.
|
26 | if (type == COLOR_PRE_X || type == COLOR_PRE_Y) { |
226 | 5 | pre = lbm_malloc(COLOR_PRECALC_LEN * sizeof(uint32_t)); | |
227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (!pre) { |
228 | ✗ | lbm_free(color); | |
229 | ✗ | return ENC_SYM_MERROR; | |
230 | } | ||
231 | } | ||
232 | |||
233 | 26 | lbm_value res = ENC_SYM_MERROR; | |
234 | |||
235 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | if (lbm_lift_array(&res, (char*)color, sizeof(color_t))) { |
236 | 26 | color->magic = COLOR_MAGIC; | |
237 | 26 | color->type = type; | |
238 | 26 | color->color1 = color1; | |
239 | 26 | color->color2 = color2; | |
240 | 26 | color->param1 = param1; | |
241 | 26 | color->param2 = param2; | |
242 | 26 | color->mirrored = mirrored; | |
243 | 26 | color->precalc = pre; | |
244 | |||
245 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
|
26 | if (pre) { |
246 | 5 | COLOR_TYPE type_old = color->type; | |
247 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | if (type == COLOR_PRE_X) { |
248 | 4 | color->type = COLOR_GRADIENT_X; | |
249 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | } else if (type == COLOR_PRE_Y) { |
250 | 1 | color->type = COLOR_GRADIENT_Y; | |
251 | } | ||
252 | |||
253 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | if (color->param1 > COLOR_PRECALC_LEN) { |
254 | 1 | color->param1 = COLOR_PRECALC_LEN; | |
255 | } | ||
256 | |||
257 |
2/2✓ Branch 0 taken 1124 times.
✓ Branch 1 taken 5 times.
|
1129 | for (int i = 0;i < color->param1;i++) { |
258 | 1124 | pre[i] = lbm_display_rgb888_from_color(*color, i + color->param2, i + color->param2); | |
259 | } | ||
260 | |||
261 | 5 | color->type = type_old; | |
262 | } | ||
263 | } else { | ||
264 | ✗ | lbm_free(pre); | |
265 | ✗ | lbm_free(color); | |
266 | } | ||
267 | |||
268 | 26 | return res; | |
269 | } | ||
270 | |||
271 | 70 | static lbm_value image_buffer_allocate(color_format_t fmt, uint16_t width, uint16_t height) { | |
272 | 70 | uint32_t size_bytes = image_dims_to_size_bytes(fmt, width, height); | |
273 | |||
274 | 70 | uint8_t *buf = lbm_malloc(IMAGE_BUFFER_HEADER_SIZE + size_bytes); | |
275 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | if (!buf) { |
276 | ✗ | return ENC_SYM_MERROR; | |
277 | } | ||
278 | 70 | memset(buf, 0, size_bytes + IMAGE_BUFFER_HEADER_SIZE); | |
279 | 70 | lbm_value res = image_buffer_lift(buf, fmt, width, height); | |
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | if (lbm_is_symbol(res)) { /* something is wrong, free */ |
281 | ✗ | lbm_free(buf); | |
282 | } | ||
283 | 70 | return res; | |
284 | } | ||
285 | |||
286 | 1 | static lbm_value image_buffer_allocate_dm(lbm_uint *dm, color_format_t fmt, uint16_t width, uint16_t height) { | |
287 | 1 | uint32_t size_bytes = image_dims_to_size_bytes(fmt, width, height); | |
288 | |||
289 | 1 | lbm_value res = lbm_defrag_mem_alloc(dm, IMAGE_BUFFER_HEADER_SIZE + size_bytes); | |
290 | 1 | lbm_array_header_t *arr = lbm_dec_array_r(res); | |
291 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (arr) { |
292 | 1 | uint8_t *buf = (uint8_t*)arr->data; | |
293 | 1 | buf[0] = (uint8_t)(width >> 8); | |
294 | 1 | buf[1] = (uint8_t)width; | |
295 | 1 | buf[2] = (uint8_t)(height >> 8); | |
296 | 1 | buf[3] = (uint8_t)height; | |
297 | 1 | buf[4] = color_format_to_byte(fmt); | |
298 | } | ||
299 | 1 | return res; | |
300 | } | ||
301 | |||
302 | // Exported interface | ||
303 | ✗ | bool display_is_color(lbm_value v) { | |
304 | ✗ | lbm_array_header_t *array = lbm_dec_array_r(v); | |
305 | ✗ | bool res = false; | |
306 | ✗ | if (array && is_color_sized(array->size)) { | |
307 | ✗ | res = (is_color((uint8_t*)array->data, array->size)); | |
308 | } | ||
309 | ✗ | return res; | |
310 | } | ||
311 | |||
312 | 77 | static color_t *get_color(lbm_value v) { | |
313 | 77 | color_t *res = NULL; | |
314 | 77 | lbm_array_header_t *array = lbm_dec_array_r(v); | |
315 |
4/4✓ Branch 0 taken 76 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 5 times.
|
77 | if (array && is_color_sized(array->size) |
316 |
1/2✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
|
71 | && (is_color((uint8_t*)array->data, array->size))) { |
317 | 71 | res = (color_t*)array->data; | |
318 | } | ||
319 | 77 | return res; | |
320 | } | ||
321 | |||
322 | |||
323 | // Register symbols | ||
324 | |||
325 | 411 | static bool register_symbols(void) { | |
326 | 411 | bool res = true; | |
327 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("indexed2", &symbol_indexed2); |
328 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("indexed4", &symbol_indexed4); |
329 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("indexed16", &symbol_indexed16); |
330 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("rgb332", &symbol_rgb332); |
331 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("rgb565", &symbol_rgb565); |
332 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("rgb888", &symbol_rgb888); |
333 | |||
334 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("thickness", &symbol_thickness); |
335 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("filled", &symbol_filled); |
336 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("rounded", &symbol_rounded); |
337 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("dotted", &symbol_dotted); |
338 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("scale", &symbol_scale); |
339 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("rotate", &symbol_rotate); |
340 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("resolution", &symbol_resolution); |
341 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("tile", &symbol_tile); |
342 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("clip", &symbol_clip); |
343 | |||
344 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("regular", &symbol_regular); |
345 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("gradient_x", &symbol_gradient_x); |
346 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("gradient_y", &symbol_gradient_y); |
347 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("gradient_x_pre", &symbol_gradient_x_pre); |
348 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("gradient_y_pre", &symbol_gradient_y_pre); |
349 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("mirrored", &symbol_mirrored); |
350 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("repeat", &symbol_repeat); |
351 | |||
352 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("color-0", &symbol_color_0); |
353 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("color-1", &symbol_color_1); |
354 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("width", &symbol_width); |
355 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("offset", &symbol_offset); |
356 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("repeat-type", &symbol_repeat_type); |
357 | |||
358 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("down", &symbol_down); |
359 |
2/4✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
|
411 | res = res && lbm_add_symbol_const("up", &symbol_up); |
360 | |||
361 | 411 | return res; | |
362 | } | ||
363 | |||
364 | // Internal functions | ||
365 | |||
366 | 975723 | static int sign(int v) { | |
367 |
2/2✓ Branch 0 taken 454833 times.
✓ Branch 1 taken 520890 times.
|
975723 | if (v > 0) { |
368 | 454833 | return 1; | |
369 |
2/2✓ Branch 0 taken 374010 times.
✓ Branch 1 taken 146880 times.
|
520890 | } else if (v < 0) { |
370 | 374010 | return -1; | |
371 | } else { | ||
372 | 146880 | return 0; | |
373 | } | ||
374 | } | ||
375 | |||
376 | // Geometry utility functions | ||
377 | |||
378 | // Checks if a point is past a line formed by the given end and start points. | ||
379 | // The returned value is 1 if it is past, -1 if it's on the other side of the | ||
380 | // line, or 0 if it's exactly on the line. | ||
381 | // Don't ask me what is considered the "positive" side of the line ;) | ||
382 | // | ||
383 | // It would probably be more logical if the sign of the result was flipped... | ||
384 | 202230 | static int point_past_line(int x, int y, int line_start_x, int line_start_y, int line_end_x, int line_end_y) { | |
385 | // source: https://stackoverflow.com/a/11908158/15507414 | ||
386 | |||
387 | // this is not really a cross product, but whatever... | ||
388 | 202230 | int cross_prod = (x - line_start_x) * (line_end_y - line_start_y) | |
389 | 202230 | - (y - line_start_y) * (line_end_x - line_start_x); | |
390 | |||
391 |
2/2✓ Branch 0 taken 86633 times.
✓ Branch 1 taken 115597 times.
|
202230 | if (cross_prod > 0) { |
392 | 86633 | return 1; | |
393 |
2/2✓ Branch 0 taken 111636 times.
✓ Branch 1 taken 3961 times.
|
115597 | } else if (cross_prod < 0) { |
394 | 111636 | return -1; | |
395 | } else { | ||
396 | 3961 | return 0; | |
397 | } | ||
398 | } | ||
399 | |||
400 | 151294 | static bool points_same_quadrant(int x0, int y0, int x1, int y1) { | |
401 |
4/4✓ Branch 0 taken 90941 times.
✓ Branch 1 taken 3548 times.
✓ Branch 2 taken 30404 times.
✓ Branch 3 taken 60537 times.
|
245783 | return (sign(x0) == sign(x1) || sign(x0) == 0 || sign(x1) == 0) |
402 |
8/8✓ Branch 0 taken 94489 times.
✓ Branch 1 taken 56805 times.
✓ Branch 2 taken 47572 times.
✓ Branch 3 taken 43185 times.
✓ Branch 4 taken 42631 times.
✓ Branch 5 taken 4941 times.
✓ Branch 6 taken 18510 times.
✓ Branch 7 taken 24121 times.
|
245783 | && (sign(y0) == sign(y1) || sign(y0) == 0 || sign(y1) == 0); |
403 | } | ||
404 | |||
405 | 24 | static inline void norm_angle(float *angle) { | |
406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | while (*angle < -M_PI) { *angle += 2.0f * (float)M_PI; } |
407 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 24 times.
|
34 | while (*angle >= M_PI) { *angle -= 2.0f * (float)M_PI; } |
408 | 24 | } | |
409 | |||
410 | 1032 | static inline void norm_angle_0_2pi(float *angle) { | |
411 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1032 times.
|
1043 | while (*angle < 0) { *angle += 2.0f * (float)M_PI; } |
412 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1032 times.
|
1064 | while (*angle >= 2.0 * M_PI) { *angle -= 2.0f * (float)M_PI; } |
413 | 1032 | } | |
414 | |||
415 | 1737 | static uint8_t rgb888to332(uint32_t rgb) { | |
416 | 1737 | uint8_t r = (uint8_t)(rgb >> (16 + 5)); | |
417 | 1737 | uint8_t g = (uint8_t)(rgb >> (8 + 5)); | |
418 | 1737 | uint8_t b = (uint8_t)(rgb >> 6); | |
419 | 1737 | r = (r & 0x7) << 5; | |
420 | 1737 | g = (g & 0x7) << 2; | |
421 | 1737 | b = (b & 0x3); | |
422 | 1737 | uint8_t res_rgb332 = r | g | b; | |
423 | 1737 | return res_rgb332; | |
424 | } | ||
425 | |||
426 | 1949 | static uint16_t rgb888to565(uint32_t rgb) { | |
427 | 1949 | uint16_t r = (uint16_t)(rgb >> (16 + 3)); | |
428 | 1949 | uint16_t g = (uint16_t)(rgb >> (8 + 2)); | |
429 | 1949 | uint16_t b = (uint16_t)(rgb >> 3); | |
430 | 1949 | r = r << 11; | |
431 | 1949 | g = (g & 0x3F) << 5; | |
432 | 1949 | b = (b & 0x1F); | |
433 | 1949 | uint16_t res_rgb565 = r | g | b; | |
434 | 1949 | return res_rgb565; | |
435 | } | ||
436 | |||
437 | // One problem with rgb332 is that | ||
438 | // if you take 3 most significant bits of 255 you get 7. | ||
439 | // There is no whole number that you can multiply 7 with to get 255. | ||
440 | // This is fundamental for any conversion from RGB888 that just uses the | ||
441 | // N < 8 most significant bits. And it means that conversion to this format | ||
442 | // and then back to rgb888 will not (without tricks) map highest intensity | ||
443 | // back to highest intensity. | ||
444 | // | ||
445 | // Another issue is that 2 bits (the blue channel) yields steps of 85 (255 / 3) | ||
446 | // while 3 bits yields steps of 36.4 (255 / 7) | ||
447 | // | ||
448 | // 36.4 72.8 109.3 145.7 182.1 218.6 254.99 | ||
449 | // 85 170 255 | ||
450 | // | ||
451 | // The multiples of 85 never coincide with the multiples of 36.4 except | ||
452 | // for at 0 and 255 | ||
453 | 16 | static uint32_t rgb332to888(uint8_t rgb) { | |
454 | 16 | uint32_t r = (uint32_t)((rgb>>5) & 0x7); | |
455 | 16 | uint32_t g = (uint32_t)((rgb>>2) & 0x7); | |
456 | |||
457 | // turn 2 bits into 3 having value 0 3 5 or 7 | ||
458 | // so that 4 points match up when doing greyscale. | ||
459 | 16 | uint32_t b = (uint32_t)(rgb & 0x3); | |
460 | |||
461 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
|
16 | b = (b > 0) ? (2 * b) + 1 : 0; |
462 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | r = (r == 7) ? 255 : 36 * r; // 36 is an approximation (36.4) |
463 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | g = (g == 7) ? 255 : 36 * g; |
464 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | b = (b == 7) ? 255 : 36 * b; |
465 | 16 | uint32_t res_rgb888 = r << 16 | g << 8 | b; | |
466 | 16 | return res_rgb888; | |
467 | } | ||
468 | |||
469 | // RGB 565 | ||
470 | // 2^5 = 32 | ||
471 | // 2^6 = 64 | ||
472 | // 255 / 31 = 8.226 | ||
473 | // 255 / 63 = 4.18 | ||
474 | // 0 1 2 3 4 5 6 7 8 ... 31 63 | ||
475 | // 5 bits 0 8.226 16.45 24.67 32.9 41.13 49.35 57.58 65.81 ... 254.9 | ||
476 | // 6 bits 0 4.047 8.09 12.14 16.19 20.24 24.29 28.33 32.38 ... 254.9 | ||
477 | // | ||
478 | // For RGB 565 the 6 and 5 bit channels match up very nicely such | ||
479 | // index i in the 5 bit channel is equal to index (2 * i) in the 6 bit channel. | ||
480 | // RGB 565 will have nice grayscales. | ||
481 | |||
482 | 22 | static uint32_t rgb565to888(uint16_t rgb) { | |
483 | 22 | uint32_t r = (uint32_t)(rgb >> 11); | |
484 | 22 | uint32_t g = (uint32_t)((rgb >> 5) & 0x3F); | |
485 | 22 | uint32_t b = (uint32_t)(rgb & 0x1F); | |
486 | 22 | uint32_t res_rgb888 = r << (16 + 3) | g << (8 + 2) | b << 3; | |
487 | 22 | return res_rgb888; | |
488 | } | ||
489 | |||
490 | 54 | void image_buffer_clear(image_buffer_t *img, uint32_t cc) { | |
491 | 54 | color_format_t fmt = img->fmt; | |
492 | 54 | uint32_t w = img->width; | |
493 | 54 | uint32_t h = img->height; | |
494 | 54 | uint32_t img_size = w * h; | |
495 | 54 | uint8_t *data = img->data; | |
496 |
6/7✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
54 | switch (fmt) { |
497 | 4 | case indexed2: { | |
498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | uint32_t bytes = (img_size / 8) + (img_size % 8 ? 1 : 0); |
499 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | uint8_t c8 = (uint8_t)((cc & 1) ? 0xFF : 0x0); |
500 | 4 | memset(data, c8, bytes); | |
501 | } | ||
502 | 4 | break; | |
503 | 12 | case indexed4: { | |
504 | static const uint8_t index4_table[4] = {0x00, 0x55, 0xAA, 0xFF}; | ||
505 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | uint32_t bytes = (img_size / 4) + (img_size % 4 ? 1 : 0); |
506 | 12 | uint8_t ix = (uint8_t)(cc & 0x3); | |
507 | 12 | memset(data, index4_table[ix], bytes); | |
508 | } | ||
509 | 12 | break; | |
510 | 18 | case indexed16: { | |
511 | 18 | uint32_t bytes = (img_size / 2) + (img_size % 2 ? 1 : 0); | |
512 | 18 | uint8_t ix = (uint8_t)(cc & 0xF); | |
513 | 18 | uint8_t color = (uint8_t)(ix | ix << 4); // create a color based on duplication of index | |
514 | 18 | memset(data, color, bytes); | |
515 | } | ||
516 | 18 | break; | |
517 | 7 | case rgb332: { | |
518 | 7 | memset(data, rgb888to332(cc), img_size); | |
519 | } | ||
520 | 7 | break; | |
521 | 6 | case rgb565: { | |
522 | 6 | uint16_t c = rgb888to565(cc); | |
523 | 6 | uint8_t *dp = (uint8_t*)data; | |
524 |
2/2✓ Branch 0 taken 45000 times.
✓ Branch 1 taken 6 times.
|
45006 | for (unsigned int i = 0; i < img_size/2; i +=2) { |
525 | 45000 | dp[i] = (uint8_t)(c >> 8); | |
526 | 45000 | dp[i+1] = (uint8_t)c; | |
527 | } | ||
528 | } | ||
529 | 6 | break; | |
530 | 7 | case rgb888: { | |
531 | 7 | uint8_t *dp = (uint8_t*)data; | |
532 |
2/2✓ Branch 0 taken 200000 times.
✓ Branch 1 taken 7 times.
|
200007 | for (unsigned int i = 0; i < img_size * 3; i+= 3) { |
533 | 200000 | dp[i] = (uint8_t)(cc >> 16); | |
534 | 200000 | dp[i+1] = (uint8_t)(cc >> 8); | |
535 | 200000 | dp[i+2] = (uint8_t)cc; | |
536 | } | ||
537 | } | ||
538 | 7 | break; | |
539 | ✗ | default: | |
540 | ✗ | break; | |
541 | } | ||
542 | 54 | } | |
543 | |||
544 | static const uint8_t indexed4_mask[4] = {0x03, 0x0C, 0x30, 0xC0}; | ||
545 | static const uint8_t indexed4_shift[4] = {0, 2, 4, 6}; | ||
546 | static const uint8_t indexed16_mask[4] = {0x0F, 0xF0}; | ||
547 | static const uint8_t indexed16_shift[4] = {0, 4}; | ||
548 | |||
549 | |||
550 | 22528621 | void putpixel(image_buffer_t* img, int x_i, int y_i, uint32_t c) { | |
551 | 22528621 | uint16_t w = img->width; | |
552 | 22528621 | uint16_t h = img->height; | |
553 | 22528621 | uint16_t x = (uint16_t)x_i; // negative numbers become really large. | |
554 | 22528621 | uint16_t y = (uint16_t)y_i; | |
555 | |||
556 |
4/4✓ Branch 0 taken 22490915 times.
✓ Branch 1 taken 37706 times.
✓ Branch 2 taken 19971133 times.
✓ Branch 3 taken 2519782 times.
|
22528621 | if (x < w && y < h) { |
557 | 19971133 | color_format_t fmt = img->fmt; | |
558 | 19971133 | uint8_t *data = img->data; | |
559 |
6/7✓ Branch 0 taken 75266 times.
✓ Branch 1 taken 17820783 times.
✓ Branch 2 taken 2047644 times.
✓ Branch 3 taken 1730 times.
✓ Branch 4 taken 1943 times.
✓ Branch 5 taken 23767 times.
✗ Branch 6 not taken.
|
19971133 | switch(fmt) { |
560 | 75266 | case indexed2: { | |
561 | 75266 | uint32_t pos = (uint32_t)y * (uint32_t)w + (uint32_t)x; | |
562 | 75266 | uint32_t byte = pos >> 3; | |
563 | 75266 | uint32_t bit = 7 - (pos & 0x7); | |
564 |
2/2✓ Branch 0 taken 6255 times.
✓ Branch 1 taken 69011 times.
|
75266 | if (c) { |
565 | 6255 | data[byte] |= (uint8_t)(1 << bit); | |
566 | } else { | ||
567 | 69011 | data[byte] &= (uint8_t)~(1 << bit); | |
568 | } | ||
569 | 75266 | break; | |
570 | } | ||
571 | 17820783 | case indexed4: { | |
572 | 17820783 | uint32_t pos = (uint32_t)y*w + x; | |
573 | 17820783 | uint32_t byte = pos >> 2; | |
574 | 17820783 | uint32_t ix = 3 - (pos & 0x3); | |
575 | 17820783 | data[byte] = (uint8_t)((uint8_t)(data[byte] & ~indexed4_mask[ix]) | (uint8_t)(c << indexed4_shift[ix])); | |
576 | 17820783 | break; | |
577 | } | ||
578 | 2047644 | case indexed16: { | |
579 | 2047644 | uint32_t pos = (uint32_t)y*w + x; | |
580 | 2047644 | uint32_t byte = pos >> 1; | |
581 | 2047644 | uint32_t ix = 1 - (pos & 0x1); | |
582 | 2047644 | data[byte] = (uint8_t)((uint8_t)(data[byte] & ~indexed16_mask[ix]) | (uint8_t)(c << indexed16_shift[ix])); | |
583 | 2047644 | break; | |
584 | } | ||
585 | 1730 | case rgb332: { | |
586 | 1730 | int pos = y*w + x; | |
587 | 1730 | data[pos] = rgb888to332(c); | |
588 | 1730 | break; | |
589 | } | ||
590 | 1943 | case rgb565: { | |
591 | 1943 | int pos = y*(w<<1) + (x<<1) ; | |
592 | 1943 | uint16_t color = rgb888to565(c); | |
593 | 1943 | data[pos] = (uint8_t)(color >> 8); | |
594 | 1943 | data[pos+1] = (uint8_t)color; | |
595 | 1943 | break; | |
596 | } | ||
597 | 23767 | case rgb888: { | |
598 | 23767 | int pos = y*(w*3) + (x*3); | |
599 | 23767 | data[pos] = (uint8_t)(c>>16); | |
600 | 23767 | data[pos+1] = (uint8_t)(c>>8); | |
601 | 23767 | data[pos+2] = (uint8_t)c; | |
602 | 23767 | break; | |
603 | } | ||
604 | ✗ | default: | |
605 | ✗ | break; | |
606 | } | ||
607 | } | ||
608 | 22528621 | } | |
609 | |||
610 | 1103765 | uint32_t getpixel(image_buffer_t* img, int x_i, int y_i) { | |
611 | 1103765 | uint16_t w = img->width; | |
612 | 1103765 | uint16_t h = img->height; | |
613 | 1103765 | uint16_t x = (uint16_t)x_i; | |
614 | 1103765 | uint16_t y = (uint16_t)y_i; | |
615 | |||
616 |
3/4✓ Branch 0 taken 1103753 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1103753 times.
✗ Branch 3 not taken.
|
1103765 | if (x < w && y < h) { |
617 | 1103753 | color_format_t fmt = img->fmt; | |
618 | 1103753 | uint8_t *data = img->data; | |
619 |
6/7✓ Branch 0 taken 61017 times.
✓ Branch 1 taken 1042640 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
|
1103753 | switch(fmt) { |
620 | 61017 | case indexed2: { | |
621 | 61017 | uint32_t pos = (uint32_t)y * w + x; | |
622 | 61017 | uint32_t byte = pos >> 3; | |
623 | 61017 | uint32_t bit = 7 - (pos & 0x7); | |
624 | 61017 | return (uint32_t)(data[byte] >> bit) & 0x1; | |
625 | } | ||
626 | 1042640 | case indexed4: { | |
627 | 1042640 | uint32_t pos = (uint32_t)y*w + x; | |
628 | 1042640 | uint32_t byte = pos >> 2; | |
629 | 1042640 | uint32_t ix = 3 - (pos & 0x3); | |
630 | 1042640 | return (uint32_t)((data[byte] & indexed4_mask[ix]) >> indexed4_shift[ix]); | |
631 | } | ||
632 | 30 | case indexed16: { | |
633 | 30 | uint32_t pos = (uint32_t)y*w + x; | |
634 | 30 | uint32_t byte = pos >> 1; | |
635 | 30 | uint32_t ix = 1 - (pos & 0x1); | |
636 | 30 | return (uint32_t)((data[byte] & indexed16_mask[ix]) >> indexed16_shift[ix]); | |
637 | } | ||
638 | 16 | case rgb332: { | |
639 | 16 | int pos = y*w + x; | |
640 | 16 | return rgb332to888(data[pos]); | |
641 | } | ||
642 | 22 | case rgb565: { | |
643 | 22 | int pos = y*(w<<1) + (x<<1); | |
644 | 22 | uint16_t c = (uint16_t)(((uint16_t)data[pos] << 8) | (uint16_t)data[pos+1]); | |
645 | 22 | return rgb565to888(c); | |
646 | } | ||
647 | 28 | case rgb888: { | |
648 | 28 | int pos = y*(w*3) + (x*3); | |
649 | 28 | uint32_t r = data[pos]; | |
650 | 28 | uint32_t g = data[pos+1]; | |
651 | 28 | uint32_t b = data[pos+2]; | |
652 | 28 | return (r << 16 | g << 8 | b); | |
653 | } | ||
654 | ✗ | default: | |
655 | ✗ | break; | |
656 | } | ||
657 | } | ||
658 | 12 | return 0; | |
659 | } | ||
660 | |||
661 | 342289 | static void h_line(image_buffer_t* img, int x, int y, int len, uint32_t c) { | |
662 |
2/2✓ Branch 0 taken 21197947 times.
✓ Branch 1 taken 342289 times.
|
21540236 | for (int i = 0; i < len; i ++) { |
663 | 21197947 | putpixel(img, x+i, y, c); | |
664 | } | ||
665 | 342289 | } | |
666 | |||
667 | 88 | static void v_line(image_buffer_t* img, int x, int y, int len, uint32_t c) { | |
668 |
2/2✓ Branch 0 taken 2840 times.
✓ Branch 1 taken 88 times.
|
2928 | for (int i = 0; i < len; i ++) { |
669 | 2840 | putpixel(img, x, y+i, c); | |
670 | } | ||
671 | 88 | } | |
672 | |||
673 | 17192 | static void fill_circle(image_buffer_t *img, int x, int y, int radius, uint32_t color) { | |
674 |
6/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 2324 times.
✓ Branch 3 taken 3141 times.
✓ Branch 4 taken 2795 times.
✓ Branch 5 taken 8877 times.
|
17192 | switch (radius) { |
675 | 18 | case 0: | |
676 | 18 | break; | |
677 | |||
678 | 37 | case 1: | |
679 | 37 | putpixel(img, x - 1, y - 1, color); | |
680 | 37 | putpixel(img, x, y - 1, color); | |
681 | 37 | putpixel(img, x - 1, y, color); | |
682 | 37 | putpixel(img, x, y, color); | |
683 | 37 | break; | |
684 | |||
685 | 2324 | case 2: | |
686 | 2324 | h_line(img, x - 1, y - 2, 2, color); | |
687 | 2324 | h_line(img, x - 2, y - 1, 4, color); | |
688 | 2324 | h_line(img, x - 2, y, 4, color); | |
689 | 2324 | h_line(img, x - 1, y + 1, 2, color); | |
690 | 2324 | break; | |
691 | |||
692 | 3141 | case 3: | |
693 | 3141 | h_line(img, x - 2, y - 3, 4, color); | |
694 | 3141 | h_line(img, x - 3, y - 2, 6, color); | |
695 | 3141 | h_line(img, x - 3, y - 1, 6, color); | |
696 | 3141 | h_line(img, x - 3, y, 6, color); | |
697 | 3141 | h_line(img, x - 3, y + 1, 6, color); | |
698 | 3141 | h_line(img, x - 2, y + 2, 4, color); | |
699 | 3141 | break; | |
700 | |||
701 | 2795 | case 4: | |
702 | 2795 | h_line(img, x - 2, y - 4, 4, color); | |
703 | 2795 | h_line(img, x - 3, y - 3, 6, color); | |
704 | 2795 | h_line(img, x - 4, y - 2, 8, color); | |
705 | 2795 | h_line(img, x - 4, y - 1, 8, color); | |
706 | 2795 | h_line(img, x - 4, y, 8, color); | |
707 | 2795 | h_line(img, x - 4, y + 1, 8, color); | |
708 | 2795 | h_line(img, x - 3, y + 2, 6, color); | |
709 | 2795 | h_line(img, x - 2, y + 3, 4, color); | |
710 | 2795 | break; | |
711 | |||
712 | 8877 | default: { | |
713 | 8877 | int r_sq = radius * radius; | |
714 |
2/2✓ Branch 0 taken 260341 times.
✓ Branch 1 taken 8877 times.
|
269218 | for (int y1 = -radius; y1 <= radius; y1++) { |
715 |
1/2✓ Branch 0 taken 3291357 times.
✗ Branch 1 not taken.
|
3291357 | for (int x1 = -radius; x1 <= radius; x1++) { |
716 |
2/2✓ Branch 0 taken 260341 times.
✓ Branch 1 taken 3031016 times.
|
3291357 | if (x1 * x1 + y1 * y1 <= r_sq) { |
717 | // Compute the start and end position for x axis | ||
718 | 260341 | int x_left = x1; | |
719 |
4/4✓ Branch 0 taken 20283832 times.
✓ Branch 1 taken 8877 times.
✓ Branch 2 taken 20032368 times.
✓ Branch 3 taken 251464 times.
|
20292709 | while ((x1 + 1) <= radius && ((x1 + 1) * (x1 + 1) + y1 * y1) <= r_sq) { |
720 | 20032368 | x1++; | |
721 | } | ||
722 | 260341 | int x_right = x1; | |
723 | |||
724 | // Draw line at this level y | ||
725 | 260341 | int length = x_right - x_left + 1; | |
726 | 260341 | h_line(img, x + x_left, y + y1, length, color); | |
727 | |||
728 | // Break out of innter loop for this level y | ||
729 | 260341 | break; | |
730 | } | ||
731 | } | ||
732 | } | ||
733 | 8877 | } break; | |
734 | } | ||
735 | 17192 | } | |
736 | |||
737 | // Circle helper function, to draw a circle with an inner and outer radius. | ||
738 | // Draws the slice at the given outer radius point. | ||
739 | 2332 | static void handle_circle_slice(int outer_x, int outer_y, image_buffer_t *img, int c_x, int c_y, int radius_inner, uint32_t color, int radius_inner_dbl_sq) { | |
740 | int width; | ||
741 | |||
742 | bool slice_filled; | ||
743 |
2/2✓ Branch 0 taken 1166 times.
✓ Branch 1 taken 1166 times.
|
2332 | if (outer_y < 0) { |
744 | 1166 | slice_filled = -outer_y > radius_inner; | |
745 | } else { | ||
746 | 1166 | slice_filled = outer_y >= radius_inner; | |
747 | } | ||
748 | |||
749 |
2/2✓ Branch 0 taken 716 times.
✓ Branch 1 taken 1616 times.
|
2332 | if (slice_filled) { |
750 |
2/2✓ Branch 0 taken 358 times.
✓ Branch 1 taken 358 times.
|
716 | if (outer_x < 0) { |
751 | 358 | width = -outer_x; | |
752 | } else { | ||
753 | 358 | width = outer_x + 1; | |
754 | 358 | outer_x = 0; | |
755 | } | ||
756 | } else { | ||
757 | 1616 | int cur_x = outer_x; | |
758 |
2/2✓ Branch 0 taken 808 times.
✓ Branch 1 taken 808 times.
|
1616 | int delta = outer_x > 0 ? -1 : 1; |
759 | |||
760 | // TODO: this could probably be binary searched | ||
761 | 1616 | int y_dbl_off = outer_y * 2 + 1; | |
762 | 1616 | int y_dbl_off_sq = y_dbl_off * y_dbl_off; | |
763 | 6848 | while (true) { | |
764 | 8464 | cur_x += delta; | |
765 | 8464 | int x_dbl_off = cur_x * 2 + 1; | |
766 |
2/2✓ Branch 0 taken 6848 times.
✓ Branch 1 taken 1616 times.
|
8464 | if (x_dbl_off * x_dbl_off + y_dbl_off_sq <= radius_inner_dbl_sq |
767 |
1/2✓ Branch 0 taken 6848 times.
✗ Branch 1 not taken.
|
6848 | || abs(cur_x) > 2000) { // failsafe |
768 | break; | ||
769 | } | ||
770 | } | ||
771 | 1616 | width = abs(cur_x - outer_x); | |
772 |
2/2✓ Branch 0 taken 808 times.
✓ Branch 1 taken 808 times.
|
1616 | if (outer_x > 0) { |
773 | 808 | outer_x = cur_x + 1; | |
774 | } | ||
775 | } | ||
776 | |||
777 | 2332 | h_line(img, outer_x + c_x, outer_y + c_y, width, color); | |
778 | 2332 | } | |
779 | |||
780 | // thickness extends inwards from the given radius circle | ||
781 | 78 | static void circle(image_buffer_t *img, int x, int y, int radius, int thickness, uint32_t color) { | |
782 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 30 times.
|
78 | if (thickness <= 0) { |
783 | 48 | int x0 = 0; | |
784 | 48 | int y0 = radius; | |
785 | 48 | int d = 5 - 4*radius; | |
786 | 48 | int da = 12; | |
787 | 48 | int db = 20 - 8*radius; | |
788 | |||
789 |
2/2✓ Branch 0 taken 385 times.
✓ Branch 1 taken 48 times.
|
433 | while (x0 < y0) { |
790 | 385 | putpixel(img, x + x0, y + y0, color); | |
791 | 385 | putpixel(img, x + x0, y - y0, color); | |
792 | 385 | putpixel(img, x - x0, y + y0, color); | |
793 | 385 | putpixel(img, x - x0, y - y0, color); | |
794 | 385 | putpixel(img, x + y0, y + x0, color); | |
795 | 385 | putpixel(img, x + y0, y - x0, color); | |
796 | 385 | putpixel(img, x - y0, y + x0, color); | |
797 | 385 | putpixel(img, x - y0, y - x0, color); | |
798 |
2/2✓ Branch 0 taken 215 times.
✓ Branch 1 taken 170 times.
|
385 | if (d < 0) { d = d + da; db = db+8; } |
799 | 170 | else { y0 = y0 - 1; d = d+db; db = db + 16; } | |
800 | 385 | x0 = x0+1; | |
801 | 385 | da = da + 8; | |
802 | } | ||
803 | } else { | ||
804 | 30 | int radius_inner = radius - thickness; | |
805 | |||
806 | 30 | int radius_outer_dbl_sq = radius * radius * 4; | |
807 | 30 | int radius_inner_dbl_sq = radius_inner * radius_inner * 4; | |
808 | |||
809 |
2/2✓ Branch 0 taken 583 times.
✓ Branch 1 taken 30 times.
|
613 | for (int y0 = 0; y0 < radius; y0++) { |
810 | 583 | int y_dbl_offs = 2 * y0 + 1; | |
811 | 583 | int y_dbl_offs_sq = y_dbl_offs * y_dbl_offs; | |
812 | |||
813 |
1/2✓ Branch 0 taken 4572 times.
✗ Branch 1 not taken.
|
4572 | for (int x0 = -radius; x0 <= 0; x0++) { |
814 | 4572 | int x_dbl_offs = 2 * x0 + 1; | |
815 |
2/2✓ Branch 0 taken 583 times.
✓ Branch 1 taken 3989 times.
|
4572 | if (x_dbl_offs * x_dbl_offs + y_dbl_offs_sq <= radius_outer_dbl_sq) { |
816 | // This is horrible... | ||
817 | 583 | handle_circle_slice(x0, y0, | |
818 | img, x, y, radius_inner, color, radius_inner_dbl_sq); | ||
819 | 583 | handle_circle_slice(-x0 - 1, y0, | |
820 | img, x, y, radius_inner, color, radius_inner_dbl_sq); | ||
821 | 583 | handle_circle_slice(x0, -y0 - 1, | |
822 | img, x, y, radius_inner, color, radius_inner_dbl_sq); | ||
823 | 583 | handle_circle_slice(-x0 - 1, -y0 - 1, | |
824 | img, x, y, radius_inner, color, radius_inner_dbl_sq); | ||
825 | 583 | break; | |
826 | } | ||
827 | } | ||
828 | } | ||
829 | } | ||
830 | 78 | } | |
831 | |||
832 | // Thickness extends outwards and inwards from the given line equally, resulting | ||
833 | // in double the total thickness. | ||
834 | // TODO: This should be more efficient | ||
835 | // http://homepages.enterprise.net/murphy/thickline/index.html | ||
836 | // https://github.com/ArminJo/STMF3-Discovery-Demos/blob/master/lib/BlueDisplay/LocalGUI/ThickLine.hpp | ||
837 | 1030 | static void line(image_buffer_t *img, int x0, int y0, int x1, int y1, int thickness, int dot1, int dot2, uint32_t c) { | |
838 | 1030 | int dx = abs(x1 - x0); | |
839 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 674 times.
|
1030 | int sx = x0 < x1 ? 1 : -1; |
840 | 1030 | int dy = -abs(y1 - y0); | |
841 |
2/2✓ Branch 0 taken 365 times.
✓ Branch 1 taken 665 times.
|
1030 | int sy = y0 < y1 ? 1 : -1; |
842 | 1030 | int error = dx + dy; | |
843 | |||
844 |
2/2✓ Branch 0 taken 547 times.
✓ Branch 1 taken 483 times.
|
1030 | if (dot1 > 0) { |
845 | // These are used to deal with consecutive calls with | ||
846 | // possibly overlapping pixels. | ||
847 | static int dotcnt = 0; | ||
848 | static int x_last = 0; | ||
849 | static int y_last = 0; | ||
850 | |||
851 | while (true) { | ||
852 |
2/2✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 621 times.
|
2325 | if (dotcnt <= dot1) { |
853 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 1559 times.
|
1704 | if (thickness > 1) { |
854 | 145 | fill_circle(img, x0, y0, thickness, c); | |
855 | } else { | ||
856 | 1559 | putpixel(img, x0, y0, c); | |
857 | } | ||
858 | } | ||
859 | |||
860 |
4/4✓ Branch 0 taken 647 times.
✓ Branch 1 taken 1678 times.
✓ Branch 2 taken 249 times.
✓ Branch 3 taken 398 times.
|
2325 | if (x0 != x_last || y0 != y_last) { |
861 | 1927 | dotcnt++; | |
862 | } | ||
863 | |||
864 | 2325 | x_last = x0; | |
865 | 2325 | y_last = y0; | |
866 | |||
867 |
2/2✓ Branch 0 taken 262 times.
✓ Branch 1 taken 2063 times.
|
2325 | if (dotcnt >= (dot1 + dot2)) { |
868 | 262 | dotcnt = 0; | |
869 | } | ||
870 | |||
871 |
4/4✓ Branch 0 taken 667 times.
✓ Branch 1 taken 1658 times.
✓ Branch 2 taken 418 times.
✓ Branch 3 taken 249 times.
|
2325 | if (x0 == x1 && y0 == y1) { |
872 | 418 | break; | |
873 | } | ||
874 |
2/2✓ Branch 0 taken 1658 times.
✓ Branch 1 taken 249 times.
|
1907 | if ((error * 2) >= dy) { |
875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1658 times.
|
1658 | if (x0 == x1) { |
876 | ✗ | break; | |
877 | } | ||
878 | 1658 | error += dy; | |
879 | 1658 | x0 += sx; | |
880 | } | ||
881 |
2/2✓ Branch 0 taken 751 times.
✓ Branch 1 taken 1156 times.
|
1907 | if ((error * 2) <= dx) { |
882 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 686 times.
|
751 | if (y0 == y1) { |
883 | 65 | break; | |
884 | } | ||
885 | 686 | error += dx; | |
886 | 686 | y0 += sy; | |
887 | } | ||
888 | } | ||
889 | } else { | ||
890 | while (true) { | ||
891 |
2/2✓ Branch 0 taken 16926 times.
✓ Branch 1 taken 19254 times.
|
36180 | if (thickness > 1) { |
892 | 16926 | fill_circle(img, x0, y0, thickness, c); | |
893 | } else { | ||
894 | 19254 | putpixel(img, x0, y0, c); | |
895 | } | ||
896 | |||
897 |
4/4✓ Branch 0 taken 11094 times.
✓ Branch 1 taken 25086 times.
✓ Branch 2 taken 526 times.
✓ Branch 3 taken 10568 times.
|
36180 | if (x0 == x1 && y0 == y1) { |
898 | 526 | break; | |
899 | } | ||
900 |
2/2✓ Branch 0 taken 23890 times.
✓ Branch 1 taken 11764 times.
|
35654 | if ((error * 2) >= dy) { |
901 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23890 times.
|
23890 | if (x0 == x1) { |
902 | ✗ | break; | |
903 | } | ||
904 | 23890 | error += dy; | |
905 | 23890 | x0 += sx; | |
906 | } | ||
907 |
2/2✓ Branch 0 taken 15156 times.
✓ Branch 1 taken 20498 times.
|
35654 | if ((error * 2) <= dx) { |
908 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15135 times.
|
15156 | if (y0 == y1) { |
909 | 21 | break; | |
910 | } | ||
911 | 15135 | error += dx; | |
912 | 15135 | y0 += sy; | |
913 | } | ||
914 | } | ||
915 | } | ||
916 | 1030 | } | |
917 | |||
918 | // thickness extends inwards from the given rectangle edge. | ||
919 | 90 | static void rectangle(image_buffer_t *img, int x, int y, int width, int height, | |
920 | bool fill, int thickness, int dot1, int dot2, uint32_t color) { | ||
921 | 90 | thickness /= 2; | |
922 | |||
923 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 68 times.
|
90 | if (fill) { |
924 |
2/2✓ Branch 0 taken 760 times.
✓ Branch 1 taken 22 times.
|
782 | for (int i = y; i < (y + height);i++) { |
925 | 760 | h_line(img, x, i, width, color); | |
926 | } | ||
927 | } else { | ||
928 |
3/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
68 | if (thickness <= 0 && dot1 == 0) { |
929 | 44 | h_line(img, x, y, width, color); | |
930 | 44 | h_line(img, x, y + height, width, color); | |
931 | 44 | v_line(img, x, y, height, color); | |
932 | 44 | v_line(img, x + width, y, height, color); | |
933 | } else { | ||
934 | 24 | x += thickness; | |
935 | 24 | y += thickness; | |
936 | 24 | width -= thickness * 2; | |
937 | 24 | height -= thickness * 2; | |
938 | // top | ||
939 | 24 | line(img, x, y, x + width, y, thickness, dot1, dot2, color); | |
940 | // bottom | ||
941 | 24 | line(img, x, y + height, x + width, y + height, thickness, dot1, dot2, color); | |
942 | // left | ||
943 | 24 | line(img, x, y, x, y + height, thickness, dot1, dot2, color); | |
944 | // right | ||
945 | 24 | line(img, x + width, y, x + width, y + height, thickness, dot1, dot2, color); | |
946 | } | ||
947 | } | ||
948 | 90 | } | |
949 | |||
950 | #define NMIN(a, b) ((a) < (b) ? (a) : (b)) | ||
951 | #define NMAX(a, b) ((a) > (b) ? (a) : (b)) | ||
952 | |||
953 | 2 | static void fill_triangle(image_buffer_t *img, int x0, int y0, | |
954 | int x1, int y1, int x2, int y2, uint32_t color) { | ||
955 | 2 | int x_min = NMIN(x0, NMIN(x1, x2)); | |
956 | 2 | int x_max = NMAX(x0, NMAX(x1, x2)); | |
957 | 2 | int y_min = NMIN(y0, NMIN(y1, y2)); | |
958 | 2 | int y_max = NMAX(y0, NMAX(y1, y2)); | |
959 | |||
960 |
2/2✓ Branch 0 taken 82 times.
✓ Branch 1 taken 2 times.
|
84 | for (int y = y_min;y <= y_max;y++) { |
961 |
2/2✓ Branch 0 taken 5822 times.
✓ Branch 1 taken 82 times.
|
5904 | for (int x = x_min;x <= x_max;x++) { |
962 | 5822 | int w0 = point_past_line(x, y, x1, y1, x2, y2); | |
963 | 5822 | int w1 = point_past_line(x, y, x2, y2, x0, y0); | |
964 | 5822 | int w2 = point_past_line(x, y, x0, y0, x1, y1); | |
965 | |||
966 |
5/6✓ Branch 0 taken 142 times.
✓ Branch 1 taken 5680 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 140 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
5822 | if ((w0 >= 0 && w1 >= 0 && w2 >= 0) |
967 |
5/6✓ Branch 0 taken 5822 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4372 times.
✓ Branch 3 taken 1450 times.
✓ Branch 4 taken 2922 times.
✓ Branch 5 taken 1450 times.
|
5822 | || (w0 <= 0 && w1 <= 0 && w2 <= 0)) { |
968 | 2922 | putpixel(img, x, y, color); | |
969 | } | ||
970 | } | ||
971 | } | ||
972 | 2 | } | |
973 | |||
974 | 12 | static void generic_arc(image_buffer_t *img, int x, int y, int rad, float ang_start, float ang_end, | |
975 | int thickness, int dot1, int dot2, int res, bool sector, bool segment, uint32_t color) { | ||
976 | 12 | ang_start *= (float)M_PI / 180.0f; | |
977 | 12 | ang_end *= (float)M_PI / 180.0f; | |
978 | |||
979 | 12 | norm_angle(&ang_start); | |
980 | 12 | norm_angle(&ang_end); | |
981 | |||
982 | 12 | float ang_range = ang_end - ang_start; | |
983 | |||
984 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (ang_range < 0.0) { |
985 | 6 | ang_range += 2.0f * (float)M_PI; | |
986 | } | ||
987 | |||
988 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (res <= 0) { |
989 | 12 | res = 80; | |
990 | } | ||
991 | |||
992 | 12 | float steps = ceilf((float)res * ang_range * (0.5f / (float)M_PI)); | |
993 | |||
994 | 12 | float ang_step = ang_range / steps; | |
995 | 12 | float sa = sinf(ang_step); | |
996 | 12 | float ca = cosf(ang_step); | |
997 | |||
998 | 12 | float px_start = cosf(ang_start) * (float)rad; | |
999 | 12 | float py_start = sinf(ang_start) * (float)rad; | |
1000 | |||
1001 | |||
1002 | 12 | float px = px_start; | |
1003 | 12 | float py = py_start; | |
1004 | |||
1005 |
2/2✓ Branch 0 taken 468 times.
✓ Branch 1 taken 12 times.
|
480 | for (int i = 0;i < steps;i++) { |
1006 | 468 | float px_before = px; | |
1007 | 468 | float py_before = py; | |
1008 | |||
1009 | 468 | px = px * ca - py * sa; | |
1010 | 468 | py = py * ca + px_before * sa; | |
1011 | |||
1012 | 468 | line(img, x + (int)px_before, y + (int)py_before, | |
1013 | 468 | x + (int)px, y + (int)py, thickness, dot1, dot2, color); | |
1014 | } | ||
1015 | |||
1016 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
|
12 | if (sector) { |
1017 | 1 | line(img, x + (int)px, y + (int)py, | |
1018 | x, y, | ||
1019 | thickness, dot1, dot2, color); | ||
1020 | 1 | line(img, x, y, | |
1021 | 1 | x + (int)px_start, y + (int)py_start, | |
1022 | thickness, dot1, dot2, color); | ||
1023 | } | ||
1024 | |||
1025 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
|
12 | if (segment) { |
1026 | 1 | line(img, x + (int)px, y + (int)py, | |
1027 | 1 | x + (int)px_start, y + (int)py_start, | |
1028 | thickness, dot1, dot2, color); | ||
1029 | } | ||
1030 | 12 | } | |
1031 | |||
1032 | // thin arc helper function | ||
1033 | // handles a single pixel in the complete circle, checking if the pixel is part | ||
1034 | // of the arc. | ||
1035 | 42976 | static void handle_thin_arc_pixel(image_buffer_t *img, int x, int y, | |
1036 | int c_x, int c_y, int cap0_x, int cap0_y, int cap1_x, int cap1_y, int min_y, int max_y, bool angle_is_closed, uint32_t color) { | ||
1037 |
4/4✓ Branch 0 taken 34386 times.
✓ Branch 1 taken 8590 times.
✓ Branch 2 taken 12736 times.
✓ Branch 3 taken 21650 times.
|
42976 | if (y > max_y || y < min_y) { |
1038 | 21326 | return; | |
1039 | } | ||
1040 | |||
1041 | 21650 | int line_is_past_0 = point_past_line(x, y, 0, 0, cap0_x, cap0_y); | |
1042 | 21650 | int line_is_past_1 = -point_past_line(x, y, 0, 0, cap1_x, cap1_y); | |
1043 | |||
1044 | 21650 | bool in_cap0_quadrant = points_same_quadrant( | |
1045 | x, y, cap0_x, cap0_y); | ||
1046 | 21650 | bool in_cap1_quadrant = points_same_quadrant( | |
1047 | x, y, cap1_x, cap1_y); | ||
1048 | |||
1049 |
2/2✓ Branch 0 taken 2798 times.
✓ Branch 1 taken 18852 times.
|
21650 | if (angle_is_closed) { |
1050 |
4/4✓ Branch 0 taken 590 times.
✓ Branch 1 taken 2208 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 431 times.
|
2798 | if (line_is_past_0 == 1 && line_is_past_1 == 1) { |
1051 | 159 | return; | |
1052 | } | ||
1053 | } else { | ||
1054 |
4/4✓ Branch 0 taken 14241 times.
✓ Branch 1 taken 4611 times.
✓ Branch 2 taken 9750 times.
✓ Branch 3 taken 4491 times.
|
18852 | if (line_is_past_0 == 1 || line_is_past_1 == 1 |
1055 |
4/4✓ Branch 0 taken 119 times.
✓ Branch 1 taken 9631 times.
✓ Branch 2 taken 111 times.
✓ Branch 3 taken 8 times.
|
9750 | || (line_is_past_0 == 0 && !in_cap0_quadrant) |
1056 |
4/4✓ Branch 0 taken 109 times.
✓ Branch 1 taken 9633 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 104 times.
|
9742 | || (line_is_past_1 == 0 && !in_cap1_quadrant)) { |
1057 | 9115 | return; | |
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | 12376 | putpixel(img, c_x + x, c_y + y, color); | |
1062 | } | ||
1063 | |||
1064 | // single pixel wide arc | ||
1065 | 166 | static void thin_arc(image_buffer_t *img, int c_x, int c_y, int radius, float angle0, float angle1, bool sector, bool segment, uint32_t color) { | |
1066 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 156 times.
|
166 | if (radius == 0) { |
1067 | 10 | return; | |
1068 | } | ||
1069 | |||
1070 | 156 | angle0 *= (float)M_PI / 180.0f; | |
1071 | 156 | angle1 *= (float)M_PI / 180.0f; | |
1072 | 156 | norm_angle_0_2pi(&angle0); | |
1073 | 156 | norm_angle_0_2pi(&angle1); | |
1074 | |||
1075 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 146 times.
|
156 | if (angle0 == angle1) { |
1076 | 10 | return; | |
1077 | } | ||
1078 | |||
1079 | bool angle_is_closed; | ||
1080 | // if the angle of the filled in part of the arc is greater than 180° | ||
1081 | // honestly unsure if it'd be better if this was called angle_is_open | ||
1082 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 28 times.
|
146 | if (angle1 - angle0 > 0.0) { |
1083 | 118 | angle_is_closed = fabsf(angle1 - angle0) > M_PI; | |
1084 | } else { | ||
1085 | 28 | angle_is_closed = fabsf(angle1 - angle0) < M_PI; | |
1086 | } | ||
1087 | |||
1088 | 146 | int cap0_x = (int)(cosf(angle0) * (float)(radius)); | |
1089 | 146 | int cap0_y = (int)(sinf(angle0) * (float)(radius)); | |
1090 | |||
1091 | 146 | int cap1_x = (int)(cosf(angle1) * (float)(radius)); | |
1092 | 146 | int cap1_y = (int)(sinf(angle1) * (float)(radius)); | |
1093 | |||
1094 | // Highest and lowest (y coord wise) drawn line of the base arc (excluding | ||
1095 | // the circular end caps). This range is *inclusive*! | ||
1096 | // Note that these might be slightly off due to inconsistent rounding between | ||
1097 | // my circle drawing algorithm and point rotation. | ||
1098 | 146 | int min_y = MIN(cap0_y, cap1_y); | |
1099 | 146 | int max_y = MAX(cap0_y, cap1_y); | |
1100 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 28 times.
|
146 | if (angle0 < angle1) { |
1101 |
4/4✓ Branch 0 taken 74 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 70 times.
|
118 | if (angle0 < M_PI_2 && angle1 >= M_3PI_2) { |
1102 | 4 | min_y = -radius; | |
1103 | 4 | max_y = radius; | |
1104 |
4/4✓ Branch 0 taken 113 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 90 times.
|
114 | } else if (angle0 < M_3PI_2 && angle1 > M_3PI_2) { |
1105 | 23 | min_y = -radius; | |
1106 |
4/4✓ Branch 0 taken 70 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 10 times.
|
91 | } else if (angle0 < M_PI_2 && angle1 > M_PI_2) { |
1107 | 60 | max_y = radius; | |
1108 | } | ||
1109 | } else { | ||
1110 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
28 | if ((angle0 < M_3PI_2 && angle1 >= M_PI_2) |
1111 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 1 times.
|
28 | || (angle0 < M_PI_2) |
1112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | || (angle1 > M_3PI_2)) { |
1113 | 1 | min_y = -radius; | |
1114 | 1 | max_y = radius; | |
1115 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
27 | } else if (angle0 < M_3PI_2 && angle1 < M_PI_2) { |
1116 | ✗ | min_y = -radius; | |
1117 |
2/4✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
27 | } else if (angle0 > M_PI_2 && angle1 > M_PI_2) { |
1118 | ✗ | max_y = radius; | |
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | 146 | int radius_dbl_sq = radius * radius * 4; | |
1123 | |||
1124 | 146 | int last_x = 0; | |
1125 |
2/2✓ Branch 0 taken 7639 times.
✓ Branch 1 taken 146 times.
|
7785 | for (int y = radius - 1; y >= 0; y--) { |
1126 | 7639 | int y_dbl_offs = 2 * y + 1; | |
1127 | 7639 | int y_dbl_offs_sq = y_dbl_offs * y_dbl_offs; | |
1128 | |||
1129 |
1/2✓ Branch 0 taken 898574 times.
✗ Branch 1 not taken.
|
898574 | for (int x = -radius; x <= 0; x++) { |
1130 | 898574 | int x_dbl_offs = 2 * x + 1; | |
1131 |
2/2✓ Branch 0 taken 7639 times.
✓ Branch 1 taken 890935 times.
|
898574 | if (x_dbl_offs * x_dbl_offs + y_dbl_offs_sq <= radius_dbl_sq) { |
1132 |
2/2✓ Branch 0 taken 6201 times.
✓ Branch 1 taken 1438 times.
|
7639 | if (last_x - x < 2) { |
1133 | // This is horrible... | ||
1134 | 6201 | handle_thin_arc_pixel(img, x, y, | |
1135 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1136 | 6201 | handle_thin_arc_pixel(img, -x - 1, y, | |
1137 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1138 | |||
1139 | 6201 | handle_thin_arc_pixel(img, x, -y - 1, | |
1140 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1141 | 6201 | handle_thin_arc_pixel(img, -x - 1, -y - 1, | |
1142 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1143 | } else { | ||
1144 |
2/2✓ Branch 0 taken 4543 times.
✓ Branch 1 taken 1438 times.
|
5981 | for (int x0 = x; x0 < last_x; x0++) { |
1145 | 4543 | handle_thin_arc_pixel(img, x0, y, | |
1146 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1147 | 4543 | handle_thin_arc_pixel(img, -x0 - 1, y, | |
1148 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1149 | |||
1150 | 4543 | handle_thin_arc_pixel(img, x0, -y - 1, | |
1151 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1152 | 4543 | handle_thin_arc_pixel(img, -x0 - 1, -y - 1, | |
1153 | c_x, c_y, cap0_x, cap0_y, cap1_x, cap1_y, min_y, max_y, angle_is_closed, color); | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | 7639 | last_x = x; | |
1158 | 7639 | break; | |
1159 | } | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 130 times.
|
146 | if (sector) { |
1164 | 16 | line(img, c_x, c_y, c_x + cap0_x, c_y + cap0_y, 1, 0, 0, color); | |
1165 | 16 | line(img, c_x, c_y, c_x + cap1_x, c_y + cap1_y, 1, 0, 0, color); | |
1166 | } | ||
1167 | |||
1168 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 108 times.
|
146 | if (segment) { |
1169 | 38 | line(img, c_x + cap0_x, c_y + cap0_y, c_x + cap1_x, c_y + cap1_y, 1, 0, 0, color); | |
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | // arc helper function | ||
1174 | // handles a horizontal slice at the given outer arc point | ||
1175 | 64540 | static void handle_arc_slice(image_buffer_t *img, int outer_x, int outer_y, int c_x, int c_y, uint32_t color, | |
1176 | int outer_x0, int outer_y0, int outer_x1, int outer_y1, | ||
1177 | int cap0_min_y, int cap0_max_y, int cap1_min_y, int cap1_max_y, | ||
1178 | int radius_outer, int radius_inner, | ||
1179 | int min_y, int max_y, | ||
1180 | float angle0, float angle1, bool angle_is_closed, | ||
1181 | bool filled, bool segment, | ||
1182 | int radius_inner_dbl_sq) { | ||
1183 | (void) radius_outer; | ||
1184 |
4/4✓ Branch 0 taken 56252 times.
✓ Branch 1 taken 8288 times.
✓ Branch 2 taken 20254 times.
✓ Branch 3 taken 35998 times.
|
64540 | if (outer_y > max_y || outer_y < min_y) { |
1185 | 28542 | return; | |
1186 | } | ||
1187 | |||
1188 | int line_is_past_0, line_is_past_1; | ||
1189 | 35998 | line_is_past_0 = point_past_line(outer_x, outer_y, 0, 0, outer_x0, outer_y0); | |
1190 | 35998 | line_is_past_1 = -point_past_line(outer_x, outer_y, 0, 0, outer_x1, outer_y1); | |
1191 | |||
1192 | 35998 | int outer_x_sign = sign(outer_x); | |
1193 | 35998 | int outer_y_sign = sign(outer_y); | |
1194 | |||
1195 | 35998 | int outer_x0_sign = sign(outer_x0); | |
1196 | 35998 | int outer_y0_sign = sign(outer_y0); | |
1197 | |||
1198 | 35998 | int outer_x1_sign = sign(outer_x1); | |
1199 | 35998 | int outer_y1_sign = sign(outer_y1); | |
1200 | |||
1201 | bool in_cap0, in_cap1, in_both_caps; | ||
1202 |
4/4✓ Branch 0 taken 22268 times.
✓ Branch 1 taken 13730 times.
✓ Branch 2 taken 1954 times.
✓ Branch 3 taken 20314 times.
|
35998 | if (segment && filled) { |
1203 | 3908 | in_cap0 = outer_y <= MAX(outer_y0, outer_y1) | |
1204 |
4/4✓ Branch 0 taken 1474 times.
✓ Branch 1 taken 480 times.
✓ Branch 2 taken 1298 times.
✓ Branch 3 taken 176 times.
|
1954 | && outer_y >= MIN(outer_y0, outer_y1); |
1205 | 1954 | in_cap1 = false; | |
1206 | } | ||
1207 |
2/2✓ Branch 0 taken 5526 times.
✓ Branch 1 taken 28518 times.
|
34044 | else if (filled) { |
1208 | 5526 | in_cap0 = outer_y <= cap0_max_y | |
1209 |
2/2✓ Branch 0 taken 828 times.
✓ Branch 1 taken 1746 times.
|
2574 | && outer_x0_sign == outer_x_sign |
1210 |
4/4✓ Branch 0 taken 2574 times.
✓ Branch 1 taken 2952 times.
✓ Branch 2 taken 310 times.
✓ Branch 3 taken 518 times.
|
8100 | && outer_y0_sign == outer_y_sign; |
1211 | 5526 | in_cap1 = outer_y <= cap1_max_y | |
1212 |
2/2✓ Branch 0 taken 963 times.
✓ Branch 1 taken 1891 times.
|
2854 | && outer_x1_sign == outer_x_sign |
1213 |
4/4✓ Branch 0 taken 2854 times.
✓ Branch 1 taken 2672 times.
✓ Branch 2 taken 670 times.
✓ Branch 3 taken 293 times.
|
8380 | && outer_y1_sign == outer_y_sign; |
1214 | } else { | ||
1215 | 28518 | in_cap0 = outer_y >= cap0_min_y | |
1216 |
2/2✓ Branch 0 taken 3376 times.
✓ Branch 1 taken 17574 times.
|
20950 | && outer_y <= cap0_max_y |
1217 |
4/4✓ Branch 0 taken 20950 times.
✓ Branch 1 taken 7568 times.
✓ Branch 2 taken 1491 times.
✓ Branch 3 taken 1885 times.
|
49468 | && outer_x_sign == outer_x0_sign; |
1218 | 28518 | in_cap1 = outer_y >= cap1_min_y | |
1219 |
2/2✓ Branch 0 taken 3578 times.
✓ Branch 1 taken 10934 times.
|
14512 | && outer_y <= cap1_max_y |
1220 |
4/4✓ Branch 0 taken 14512 times.
✓ Branch 1 taken 14006 times.
✓ Branch 2 taken 1586 times.
✓ Branch 3 taken 1992 times.
|
43030 | && outer_x_sign == outer_x1_sign; |
1221 | } | ||
1222 |
4/4✓ Branch 0 taken 3099 times.
✓ Branch 1 taken 32899 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 3077 times.
|
35998 | in_both_caps = in_cap0 && in_cap1; |
1223 | |||
1224 | 35998 | bool in_cap0_quadrant = points_same_quadrant(outer_x, outer_y, outer_x0, outer_y0); | |
1225 | 35998 | bool in_cap1_quadrant = points_same_quadrant(outer_x, outer_y, outer_x1, outer_y1); | |
1226 | |||
1227 | 35998 | bool caps_in_same_quadrant = points_same_quadrant(outer_x0, outer_y0, outer_x1, outer_y1); | |
1228 | |||
1229 | // Check if slice is outside caps and drawn sections of the arc. | ||
1230 |
4/4✓ Branch 0 taken 32899 times.
✓ Branch 1 taken 3099 times.
✓ Branch 2 taken 30665 times.
✓ Branch 3 taken 2234 times.
|
35998 | if (!in_cap0 && !in_cap1) { |
1231 |
2/2✓ Branch 0 taken 16214 times.
✓ Branch 1 taken 14451 times.
|
30665 | if (angle_is_closed) { |
1232 |
4/4✓ Branch 0 taken 5879 times.
✓ Branch 1 taken 10335 times.
✓ Branch 2 taken 2486 times.
✓ Branch 3 taken 3393 times.
|
16214 | if (line_is_past_0 == 1 && line_is_past_1 == 1 |
1233 | // Failsafe for closed angles with a very small difference. | ||
1234 | // Otherwise a tiny section at the opposite side of the arc | ||
1235 | // might get skipped. | ||
1236 |
4/6✓ Branch 0 taken 169 times.
✓ Branch 1 taken 2317 times.
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 169 times.
✗ Branch 5 not taken.
|
2486 | && (!caps_in_same_quadrant || (in_cap0_quadrant && in_cap1_quadrant))) { |
1237 | 2486 | return; | |
1238 | } | ||
1239 | } else { | ||
1240 |
4/4✓ Branch 0 taken 10850 times.
✓ Branch 1 taken 3601 times.
✓ Branch 2 taken 9989 times.
✓ Branch 3 taken 861 times.
|
14451 | if (line_is_past_0 == 1 || line_is_past_1 == 1 |
1241 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9988 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
9989 | || (line_is_past_0 == 0 && !in_cap0_quadrant) |
1242 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9987 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
9988 | || (line_is_past_1 == 0 && !in_cap1_quadrant)) { |
1243 | 4463 | return; | |
1244 | } | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | // Find slice width if arc spanned the complete circle. | ||
1249 | int x, x1; | ||
1250 | 29049 | int width = 0; | |
1251 | 29049 | int width1 = 0; | |
1252 | 29049 | bool slice_is_split = false; | |
1253 | |||
1254 | bool slice_filled; | ||
1255 |
2/2✓ Branch 0 taken 6229 times.
✓ Branch 1 taken 22820 times.
|
29049 | if (filled) { |
1256 | 6229 | slice_filled = true; | |
1257 | } else { | ||
1258 |
2/2✓ Branch 0 taken 8996 times.
✓ Branch 1 taken 13824 times.
|
22820 | if (outer_y < 0) { |
1259 | 8996 | slice_filled = -outer_y > radius_inner; | |
1260 | } else { | ||
1261 | 13824 | slice_filled = outer_y >= radius_inner; | |
1262 | } | ||
1263 | } | ||
1264 | |||
1265 |
2/2✓ Branch 0 taken 11257 times.
✓ Branch 1 taken 17792 times.
|
29049 | if (slice_filled) { |
1266 |
2/2✓ Branch 0 taken 5360 times.
✓ Branch 1 taken 5897 times.
|
11257 | if (outer_x < 0) { |
1267 | 5360 | x = outer_x; | |
1268 | 5360 | width = -x; | |
1269 | } else { | ||
1270 | 5897 | x = 0; | |
1271 | 5897 | width = outer_x + 1; | |
1272 | } | ||
1273 | } else { | ||
1274 | 17792 | x = outer_x; | |
1275 | 17792 | int cur_x = outer_x; | |
1276 |
2/2✓ Branch 0 taken 10515 times.
✓ Branch 1 taken 7277 times.
|
17792 | int delta = outer_x > 0 ? -1 : 1; |
1277 | |||
1278 | // TODO: this could probably be binary searched | ||
1279 | 17792 | int y_dbl_off = outer_y * 2 + 1; | |
1280 | 17792 | int y_dbl_off_sq = y_dbl_off * y_dbl_off; | |
1281 | 239064 | while (true) { | |
1282 | 256856 | cur_x += delta; | |
1283 | 256856 | int x_dbl_off = cur_x * 2 + 1; | |
1284 |
2/2✓ Branch 0 taken 239064 times.
✓ Branch 1 taken 17792 times.
|
256856 | if (x_dbl_off * x_dbl_off + y_dbl_off_sq <= radius_inner_dbl_sq |
1285 |
1/2✓ Branch 0 taken 239064 times.
✗ Branch 1 not taken.
|
239064 | || abs(x) > 2000) { // failsafe |
1286 | break; | ||
1287 | } | ||
1288 | } | ||
1289 | 17792 | width = abs(cur_x - x); | |
1290 |
2/2✓ Branch 0 taken 10515 times.
✓ Branch 1 taken 7277 times.
|
17792 | if (outer_x > 0) { |
1291 | 10515 | x = cur_x + 1; | |
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | // Check which cap lines intersects this slice | ||
1296 |
8/8✓ Branch 0 taken 25950 times.
✓ Branch 1 taken 3099 times.
✓ Branch 2 taken 2234 times.
✓ Branch 3 taken 23716 times.
✓ Branch 4 taken 4048 times.
✓ Branch 5 taken 1285 times.
✓ Branch 6 taken 2750 times.
✓ Branch 7 taken 1298 times.
|
29049 | if ((in_cap0 || in_cap1) && !(segment && filled)) { |
1297 | // the range from x_start to x_end is *inclusive* | ||
1298 | 4035 | int x_start = x; | |
1299 | 4035 | int x_end = x_start + width - 1; | |
1300 | |||
1301 | // when a point is "past" a line, it is on the wrong cleared side of it | ||
1302 | 4035 | int start_is_past0 = point_past_line(x_start, outer_y, | |
1303 | 0, 0, | ||
1304 | outer_x0, outer_y0); | ||
1305 | 4035 | int end_is_past0 = point_past_line(x_end, outer_y, | |
1306 | 0, 0, | ||
1307 | outer_x0, outer_y0); | ||
1308 | |||
1309 | 4035 | int start_is_past1 = -point_past_line(x_start, outer_y, | |
1310 | 0, 0, | ||
1311 | outer_x1, outer_y1); | ||
1312 | 4035 | int end_is_past1 = -point_past_line(x_end, outer_y, | |
1313 | 0, 0, | ||
1314 | outer_x1, outer_y1); | ||
1315 | |||
1316 | // TODO: look into this: | ||
1317 | // end_is_past0!=0 is always true. | ||
1318 | // end_is_part1!=0 is always true. | ||
1319 | 4035 | bool slice_overlaps0 = start_is_past0 != end_is_past0 | |
1320 |
5/6✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 1630 times.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
|
4035 | && (start_is_past0 != 0 || end_is_past0 != 0); |
1321 | 4035 | bool slice_overlaps1 = start_is_past1 != end_is_past1 | |
1322 |
5/6✓ Branch 0 taken 1824 times.
✓ Branch 1 taken 2211 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 1741 times.
✓ Branch 4 taken 83 times.
✗ Branch 5 not taken.
|
4035 | && (start_is_past1 != 0 || end_is_past1 != 0); |
1323 | |||
1324 |
8/8✓ Branch 0 taken 1801 times.
✓ Branch 1 taken 2234 times.
✓ Branch 2 taken 1779 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 768 times.
✓ Branch 5 taken 1011 times.
✓ Branch 6 taken 659 times.
✓ Branch 7 taken 109 times.
|
4035 | if ((in_cap0 && !in_cap1 && start_is_past0 == 1 && end_is_past0 == 1) |
1325 |
7/8✓ Branch 0 taken 2234 times.
✓ Branch 1 taken 1692 times.
✓ Branch 2 taken 2234 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1435 times.
✓ Branch 5 taken 799 times.
✓ Branch 6 taken 1202 times.
✓ Branch 7 taken 233 times.
|
3926 | || (!in_cap0 && in_cap1 && start_is_past1 == 1 && end_is_past1 == 1) |
1326 |
5/6✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3671 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
3693 | || (in_both_caps && !angle_is_closed && ( |
1327 | ✗ | (start_is_past0 == 1 && end_is_past0 == 1) | |
1328 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | || (start_is_past1 == 1 && end_is_past1 == 1) |
1329 | )) | ||
1330 |
6/6✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3671 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 6 times.
|
3693 | || (in_both_caps && angle_is_closed && ( |
1331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | (start_is_past0 == 1 && end_is_past0 == 1) |
1332 | ✗ | && (start_is_past1 == 1 && end_is_past1 == 1) | |
1333 | ))) { | ||
1334 | 342 | return; | |
1335 | } | ||
1336 | |||
1337 | // The repetition in all these cases could probably be reduced... | ||
1338 |
6/6✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3671 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 1 times.
|
3693 | if ((in_both_caps && slice_overlaps0 && !slice_overlaps1) |
1339 |
6/6✓ Branch 0 taken 1691 times.
✓ Branch 1 taken 2001 times.
✓ Branch 2 taken 1670 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1467 times.
✓ Branch 5 taken 203 times.
|
3692 | || (in_cap0 && !in_cap1 && slice_overlaps0)) { |
1340 | // intersect with cap line 0 | ||
1341 |
4/4✓ Branch 0 taken 681 times.
✓ Branch 1 taken 787 times.
✓ Branch 2 taken 666 times.
✓ Branch 3 taken 15 times.
|
1468 | if (start_is_past0 != -1 && end_is_past0 != 1) { |
1342 |
2/2✓ Branch 0 taken 9536 times.
✓ Branch 1 taken 666 times.
|
10202 | while (start_is_past0 == 1) { |
1343 | 9536 | x_start += 1; | |
1344 | 9536 | start_is_past0 = point_past_line(x_start, outer_y, | |
1345 | 0, 0, | ||
1346 | outer_x0, outer_y0); | ||
1347 | } | ||
1348 | } else { | ||
1349 |
2/2✓ Branch 0 taken 9128 times.
✓ Branch 1 taken 802 times.
|
9930 | while (end_is_past0 == 1) { |
1350 | 9128 | x_end -= 1; | |
1351 | 9128 | end_is_past0 = point_past_line(x_end, outer_y, | |
1352 | 0, 0, | ||
1353 | outer_x0, outer_y0); | ||
1354 | } | ||
1355 | } | ||
1356 |
5/6✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2204 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
2225 | } else if ((in_both_caps && !slice_overlaps0 && slice_overlaps1) |
1357 |
5/6✓ Branch 0 taken 2001 times.
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 2001 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1609 times.
✓ Branch 5 taken 392 times.
|
2225 | || (!in_cap0 && in_cap1 && slice_overlaps1)) { |
1358 | // intersect with cap line 1 | ||
1359 |
4/4✓ Branch 0 taken 1250 times.
✓ Branch 1 taken 359 times.
✓ Branch 2 taken 1249 times.
✓ Branch 3 taken 1 times.
|
1609 | if (start_is_past1 != -1 && end_is_past1 != 1) { |
1360 |
2/2✓ Branch 0 taken 14004 times.
✓ Branch 1 taken 1249 times.
|
15253 | while (start_is_past1 == 1) { |
1361 | 14004 | x_start += 1; | |
1362 | 14004 | start_is_past1 = -point_past_line(x_start, outer_y, | |
1363 | 0, 0, | ||
1364 | outer_x1, outer_y1); | ||
1365 | } | ||
1366 | } else { | ||
1367 |
2/2✓ Branch 0 taken 5076 times.
✓ Branch 1 taken 360 times.
|
5436 | while (end_is_past1 == 1) { |
1368 | 5076 | x_end -= 1; | |
1369 | 5076 | end_is_past1 = -point_past_line(x_end, outer_y, | |
1370 | 0, 0, | ||
1371 | outer_x1, outer_y1); | ||
1372 | } | ||
1373 | } | ||
1374 |
5/6✓ Branch 0 taken 21 times.
✓ Branch 1 taken 595 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
616 | } else if (in_both_caps && slice_overlaps0 && slice_overlaps1) { |
1375 | // intersect with both cap lines | ||
1376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (angle0 < angle1) { |
1377 | ✗ | if (angle0 < M_PI) { | |
1378 | ✗ | while (start_is_past1 == 1) { | |
1379 | ✗ | x_start += 1; | |
1380 | ✗ | start_is_past1 = -point_past_line(x_start, outer_y, | |
1381 | 0, 0, | ||
1382 | outer_x1, outer_y1); | ||
1383 | } | ||
1384 | ✗ | while (end_is_past0 == 1) { | |
1385 | ✗ | x_end -= 1; | |
1386 | ✗ | end_is_past0 = point_past_line(x_end, outer_y, | |
1387 | 0, 0, | ||
1388 | outer_x0, outer_y0); | ||
1389 | } | ||
1390 | } else { | ||
1391 | ✗ | while (start_is_past0 == 1) { | |
1392 | ✗ | x_start += 1; | |
1393 | ✗ | start_is_past0 = point_past_line(x_start, outer_y, | |
1394 | 0, 0, | ||
1395 | outer_x0, outer_y0); | ||
1396 | } | ||
1397 | ✗ | while (end_is_past1 == 1) { | |
1398 | ✗ | x_end -= 1; | |
1399 | ✗ | end_is_past1 = -point_past_line(x_end, outer_y, | |
1400 | 0, 0, | ||
1401 | outer_x1, outer_y1); | ||
1402 | } | ||
1403 | } | ||
1404 | } else { | ||
1405 | // split the slice into two | ||
1406 | |||
1407 | 14 | slice_is_split = true; | |
1408 | |||
1409 | 14 | int x_start1 = x_start; | |
1410 | 14 | int x_end1 = x_end; | |
1411 | |||
1412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (angle0 < M_PI) { |
1413 | ✗ | while (end_is_past0 == 1) { | |
1414 | ✗ | x_end -= 1; | |
1415 | ✗ | end_is_past0 = point_past_line(x_end, outer_y, | |
1416 | 0, 0, | ||
1417 | outer_x0, outer_y0); | ||
1418 | } | ||
1419 | ✗ | while (start_is_past1 == 1) { | |
1420 | ✗ | x_start1 += 1; | |
1421 | ✗ | start_is_past1 = -point_past_line(x_start1, outer_y, | |
1422 | 0, 0, | ||
1423 | outer_x1, outer_y1); | ||
1424 | } | ||
1425 | } else { | ||
1426 |
2/2✓ Branch 0 taken 314 times.
✓ Branch 1 taken 14 times.
|
328 | while (end_is_past1 == 1) { |
1427 | 314 | x_end1 -= 1; | |
1428 | 314 | end_is_past1 = -point_past_line(x_end1, outer_y, | |
1429 | 0, 0, | ||
1430 | outer_x1, outer_y1); | ||
1431 | } | ||
1432 |
2/2✓ Branch 0 taken 362 times.
✓ Branch 1 taken 14 times.
|
376 | while (start_is_past0 == 1) { |
1433 | 362 | x_start += 1; | |
1434 | 362 | start_is_past0 = point_past_line(x_start, outer_y, | |
1435 | 0, 0, | ||
1436 | outer_x0, outer_y0); | ||
1437 | } | ||
1438 | } | ||
1439 | |||
1440 | 14 | x1 = x_start1; | |
1441 | 14 | width1 = x_end1 + 1 - x_start1 ; | |
1442 | } | ||
1443 | } | ||
1444 | 3693 | x = x_start; | |
1445 | 3693 | width = x_end + 1 - x_start; | |
1446 |
4/6✓ Branch 0 taken 1298 times.
✓ Branch 1 taken 23716 times.
✓ Branch 2 taken 1298 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1298 times.
✗ Branch 5 not taken.
|
25014 | } else if (in_cap0 && segment && filled) { |
1447 | // the range from x_start to x_end is *inclusive* | ||
1448 | 1298 | int x_start = x; | |
1449 | 1298 | int x_end = x_start + width - 1; | |
1450 | |||
1451 | // when a point is "past" a line, it is on the wrong cleared side of it | ||
1452 | 1298 | int start_is_past = -point_past_line(x_start, outer_y, | |
1453 | outer_x0, outer_y0, outer_x1, outer_y1); | ||
1454 | 1298 | int end_is_past = -point_past_line(x_end, outer_y, | |
1455 | outer_x0, outer_y0, outer_x1, outer_y1); | ||
1456 | |||
1457 | 1298 | bool slice_overlaps = start_is_past != end_is_past | |
1458 |
5/6✓ Branch 0 taken 610 times.
✓ Branch 1 taken 688 times.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 528 times.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
|
1298 | && (start_is_past != 0 || end_is_past != 0); |
1459 | |||
1460 |
4/4✓ Branch 0 taken 739 times.
✓ Branch 1 taken 559 times.
✓ Branch 2 taken 455 times.
✓ Branch 3 taken 284 times.
|
1298 | if (start_is_past == 1 && end_is_past == 1) { |
1461 | 455 | return; | |
1462 | } | ||
1463 | |||
1464 |
2/2✓ Branch 0 taken 610 times.
✓ Branch 1 taken 233 times.
|
843 | if (slice_overlaps) { |
1465 |
4/4✓ Branch 0 taken 366 times.
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 285 times.
✓ Branch 3 taken 81 times.
|
610 | if (start_is_past != -1 && end_is_past != 1) { |
1466 |
2/2✓ Branch 0 taken 5815 times.
✓ Branch 1 taken 285 times.
|
6100 | while (start_is_past == 1) { |
1467 | 5815 | x_start += 1; | |
1468 | 5815 | start_is_past = -point_past_line(x_start, outer_y, | |
1469 | outer_x0, outer_y0, outer_x1, outer_y1); | ||
1470 | } | ||
1471 | } else { | ||
1472 |
2/2✓ Branch 0 taken 6497 times.
✓ Branch 1 taken 325 times.
|
6822 | while (end_is_past == 1) { |
1473 | 6497 | x_end -= 1; | |
1474 | 6497 | end_is_past = -point_past_line(x_end, outer_y, | |
1475 | outer_x0, outer_y0, outer_x1, outer_y1); | ||
1476 | } | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | 843 | x = x_start; | |
1481 | 843 | width = x_end + 1 - x_start; | |
1482 | } | ||
1483 | |||
1484 | 28252 | h_line(img, c_x + x, c_y + outer_y, width, color); | |
1485 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28238 times.
|
28252 | if (slice_is_split) { |
1486 | 14 | h_line(img, c_x + x1, c_y + outer_y, width1, color); | |
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | // TODO: Fix unwanted slice with angles 130 to 115 (I think, angles might be | ||
1491 | // slightly off). | ||
1492 | // TODO: Look into buggy rendering with angles around 180°-270°. This seems to | ||
1493 | // affect arcs, sectors, and segments likewise. | ||
1494 | 545 | static void arc(image_buffer_t *img, int c_x, int c_y, int radius, float angle0, float angle1, | |
1495 | int thickness, bool rounded, bool filled, bool sector, bool segment, int dot1, int dot2, int resolution, uint32_t color) { | ||
1496 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 533 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
545 | if (dot1 > 0 && !filled) { |
1497 | 12 | thickness /= 2; | |
1498 | |||
1499 | 12 | radius -= thickness; | |
1500 | |||
1501 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (thickness == 0) { |
1502 | 12 | thickness = 1; | |
1503 | } | ||
1504 | |||
1505 | 12 | generic_arc(img, c_x, c_y, radius, angle0, angle1, thickness, dot1, dot2, resolution, sector, segment, color); | |
1506 | |||
1507 | 12 | return; | |
1508 | } | ||
1509 | |||
1510 |
4/4✓ Branch 0 taken 260 times.
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 166 times.
✓ Branch 3 taken 94 times.
|
533 | if (thickness <= 1 && !filled) { |
1511 | 166 | thin_arc(img, c_x, c_y, radius, angle0, angle1, sector, segment, color); | |
1512 | |||
1513 | 166 | return; | |
1514 | } | ||
1515 | |||
1516 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 360 times.
|
367 | if (radius == 0) { |
1517 | 7 | return; | |
1518 | } | ||
1519 | |||
1520 | 360 | angle0 *= (float)M_PI / 180.0f; | |
1521 | 360 | angle1 *= (float)M_PI / 180.0f; | |
1522 | 360 | norm_angle_0_2pi(&angle0); // theses are probably unecessary? | |
1523 | 360 | norm_angle_0_2pi(&angle1); // but who knows with floating point imprecision... | |
1524 | |||
1525 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 354 times.
|
360 | if (angle0 == angle1) { |
1526 | 6 | return; | |
1527 | } | ||
1528 | |||
1529 | bool angle_is_closed; | ||
1530 | // if the angle of the filled in part of the arc is greater than 180° | ||
1531 |
2/2✓ Branch 0 taken 252 times.
✓ Branch 1 taken 102 times.
|
354 | if (angle1 - angle0 > 0.0) { |
1532 | 252 | angle_is_closed = fabsf(angle1 - angle0) > M_PI; | |
1533 | } else { | ||
1534 | 102 | angle_is_closed = fabsf(angle1 - angle0) < M_PI; | |
1535 | } | ||
1536 | |||
1537 | // angles smaller than 1 degree seem to cause issues (with a radius of 62) | ||
1538 | // this is kinda ugly though, and it will probably still break at larger | ||
1539 | // radii or something... | ||
1540 |
4/4✓ Branch 0 taken 256 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 233 times.
|
354 | if (!angle_is_closed && fabsf(angle1 - angle0) < 0.0174532925) { // one degree in radians |
1541 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9 times.
|
23 | if (rounded) { |
1542 | 14 | float rad_f = (float)radius - ((float)thickness / 2.0f); | |
1543 | |||
1544 | 14 | float angle = (angle0 + angle1) / 2.0f; | |
1545 | |||
1546 | 14 | int cap_center_x = (int)floorf(cosf(angle) * rad_f); | |
1547 | 14 | int cap_center_y = (int)floorf(sinf(angle) * rad_f); | |
1548 | |||
1549 | 14 | fill_circle(img, c_x + cap_center_x, c_y + cap_center_y, thickness / 2, color); | |
1550 | } | ||
1551 | 23 | return; | |
1552 | } | ||
1553 | |||
1554 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 329 times.
|
331 | if (thickness >= radius) { |
1555 | 2 | filled = true; | |
1556 | } | ||
1557 | |||
1558 | int radius_outer, radius_inner; | ||
1559 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 254 times.
|
331 | if (filled) { |
1560 | 77 | radius_outer = radius; | |
1561 | 77 | radius_inner = 0; | |
1562 | } else { | ||
1563 | 254 | radius_outer = radius; | |
1564 | 254 | radius_inner = radius - thickness; | |
1565 | } | ||
1566 | 331 | int radius_outer_dbl_sq = radius_outer * radius_outer * 4; | |
1567 | 331 | int radius_inner_dbl_sq = radius_inner * radius_inner * 4; | |
1568 | |||
1569 | 331 | float angle0_cos = cosf(angle0); | |
1570 | 331 | float angle0_sin = sinf(angle0); | |
1571 | 331 | float angle1_cos = cosf(angle1); | |
1572 | 331 | float angle1_sin = sinf(angle1); | |
1573 | |||
1574 | 331 | int outer_x0 = (int)(angle0_cos * (float)radius_outer); | |
1575 | 331 | int outer_y0 = (int)(angle0_sin * (float)radius_outer); | |
1576 | |||
1577 | 331 | int outer_x1 = (int)(angle1_cos * (float)radius_outer); | |
1578 | 331 | int outer_y1 = (int)(angle1_sin * (float)radius_outer); | |
1579 | |||
1580 | int inner_y0; | ||
1581 | int inner_y1; | ||
1582 | |||
1583 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 254 times.
|
331 | if (filled) { |
1584 | 77 | inner_y0 = 0; | |
1585 | |||
1586 | 77 | inner_y1 = 0; | |
1587 | } else { | ||
1588 | 254 | inner_y0 = (int)(angle0_sin * (float)radius_inner); | |
1589 | |||
1590 | 254 | inner_y1 = (int)(angle1_sin * (float)radius_inner); | |
1591 | } | ||
1592 | |||
1593 | 331 | int cap0_min_y = MIN(inner_y0, outer_y0); | |
1594 | 331 | int cap0_max_y = MAX(inner_y0, outer_y0); | |
1595 | |||
1596 | 331 | int cap1_min_y = MIN(inner_y1, outer_y1); | |
1597 | 331 | int cap1_max_y = MAX(inner_y1, outer_y1); | |
1598 | |||
1599 | // Highest and lowest (y coord wise) drawn line of the base arc (excluding | ||
1600 | // the circular end caps). This range is *inclusive*! | ||
1601 | // Note that these might be slightly off due to inconsistent rounding between | ||
1602 | // Bresenhamn's algorithm and point rotation. (I don't think the point about | ||
1603 | // Bresenhamn is relevant as we don't use it anymore. Still wouldn't trust | ||
1604 | // them completely though...) | ||
1605 | 331 | int min_y = MIN(outer_y0, MIN(outer_y1, MIN(inner_y0, inner_y1))); | |
1606 | 331 | int max_y = MAX(outer_y0, MAX(outer_y1, MAX(inner_y0, inner_y1))); | |
1607 |
2/2✓ Branch 0 taken 229 times.
✓ Branch 1 taken 102 times.
|
331 | if (angle0 < angle1) { |
1608 |
4/4✓ Branch 0 taken 179 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 162 times.
|
229 | if (angle0 < M_PI_2 && angle1 >= M_3PI_2) { |
1609 | 17 | min_y = -radius_outer; | |
1610 | 17 | max_y = radius_outer; | |
1611 |
3/4✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 172 times.
|
212 | } else if (angle0 < M_3PI_2 && angle1 > M_3PI_2) { |
1612 | 40 | min_y = -radius_outer; | |
1613 |
4/4✓ Branch 0 taken 162 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 153 times.
✓ Branch 3 taken 9 times.
|
172 | } else if (angle0 < M_PI_2 && angle1 > M_PI_2) { |
1614 | 153 | max_y = radius_outer; | |
1615 | } | ||
1616 | } else { | ||
1617 |
4/4✓ Branch 0 taken 34 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 9 times.
|
102 | if ((angle0 < M_3PI_2 && angle1 >= M_PI_2) |
1618 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1 times.
|
93 | || (angle0 < M_PI_2) |
1619 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91 times.
|
92 | || (angle1 > M_3PI_2)) { |
1620 | 11 | min_y = -radius_outer; | |
1621 | 11 | max_y = radius_outer; | |
1622 |
3/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
|
91 | } else if (angle0 < M_3PI_2 && angle1 < M_PI_2) { |
1623 | 24 | min_y = -radius_outer; | |
1624 |
3/4✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 50 times.
|
67 | } else if (angle0 > M_PI_2 && angle1 > M_PI_2) { |
1625 | 17 | max_y = radius_outer; | |
1626 | } | ||
1627 | } | ||
1628 | |||
1629 |
2/2✓ Branch 0 taken 16135 times.
✓ Branch 1 taken 331 times.
|
16466 | for (int y = 0; y < radius_outer; y++) { |
1630 | 16135 | int y_dbl_offs = 2 * (y + 1); | |
1631 | 16135 | int y_dbl_offs_sq = y_dbl_offs * y_dbl_offs; | |
1632 | |||
1633 |
1/2✓ Branch 0 taken 223585 times.
✗ Branch 1 not taken.
|
223585 | for (int x = -radius_outer; x <= 0; x++) { |
1634 | 223585 | int x_dbl_offs = 2 * (x + 1); | |
1635 |
2/2✓ Branch 0 taken 16135 times.
✓ Branch 1 taken 207450 times.
|
223585 | if (x_dbl_offs * x_dbl_offs + y_dbl_offs_sq <= radius_outer_dbl_sq) { |
1636 | // This is horrible... | ||
1637 | 16135 | handle_arc_slice(img, x, y, | |
1638 | c_x, c_y, color, outer_x0, outer_y0, outer_x1, outer_y1, | ||
1639 | cap0_min_y, cap0_max_y, cap1_min_y, cap1_max_y, radius_outer, radius_inner, min_y, max_y, | ||
1640 | angle0, angle1, angle_is_closed, filled, segment, radius_inner_dbl_sq); | ||
1641 | 16135 | handle_arc_slice(img, -x - 1, y, | |
1642 | c_x, c_y, color, outer_x0, outer_y0, outer_x1, outer_y1, | ||
1643 | cap0_min_y, cap0_max_y, cap1_min_y, cap1_max_y, radius_outer, radius_inner, min_y, max_y, | ||
1644 | angle0, angle1, angle_is_closed, filled, segment, radius_inner_dbl_sq); | ||
1645 | |||
1646 | 16135 | handle_arc_slice(img, x, -y - 1, | |
1647 | c_x, c_y, color, outer_x0, outer_y0, outer_x1, outer_y1, | ||
1648 | cap0_min_y, cap0_max_y, cap1_min_y, cap1_max_y, radius_outer, radius_inner, min_y, max_y, | ||
1649 | angle0, angle1, angle_is_closed, filled, segment, radius_inner_dbl_sq); | ||
1650 | 16135 | handle_arc_slice(img, -x - 1, -y - 1, | |
1651 | c_x, c_y, color, outer_x0, outer_y0, outer_x1, outer_y1, | ||
1652 | cap0_min_y, cap0_max_y, cap1_min_y, cap1_max_y, radius_outer, radius_inner, min_y, max_y, | ||
1653 | angle0, angle1, angle_is_closed, filled, segment, radius_inner_dbl_sq); | ||
1654 | |||
1655 | 16135 | break; | |
1656 | } | ||
1657 | } | ||
1658 | } | ||
1659 | |||
1660 | // draw rounded line corners | ||
1661 |
8/8✓ Branch 0 taken 285 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 234 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 200 times.
|
331 | if (rounded && !filled && !sector && !segment) { |
1662 | 34 | float rad_f = (float)radius - ((float)thickness / 2.0f); | |
1663 | |||
1664 | 34 | int cap0_center_x = (int)floorf(angle0_cos * rad_f); | |
1665 | 34 | int cap0_center_y = (int)floorf(angle0_sin * rad_f); | |
1666 | |||
1667 | 34 | int cap1_center_x = (int)floorf(angle1_cos * rad_f); | |
1668 | 34 | int cap1_center_y = (int)floorf(angle1_sin * rad_f); | |
1669 | |||
1670 | 34 | thickness /= 2; | |
1671 | |||
1672 | 34 | fill_circle(img, c_x + cap0_center_x, c_y + cap0_center_y, thickness, color); | |
1673 | 34 | fill_circle(img, c_x + cap1_center_x, c_y + cap1_center_y, thickness, color); | |
1674 | } | ||
1675 | |||
1676 | // draw sector arc cap to center lines | ||
1677 | // (sectors are always rounded) | ||
1678 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 305 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 23 times.
|
331 | if (sector && !filled) { |
1679 | 3 | float rad_f = (float)radius - ((float)thickness / 2.0f); | |
1680 | |||
1681 | 3 | int cap0_center_x = (int)floorf(angle0_cos * rad_f); | |
1682 | 3 | int cap0_center_y = (int)floorf(angle0_sin * rad_f); | |
1683 | |||
1684 | 3 | int cap1_center_x = (int)floorf(angle1_cos * rad_f); | |
1685 | 3 | int cap1_center_y = (int)floorf(angle1_sin * rad_f); | |
1686 | |||
1687 | 3 | thickness /= 2; | |
1688 | |||
1689 | 3 | line(img, c_x + cap0_center_x, c_y + cap0_center_y, | |
1690 | c_x, c_y, thickness, 0, 0, color); | ||
1691 | 3 | line(img, c_x + cap1_center_x, c_y + cap1_center_y, | |
1692 | c_x, c_y, thickness, 0, 0, color); | ||
1693 | } | ||
1694 | |||
1695 |
4/4✓ Branch 0 taken 225 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 25 times.
|
331 | if (segment && !filled) { |
1696 | 200 | float rad_f = (float)radius - ((float)thickness / 2.0f); | |
1697 | |||
1698 | 200 | int cap0_center_x = (int)floorf(angle0_cos * rad_f); | |
1699 | 200 | int cap0_center_y = (int)floorf(angle0_sin * rad_f); | |
1700 | |||
1701 | 200 | int cap1_center_x = (int)floorf(angle1_cos * rad_f); | |
1702 | 200 | int cap1_center_y = (int)floorf(angle1_sin * rad_f); | |
1703 | |||
1704 | 200 | thickness /= 2; | |
1705 | |||
1706 | 200 | line(img, c_x + cap0_center_x, c_y + cap0_center_y, | |
1707 | c_x + cap1_center_x, c_y + cap1_center_y, thickness, 0, 0, color); | ||
1708 | } | ||
1709 | } | ||
1710 | |||
1711 | 734 | static void img_putc(image_buffer_t *img, int x, int y, uint32_t *colors, int num_colors, | |
1712 | uint8_t *font_data, uint8_t ch, bool up, bool down) { | ||
1713 | 734 | uint8_t w = font_data[0]; | |
1714 | 734 | uint8_t h = font_data[1]; | |
1715 | 734 | uint8_t char_num = font_data[2]; | |
1716 | 734 | uint8_t bits_per_pixel = font_data[3]; | |
1717 | |||
1718 | 734 | int pixels_per_byte = (int)(8 / bits_per_pixel); | |
1719 | 734 | int bytes_per_char = (int)((w * h) / pixels_per_byte); | |
1720 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 734 times.
|
734 | if ((w * h) % pixels_per_byte != 0) { |
1721 | ✗ | bytes_per_char += 1; | |
1722 | } | ||
1723 | |||
1724 | // There are some expectations on ch that are not documented here. | ||
1725 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 734 times.
|
734 | if (char_num == 10) { |
1726 | ✗ | ch = (uint8_t)(ch - '0'); | |
1727 | } else { | ||
1728 | 734 | ch = (uint8_t)(ch - ' '); | |
1729 | } | ||
1730 | |||
1731 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 734 times.
|
734 | if (ch >= char_num) { |
1732 | ✗ | return; | |
1733 | } | ||
1734 | |||
1735 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 210 times.
|
734 | if (bits_per_pixel == 2) { |
1736 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
|
524 | if (num_colors < 4) { |
1737 | ✗ | return; | |
1738 | } | ||
1739 | |||
1740 |
2/2✓ Branch 0 taken 217984 times.
✓ Branch 1 taken 524 times.
|
218508 | for (int i = 0; i < w * h; i++) { |
1741 | 217984 | uint8_t byte = font_data[4 + bytes_per_char * ch + (i / 4)]; | |
1742 | 217984 | uint8_t bit_pos = (uint8_t)(i % pixels_per_byte); | |
1743 | 217984 | uint8_t pixel_value = (byte >> (bit_pos * 2)) & 0x03; | |
1744 | 217984 | int x0 = i % w; | |
1745 | 217984 | int y0 = i / w; | |
1746 |
2/2✓ Branch 0 taken 2912 times.
✓ Branch 1 taken 215072 times.
|
217984 | if (up) { |
1747 | 2912 | putpixel(img, x + y0, y - x0, colors[pixel_value]); | |
1748 |
2/2✓ Branch 0 taken 4576 times.
✓ Branch 1 taken 210496 times.
|
215072 | } else if (down) { |
1749 | 4576 | putpixel(img, x - y0, y + x0, colors[pixel_value]); | |
1750 | } else { | ||
1751 | 210496 | putpixel(img, x + x0, y + y0, colors[pixel_value]); | |
1752 | } | ||
1753 | } | ||
1754 | } else { | ||
1755 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
|
210 | if (num_colors < 1) { |
1756 | ✗ | return; | |
1757 | } | ||
1758 | |||
1759 | 210 | int32_t fg = (int32_t)colors[0]; | |
1760 | 210 | int32_t bg = -1; | |
1761 | |||
1762 |
1/2✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
|
210 | if (num_colors > 1) { |
1763 | 210 | bg = (int32_t)colors[1]; | |
1764 | } | ||
1765 | |||
1766 |
2/2✓ Branch 0 taken 87360 times.
✓ Branch 1 taken 210 times.
|
87570 | for (int i = 0; i < w * h; i++) { |
1767 | 87360 | uint8_t byte = font_data[4 + bytes_per_char * ch + (i / 8)]; | |
1768 | 87360 | uint8_t bit_pos = (uint8_t)(i % 8); | |
1769 | 87360 | uint8_t bit = (uint8_t)(byte & (1 << bit_pos)); | |
1770 |
3/4✓ Branch 0 taken 74918 times.
✓ Branch 1 taken 12442 times.
✓ Branch 2 taken 74918 times.
✗ Branch 3 not taken.
|
87360 | if (bit || bg >= 0) { |
1771 | 87360 | int x0 = i % w; | |
1772 | 87360 | int y0 = i / w; | |
1773 | |||
1774 |
2/2✓ Branch 0 taken 32448 times.
✓ Branch 1 taken 54912 times.
|
87360 | if (up) { |
1775 |
2/2✓ Branch 0 taken 4433 times.
✓ Branch 1 taken 28015 times.
|
32448 | putpixel(img, x + y0, y - x0, bit ? (uint32_t)fg : (uint32_t)bg); |
1776 |
2/2✓ Branch 0 taken 37856 times.
✓ Branch 1 taken 17056 times.
|
54912 | } else if (down) { |
1777 |
2/2✓ Branch 0 taken 5566 times.
✓ Branch 1 taken 32290 times.
|
37856 | putpixel(img, x - y0, y + x0, bit ? (uint32_t)fg : (uint32_t)bg); |
1778 | } else { | ||
1779 |
2/2✓ Branch 0 taken 2443 times.
✓ Branch 1 taken 14613 times.
|
17056 | putpixel(img, x + x0, y + y0, bit ? (uint32_t)fg : (uint32_t)bg); |
1780 | } | ||
1781 | } | ||
1782 | } | ||
1783 | } | ||
1784 | } | ||
1785 | |||
1786 | 4386100 | static inline void copy_pixel( | |
1787 | image_buffer_t *img_dest, | ||
1788 | image_buffer_t *img_src, | ||
1789 | int dest_x, int dest_y, | ||
1790 | int src_x, int src_y, | ||
1791 | int src_w, int src_h, | ||
1792 | int transparent_color, | ||
1793 | bool tile | ||
1794 | ) { | ||
1795 |
2/2✓ Branch 0 taken 923300 times.
✓ Branch 1 taken 3462800 times.
|
4386100 | if (tile) { |
1796 | 923300 | src_x = src_x % src_w; | |
1797 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 923300 times.
|
923300 | if (src_x < 0) src_x = src_x + src_w; |
1798 | 923300 | src_y = src_y % src_h; | |
1799 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 923300 times.
|
923300 | if (src_y < 0) src_y = src_y + src_h; |
1800 | } | ||
1801 | |||
1802 |
8/8✓ Branch 0 taken 2553092 times.
✓ Branch 1 taken 1833008 times.
✓ Branch 2 taken 1223499 times.
✓ Branch 3 taken 1329593 times.
✓ Branch 4 taken 1130161 times.
✓ Branch 5 taken 93338 times.
✓ Branch 6 taken 1013488 times.
✓ Branch 7 taken 116673 times.
|
4386100 | if (src_x >= 0 && src_x < src_w && src_y >= 0 && src_y < src_h) { |
1803 | 1013488 | uint32_t p = getpixel(img_src, src_x, src_y); | |
1804 |
4/4✓ Branch 0 taken 122331 times.
✓ Branch 1 taken 891157 times.
✓ Branch 2 taken 53950 times.
✓ Branch 3 taken 68381 times.
|
1013488 | if (transparent_color == -1 || p != (uint32_t)transparent_color) { |
1805 | 945107 | putpixel(img_dest, dest_x, dest_y, p); | |
1806 | } | ||
1807 | } | ||
1808 | 4386100 | } | |
1809 | |||
1810 | // Copy pixels from source to destination with transformations | ||
1811 | 42 | void blit( | |
1812 | image_buffer_t *img_dest, // Destination image buffer | ||
1813 | image_buffer_t *img_src, // Source image buffer | ||
1814 | int dest_offset_x, int dest_offset_y, // Where on dest to start writing pixels | ||
1815 | float rot_x, float rot_y, // Coordinate in src to rotate around | ||
1816 | float rot_angle, // Rotation angle in degrees | ||
1817 | float scale, // Scale factor | ||
1818 | int32_t transparent_color, // Color that will not be drawn -1 to disable | ||
1819 | bool tile, // Tile src to fill dest | ||
1820 | int clip_x, int clip_y, // Clip start in dest | ||
1821 | int clip_w, int clip_h // Clip width and height | ||
1822 | ) { | ||
1823 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 41 times.
|
42 | if (scale == 0.0) return; |
1824 | 41 | int src_w = img_src->width; | |
1825 | 41 | int src_h = img_src->height; | |
1826 | |||
1827 | 41 | int dest_x_start = clip_x; | |
1828 | 41 | int dest_y_start = clip_y; | |
1829 | 41 | int dest_x_end = clip_w; | |
1830 | 41 | int dest_y_end = clip_h; | |
1831 | |||
1832 |
4/4✓ Branch 0 taken 31 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 10 times.
|
41 | if (rot_angle == 0.0 && scale == 1.0) { |
1833 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
|
21 | if (dest_offset_x > 0) dest_x_start += dest_offset_x; |
1834 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
|
21 | if (dest_offset_y > 0) dest_y_start += dest_offset_y; |
1835 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 10 times.
|
21 | if (!tile) { |
1836 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | if ((dest_x_end - dest_offset_x) > src_w) dest_x_end = src_w + dest_offset_x; |
1837 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
|
11 | if ((dest_y_end - dest_offset_y) > src_h) dest_y_end = src_h + dest_offset_y; |
1838 | } | ||
1839 | |||
1840 |
2/2✓ Branch 0 taken 2415 times.
✓ Branch 1 taken 21 times.
|
2436 | for (int dest_y = dest_y_start; dest_y < dest_y_end; dest_y++) { |
1841 |
2/2✓ Branch 0 taken 866100 times.
✓ Branch 1 taken 2415 times.
|
868515 | for (int dest_x = dest_x_start; dest_x < dest_x_end; dest_x++) { |
1842 | 866100 | int src_x = dest_x - dest_offset_x; | |
1843 | 866100 | int src_y = dest_y - dest_offset_y; | |
1844 | 866100 | copy_pixel(img_dest, img_src, dest_x, dest_y, src_x, src_y, src_w, src_h, transparent_color, tile); | |
1845 | } | ||
1846 | } | ||
1847 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | } else if (rot_angle == 0.0) { |
1848 | 10 | rot_x *= scale; | |
1849 | 10 | rot_y *= scale; | |
1850 | |||
1851 | 10 | const int fp_scale = 1000; | |
1852 | |||
1853 | 10 | int rot_x_x = (int)rot_x; | |
1854 | 10 | int rot_y_i = (int)rot_y; | |
1855 | 10 | int scale_i = (int)(scale * (float) fp_scale); | |
1856 | |||
1857 |
2/2✓ Branch 0 taken 3500 times.
✓ Branch 1 taken 10 times.
|
3510 | for (int dest_y = dest_y_start; dest_y < dest_y_end; dest_y++) { |
1858 |
2/2✓ Branch 0 taken 1720000 times.
✓ Branch 1 taken 3500 times.
|
1723500 | for (int dest_x = dest_x_start; dest_x < dest_x_end; dest_x++) { |
1859 | 1720000 | int src_x = (dest_x - dest_offset_x - rot_x_x) * fp_scale; | |
1860 | 1720000 | int src_y = (dest_y - dest_offset_y - rot_y_i) * fp_scale; | |
1861 | |||
1862 | 1720000 | src_x += rot_x_x * fp_scale; | |
1863 | 1720000 | src_y += rot_y_i * fp_scale; | |
1864 | |||
1865 | 1720000 | src_x /= scale_i; | |
1866 | 1720000 | src_y /= scale_i; | |
1867 | 1720000 | copy_pixel(img_dest, img_src, dest_x, dest_y, src_x, src_y, src_w, src_h, transparent_color, tile); | |
1868 | } | ||
1869 | } | ||
1870 | } else { | ||
1871 | 10 | float sin_rot_angle = sinf(-rot_angle * (float)M_PI / 180.0f); | |
1872 | 10 | float cos_rot_angle = cosf(-rot_angle * (float)M_PI / 180.0f); | |
1873 | |||
1874 | 10 | rot_x *= scale; | |
1875 | 10 | rot_y *= scale; | |
1876 | |||
1877 | 10 | const int fp_scale = 1000; | |
1878 | |||
1879 | 10 | int sin_rot_angle_i = (int)(sin_rot_angle * (float)fp_scale); | |
1880 | 10 | int cos_rot_angle_i = (int)(cos_rot_angle * (float)fp_scale); | |
1881 | 10 | int rot_x_i = (int)rot_x; | |
1882 | 10 | int rot_y_i = (int)rot_y; | |
1883 | 10 | int scale_i = (int)(scale * (float) fp_scale); | |
1884 | |||
1885 |
2/2✓ Branch 0 taken 3600 times.
✓ Branch 1 taken 10 times.
|
3610 | for (int dest_y = dest_y_start; dest_y < dest_y_end; dest_y++) { |
1886 |
2/2✓ Branch 0 taken 1800000 times.
✓ Branch 1 taken 3600 times.
|
1803600 | for (int dest_x = dest_x_start; dest_x < dest_x_end; dest_x++) { |
1887 | 1800000 | int src_x = (dest_x - dest_offset_x - rot_x_i) * cos_rot_angle_i + (dest_y - dest_offset_y - rot_y_i) * sin_rot_angle_i; | |
1888 | 1800000 | int src_y = -(dest_x - dest_offset_x - rot_x_i) * sin_rot_angle_i + (dest_y - dest_offset_y - rot_y_i) * cos_rot_angle_i; | |
1889 | |||
1890 | 1800000 | src_x += rot_x_i * fp_scale; | |
1891 | 1800000 | src_y += rot_y_i * fp_scale; | |
1892 | |||
1893 | 1800000 | src_x /= scale_i; | |
1894 | 1800000 | src_y /= scale_i; | |
1895 | 1800000 | copy_pixel(img_dest, img_src, dest_x, dest_y, src_x, src_y, src_w, src_h, transparent_color, tile); | |
1896 | } | ||
1897 | } | ||
1898 | } | ||
1899 | } | ||
1900 | |||
1901 | // Extensions | ||
1902 | |||
1903 | #define ATTR_MAX_ARGS 4 | ||
1904 | #define ARG_MAX_NUM 8 | ||
1905 | |||
1906 | typedef struct { | ||
1907 | bool is_valid; | ||
1908 | uint16_t arg_num; | ||
1909 | lbm_value args[ATTR_MAX_ARGS]; | ||
1910 | } attr_t; | ||
1911 | |||
1912 | typedef struct { | ||
1913 | bool is_valid; | ||
1914 | image_buffer_t img; | ||
1915 | lbm_value args[ARG_MAX_NUM]; | ||
1916 | attr_t attr_thickness; | ||
1917 | attr_t attr_filled; | ||
1918 | attr_t attr_rounded; | ||
1919 | attr_t attr_dotted; | ||
1920 | attr_t attr_scale; | ||
1921 | attr_t attr_rotate; | ||
1922 | attr_t attr_resolution; | ||
1923 | attr_t attr_tile; | ||
1924 | attr_t attr_clip; | ||
1925 | } img_args_t; | ||
1926 | |||
1927 | 1085 | static img_args_t decode_args(lbm_value *args, lbm_uint argn, int num_expected) { | |
1928 | img_args_t res; | ||
1929 | 1085 | memset(&res, 0, sizeof(res)); | |
1930 | 1085 | res.is_valid = false; | |
1931 | |||
1932 | lbm_array_header_t *arr; | ||
1933 |
3/4✓ Branch 0 taken 1085 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1048 times.
✓ Branch 3 taken 37 times.
|
1085 | if (argn >= 1 && (arr = get_image_buffer(args[0]))) { |
1934 | // at least one argument which is an image buffer. | ||
1935 | 1048 | res.img.width = image_buffer_width((uint8_t*)arr->data); | |
1936 | 1048 | res.img.height = image_buffer_height((uint8_t*)arr->data); | |
1937 | 1048 | res.img.fmt = image_buffer_format((uint8_t*)arr->data); | |
1938 | 1048 | res.img.mem_base = (uint8_t*)arr->data; | |
1939 | 1048 | res.img.data = image_buffer_data((uint8_t*)arr->data); | |
1940 | |||
1941 | |||
1942 | 1048 | int num_dec = 0; | |
1943 |
2/2✓ Branch 0 taken 5391 times.
✓ Branch 1 taken 1022 times.
|
6413 | for (unsigned int i = 1;i < argn;i++) { |
1944 |
4/4✓ Branch 0 taken 668 times.
✓ Branch 1 taken 4723 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 648 times.
|
5391 | if (!lbm_is_number(args[i]) && !lbm_is_cons(args[i])) { |
1945 | 20 | return res; | |
1946 | } | ||
1947 | |||
1948 |
2/2✓ Branch 0 taken 4723 times.
✓ Branch 1 taken 648 times.
|
5371 | if (lbm_is_number(args[i])) { |
1949 | 4723 | res.args[num_dec] = args[i]; | |
1950 | 4723 | num_dec++; | |
1951 | |||
1952 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4723 times.
|
4723 | if (num_dec > ARG_MAX_NUM) { |
1953 | ✗ | return res; | |
1954 | } | ||
1955 | } else { | ||
1956 | 648 | lbm_value curr = args[i]; | |
1957 | 648 | int attr_ind = 0; | |
1958 | 648 | attr_t *attr_now = 0; | |
1959 |
2/2✓ Branch 0 taken 1156 times.
✓ Branch 1 taken 646 times.
|
1802 | while (lbm_is_cons(curr)) { |
1960 | 1156 | lbm_value arg = lbm_car(curr); | |
1961 | |||
1962 |
2/2✓ Branch 0 taken 648 times.
✓ Branch 1 taken 508 times.
|
1156 | if (attr_ind == 0) { |
1963 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 648 times.
|
648 | if (!lbm_is_symbol(arg)) { |
1964 | ✗ | return res; | |
1965 | } | ||
1966 | |||
1967 |
2/2✓ Branch 0 taken 346 times.
✓ Branch 1 taken 302 times.
|
648 | if (lbm_dec_sym(arg) == symbol_thickness) { |
1968 | 346 | attr_now = &res.attr_thickness; | |
1969 | 346 | attr_now->arg_num = 1; | |
1970 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 168 times.
|
302 | } else if (lbm_dec_sym(arg) == symbol_filled) { |
1971 | 134 | attr_now = &res.attr_filled; | |
1972 | 134 | attr_now->arg_num = 0; | |
1973 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 77 times.
|
168 | } else if (lbm_dec_sym(arg) == symbol_rounded) { |
1974 | 91 | attr_now = &res.attr_rounded; | |
1975 | 91 | attr_now->arg_num = 1; | |
1976 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 49 times.
|
77 | } else if (lbm_dec_sym(arg) == symbol_dotted) { |
1977 | 28 | attr_now = &res.attr_dotted; | |
1978 | 28 | attr_now->arg_num = 2; | |
1979 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 34 times.
|
49 | } else if (lbm_dec_sym(arg) == symbol_scale) { |
1980 | 15 | attr_now = &res.attr_scale; | |
1981 | 15 | attr_now->arg_num = 1; | |
1982 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 23 times.
|
34 | } else if (lbm_dec_sym(arg) == symbol_rotate) { |
1983 | 11 | attr_now = &res.attr_rotate; | |
1984 | 11 | attr_now->arg_num = 3; | |
1985 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | } else if (lbm_dec_sym(arg) == symbol_resolution) { |
1986 | ✗ | attr_now = &res.attr_resolution; | |
1987 | ✗ | attr_now->arg_num = 1; | |
1988 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | } else if (lbm_dec_sym(arg) == symbol_tile) { |
1989 | 13 | attr_now = &res.attr_tile; | |
1990 | 13 | attr_now->arg_num = 0; | |
1991 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | } else if (lbm_dec_sym(arg) == symbol_clip) { |
1992 | 9 | attr_now = &res.attr_clip; | |
1993 | 9 | attr_now->arg_num = 4; | |
1994 | } | ||
1995 | else { | ||
1996 | 1 | return res; | |
1997 | } | ||
1998 | } else { | ||
1999 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 507 times.
|
508 | if (!lbm_is_number(arg)) { |
2000 | 1 | return res; | |
2001 | } | ||
2002 | |||
2003 | 507 | attr_now->args[attr_ind - 1] = arg; | |
2004 | } | ||
2005 | |||
2006 | 1154 | attr_ind++; | |
2007 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1154 times.
|
1154 | if (attr_ind > (ATTR_MAX_ARGS + 1)) { |
2008 | ✗ | return res; | |
2009 | } | ||
2010 | |||
2011 | 1154 | curr = lbm_cdr(curr); | |
2012 | } | ||
2013 | |||
2014 | // does this really compare the pointer addresses? | ||
2015 |
4/4✓ Branch 0 taken 91 times.
✓ Branch 1 taken 555 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 26 times.
|
646 | if (attr_now == &res.attr_rounded && attr_ind == 1) { |
2016 | 65 | attr_now->arg_num = 0; // the `rounded` attribute may be empty | |
2017 | } | ||
2018 | |||
2019 | |||
2020 |
2/2✓ Branch 0 taken 642 times.
✓ Branch 1 taken 4 times.
|
646 | if ((attr_ind - 1) == attr_now->arg_num) { |
2021 | 642 | attr_now->is_valid = true; | |
2022 | } else { | ||
2023 | 4 | return res; | |
2024 | } | ||
2025 | } | ||
2026 | } | ||
2027 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1022 times.
|
1022 | if (num_dec != num_expected) { |
2028 | ✗ | return res; | |
2029 | } | ||
2030 | // I think this should go here ??? | ||
2031 | 1022 | res.is_valid = true; | |
2032 | } | ||
2033 | 1059 | return res; | |
2034 | } | ||
2035 | |||
2036 | 26 | static lbm_value ext_image_dims(lbm_value *args, lbm_uint argn) { | |
2037 | 26 | img_args_t arg_dec = decode_args(args, argn, 0); | |
2038 | |||
2039 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
|
26 | if (!arg_dec.is_valid) { |
2040 | 2 | return ENC_SYM_TERROR; | |
2041 | } | ||
2042 | |||
2043 | 24 | lbm_value dims = lbm_heap_allocate_list(2); | |
2044 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if (lbm_is_symbol(dims)) { |
2045 | ✗ | return dims; | |
2046 | } | ||
2047 | 24 | lbm_value curr = dims; | |
2048 | 24 | lbm_set_car(curr, lbm_enc_i(arg_dec.img.width)); | |
2049 | 24 | curr = lbm_cdr(curr); | |
2050 | 24 | lbm_set_car(curr, lbm_enc_i(arg_dec.img.height)); | |
2051 | 24 | return dims; | |
2052 | } | ||
2053 | |||
2054 | 76 | static lbm_value ext_image_buffer(lbm_value *args, lbm_uint argn) { | |
2055 | 76 | lbm_value res = ENC_SYM_TERROR; | |
2056 | 76 | bool args_ok = false; | |
2057 | 76 | color_format_t fmt = indexed2; | |
2058 | 76 | lbm_uint w = 0; | |
2059 | 76 | lbm_uint h = 0; | |
2060 | |||
2061 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
77 | if (argn == 4 && |
2062 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | lbm_is_defrag_mem(args[0]) && |
2063 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | lbm_is_symbol(args[1]) && |
2064 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | lbm_is_number(args[2]) && |
2065 | 1 | lbm_is_number(args[3])) { | |
2066 | 1 | fmt = sym_to_color_format(args[1]); | |
2067 | 1 | w = lbm_dec_as_u32(args[2]); | |
2068 | 1 | h = lbm_dec_as_u32(args[3]); | |
2069 | 1 | args_ok = true; | |
2070 |
2/4✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
|
150 | } else if (argn == 3 && |
2071 |
1/2✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
|
150 | lbm_is_symbol(args[0]) && |
2072 |
1/2✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
|
150 | lbm_is_number(args[1]) && |
2073 | 75 | lbm_is_number(args[2])) { | |
2074 | 75 | fmt = sym_to_color_format(args[0]); | |
2075 | 75 | w = lbm_dec_as_u32(args[1]); | |
2076 | 75 | h = lbm_dec_as_u32(args[2]); | |
2077 | 75 | args_ok = true; | |
2078 | } | ||
2079 | |||
2080 |
9/12✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 72 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 71 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 71 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 71 times.
✗ Branch 11 not taken.
|
76 | if (args_ok && fmt != format_not_supported && w > 0 && h > 0 && w < MAX_WIDTH && h < MAX_HEIGHT) { |
2081 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 1 times.
|
71 | if (argn == 3) { |
2082 | 70 | res = image_buffer_allocate(fmt, (uint16_t)w, (uint16_t)h); | |
2083 | } else { | ||
2084 | 1 | res = image_buffer_allocate_dm((lbm_uint*)lbm_car(args[0]), fmt, (uint16_t)w, (uint16_t)h); | |
2085 | } | ||
2086 | } | ||
2087 | 76 | return res; | |
2088 | } | ||
2089 | |||
2090 | |||
2091 | 20 | static lbm_value ext_is_image_buffer(lbm_value *args, lbm_uint argn) { | |
2092 | 20 | lbm_value res = ENC_SYM_TERROR; | |
2093 | |||
2094 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (argn == 1) { |
2095 | 20 | res = ENC_SYM_NIL; | |
2096 | 20 | lbm_array_header_t *array = lbm_dec_array_r(args[0]); | |
2097 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1 times.
|
20 | if (array) { |
2098 | 19 | uint8_t *data = (uint8_t*)array->data; | |
2099 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (image_buffer_is_valid(data, array->size)) { |
2100 | 19 | res = ENC_SYM_TRUE;; | |
2101 | } | ||
2102 | } | ||
2103 | } | ||
2104 | 20 | return res; | |
2105 | } | ||
2106 | |||
2107 | 28 | static lbm_value ext_color(lbm_value *args, lbm_uint argn) { | |
2108 | 28 | lbm_value res = ENC_SYM_TERROR; | |
2109 | |||
2110 |
4/6✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 1 times.
|
56 | if (argn >= 2 && argn <= 6 && |
2111 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
55 | lbm_is_symbol(args[0]) && |
2112 | 27 | lbm_is_number(args[1])) { | |
2113 | |||
2114 | // Color1 and color2 are int in the struct and decoded as i32, why | ||
2115 | // where they stored in uint32_t? | ||
2116 | 27 | int32_t color1 = lbm_dec_as_i32(args[1]); | |
2117 | |||
2118 | 27 | int32_t color2 = 0; | |
2119 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 13 times.
|
27 | if (argn >= 3) { |
2120 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (lbm_is_number(args[2])) { |
2121 | 14 | color2 = lbm_dec_as_i32(args[2]); | |
2122 | } else { | ||
2123 | ✗ | return ENC_SYM_TERROR; | |
2124 | } | ||
2125 | } | ||
2126 | |||
2127 | 27 | int32_t param1 = 0; | |
2128 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 13 times.
|
27 | if (argn >= 4) { |
2129 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (lbm_is_number(args[3])) { |
2130 | 14 | param1 = lbm_dec_as_i32(args[3]); | |
2131 | } else { | ||
2132 | ✗ | return ENC_SYM_TERROR; | |
2133 | } | ||
2134 | } | ||
2135 | |||
2136 | 27 | int32_t param2 = 0; | |
2137 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 13 times.
|
27 | if (argn >= 5) { |
2138 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (lbm_is_number(args[4])) { |
2139 | 14 | param2 = lbm_dec_as_i32(args[4]); | |
2140 | } else { | ||
2141 | ✗ | return ENC_SYM_TERROR; | |
2142 | } | ||
2143 | } | ||
2144 | |||
2145 | 27 | bool mirrored = false; | |
2146 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17 times.
|
27 | if (argn >= 6) { |
2147 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (lbm_is_symbol(args[5])) { |
2148 | 10 | lbm_uint sym = lbm_dec_sym(args[5]); | |
2149 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
|
10 | if (sym == symbol_repeat) { |
2150 | 7 | mirrored = false; | |
2151 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | } else if (sym == symbol_mirrored) { |
2152 | 3 | mirrored = true; | |
2153 | } else { | ||
2154 | ✗ | return ENC_SYM_TERROR; | |
2155 | } | ||
2156 | } else { | ||
2157 | ✗ | return ENC_SYM_TERROR; | |
2158 | } | ||
2159 | } | ||
2160 | |||
2161 | COLOR_TYPE t; | ||
2162 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
|
27 | if (lbm_dec_sym(args[0]) == symbol_regular) { |
2163 | 12 | t = COLOR_REGULAR; | |
2164 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
|
15 | } else if (lbm_dec_sym(args[0]) == symbol_gradient_x) { |
2165 | 6 | t = COLOR_GRADIENT_X; | |
2166 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9 | } else if (lbm_dec_sym(args[0]) == symbol_gradient_y) { |
2167 | 3 | t = COLOR_GRADIENT_Y; | |
2168 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | } else if (lbm_dec_sym(args[0]) == symbol_gradient_x_pre) { |
2169 | 4 | t = COLOR_PRE_X; | |
2170 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | } else if (lbm_dec_sym(args[0]) == symbol_gradient_y_pre) { |
2171 | 1 | t = COLOR_PRE_Y; | |
2172 | } else { | ||
2173 | 1 | return ENC_SYM_TERROR; | |
2174 | } | ||
2175 | |||
2176 | // Maybe check if param is in ranges first ? | ||
2177 | 26 | res = color_allocate(t, color1, color2, (uint16_t)param1, (uint16_t)param2, mirrored); | |
2178 | } | ||
2179 | |||
2180 | 27 | return res; | |
2181 | } | ||
2182 | |||
2183 | 25 | static lbm_value ext_color_set(lbm_value *args, lbm_uint argn) { | |
2184 | color_t *color; | ||
2185 |
3/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 3 times.
|
25 | if (argn != 3 || !(color = get_color(args[0])) || // color assignment |
2186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | !lbm_is_symbol(args[1])) { |
2187 | 3 | return ENC_SYM_TERROR; | |
2188 | } | ||
2189 | |||
2190 | 22 | bool is_regular = color->type == COLOR_REGULAR; | |
2191 |
4/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
|
22 | bool is_gradient = color->type == COLOR_GRADIENT_X || color->type == COLOR_GRADIENT_Y; |
2192 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
22 | bool is_pre = color->type == COLOR_PRE_X || color->type == COLOR_PRE_Y; |
2193 | |||
2194 | 22 | lbm_uint prop = lbm_dec_sym(args[1]); | |
2195 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
|
22 | if (prop == symbol_color_0) { |
2196 |
5/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
6 | if (!lbm_is_number(args[2]) || !(is_regular || is_gradient)) { |
2197 | 2 | return ENC_SYM_TERROR; | |
2198 | } | ||
2199 | 4 | color->color1 = lbm_dec_as_i32(args[2]); | |
2200 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
|
16 | } else if (prop == symbol_color_1) { |
2201 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
3 | if (!lbm_is_number(args[2]) || !is_gradient) { |
2202 | 2 | return ENC_SYM_TERROR; | |
2203 | } | ||
2204 | 1 | color->color2 = lbm_dec_as_i32(args[2]); | |
2205 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
|
13 | } else if (prop == symbol_width) { |
2206 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
|
5 | if (!lbm_is_number(args[2]) || !is_gradient) { |
2207 | 3 | return ENC_SYM_TERROR; | |
2208 | } | ||
2209 | 2 | color->param1 = (uint16_t)lbm_dec_as_u32(args[2]); | |
2210 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
|
8 | } else if (prop == symbol_offset) { |
2211 |
4/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3 | if (!lbm_is_number(args[2]) || !(is_gradient || is_pre)) { |
2212 | 1 | return ENC_SYM_TERROR; | |
2213 | } | ||
2214 | 2 | color->param2 = (uint16_t)lbm_dec_as_u32(args[2]); | |
2215 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | } else if (prop == symbol_repeat_type) { |
2216 |
2/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3 | if (!lbm_is_symbol(args[2]) || !(is_gradient || is_pre)) { |
2217 | ✗ | return ENC_SYM_TERROR; | |
2218 | } | ||
2219 | 3 | lbm_uint sym = lbm_dec_sym(args[2]); | |
2220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (sym == symbol_repeat) { |
2221 | ✗ | color->mirrored = false; | |
2222 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | } else if (sym == symbol_mirrored) { |
2223 | 2 | color->mirrored = true; | |
2224 | } else { | ||
2225 | 1 | return ENC_SYM_TERROR; | |
2226 | } | ||
2227 | } else { | ||
2228 | 2 | return ENC_SYM_TERROR; | |
2229 | } | ||
2230 | |||
2231 | 11 | return ENC_SYM_TRUE; | |
2232 | } | ||
2233 | |||
2234 | 23 | static lbm_value ext_color_get(lbm_value *args, lbm_uint argn) { | |
2235 | color_t *color; | ||
2236 |
3/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 1 times.
|
23 | if (argn != 2 || !(color = get_color(args[0])) || // color assignment |
2237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | !lbm_is_symbol(args[1])) { |
2238 | 1 | return ENC_SYM_TERROR; | |
2239 | } | ||
2240 | |||
2241 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
|
22 | bool is_gradient = color->type == COLOR_GRADIENT_X || color->type == COLOR_GRADIENT_Y; |
2242 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
22 | bool is_pre = color->type == COLOR_PRE_X || color->type == COLOR_PRE_Y; |
2243 | |||
2244 | 22 | lbm_uint prop = lbm_dec_sym(args[1]); | |
2245 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 13 times.
|
22 | if (prop == symbol_color_0) { |
2246 | // always allowed | ||
2247 | 9 | return lbm_enc_u32((uint32_t)color->color1); | |
2248 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
|
13 | } else if (prop == symbol_color_1) { |
2249 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
4 | if (!is_gradient && !is_pre) { |
2250 | 1 | return ENC_SYM_TERROR; | |
2251 | } | ||
2252 | 3 | return lbm_enc_u32((uint32_t)color->color2); | |
2253 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
|
9 | } else if (prop == symbol_width) { |
2254 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
5 | if (!is_gradient && !is_pre) { |
2255 | 1 | return ENC_SYM_TERROR; | |
2256 | } | ||
2257 | 4 | return lbm_enc_i32((int32_t)color->param1); | |
2258 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | } else if (prop == symbol_offset) { |
2259 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | if (!is_gradient && !is_pre) { |
2260 | ✗ | return ENC_SYM_TERROR; | |
2261 | } | ||
2262 | 3 | return lbm_enc_i32((int32_t)color->param2); | |
2263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (prop == symbol_repeat_type) { |
2264 | ✗ | if (!is_gradient && !is_pre) { | |
2265 | ✗ | return ENC_SYM_TERROR; | |
2266 | } | ||
2267 | ✗ | return lbm_enc_sym(color->mirrored ? symbol_mirrored : symbol_repeat); | |
2268 | } else { | ||
2269 | 1 | return ENC_SYM_TERROR; | |
2270 | } | ||
2271 | |||
2272 | return ENC_SYM_TRUE; | ||
2273 | } | ||
2274 | |||
2275 | 7 | static lbm_value ext_color_setpre(lbm_value *args, lbm_uint argn) { | |
2276 | color_t *color; | ||
2277 |
3/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
|
7 | if (argn != 3 || !(color = get_color(args[0])) || |
2278 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
|
6 | !lbm_is_number(args[1]) || !lbm_is_number(args[2])) { |
2279 | 3 | return ENC_SYM_TERROR; | |
2280 | } | ||
2281 | |||
2282 | 4 | uint32_t pos = lbm_dec_as_u32(args[1]); | |
2283 | 4 | int new_color = lbm_dec_as_i32(args[2]); | |
2284 | |||
2285 |
3/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
|
4 | if (color->precalc == 0 || pos >= COLOR_PRECALC_LEN) { |
2286 | 1 | return ENC_SYM_EERROR; | |
2287 | } | ||
2288 | |||
2289 | 3 | color->precalc[pos] = (uint32_t)new_color; | |
2290 | |||
2291 | 3 | return ENC_SYM_TRUE; | |
2292 | } | ||
2293 | |||
2294 | 14 | static lbm_value ext_color_getpre(lbm_value *args, lbm_uint argn) { | |
2295 | color_t *color; | ||
2296 |
3/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 1 times.
|
14 | if (argn != 2 || !(color = get_color(args[0])) || |
2297 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | !lbm_is_number(args[1])) { |
2298 | 2 | return ENC_SYM_TERROR; | |
2299 | } | ||
2300 | 12 | uint32_t pos = lbm_dec_as_u32(args[1]); | |
2301 | |||
2302 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 11 times.
|
12 | if (color->precalc == 0 || pos >= COLOR_PRECALC_LEN) { |
2303 | 1 | return ENC_SYM_EERROR; | |
2304 | } | ||
2305 | |||
2306 | 11 | return lbm_enc_u32(color->precalc[pos]); | |
2307 | } | ||
2308 | |||
2309 | 57 | static lbm_value ext_clear(lbm_value *args, lbm_uint argn) { | |
2310 | |||
2311 | 57 | lbm_value res = ENC_SYM_TERROR; | |
2312 | lbm_array_header_t *arr; | ||
2313 |
5/6✓ Branch 0 taken 56 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
✓ Branch 5 taken 3 times.
|
114 | if ((argn == 1 || argn == 2) && |
2314 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1 times.
|
111 | (arr = get_image_buffer(args[0])) && // assignment |
2315 |
1/2✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
|
53 | (argn != 2 || lbm_is_number(args[1]))) { // ( argn == 2 -> lbm_is_number(args[1])) |
2316 | image_buffer_t img_buf; | ||
2317 | 54 | img_buf.width = image_buffer_width((uint8_t*)arr->data); | |
2318 | 54 | img_buf.height = image_buffer_height((uint8_t*)arr->data); | |
2319 | 54 | img_buf.fmt = image_buffer_format((uint8_t*)arr->data); | |
2320 | 54 | img_buf.mem_base = (uint8_t*)arr->data; | |
2321 | 54 | img_buf.data = image_buffer_data((uint8_t*)arr->data); | |
2322 | |||
2323 | 54 | uint32_t color = 0; | |
2324 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 1 times.
|
54 | if (argn == 2) { |
2325 | 53 | color = lbm_dec_as_u32(args[1]); | |
2326 | } | ||
2327 | |||
2328 | 54 | image_buffer_clear(&img_buf, color); | |
2329 | 54 | res = ENC_SYM_TRUE; | |
2330 | } | ||
2331 | 57 | return res; | |
2332 | } | ||
2333 | |||
2334 | 113 | static lbm_value ext_putpixel(lbm_value *args, lbm_uint argn) { | |
2335 | 113 | img_args_t arg_dec = decode_args(args, argn, 3); | |
2336 | |||
2337 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | if (!arg_dec.is_valid) { |
2338 | ✗ | return ENC_SYM_TERROR; | |
2339 | } | ||
2340 | |||
2341 | 113 | putpixel(&arg_dec.img, | |
2342 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2343 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2344 | lbm_dec_as_u32(arg_dec.args[2])); | ||
2345 | 113 | return ENC_SYM_TRUE; | |
2346 | } | ||
2347 | |||
2348 | 167 | static lbm_value ext_getpixel(lbm_value *args, lbm_uint argn) { | |
2349 | 167 | img_args_t arg_dec = decode_args(args, argn, 2); | |
2350 | |||
2351 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 143 times.
|
167 | if (!arg_dec.is_valid) { |
2352 | 24 | return ENC_SYM_TERROR; | |
2353 | } | ||
2354 | |||
2355 | 143 | uint32_t c = getpixel(&arg_dec.img, | |
2356 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2357 | lbm_dec_as_i32(arg_dec.args[1])); | ||
2358 | 143 | return lbm_enc_u32(c); | |
2359 | } | ||
2360 | |||
2361 | // lisp args: img x1 y1 x2 y2 color opt-attr1 ... opt-attrN | ||
2362 | 43 | static lbm_value ext_line(lbm_value *args, lbm_uint argn) { | |
2363 | 43 | img_args_t arg_dec = decode_args(args, argn, 5); | |
2364 | |||
2365 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
|
43 | if (!arg_dec.is_valid) { |
2366 | 2 | return ENC_SYM_TERROR; | |
2367 | } | ||
2368 | |||
2369 | 41 | line(&arg_dec.img, | |
2370 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2371 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2372 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2373 | lbm_dec_as_i32(arg_dec.args[3]), | ||
2374 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2375 | lbm_dec_as_i32(arg_dec.attr_dotted.args[0]), | ||
2376 | lbm_dec_as_i32(arg_dec.attr_dotted.args[1]), | ||
2377 | lbm_dec_as_u32(arg_dec.args[4])); | ||
2378 | |||
2379 | 41 | return ENC_SYM_TRUE; | |
2380 | } | ||
2381 | |||
2382 | // lisp args: img cx cy r color opt-attr1 ... opt-attrN | ||
2383 | 83 | static lbm_value ext_circle(lbm_value *args, lbm_uint argn) { | |
2384 | 83 | img_args_t arg_dec = decode_args(args, argn, 4); | |
2385 | |||
2386 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 80 times.
|
83 | if (!arg_dec.is_valid) { |
2387 | 3 | return ENC_SYM_TERROR; | |
2388 | } | ||
2389 | |||
2390 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 57 times.
|
80 | if (arg_dec.attr_filled.is_valid) { |
2391 | 23 | fill_circle(&arg_dec.img, | |
2392 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2393 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2394 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2395 | lbm_dec_as_u32(arg_dec.args[3])); | ||
2396 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 78 times.
|
80 | } if (arg_dec.attr_dotted.is_valid) { |
2397 | 4 | arc(&arg_dec.img, | |
2398 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2399 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2400 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2401 | 0, 359.9f, | ||
2402 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2403 | 2 | arg_dec.attr_rounded.is_valid, // currently does nothing as the line function doesn't support square ends. | |
2404 | false, | ||
2405 | false, false, | ||
2406 | lbm_dec_as_i32(arg_dec.attr_dotted.args[0]), | ||
2407 | lbm_dec_as_i32(arg_dec.attr_dotted.args[1]), | ||
2408 | lbm_dec_as_i32(arg_dec.attr_resolution.args[0]), | ||
2409 | lbm_dec_as_u32(arg_dec.args[3])); | ||
2410 | } else { | ||
2411 | 78 | circle(&arg_dec.img, | |
2412 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2413 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2414 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2415 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2416 | lbm_dec_as_u32(arg_dec.args[3])); | ||
2417 | } | ||
2418 | |||
2419 | 80 | return ENC_SYM_TRUE; | |
2420 | } | ||
2421 | |||
2422 | // lisp args: img cx cy r ang-s ang-e color opt-attr1 ... opt-attrN | ||
2423 | 137 | static lbm_value ext_arc(lbm_value *args, lbm_uint argn) { | |
2424 | 137 | img_args_t arg_dec = decode_args(args, argn, 6); | |
2425 | |||
2426 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 128 times.
|
137 | if (!arg_dec.is_valid) { |
2427 | 9 | return ENC_SYM_TERROR; | |
2428 | } | ||
2429 | |||
2430 | 256 | arc(&arg_dec.img, | |
2431 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2432 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2433 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2434 | lbm_dec_as_float(arg_dec.args[3]), | ||
2435 | lbm_dec_as_float(arg_dec.args[4]), | ||
2436 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2437 | 128 | arg_dec.attr_rounded.is_valid, | |
2438 | 128 | arg_dec.attr_filled.is_valid, | |
2439 | false, false, | ||
2440 | lbm_dec_as_i32(arg_dec.attr_dotted.args[0]), | ||
2441 | lbm_dec_as_i32(arg_dec.attr_dotted.args[1]), | ||
2442 | lbm_dec_as_i32(arg_dec.attr_resolution.args[0]), | ||
2443 | lbm_dec_as_u32(arg_dec.args[5])); | ||
2444 | |||
2445 | 128 | return ENC_SYM_TRUE; | |
2446 | } | ||
2447 | |||
2448 | // lisp args: img cx cy r ang-s ang-e color opt-attr1 ... opt-attrN | ||
2449 | 51 | static lbm_value ext_circle_sector(lbm_value *args, lbm_uint argn) { | |
2450 | 51 | img_args_t arg_dec = decode_args(args, argn, 6); | |
2451 | |||
2452 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 50 times.
|
51 | if (!arg_dec.is_valid) { |
2453 | 1 | return ENC_SYM_TERROR; | |
2454 | } | ||
2455 | |||
2456 | 100 | arc(&arg_dec.img, | |
2457 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2458 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2459 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2460 | lbm_dec_as_float(arg_dec.args[3]), | ||
2461 | lbm_dec_as_float(arg_dec.args[4]), | ||
2462 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2463 | true, | ||
2464 | 50 | arg_dec.attr_filled.is_valid, | |
2465 | true, false, | ||
2466 | lbm_dec_as_i32(arg_dec.attr_dotted.args[0]), | ||
2467 | lbm_dec_as_i32(arg_dec.attr_dotted.args[1]), | ||
2468 | lbm_dec_as_i32(arg_dec.attr_resolution.args[0]), | ||
2469 | lbm_dec_as_u32(arg_dec.args[5])); | ||
2470 | |||
2471 | 50 | return ENC_SYM_TRUE; | |
2472 | } | ||
2473 | |||
2474 | // lisp args: img cx cy r ang-s ang-e color opt-attr1 ... opt-attrN | ||
2475 | 284 | static lbm_value ext_circle_segment(lbm_value *args, lbm_uint argn) { | |
2476 | 284 | img_args_t arg_dec = decode_args(args, argn, 6); | |
2477 | |||
2478 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 273 times.
|
284 | if (!arg_dec.is_valid) { |
2479 | 11 | return ENC_SYM_TERROR; | |
2480 | } | ||
2481 | |||
2482 | 546 | arc(&arg_dec.img, | |
2483 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2484 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2485 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2486 | lbm_dec_as_float(arg_dec.args[3]), | ||
2487 | lbm_dec_as_float(arg_dec.args[4]), | ||
2488 | lbm_dec_as_i32(arg_dec.attr_thickness.args[0]), | ||
2489 | true, | ||
2490 | 273 | arg_dec.attr_filled.is_valid, | |
2491 | false, true, | ||
2492 | lbm_dec_as_i32(arg_dec.attr_dotted.args[0]), | ||
2493 | lbm_dec_as_i32(arg_dec.attr_dotted.args[1]), | ||
2494 | lbm_dec_as_i32(arg_dec.attr_resolution.args[0]), | ||
2495 | lbm_dec_as_u32(arg_dec.args[5])); | ||
2496 | |||
2497 | |||
2498 | 273 | return ENC_SYM_TRUE; | |
2499 | } | ||
2500 | |||
2501 | // lisp args: img x y width height color opt-attr1 ... opt-attrN | ||
2502 | 108 | static lbm_value ext_rectangle(lbm_value *args, lbm_uint argn) { | |
2503 | 108 | img_args_t arg_dec = decode_args(args, argn, 5); | |
2504 | |||
2505 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 105 times.
|
108 | if (!arg_dec.is_valid) { |
2506 | 3 | return ENC_SYM_TERROR; | |
2507 | } | ||
2508 | |||
2509 | 105 | image_buffer_t *img = &arg_dec.img; | |
2510 | 105 | int x = lbm_dec_as_i32(arg_dec.args[0]); | |
2511 | 105 | int y = lbm_dec_as_i32(arg_dec.args[1]); | |
2512 | 105 | int width = lbm_dec_as_i32(arg_dec.args[2]); | |
2513 | 105 | int height = lbm_dec_as_i32(arg_dec.args[3]); | |
2514 | 105 | int rad = lbm_dec_as_i32(arg_dec.attr_rounded.args[0]); | |
2515 | 105 | int thickness = lbm_dec_as_i32(arg_dec.attr_thickness.args[0]); | |
2516 | 105 | uint32_t color = lbm_dec_as_u32(arg_dec.args[4]); | |
2517 | 105 | int dot1 = lbm_dec_as_i32(arg_dec.attr_dotted.args[0]); | |
2518 | 105 | int dot2 = lbm_dec_as_i32(arg_dec.attr_dotted.args[1]); | |
2519 | 105 | int resolution = lbm_dec_as_i32(arg_dec.attr_resolution.args[0]); | |
2520 | |||
2521 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 78 times.
|
105 | if (arg_dec.attr_rounded.is_valid) { |
2522 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 23 times.
|
27 | if (arg_dec.attr_filled.is_valid) { |
2523 | 4 | rectangle(img, x + rad, y, width - 2 * rad, rad, 1, 1, 0, 0, color); | |
2524 | 4 | rectangle(img, x + rad, y + height - rad, width - 2 * rad, rad, 1, 1, 0, 0, color); | |
2525 | 4 | rectangle(img, x, y + rad, width, height - 2 * rad, 1, 1, 0, 0, color); | |
2526 | 4 | fill_circle(img, x + rad, y + rad, rad, color); | |
2527 | 4 | fill_circle(img, x + rad, y + height - rad, rad, color); | |
2528 | 4 | fill_circle(img, x + width - rad, y + rad, rad, color); | |
2529 | 4 | fill_circle(img, x + width - rad, y + height - rad, rad, color); | |
2530 | } else { | ||
2531 | // Remember to change these to use the rounded attribute, | ||
2532 | // when/if line supports it! | ||
2533 | |||
2534 | 23 | int line_thickness = thickness / 2; | |
2535 | 23 | thickness = line_thickness * 2; // round it to even for consistency. | |
2536 | |||
2537 | // top | ||
2538 | 23 | line(img, x + rad, y + line_thickness, x + width - rad, y + line_thickness, line_thickness, dot1, dot2, color); | |
2539 | // bottom | ||
2540 | 23 | line(img, x + rad, y + height - line_thickness, x + width - rad, y + height - line_thickness, line_thickness, dot1, dot2, color); | |
2541 | // left | ||
2542 | 23 | line(img, x + line_thickness, y + rad, x + line_thickness, y + height - rad, line_thickness, dot1, dot2, color); | |
2543 | // right | ||
2544 | 23 | line(img, x + width - line_thickness, y + rad, x + width - line_thickness, y + height - rad, line_thickness, dot1, dot2, color); | |
2545 | |||
2546 | // upper left | ||
2547 | 23 | arc(img, x + rad, y + rad, rad, 180, 270, thickness, false, false, false, false, dot1, dot2, resolution, color); | |
2548 | // upper right | ||
2549 | 23 | arc(img, x + width - rad, y + rad, rad, 270, 0, thickness, false, false, false, false, dot1, dot2, resolution, color); | |
2550 | // bottom left | ||
2551 | 23 | arc(img, x + rad, y + height - rad, rad, 90, 180, thickness, false, false, false, false, dot1, dot2, resolution, color); | |
2552 | // bottom right | ||
2553 | 23 | arc(img, x + width - rad, y + height - rad, rad, 0, 90, thickness, false, false, false, false, dot1, dot2, resolution, color); | |
2554 | } | ||
2555 | } else { | ||
2556 | 78 | rectangle(img, | |
2557 | x, y, | ||
2558 | width, height, | ||
2559 | 78 | arg_dec.attr_filled.is_valid, | |
2560 | thickness, | ||
2561 | dot1, dot2, | ||
2562 | color); | ||
2563 | } | ||
2564 | |||
2565 | 105 | return ENC_SYM_TRUE; | |
2566 | } | ||
2567 | |||
2568 | // lisp args: img x1 y1 x2 y2 x3 y3 color opt-attr1 ... opt-attrN | ||
2569 | 22 | static lbm_value ext_triangle(lbm_value *args, lbm_uint argn) { | |
2570 | 22 | img_args_t arg_dec = decode_args(args, argn, 7); | |
2571 | |||
2572 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
|
22 | if (!arg_dec.is_valid) { |
2573 | 2 | return ENC_SYM_TERROR; | |
2574 | } | ||
2575 | |||
2576 | 20 | image_buffer_t *img = &arg_dec.img; | |
2577 | 20 | int x0 = lbm_dec_as_i32(arg_dec.args[0]); | |
2578 | 20 | int y0 = lbm_dec_as_i32(arg_dec.args[1]); | |
2579 | 20 | int x1 = lbm_dec_as_i32(arg_dec.args[2]); | |
2580 | 20 | int y1 = lbm_dec_as_i32(arg_dec.args[3]); | |
2581 | 20 | int x2 = lbm_dec_as_i32(arg_dec.args[4]); | |
2582 | 20 | int y2 = lbm_dec_as_i32(arg_dec.args[5]); | |
2583 | 20 | int thickness = lbm_dec_as_i32(arg_dec.attr_thickness.args[0]); | |
2584 | 20 | int dot1 = lbm_dec_as_i32(arg_dec.attr_dotted.args[0]); | |
2585 | 20 | int dot2 = lbm_dec_as_i32(arg_dec.attr_dotted.args[1]); | |
2586 | 20 | uint32_t color = lbm_dec_as_u32(arg_dec.args[6]); | |
2587 | |||
2588 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
|
20 | if (arg_dec.attr_filled.is_valid) { |
2589 | 2 | fill_triangle(img, x0, y0, x1, y1, x2, y2, color); | |
2590 | } else { | ||
2591 | 18 | line(img, x0, y0, x1, y1, thickness, dot1, dot2, color); | |
2592 | 18 | line(img, x1, y1, x2, y2, thickness, dot1, dot2, color); | |
2593 | 18 | line(img, x2, y2, x0, y0, thickness, dot1, dot2, color); | |
2594 | } | ||
2595 | |||
2596 | 20 | return ENC_SYM_TRUE; | |
2597 | } | ||
2598 | |||
2599 | // lisp args: img x y fg bg font str | ||
2600 | 107 | static lbm_value ext_text(lbm_value *args, lbm_uint argn) { | |
2601 | 107 | bool up = false; | |
2602 | 107 | bool down = false; | |
2603 | |||
2604 |
4/4✓ Branch 0 taken 91 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 63 times.
|
107 | if (argn >= 7 && lbm_is_symbol(args[argn - 1])) { |
2605 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 15 times.
|
28 | if (lbm_dec_sym(args[argn - 1]) == symbol_up) { |
2606 | 13 | up = true; | |
2607 | 13 | argn--; | |
2608 | } | ||
2609 | |||
2610 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 15 times.
|
28 | if (lbm_dec_sym(args[argn - 1]) == symbol_down) { |
2611 | 13 | down = true; | |
2612 | 13 | argn--; | |
2613 | } | ||
2614 | } | ||
2615 | |||
2616 |
4/4✓ Branch 0 taken 91 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 88 times.
|
107 | if (argn != 6 && argn != 7) { |
2617 | 3 | return ENC_SYM_TERROR; | |
2618 | } | ||
2619 | |||
2620 | 104 | int x = lbm_dec_as_i32(args[1]); | |
2621 | 104 | int y = lbm_dec_as_i32(args[2]); | |
2622 | |||
2623 | 104 | int32_t colors[4] = {-1, -1, -1, -1}; // how big? int vs int32 | |
2624 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 16 times.
|
104 | if (argn == 7) { |
2625 |
2/4✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
|
88 | if (!lbm_is_number(args[3]) || !lbm_is_number(args[4])) { |
2626 | ✗ | return ENC_SYM_TERROR; | |
2627 | } | ||
2628 | 88 | colors[0] = lbm_dec_as_i32(args[3]); | |
2629 | 88 | colors[1] = lbm_dec_as_i32(args[4]); | |
2630 | } else { | ||
2631 | 16 | lbm_value curr = args[3]; | |
2632 | 16 | int ind = 0; | |
2633 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 11 times.
|
58 | while (lbm_is_cons(curr)) { |
2634 | 47 | lbm_value arg = lbm_car(curr); | |
2635 |
1/2✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
|
47 | if (lbm_is_number(arg)) { |
2636 | 47 | colors[ind++] = lbm_dec_as_i32(arg); | |
2637 | } else { | ||
2638 | ✗ | return ENC_SYM_TERROR; | |
2639 | } | ||
2640 | |||
2641 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 42 times.
|
47 | if (ind == 4) { |
2642 | 5 | break; | |
2643 | } | ||
2644 | |||
2645 | 42 | curr = lbm_cdr(curr); | |
2646 | } | ||
2647 | } | ||
2648 | |||
2649 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 100 times.
|
104 | if (!array_is_image_buffer(args[0])) { |
2650 | 4 | return ENC_SYM_TERROR; | |
2651 | } | ||
2652 | 100 | lbm_array_header_t *arr = (lbm_array_header_t *)lbm_car(args[0]); | |
2653 | image_buffer_t img_buf; | ||
2654 | 100 | img_buf.width = image_buffer_width((uint8_t*)arr->data); | |
2655 | 100 | img_buf.height = image_buffer_height((uint8_t*)arr->data); | |
2656 | 100 | img_buf.fmt = image_buffer_format((uint8_t*)arr->data); | |
2657 | 100 | img_buf.mem_base = (uint8_t*)arr->data; | |
2658 | 100 | img_buf.data = image_buffer_data((uint8_t*)arr->data); | |
2659 | |||
2660 | 100 | lbm_array_header_t *font = 0; | |
2661 | // Allow both const and non-const fonts. | ||
2662 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | if (lbm_type_of_functional(args[argn - 2]) == LBM_TYPE_ARRAY) { |
2663 | 100 | font = (lbm_array_header_t *)lbm_car(args[argn - 2]); | |
2664 | } | ||
2665 | |||
2666 | 100 | char *txt = lbm_dec_str(args[argn - 1]); | |
2667 | |||
2668 |
5/6✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 97 times.
|
100 | if (!font || !txt || font->size < (4 + 5 * 5 * 10)) { |
2669 | 3 | return ENC_SYM_TERROR; | |
2670 | } | ||
2671 | |||
2672 | 97 | uint8_t *font_data = (uint8_t*)font->data; | |
2673 | 97 | uint8_t w = font_data[0]; | |
2674 | 97 | uint8_t h = font_data[1]; | |
2675 | |||
2676 | 97 | int incx = 1; | |
2677 | 97 | int incy = 0; | |
2678 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 84 times.
|
97 | if (up) { |
2679 | 13 | incx = 0; | |
2680 | 13 | incy = -1; | |
2681 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 71 times.
|
84 | } else if (down) { |
2682 | 13 | incx = 0; | |
2683 | 13 | incy = 1; | |
2684 | } | ||
2685 | |||
2686 | 97 | int ind = 0; | |
2687 |
2/2✓ Branch 0 taken 734 times.
✓ Branch 1 taken 97 times.
|
831 | while (txt[ind] != 0) { |
2688 | 2202 | img_putc(&img_buf, | |
2689 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 547 times.
|
734 | x + ind * ((up || down) ? h : w) * incx, |
2690 |
4/4✓ Branch 0 taken 102 times.
✓ Branch 1 taken 547 times.
✓ Branch 2 taken 649 times.
✓ Branch 3 taken 85 times.
|
734 | y + ind * ((up || down) ? w : h) * incy, |
2691 | (uint32_t *)colors, | ||
2692 | 4, | ||
2693 | font_data, | ||
2694 |
2/2✓ Branch 0 taken 649 times.
✓ Branch 1 taken 85 times.
|
734 | (uint8_t)txt[ind], |
2695 | up, | ||
2696 | down); | ||
2697 | 734 | ind++; | |
2698 | } | ||
2699 | |||
2700 | 97 | return ENC_SYM_TRUE; | |
2701 | } | ||
2702 | |||
2703 | 51 | static lbm_value ext_blit(lbm_value *args, lbm_uint argn) { | |
2704 | 51 | img_args_t arg_dec = decode_args(args + 1, argn - 1, 3); | |
2705 | |||
2706 | 51 | lbm_value res = ENC_SYM_TERROR; | |
2707 | lbm_array_header_t *arr; | ||
2708 |
4/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 3 times.
|
51 | if (arg_dec.is_valid && (arr = get_image_buffer(args[0]))) { //assignment |
2709 | image_buffer_t dest_buf; | ||
2710 | 42 | dest_buf.width = image_buffer_width((uint8_t*)arr->data); | |
2711 | 42 | dest_buf.height = image_buffer_height((uint8_t*)arr->data); | |
2712 | 42 | dest_buf.fmt = image_buffer_format((uint8_t*)arr->data); | |
2713 | 42 | dest_buf.mem_base = (uint8_t*)arr->data; | |
2714 | 42 | dest_buf.data = image_buffer_data((uint8_t*)arr->data); | |
2715 | |||
2716 | 42 | float scale = 1.0; | |
2717 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
|
42 | if (arg_dec.attr_scale.is_valid) { |
2718 | 14 | scale = lbm_dec_as_float(arg_dec.attr_scale.args[0]); | |
2719 | } | ||
2720 | |||
2721 | 108 | blit( | |
2722 | &dest_buf, | ||
2723 | &arg_dec.img, | ||
2724 | lbm_dec_as_i32(arg_dec.args[0]), | ||
2725 | lbm_dec_as_i32(arg_dec.args[1]), | ||
2726 | lbm_dec_as_float(arg_dec.attr_rotate.args[0]), | ||
2727 | lbm_dec_as_float(arg_dec.attr_rotate.args[1]), | ||
2728 | lbm_dec_as_float(arg_dec.attr_rotate.args[2]), | ||
2729 | scale, | ||
2730 | lbm_dec_as_i32(arg_dec.args[2]), | ||
2731 | 42 | arg_dec.attr_tile.is_valid, | |
2732 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33 times.
|
42 | arg_dec.attr_clip.is_valid ? lbm_dec_as_i32(arg_dec.attr_clip.args[0]) : 0, |
2733 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33 times.
|
42 | arg_dec.attr_clip.is_valid ? lbm_dec_as_i32(arg_dec.attr_clip.args[1]) : 0, |
2734 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33 times.
|
42 | arg_dec.attr_clip.is_valid ? lbm_dec_as_i32(arg_dec.attr_clip.args[2]) : dest_buf.width, |
2735 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33 times.
|
42 | arg_dec.attr_clip.is_valid ? lbm_dec_as_i32(arg_dec.attr_clip.args[3]) : dest_buf.height |
2736 | ); | ||
2737 | 42 | res = ENC_SYM_TRUE; | |
2738 | } | ||
2739 | 51 | return res; | |
2740 | } | ||
2741 | |||
2742 | ✗ | void display_dummy_reset(void) { | |
2743 | ✗ | return; | |
2744 | } | ||
2745 | |||
2746 | ✗ | void display_dummy_clear(uint32_t color) { | |
2747 | (void) color; | ||
2748 | ✗ | return; | |
2749 | } | ||
2750 | |||
2751 | ✗ | bool display_dummy_render_image(image_buffer_t *img, uint16_t x, uint16_t y, color_t *colors) { | |
2752 | (void) img; | ||
2753 | (void) x; | ||
2754 | (void) y; | ||
2755 | (void) colors; | ||
2756 | ✗ | return false; | |
2757 | } | ||
2758 | |||
2759 | static bool(* volatile disp_render_image)(image_buffer_t *img, uint16_t x, uint16_t y, color_t *colors) = display_dummy_render_image; | ||
2760 | static void(* volatile disp_clear)(uint32_t color) = display_dummy_clear; | ||
2761 | static void(* volatile disp_reset)(void) = display_dummy_reset; | ||
2762 | |||
2763 | static char *msg_not_supported = "Command not supported or display driver not initialized"; | ||
2764 | |||
2765 | 1 | static lbm_value ext_disp_reset(lbm_value *args, lbm_uint argn) { | |
2766 | (void) args; | ||
2767 | (void) argn; | ||
2768 | |||
2769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (disp_reset == NULL) { |
2770 | ✗ | lbm_set_error_reason(msg_not_supported); | |
2771 | ✗ | return ENC_SYM_EERROR; | |
2772 | } | ||
2773 | |||
2774 | 1 | disp_reset(); | |
2775 | |||
2776 | 1 | return ENC_SYM_TRUE; | |
2777 | } | ||
2778 | |||
2779 | 1 | static lbm_value ext_disp_clear(lbm_value *args, lbm_uint argn) { | |
2780 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (disp_clear == NULL) { |
2781 | ✗ | lbm_set_error_reason(msg_not_supported); | |
2782 | ✗ | return ENC_SYM_EERROR; | |
2783 | } | ||
2784 | |||
2785 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (argn > 1) { |
2786 | ✗ | return ENC_SYM_TERROR; | |
2787 | } | ||
2788 | |||
2789 | 1 | uint32_t clear_color = 0; | |
2790 | |||
2791 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (argn == 1) { |
2792 | ✗ | if (!lbm_is_number(args[0])) { | |
2793 | ✗ | return ENC_SYM_TERROR; | |
2794 | } | ||
2795 | |||
2796 | ✗ | clear_color = lbm_dec_as_u32(args[0]); | |
2797 | } | ||
2798 | |||
2799 | 1 | disp_clear(clear_color); | |
2800 | |||
2801 | 1 | return ENC_SYM_TRUE; | |
2802 | } | ||
2803 | |||
2804 | 50 | static lbm_value ext_disp_render(lbm_value *args, lbm_uint argn) { | |
2805 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (disp_render_image == NULL) { |
2806 | ✗ | lbm_set_error_reason(msg_not_supported); | |
2807 | ✗ | return ENC_SYM_EERROR; | |
2808 | } | ||
2809 | |||
2810 | 50 | lbm_value res = ENC_SYM_TERROR; | |
2811 | lbm_array_header_t *arr; | ||
2812 |
4/6✓ Branch 0 taken 45 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50 times.
✗ Branch 5 not taken.
|
100 | if ((argn == 3 || argn == 4) && |
2813 |
1/2✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
|
100 | (arr = get_image_buffer(args[0])) && |
2814 |
1/2✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
|
100 | lbm_is_number(args[1]) && |
2815 | 50 | lbm_is_number(args[2])) { | |
2816 | image_buffer_t img_buf; | ||
2817 | 50 | img_buf.fmt = image_buffer_format((uint8_t*)arr->data); | |
2818 | 50 | img_buf.width = image_buffer_width((uint8_t*)arr->data); | |
2819 | 50 | img_buf.height = image_buffer_height((uint8_t*)arr->data); | |
2820 | 50 | img_buf.mem_base = (uint8_t*)arr->data; | |
2821 | 50 | img_buf.data = image_buffer_data((uint8_t*)arr->data); | |
2822 | |||
2823 | color_t colors[16]; | ||
2824 | 50 | memset(colors, 0, sizeof(color_t) * 16); | |
2825 | |||
2826 |
3/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
|
50 | if (argn == 4 && lbm_is_list(args[3])) { |
2827 | 45 | int i = 0; | |
2828 | 45 | lbm_value curr = args[3]; | |
2829 |
3/4✓ Branch 0 taken 298 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 298 times.
✗ Branch 3 not taken.
|
343 | while (lbm_is_cons(curr) && i < 16) { |
2830 | 298 | lbm_value arg = lbm_car(curr); | |
2831 | color_t *color; | ||
2832 |
2/2✓ Branch 0 taken 290 times.
✓ Branch 1 taken 8 times.
|
298 | if (lbm_is_number(arg)) { |
2833 | 290 | colors[i].color1 = (int)lbm_dec_as_u32(arg); | |
2834 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | } else if ((color = get_color(arg))) { // color assignment |
2835 | 8 | colors[i] = *color; | |
2836 | } else { | ||
2837 | ✗ | return ENC_SYM_TERROR; | |
2838 | } | ||
2839 | |||
2840 | 298 | curr = lbm_cdr(curr); | |
2841 | 298 | i++; | |
2842 | } | ||
2843 | } | ||
2844 | |||
2845 | // img_buf is a stack allocated image_buffer_t. | ||
2846 | 50 | bool render_res = disp_render_image(&img_buf, (uint16_t)lbm_dec_as_u32(args[1]), (uint16_t)lbm_dec_as_u32(args[2]), colors); | |
2847 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (!render_res) { |
2848 | ✗ | lbm_set_error_reason("Could not render image. Check if the format and location is compatible with the display."); | |
2849 | ✗ | return ENC_SYM_EERROR; | |
2850 | } | ||
2851 | 50 | res = ENC_SYM_TRUE; | |
2852 | } | ||
2853 | 50 | return res; | |
2854 | } | ||
2855 | |||
2856 | // Jpg decoder | ||
2857 | |||
2858 | typedef struct { | ||
2859 | uint8_t *data; | ||
2860 | int pos; | ||
2861 | int size; | ||
2862 | int ofs_x; | ||
2863 | int ofs_y; | ||
2864 | } jpg_bufdef; | ||
2865 | |||
2866 | 105 | size_t jpg_input_func (JDEC* jd, uint8_t* buff, size_t ndata) { | |
2867 | 105 | jpg_bufdef *dev = (jpg_bufdef*)jd->device; | |
2868 | |||
2869 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 104 times.
|
105 | if ((int)ndata > (dev->size - dev->pos)) { |
2870 | 1 | ndata = (size_t)(dev->size - dev->pos); | |
2871 | } | ||
2872 | |||
2873 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 3 times.
|
105 | if (buff) { |
2874 | 102 | memcpy(buff, dev->data + dev->pos, ndata); | |
2875 | } | ||
2876 | 105 | dev->pos += (int)ndata; | |
2877 | 105 | return ndata; | |
2878 | } | ||
2879 | |||
2880 | 1530 | int jpg_output_func ( /* 1:Ok, 0:Aborted */ | |
2881 | JDEC* jd, /* Decompression object */ | ||
2882 | void* bitmap, /* Bitmap data to be output */ | ||
2883 | JRECT* rect /* Rectangular region to output */ | ||
2884 | ) { | ||
2885 | 1530 | jpg_bufdef *dev = (jpg_bufdef*)jd->device; | |
2886 | |||
2887 | image_buffer_t img; | ||
2888 | 1530 | img.mem_base = (uint8_t*)bitmap; | |
2889 | 1530 | img.data = (uint8_t*)bitmap; | |
2890 | 1530 | img.width = (uint16_t)(rect->right - rect->left + 1); | |
2891 | 1530 | img.height = (uint16_t)(rect->bottom - rect->top + 1); | |
2892 | 1530 | img.fmt = rgb888; | |
2893 | |||
2894 | 1530 | disp_render_image(&img, (uint16_t)(rect->left + dev->ofs_x), (uint16_t)(rect->top + dev->ofs_y), 0); | |
2895 | |||
2896 | 1530 | return 1; | |
2897 | } | ||
2898 | |||
2899 | 1 | static lbm_value ext_disp_render_jpg(lbm_value *args, lbm_uint argn) { | |
2900 | |||
2901 | lbm_array_header_t *array; | ||
2902 | 1 | lbm_value res = ENC_SYM_TERROR; | |
2903 | |||
2904 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | if (argn == 3 && |
2905 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | (array = lbm_dec_array_r(args[0])) && //asignment |
2906 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | lbm_is_number(args[1]) && |
2907 | 1 | lbm_is_number(args[2])) { | |
2908 | |||
2909 | JDEC jd; | ||
2910 | void *jdwork; | ||
2911 | // make a bit of room before the buffer. | ||
2912 | 1 | const size_t sz_work = 4096 + IMAGE_BUFFER_HEADER_SIZE; | |
2913 | |||
2914 | 1 | jdwork = lbm_malloc(sz_work); | |
2915 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!jdwork) { |
2916 | ✗ | return ENC_SYM_MERROR; | |
2917 | } | ||
2918 | |||
2919 | |||
2920 | |||
2921 | jpg_bufdef iodev; | ||
2922 | 1 | iodev.data = (uint8_t*)(array->data); | |
2923 | 1 | iodev.size = (int)array->size; | |
2924 | 1 | iodev.pos = 0; | |
2925 | 1 | iodev.ofs_x = lbm_dec_as_i32(args[1]); | |
2926 | 1 | iodev.ofs_y = lbm_dec_as_i32(args[2]); | |
2927 | 1 | jd_prepare(&jd, jpg_input_func, jdwork, sz_work + IMAGE_BUFFER_HEADER_SIZE, &iodev); | |
2928 | 1 | jd_decomp(&jd, jpg_output_func, 0); | |
2929 | 1 | lbm_free(jdwork); | |
2930 | 1 | res = ENC_SYM_TRUE; | |
2931 | } | ||
2932 | 1 | return res; | |
2933 | } | ||
2934 | |||
2935 | 411 | void lbm_display_extensions_init(void) { | |
2936 | 411 | register_symbols(); | |
2937 | |||
2938 | 411 | disp_render_image = NULL; | |
2939 | 411 | disp_clear = NULL; | |
2940 | 411 | disp_reset = NULL; | |
2941 | |||
2942 | 411 | lbm_add_extension("img-buffer", ext_image_buffer); | |
2943 | 411 | lbm_add_extension("img-buffer?", ext_is_image_buffer); | |
2944 | 411 | lbm_add_extension("img-color", ext_color); | |
2945 | 411 | lbm_add_extension("img-color-set", ext_color_set); | |
2946 | 411 | lbm_add_extension("img-color-get", ext_color_get); | |
2947 | 411 | lbm_add_extension("img-color-setpre", ext_color_setpre); | |
2948 | 411 | lbm_add_extension("img-color-getpre", ext_color_getpre); | |
2949 | 411 | lbm_add_extension("img-dims", ext_image_dims); | |
2950 | 411 | lbm_add_extension("img-setpix", ext_putpixel); | |
2951 | 411 | lbm_add_extension("img-getpix", ext_getpixel); | |
2952 | 411 | lbm_add_extension("img-line", ext_line); | |
2953 | 411 | lbm_add_extension("img-text", ext_text); | |
2954 | 411 | lbm_add_extension("img-clear", ext_clear); | |
2955 | 411 | lbm_add_extension("img-circle", ext_circle); | |
2956 | 411 | lbm_add_extension("img-arc", ext_arc); | |
2957 | 411 | lbm_add_extension("img-circle-sector", ext_circle_sector); | |
2958 | 411 | lbm_add_extension("img-circle-segment", ext_circle_segment); | |
2959 | 411 | lbm_add_extension("img-rectangle", ext_rectangle); | |
2960 | 411 | lbm_add_extension("img-triangle", ext_triangle); | |
2961 | 411 | lbm_add_extension("img-blit", ext_blit); | |
2962 | |||
2963 | 411 | lbm_add_extension("disp-reset", ext_disp_reset); | |
2964 | 411 | lbm_add_extension("disp-clear", ext_disp_clear); | |
2965 | 411 | lbm_add_extension("disp-render", ext_disp_render); | |
2966 | 411 | lbm_add_extension("disp-render-jpg", ext_disp_render_jpg); | |
2967 | 411 | } | |
2968 | |||
2969 | 223 | void lbm_display_extensions_set_callbacks( | |
2970 | bool(* volatile render_image)(image_buffer_t *img, uint16_t x, uint16_t y, color_t *colors), | ||
2971 | void(* volatile clear)(uint32_t color), | ||
2972 | void(* volatile reset)(void) | ||
2973 | ) { | ||
2974 |
1/2✓ Branch 0 taken 223 times.
✗ Branch 1 not taken.
|
223 | disp_render_image = render_image ? render_image : display_dummy_render_image; |
2975 |
1/2✓ Branch 0 taken 223 times.
✗ Branch 1 not taken.
|
223 | disp_clear = clear ? clear : display_dummy_clear; |
2976 |
1/2✓ Branch 0 taken 223 times.
✗ Branch 1 not taken.
|
223 | disp_reset = reset ? reset : display_dummy_reset; |
2977 | 223 | } | |
2978 |