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