clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name generic.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-libnsfb -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _POSIX_C_SOURCE=200112L -I /var/lib/jenkins/workspace/scan-build-libnsfb/include/ -I /var/lib/jenkins/workspace/scan-build-libnsfb/src -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-libnsfb -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-libnsfb/clangScanBuildReports/2024-12-27-082852-3253776-1 -x c src/plot/generic.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include <stdbool.h> |
15 | #include <limits.h> |
16 | #include <stdlib.h> |
17 | #include <string.h> |
18 | |
19 | #include "libnsfb.h" |
20 | #include "libnsfb_plot.h" |
21 | #include "libnsfb_plot_util.h" |
22 | |
23 | #include "nsfb.h" |
24 | #include "plot.h" |
25 | #include "surface.h" |
26 | |
27 | extern const nsfb_plotter_fns_t _nsfb_1bpp_plotters; |
28 | extern const nsfb_plotter_fns_t _nsfb_8bpp_plotters; |
29 | extern const nsfb_plotter_fns_t _nsfb_16bpp_plotters; |
30 | extern const nsfb_plotter_fns_t _nsfb_24bpp_plotters; |
31 | extern const nsfb_plotter_fns_t _nsfb_32bpp_xrgb8888_plotters; |
32 | extern const nsfb_plotter_fns_t _nsfb_32bpp_xbgr8888_plotters; |
33 | |
34 | static bool set_clip(nsfb_t *nsfb, nsfb_bbox_t *clip) |
35 | { |
36 | nsfb_bbox_t fbarea; |
37 | |
38 | |
39 | fbarea.x0 = 0; |
40 | fbarea.y0 = 0; |
41 | fbarea.x1 = nsfb->width; |
42 | fbarea.y1 = nsfb->height; |
43 | |
44 | if (clip == NULL) { |
45 | nsfb->clip = fbarea; |
46 | } else { |
47 | if (!nsfb_plot_clip(&fbarea, clip)) |
48 | return false; |
49 | |
50 | nsfb->clip = *clip; |
51 | } |
52 | return true; |
53 | } |
54 | |
55 | static bool get_clip(nsfb_t *nsfb, nsfb_bbox_t *clip) |
56 | { |
57 | *clip = nsfb->clip; |
58 | return true; |
59 | } |
60 | |
61 | static bool clg(nsfb_t *nsfb, nsfb_colour_t c) |
62 | { |
63 | return nsfb->plotter_fns->fill(nsfb, &nsfb->clip, c); |
64 | } |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | static bool establish_crossing_value(int x, int y, int x0, int y0, |
101 | int x1, int y1) |
102 | { |
103 | bool v1 = (x == x0 && y == y0); |
104 | bool v2 = (x == x1 && y == y1); |
105 | |
106 | if ((v1 && (y0 < y1)) || (v2 && (y1 < y0))) { |
107 | |
108 | return true; |
109 | } else if (!v1 && !v2) { |
110 | |
111 | |
112 | return true; |
113 | } |
114 | return false; |
115 | } |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | static bool find_span(const int *p, int n, int x, int y, int *x0, int *x1) |
130 | { |
131 | enum { |
132 | NO_MIN = INT_MIN + 1, |
133 | NO_MAX = INT_MAX - 1, |
134 | }; |
135 | int i; |
136 | int p_x0, p_y0; |
137 | int p_x1, p_y1; |
138 | int x0_min, x1_min; |
139 | int x_new; |
140 | unsigned int x0c, x1c; |
141 | bool crossing_value; |
142 | bool found_span_start = false; |
143 | |
144 | x0_min = x1_min = NO_MIN; |
145 | x0c = x1c = 0; |
146 | |
147 | |
148 | do { |
149 | |
150 | if (!found_span_start) { |
| |
151 | *x0 = NO_MAX; |
152 | } |
153 | *x1 = NO_MAX; |
154 | |
155 | |
156 | for (i = 0; i < n; i = i + 2) { |
| 38 | | Loop condition is true. Entering loop body | |
|
| 46 | | Loop condition is true. Entering loop body | |
|
157 | |
158 | if (i != n - 2) { |
| |
| 47 | | Assuming the condition is false | |
|
| |
159 | |
160 | p_x0 = p[i]; p_y0 = p[i + 1]; |
161 | p_x1 = p[i + 2]; p_y1 = p[i + 3]; |
162 | } else { |
163 | |
164 | p_x0 = p[i]; p_y0 = p[i + 1]; |
165 | p_x1 = p[0]; p_y1 = p[1]; |
166 | } |
167 | |
168 | if (p_y0 == p_y1) |
169 | continue; |
170 | |
171 | |
172 | if ((y < p_y0 && y < p_y1) || (y > p_y0 && y > p_y1)) |
173 | continue; |
174 | |
175 | if (p_x0 == p_x1) { |
| |
| |
176 | |
177 | x_new = p_x0; |
178 | } else { |
179 | |
180 | |
181 | int num = (y - p_y0) * (p_x1 - p_x0); |
182 | int den = (p_y1 - p_y0); |
| |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | num = ((num < 0) == (den < 0)) ? |
| |
| |
| |
| |
| |
190 | num + (den / 2) : |
191 | num - (den / 2); |
192 | x_new = p_x0 + num / den; |
| |
193 | } |
194 | |
195 | |
196 | if (x_new < x || |
| 44 | | Assuming 'x_new' is < 'x' | |
|
197 | (!found_span_start && x_new < x0_min) || |
198 | (found_span_start && x_new < x1_min)) |
199 | continue; |
| 45 | | Execution continues on line 156 | |
|
200 | |
201 | crossing_value = establish_crossing_value(x_new, y, |
202 | p_x0, p_y0, p_x1, p_y1); |
203 | |
204 | |
205 | if (!found_span_start && |
206 | x_new < *x0 && crossing_value) { |
207 | |
208 | *x1 = *x0; |
209 | x1c = x0c; |
210 | *x0 = x_new; |
211 | x0c = 1; |
212 | } else if (!found_span_start && |
213 | x_new == *x0 && crossing_value) { |
214 | |
215 | x0c++; |
216 | } else if (x_new < *x1 && crossing_value) { |
217 | |
218 | *x1 = x_new; |
219 | x1c = 1; |
220 | } else if (x_new == *x1 && crossing_value) { |
221 | |
222 | x1c++; |
223 | } |
224 | } |
225 | |
226 | if (!found_span_start && x0c % 2 == 1) { |
227 | |
228 | found_span_start = true; |
229 | |
230 | } |
231 | if (x1c % 2 == 1) { |
232 | |
233 | if (!found_span_start) { |
234 | |
235 | found_span_start = true; |
236 | x0c = x1c; |
237 | *x0 = *x1; |
238 | } else { |
239 | |
240 | return true; |
241 | } |
242 | } |
243 | |
244 | |
245 | if (!found_span_start) |
246 | x0_min = *x0 + 1; |
247 | x1_min = *x1 + 1; |
248 | |
249 | } while (*x1 != NO_MAX); |
250 | |
251 | |
252 | return false; |
253 | } |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | static bool polygon(nsfb_t *nsfb, const int *p, unsigned int n, nsfb_colour_t c) |
266 | { |
267 | int poly_x0, poly_y0; |
268 | int poly_x1, poly_y1; |
269 | int i, j; |
270 | int x0 = 0, x1 = 0; |
271 | int y; |
272 | int y_max; |
273 | nsfb_bbox_t fline; |
274 | nsfb_plot_pen_t pen; |
275 | |
276 | |
277 | int v = n * 2; |
278 | |
279 | |
280 | if (n <= 2) |
| |
| |
281 | return true; |
282 | |
283 | pen.stroke_colour = c; |
284 | |
285 | |
286 | poly_x0 = poly_x1 = *p; |
287 | poly_y0 = poly_y1 = p[1]; |
288 | for (i = 2; i < v; i = i + 2) { |
| |
| 18 | | Loop condition is true. Entering loop body | |
|
| |
289 | j = i + 1; |
290 | if (p[i] < poly_x0) |
| 19 | | Assuming the condition is false | |
|
| |
291 | poly_x0 = p[i]; |
292 | else if (p[i] > poly_x1) |
| 21 | | Assuming the condition is true | |
|
| |
293 | poly_x1 = p[i]; |
294 | if (p[j] < poly_y0) |
| 23 | | Assuming the condition is true | |
|
| |
295 | poly_y0 = p[j]; |
296 | else if (p[j] > poly_y1) |
297 | poly_y1 = p[j]; |
298 | } |
299 | |
300 | |
301 | if (nsfb->clip.y1 < poly_y0 || |
| 26 | | Assuming 'poly_y0' is <= field 'y1' | |
|
| |
302 | nsfb->clip.y0 > poly_y1 || |
| 27 | | Assuming 'poly_y1' is >= field 'y0' | |
|
303 | nsfb->clip.x1 < poly_x0 || |
| 28 | | Assuming 'poly_x0' is <= field 'x1' | |
|
304 | nsfb->clip.x0 > poly_x1) |
| 29 | | Assuming 'poly_x1' is >= field 'x0' | |
|
305 | return true; |
306 | |
307 | |
308 | if (poly_y0 > nsfb->clip.y0) |
| 31 | | Assuming 'poly_y0' is > field 'y0' | |
|
| |
309 | y = poly_y0; |
310 | else |
311 | y = nsfb->clip.y0; |
312 | |
313 | |
314 | if (poly_y1 < nsfb->clip.y1) |
| 33 | | Assuming 'poly_y1' is < field 'y1' | |
|
| |
315 | y_max = poly_y1; |
316 | else |
317 | y_max = nsfb->clip.y1; |
318 | |
319 | for (; y < y_max; y++) { |
| 35 | | Loop condition is true. Entering loop body | |
|
320 | x1 = poly_x0 - 1; |
321 | |
322 | while (find_span(p, v, x1 + 1, y, &x0, &x1)) { |
| |
323 | |
324 | if (x1 < nsfb->clip.x0) |
325 | continue; |
326 | else if (x0 < nsfb->clip.x0) |
327 | x0 = nsfb->clip.x0; |
328 | if (x0 > nsfb->clip.x1) |
329 | break; |
330 | else if (x1 > nsfb->clip.x1) |
331 | x1 = nsfb->clip.x1; |
332 | |
333 | fline.x0 = x0; |
334 | fline.y0 = y; |
335 | fline.x1 = x1; |
336 | fline.y1 = y; |
337 | |
338 | |
339 | nsfb->plotter_fns->line(nsfb, 1, &fline, &pen); |
340 | |
341 | |
342 | |
343 | if (x1 == nsfb->clip.x1 || x1 == poly_x1) |
344 | break; |
345 | } |
346 | } |
347 | return true; |
348 | } |
349 | |
350 | static bool |
351 | rectangle(nsfb_t *nsfb, nsfb_bbox_t *rect, |
352 | int line_width, nsfb_colour_t c, |
353 | bool dotted, bool dashed) |
354 | { |
355 | nsfb_bbox_t side[4]; |
356 | nsfb_plot_pen_t pen; |
357 | |
358 | pen.stroke_colour = c; |
359 | pen.stroke_width = line_width; |
360 | if (dotted || dashed) { |
361 | pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN; |
362 | } else { |
363 | pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID; |
364 | } |
365 | |
366 | side[0] = *rect; |
367 | side[1] = *rect; |
368 | side[2] = *rect; |
369 | side[3] = *rect; |
370 | |
371 | side[0].y1 = side[0].y0; |
372 | side[1].y0 = side[1].y1; |
373 | side[2].x1 = side[2].x0; |
374 | side[3].x0 = side[3].x1; |
375 | |
376 | return nsfb->plotter_fns->line(nsfb, 4, side, &pen); |
377 | } |
378 | |
379 | |
380 | static void |
381 | ellipsepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c) |
382 | { |
383 | nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c); |
384 | nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c); |
385 | nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c); |
386 | nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c); |
387 | } |
388 | |
389 | static void |
390 | ellipsefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c) |
391 | { |
392 | nsfb_bbox_t fline[2]; |
393 | nsfb_plot_pen_t pen; |
394 | |
395 | pen.stroke_colour = c; |
396 | |
397 | fline[0].x0 = fline[1].x0 = cx - x; |
398 | fline[0].x1 = fline[1].x1 = cx + x; |
399 | fline[0].y0 = fline[0].y1 = cy + y; |
400 | fline[1].y0 = fline[1].y1 = cy - y; |
401 | |
402 | nsfb->plotter_fns->line(nsfb, 2, fline, &pen); |
403 | |
404 | } |
405 | |
406 | #define ROUND(a) ((int)(a+0.5)) |
407 | |
408 | static bool |
409 | ellipse_midpoint(nsfb_t *nsfb, |
410 | int cx, |
411 | int cy, |
412 | int rx, |
413 | int ry, |
414 | nsfb_colour_t c, |
415 | void (ellipsefn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)) |
416 | { |
417 | int rx2 = rx * rx; |
418 | int ry2 = ry * ry; |
419 | int tworx2 = 2 * rx2; |
420 | int twory2 = 2 * ry2; |
421 | int p; |
422 | int x = 0; |
423 | int y = ry; |
424 | int px = 0; |
425 | int py = tworx2 * y; |
426 | |
427 | ellipsefn(nsfb, cx, cy, x, y, c); |
428 | |
429 | |
430 | p = ROUND(ry2 - (rx2 * ry) + (0.25 * rx2)); |
431 | while (px < py) { |
432 | x++; |
433 | px += twory2; |
434 | if (p <0) { |
435 | p+=ry2 + px; |
436 | } else { |
437 | y--; |
438 | py -= tworx2; |
439 | p+=ry2 + px - py; |
440 | } |
441 | ellipsefn(nsfb, cx, cy, x, y, c); |
442 | } |
443 | |
444 | |
445 | p = ROUND(ry2*(x+0.5)*(x+0.5) + rx2*(y-1)*(y-1) - rx2*ry2); |
446 | while (y > 0) { |
447 | y--; |
448 | py -= tworx2; |
449 | if (p > 0) { |
450 | p+=rx2 - py; |
451 | } else { |
452 | x++; |
453 | px += twory2; |
454 | p+=rx2 - py + px; |
455 | } |
456 | ellipsefn(nsfb, cx, cy, x, y, c); |
457 | } |
458 | return true; |
459 | } |
460 | |
461 | |
462 | |
463 | static void |
464 | circlepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c) |
465 | { |
466 | nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c); |
467 | nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c); |
468 | nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c); |
469 | nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c); |
470 | nsfb->plotter_fns->point(nsfb, cx + y, cy + x, c); |
471 | nsfb->plotter_fns->point(nsfb, cx - y, cy + x, c); |
472 | nsfb->plotter_fns->point(nsfb, cx + y, cy - x, c); |
473 | nsfb->plotter_fns->point(nsfb, cx - y, cy - x, c); |
474 | } |
475 | |
476 | static void |
477 | circlefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c) |
478 | { |
479 | nsfb_bbox_t fline[4]; |
480 | nsfb_plot_pen_t pen; |
481 | |
482 | pen.stroke_colour = c; |
483 | |
484 | fline[0].x0 = fline[1].x0 = cx - x; |
485 | fline[0].x1 = fline[1].x1 = cx + x; |
486 | fline[0].y0 = fline[0].y1 = cy + y; |
487 | fline[1].y0 = fline[1].y1 = cy - y; |
488 | |
489 | fline[2].x0 = fline[3].x0 = cx - y; |
490 | fline[2].x1 = fline[3].x1 = cx + y; |
491 | fline[2].y0 = fline[2].y1 = cy + x; |
492 | fline[3].y0 = fline[3].y1 = cy - x; |
493 | |
494 | nsfb->plotter_fns->line(nsfb, 4, fline, &pen); |
495 | } |
496 | |
497 | static bool circle_midpoint(nsfb_t *nsfb, |
498 | int cx, |
499 | int cy, |
500 | int r, |
501 | nsfb_colour_t c, |
502 | void (circfn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)) |
503 | { |
504 | int x = 0; |
505 | int y = r; |
506 | int p = 1 - r; |
507 | |
508 | circfn(nsfb, cx, cy, x, y, c); |
509 | while (x < y) { |
510 | x++; |
511 | if (p < 0) { |
512 | p += 2 * x + 1; |
513 | } else { |
514 | y--; |
515 | p += 2 * (x - y) + 1; |
516 | } |
517 | circfn(nsfb, cx, cy, x, y, c); |
518 | } |
519 | return true; |
520 | } |
521 | |
522 | static bool ellipse(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c) |
523 | { |
524 | int width = (ellipse->x1 - ellipse->x0)>>1; |
525 | int height = (ellipse->y1 - ellipse->y0)>>1; |
526 | |
527 | if (width == height) { |
528 | |
529 | return circle_midpoint(nsfb, ellipse->x0 + width, |
530 | ellipse->y0 + height, width, c, circlepoints); |
531 | } else { |
532 | return ellipse_midpoint(nsfb, ellipse->x0 + width, |
533 | ellipse->y0 + height, width, height, c, |
534 | ellipsepoints); |
535 | } |
536 | } |
537 | |
538 | static bool ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c) |
539 | { |
540 | int width = (ellipse->x1 - ellipse->x0) >> 1; |
541 | int height = (ellipse->y1 - ellipse->y0) >> 1; |
542 | |
543 | if (width == height) { |
544 | |
545 | return circle_midpoint(nsfb, ellipse->x0 + width, |
546 | ellipse->y0 + height, width, c, circlefill); |
547 | } else { |
548 | return ellipse_midpoint(nsfb, ellipse->x0 + width, |
549 | ellipse->y0 + height, width, height, c, |
550 | ellipsefill); |
551 | } |
552 | } |
553 | |
554 | |
555 | |
556 | |
557 | |
558 | |
559 | |
560 | static bool |
561 | copy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox) |
562 | { |
563 | int srcx = srcbox->x0; |
564 | int srcy = srcbox->y0; |
565 | int dstx = dstbox->x0; |
566 | int dsty = dstbox->y0; |
567 | int width = dstbox->x1 - dstbox->x0; |
568 | int height = dstbox->y1 - dstbox->y0; |
569 | uint8_t *srcptr; |
570 | uint8_t *dstptr; |
571 | int hloop; |
572 | nsfb_bbox_t allbox; |
573 | |
574 | nsfb_plot_add_rect(srcbox, dstbox, &allbox); |
575 | |
576 | nsfb->surface_rtns->claim(nsfb, &allbox); |
577 | |
578 | srcptr = (nsfb->ptr + |
579 | (srcy * nsfb->linelen) + |
580 | ((srcx * nsfb->bpp) / 8)); |
581 | |
582 | dstptr = (nsfb->ptr + |
583 | (dsty * nsfb->linelen) + |
584 | ((dstx * nsfb->bpp) / 8)); |
585 | |
586 | |
587 | if (width == nsfb->width) { |
588 | |
589 | memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8); |
590 | } else { |
591 | if (srcy > dsty) { |
592 | for (hloop = height; hloop > 0; hloop--) { |
593 | memmove(dstptr, srcptr, (width * nsfb->bpp) / 8); |
594 | srcptr += nsfb->linelen; |
595 | dstptr += nsfb->linelen; |
596 | } |
597 | } else { |
598 | srcptr += height * nsfb->linelen; |
599 | dstptr += height * nsfb->linelen; |
600 | for (hloop = height; hloop > 0; hloop--) { |
601 | srcptr -= nsfb->linelen; |
602 | dstptr -= nsfb->linelen; |
603 | memmove(dstptr, srcptr, (width * nsfb->bpp) / 8); |
604 | } |
605 | } |
606 | } |
607 | |
608 | nsfb->surface_rtns->update(nsfb, dstbox); |
609 | |
610 | return true; |
611 | } |
612 | |
613 | |
614 | |
615 | static bool arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, |
616 | int angle2, nsfb_colour_t c) |
617 | { |
618 | (void)nsfb; |
619 | (void)x; |
620 | (void)y; |
621 | (void)radius; |
622 | (void)c; |
623 | (void)angle1; |
624 | (void)angle2; |
625 | return true; |
626 | } |
627 | |
628 | #define N_SEG 30 |
629 | |
630 | static int |
631 | cubic_points(unsigned int pointc, |
632 | nsfb_point_t *point, |
633 | nsfb_bbox_t *curve, |
634 | nsfb_point_t *ctrla, |
635 | nsfb_point_t *ctrlb) |
636 | { |
637 | unsigned int seg_loop; |
638 | double t; |
639 | double one_minus_t; |
640 | double a; |
641 | double b; |
642 | double c; |
643 | double d; |
644 | double x; |
645 | double y; |
646 | int cur_point; |
647 | |
648 | point[0].x = curve->x0; |
649 | point[0].y = curve->y0; |
650 | cur_point = 1; |
651 | pointc--; |
652 | |
653 | for (seg_loop = 1; seg_loop < pointc; ++seg_loop) { |
654 | t = (double)seg_loop / (double)pointc; |
655 | |
656 | one_minus_t = 1.0 - t; |
657 | |
658 | a = one_minus_t * one_minus_t * one_minus_t; |
659 | b = 3.0 * t * one_minus_t * one_minus_t; |
660 | c = 3.0 * t * t * one_minus_t; |
661 | d = t * t * t; |
662 | |
663 | x = a * curve->x0 + b * ctrla->x + c * ctrlb->x + d * curve->x1; |
664 | y = a * curve->y0 + b * ctrla->y + c * ctrlb->y + d * curve->y1; |
665 | |
666 | point[cur_point].x = x; |
667 | point[cur_point].y = y; |
668 | if ((point[cur_point].x != point[cur_point - 1].x) || |
669 | (point[cur_point].y != point[cur_point - 1].y)) |
670 | cur_point++; |
671 | } |
672 | |
673 | point[cur_point].x = curve->x1; |
674 | point[cur_point].y = curve->y1; |
675 | if ((point[cur_point].x != point[cur_point - 1].x) || |
676 | (point[cur_point].y != point[cur_point - 1].y)) |
677 | cur_point++; |
678 | |
679 | return cur_point; |
680 | } |
681 | |
682 | |
683 | |
684 | |
685 | |
686 | |
687 | |
688 | |
689 | |
690 | static int |
691 | quadratic_points(unsigned int pointc, |
692 | nsfb_point_t *point, |
693 | nsfb_bbox_t *curve, |
694 | nsfb_point_t *ctrla) |
695 | { |
696 | unsigned int seg_loop; |
697 | double t; |
698 | double one_minus_t; |
699 | double a; |
700 | double b; |
701 | double c; |
702 | double x; |
703 | double y; |
704 | int cur_point; |
705 | |
706 | point[0].x = curve->x0; |
707 | point[0].y = curve->y0; |
708 | cur_point = 1; |
709 | pointc--; |
710 | |
711 | for (seg_loop = 1; seg_loop < pointc; ++seg_loop) { |
712 | t = (double)seg_loop / (double)pointc; |
713 | |
714 | one_minus_t = 1.0 - t; |
715 | |
716 | a = one_minus_t * one_minus_t; |
717 | b = 2.0 * t * one_minus_t; |
718 | c = t * t; |
719 | |
720 | x = a * curve->x0 + b * ctrla->x + c * curve->x1; |
721 | y = a * curve->y0 + b * ctrla->y + c * curve->y1; |
722 | |
723 | point[cur_point].x = x; |
724 | point[cur_point].y = y; |
725 | if ((point[cur_point].x != point[cur_point - 1].x) || |
726 | (point[cur_point].y != point[cur_point - 1].y)) |
727 | cur_point++; |
728 | } |
729 | |
730 | point[cur_point].x = curve->x1; |
731 | point[cur_point].y = curve->y1; |
732 | if ((point[cur_point].x != point[cur_point - 1].x) || |
733 | (point[cur_point].y != point[cur_point - 1].y)) |
734 | cur_point++; |
735 | |
736 | return cur_point; |
737 | } |
738 | |
739 | static bool |
740 | polylines(nsfb_t *nsfb, |
741 | int pointc, |
742 | const nsfb_point_t *points, |
743 | nsfb_plot_pen_t *pen) |
744 | { |
745 | int point_loop; |
746 | nsfb_bbox_t line; |
747 | |
748 | if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) { |
749 | for (point_loop = 0; point_loop < (pointc - 1); point_loop++) { |
750 | line = *(nsfb_bbox_t *)&points[point_loop]; |
751 | nsfb->plotter_fns->line(nsfb, 1, &line, pen); |
752 | } |
753 | } |
754 | return true; |
755 | } |
756 | |
757 | |
758 | |
759 | static bool |
760 | quadratic(nsfb_t *nsfb, |
761 | nsfb_bbox_t *curve, |
762 | nsfb_point_t *ctrla, |
763 | nsfb_plot_pen_t *pen) |
764 | { |
765 | nsfb_point_t points[N_SEG]; |
766 | |
767 | if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE) |
768 | return false; |
769 | |
770 | return polylines(nsfb, quadratic_points(N_SEG, points, curve, ctrla), |
771 | points, pen); |
772 | } |
773 | |
774 | static bool |
775 | cubic(nsfb_t *nsfb, |
776 | nsfb_bbox_t *curve, |
777 | nsfb_point_t *ctrla, |
778 | nsfb_point_t *ctrlb, |
779 | nsfb_plot_pen_t *pen) |
780 | { |
781 | nsfb_point_t points[N_SEG]; |
782 | |
783 | if (pen->stroke_type == NFSB_PLOT_OPTYPE_NONE) |
784 | return false; |
785 | |
786 | return polylines(nsfb, cubic_points(N_SEG, points, curve, ctrla,ctrlb), |
787 | points, pen); |
788 | } |
789 | |
790 | |
791 | static bool |
792 | path(nsfb_t *nsfb, int pathc, nsfb_plot_pathop_t *pathop, nsfb_plot_pen_t *pen) |
793 | { |
794 | int path_loop; |
795 | nsfb_point_t *pts; |
796 | nsfb_point_t *curpt; |
797 | int ptc = 0; |
798 | nsfb_bbox_t curve; |
799 | nsfb_point_t ctrla; |
800 | nsfb_point_t ctrlb; |
801 | int added_count = 0; |
802 | int bpts; |
803 | |
804 | |
805 | for (path_loop = 0; path_loop < pathc; path_loop++) { |
| 1 | Assuming 'path_loop' is < 'pathc' | |
|
| 2 | | Loop condition is true. Entering loop body | |
|
| 4 | | Assuming 'path_loop' is >= 'pathc' | |
|
| 5 | | Loop condition is false. Execution continues on line 814 | |
|
806 | ptc++; |
807 | if ((pathop[path_loop].operation == NFSB_PLOT_PATHOP_QUAD) || |
| 3 | | Assuming field 'operation' is equal to NFSB_PLOT_PATHOP_QUAD | |
|
808 | (pathop[path_loop].operation == |
809 | NFSB_PLOT_PATHOP_CUBIC)) |
810 | ptc += N_SEG; |
811 | } |
812 | |
813 | |
814 | curpt = pts = malloc(ptc * sizeof(nsfb_point_t)); |
815 | if (curpt == NULL) { |
| 6 | | Assuming 'curpt' is not equal to NULL | |
|
| |
816 | return false; |
817 | } |
818 | |
819 | for (path_loop = 0; path_loop < pathc; path_loop++) { |
| 8 | | Loop condition is true. Entering loop body | |
|
| 11 | | Loop condition is false. Execution continues on line 859 | |
|
820 | switch (pathop[path_loop].operation) { |
| 9 | | Control jumps to 'case NFSB_PLOT_PATHOP_QUAD:' at line 821 | |
|
821 | case NFSB_PLOT_PATHOP_QUAD: |
822 | curpt-=2; |
823 | added_count -= 2; |
824 | curve.x0 = pathop[path_loop - 2].point.x; |
825 | curve.y0 = pathop[path_loop - 2].point.y; |
826 | ctrla.x = pathop[path_loop - 1].point.x; |
827 | ctrla.y = pathop[path_loop - 1].point.y; |
828 | curve.x1 = pathop[path_loop].point.x; |
829 | curve.y1 = pathop[path_loop].point.y; |
830 | bpts = quadratic_points(N_SEG, curpt, &curve, &ctrla); |
831 | curpt += bpts; |
832 | added_count += bpts; |
833 | break; |
| 10 | | Execution continues on line 819 | |
|
834 | |
835 | case NFSB_PLOT_PATHOP_CUBIC: |
836 | curpt-=3; |
837 | added_count -=3; |
838 | curve.x0 = pathop[path_loop - 3].point.x; |
839 | curve.y0 = pathop[path_loop - 3].point.y; |
840 | ctrla.x = pathop[path_loop - 2].point.x; |
841 | ctrla.y = pathop[path_loop - 2].point.y; |
842 | ctrlb.x = pathop[path_loop - 1].point.x; |
843 | ctrlb.y = pathop[path_loop - 1].point.y; |
844 | curve.x1 = pathop[path_loop].point.x; |
845 | curve.y1 = pathop[path_loop].point.y; |
846 | bpts = cubic_points(N_SEG, curpt, &curve, &ctrla, &ctrlb); |
847 | curpt += bpts; |
848 | added_count += bpts; |
849 | break; |
850 | |
851 | default: |
852 | *curpt = pathop[path_loop].point; |
853 | curpt++; |
854 | added_count ++; |
855 | break; |
856 | } |
857 | } |
858 | |
859 | if (pen->fill_type != NFSB_PLOT_OPTYPE_NONE) { |
| 12 | | Assuming field 'fill_type' is not equal to NFSB_PLOT_OPTYPE_NONE | |
|
| |
860 | polygon(nsfb, (int *)pts, added_count, pen->fill_colour); |
| |
861 | } |
862 | |
863 | if (pen->stroke_type != NFSB_PLOT_OPTYPE_NONE) { |
864 | polylines(nsfb, added_count, pts, pen); |
865 | } |
866 | |
867 | free(pts); |
868 | |
869 | return true; |
870 | } |
871 | |
872 | bool select_plotters(nsfb_t *nsfb) |
873 | { |
874 | const nsfb_plotter_fns_t *table = NULL; |
875 | |
876 | switch (nsfb->format) { |
877 | |
878 | case NSFB_FMT_XBGR8888: |
879 | case NSFB_FMT_ABGR8888: |
880 | table = &_nsfb_32bpp_xbgr8888_plotters; |
881 | nsfb->bpp = 32; |
882 | break; |
883 | |
884 | case NSFB_FMT_XRGB8888: |
885 | case NSFB_FMT_ARGB8888: |
886 | table = &_nsfb_32bpp_xrgb8888_plotters; |
887 | nsfb->bpp = 32; |
888 | break; |
889 | |
890 | |
891 | case NSFB_FMT_RGB888: |
892 | #ifdef ENABLE_24_BPP |
893 | table = &_nsfb_24bpp_plotters; |
894 | nsfb->bpp = 24; |
895 | break; |
896 | #else |
897 | return false; |
898 | #endif |
899 | |
900 | case NSFB_FMT_ARGB1555: |
901 | case NSFB_FMT_RGB565: |
902 | table = &_nsfb_16bpp_plotters; |
903 | nsfb->bpp = 16; |
904 | break; |
905 | |
906 | case NSFB_FMT_I8: |
907 | table = &_nsfb_8bpp_plotters; |
908 | nsfb->bpp = 8; |
909 | break; |
910 | |
911 | case NSFB_FMT_I1: |
912 | #ifdef ENABLE_1_BPP |
913 | table = &_nsfb_1bpp_plotters; |
914 | nsfb->bpp = 1 |
915 | break; |
916 | #else |
917 | return false; |
918 | #endif |
919 | |
920 | case NSFB_FMT_ANY: |
921 | default: |
922 | return false; |
923 | } |
924 | |
925 | if (nsfb->plotter_fns != NULL) { |
926 | free(nsfb->plotter_fns); |
927 | } |
928 | |
929 | nsfb->plotter_fns = calloc(1, sizeof(nsfb_plotter_fns_t)); |
930 | if (nsfb->plotter_fns == NULL) { |
931 | return false; |
932 | } |
933 | |
934 | memcpy(nsfb->plotter_fns, table, sizeof(nsfb_plotter_fns_t)); |
935 | |
936 | |
937 | nsfb->plotter_fns->clg = clg; |
938 | nsfb->plotter_fns->set_clip = set_clip; |
939 | nsfb->plotter_fns->get_clip = get_clip; |
940 | nsfb->plotter_fns->polygon = polygon; |
941 | nsfb->plotter_fns->rectangle = rectangle; |
942 | nsfb->plotter_fns->ellipse = ellipse; |
943 | nsfb->plotter_fns->ellipse_fill = ellipse_fill; |
944 | nsfb->plotter_fns->copy = copy; |
945 | nsfb->plotter_fns->arc = arc; |
946 | nsfb->plotter_fns->quadratic = quadratic; |
947 | nsfb->plotter_fns->cubic = cubic; |
948 | nsfb->plotter_fns->path = path; |
949 | nsfb->plotter_fns->polylines = polylines; |
950 | |
951 | |
952 | nsfb->clip.x0 = 0; |
953 | nsfb->clip.y0 = 0; |
954 | nsfb->clip.x1 = nsfb->width; |
955 | nsfb->clip.y1 = nsfb->height; |
956 | |
957 | return true; |
958 | } |
959 | |
960 | |
961 | |
962 | |
963 | |
964 | |
965 | |