1 /**
2 * @file lv_draw_vglite_arc.c
3 *
4 */
5
6 /**
7 * Copyright 2021-2024 NXP
8 *
9 * SPDX-License-Identifier: MIT
10 */
11
12 /*********************
13 * INCLUDES
14 *********************/
15
16 #include "lv_draw_vglite.h"
17
18 #if LV_USE_DRAW_VGLITE
19 #include "lv_vglite_buf.h"
20 #include "lv_vglite_path.h"
21 #include "lv_vglite_utils.h"
22
23 #include "../../../stdlib/lv_string.h"
24 #include <math.h>
25
26 /*********************
27 * DEFINES
28 *********************/
29
30 #define T_FRACTION 16384.0f
31
32 #define DICHOTO_ITER 5
33
34 static const uint16_t TperDegree[90] = {
35 0, 174, 348, 522, 697, 873, 1049, 1226, 1403, 1581,
36 1759, 1938, 2117, 2297, 2477, 2658, 2839, 3020, 3202, 3384,
37 3567, 3749, 3933, 4116, 4300, 4484, 4668, 4852, 5037, 5222,
38 5407, 5592, 5777, 5962, 6148, 6334, 6519, 6705, 6891, 7077,
39 7264, 7450, 7636, 7822, 8008, 8193, 8378, 8564, 8750, 8936,
40 9122, 9309, 9495, 9681, 9867, 10052, 10238, 10424, 10609, 10794,
41 10979, 11164, 11349, 11534, 11718, 11902, 12086, 12270, 12453, 12637,
42 12819, 13002, 13184, 13366, 13547, 13728, 13909, 14089, 14269, 14448,
43 14627, 14805, 14983, 15160, 15337, 15513, 15689, 15864, 16038, 16212
44 };
45
46 /**********************
47 * TYPEDEFS
48 **********************/
49
50 /* intermediate arc params */
51 typedef struct _vg_arc {
52 int32_t angle; /* angle <90deg */
53 int32_t quarter; /* 0-3 counter-clockwise */
54 int32_t rad; /* radius */
55 int32_t p0x; /* point P0 */
56 int32_t p0y;
57 int32_t p1x; /* point P1 */
58 int32_t p1y;
59 int32_t p2x; /* point P2 */
60 int32_t p2y;
61 int32_t p3x; /* point P3 */
62 int32_t p3y;
63 } vg_arc;
64
65 typedef struct _cubic_cont_pt {
66 float p0;
67 float p1;
68 float p2;
69 float p3;
70 } cubic_cont_pt;
71
72 /**********************
73 * STATIC PROTOTYPES
74 **********************/
75
76 /**
77 * Draw arc shape with effects
78 *
79 * @param[in] center Arc center with relative coordinates
80 * @param[in] clip_area Clip area with relative coordinates to dest buff
81 * @param[in] dsc Arc description structure (width, rounded ending, opacity)
82 *
83 */
84 static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_area,
85 const lv_draw_arc_dsc_t * dsc);
86
87 /**********************
88 * STATIC VARIABLES
89 **********************/
90
91 /**********************
92 * MACROS
93 **********************/
94
95 /**********************
96 * GLOBAL FUNCTIONS
97 **********************/
98
lv_draw_vglite_arc(lv_draw_unit_t * draw_unit,const lv_draw_arc_dsc_t * dsc,const lv_area_t * coords)99 void lv_draw_vglite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
100 const lv_area_t * coords)
101 {
102 LV_UNUSED(coords);
103
104 if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
105 return;
106 if(dsc->width == 0)
107 return;
108 if(dsc->start_angle == dsc->end_angle)
109 return;
110
111 lv_layer_t * layer = draw_unit->target_layer;
112 lv_point_t center = {dsc->center.x - layer->buf_area.x1, dsc->center.y - layer->buf_area.y1};
113
114 lv_area_t clip_area;
115 lv_area_copy(&clip_area, draw_unit->clip_area);
116 lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
117
118 _vglite_draw_arc(¢er, &clip_area, dsc);
119 }
120
121 /**********************
122 * STATIC FUNCTIONS
123 **********************/
124
_copy_arc(vg_arc * dst,vg_arc * src)125 static void _copy_arc(vg_arc * dst, vg_arc * src)
126 {
127 dst->quarter = src->quarter;
128 dst->rad = src->rad;
129 dst->angle = src->angle;
130 dst->p0x = src->p0x;
131 dst->p1x = src->p1x;
132 dst->p2x = src->p2x;
133 dst->p3x = src->p3x;
134 dst->p0y = src->p0y;
135 dst->p1y = src->p1y;
136 dst->p2y = src->p2y;
137 dst->p3y = src->p3y;
138 }
139
140 /**
141 * Rotate the point according given rotation angle rotation center is 0,0
142 */
_rotate_point(int32_t angle,int32_t * x,int32_t * y)143 static void _rotate_point(int32_t angle, int32_t * x, int32_t * y)
144 {
145 int32_t ori_x = *x;
146 int32_t ori_y = *y;
147 int16_t alpha = (int16_t)angle;
148 *x = ((lv_trigo_cos(alpha) * ori_x) / LV_TRIGO_SIN_MAX) - ((lv_trigo_sin(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
149 *y = ((lv_trigo_sin(alpha) * ori_x) / LV_TRIGO_SIN_MAX) + ((lv_trigo_cos(alpha) * ori_y) / LV_TRIGO_SIN_MAX);
150 }
151
152 /**
153 * Set full arc control points depending on quarter.
154 * Control points match the best approximation of a circle.
155 * Arc Quarter position is:
156 * Q2 | Q3
157 * ---+---
158 * Q1 | Q0
159 */
_set_full_arc(vg_arc * fullarc)160 static void _set_full_arc(vg_arc * fullarc)
161 {
162 /* the tangent length for the bezier circle approx */
163 float tang = ((float)fullarc->rad) * BEZIER_OPTIM_CIRCLE;
164 switch(fullarc->quarter) {
165 case 0:
166 /* first quarter */
167 fullarc->p0x = fullarc->rad;
168 fullarc->p0y = 0;
169 fullarc->p1x = fullarc->rad;
170 fullarc->p1y = (int32_t)tang;
171 fullarc->p2x = (int32_t)tang;
172 fullarc->p2y = fullarc->rad;
173 fullarc->p3x = 0;
174 fullarc->p3y = fullarc->rad;
175 break;
176 case 1:
177 /* second quarter */
178 fullarc->p0x = 0;
179 fullarc->p0y = fullarc->rad;
180 fullarc->p1x = 0 - (int32_t)tang;
181 fullarc->p1y = fullarc->rad;
182 fullarc->p2x = 0 - fullarc->rad;
183 fullarc->p2y = (int32_t)tang;
184 fullarc->p3x = 0 - fullarc->rad;
185 fullarc->p3y = 0;
186 break;
187 case 2:
188 /* third quarter */
189 fullarc->p0x = 0 - fullarc->rad;
190 fullarc->p0y = 0;
191 fullarc->p1x = 0 - fullarc->rad;
192 fullarc->p1y = 0 - (int32_t)tang;
193 fullarc->p2x = 0 - (int32_t)tang;
194 fullarc->p2y = 0 - fullarc->rad;
195 fullarc->p3x = 0;
196 fullarc->p3y = 0 - fullarc->rad;
197 break;
198 case 3:
199 /* fourth quarter */
200 fullarc->p0x = 0;
201 fullarc->p0y = 0 - fullarc->rad;
202 fullarc->p1x = (int32_t)tang;
203 fullarc->p1y = 0 - fullarc->rad;
204 fullarc->p2x = fullarc->rad;
205 fullarc->p2y = 0 - (int32_t)tang;
206 fullarc->p3x = fullarc->rad;
207 fullarc->p3y = 0;
208 break;
209 default:
210 VGLITE_ASSERT_MSG(false, "Invalid arc quarter.");
211 break;
212 }
213 }
214
215 /**
216 * Linear interpolation between two points 'a' and 'b'
217 * 't' parameter is the proportion ratio expressed in range [0 ; T_FRACTION ]
218 */
_lerp(float coord_a,float coord_b,uint16_t t)219 static inline float _lerp(float coord_a, float coord_b, uint16_t t)
220 {
221 float tf = (float)t;
222 return ((T_FRACTION - tf) * coord_a + tf * coord_b) / T_FRACTION;
223 }
224
225 /**
226 * Computes a point of bezier curve given 't' param
227 */
_comp_bezier_point(float t,cubic_cont_pt cp)228 static inline float _comp_bezier_point(float t, cubic_cont_pt cp)
229 {
230 float t_sq = t * t;
231 float inv_t_sq = (1.0f - t) * (1.0f - t);
232 float apt = (1.0f - t) * inv_t_sq * cp.p0 + 3.0f * inv_t_sq * t * cp.p1 + 3.0f * (1.0f - t) * t_sq * cp.p2 + t * t_sq *
233 cp.p3;
234 return apt;
235 }
236
237 /**
238 * Find parameter 't' in curve at point 'pt'
239 * proceed by dichotomy on only 1 dimension,
240 * works only if the curve is monotonic
241 * bezier curve is defined by control points [p0 p1 p2 p3]
242 * 'dec' tells if curve is decreasing (true) or increasing (false)
243 */
_get_bez_t_from_pos(float pt,cubic_cont_pt cp,bool dec)244 static uint16_t _get_bez_t_from_pos(float pt, cubic_cont_pt cp, bool dec)
245 {
246 /* initialize dichotomy with boundary 't' values */
247 float t_low = 0.0f;
248 float t_mid = 0.5f;
249 float t_hig = 1.0f;
250 float a_pt;
251 /* dichotomy loop */
252 for(int i = 0; i < DICHOTO_ITER; i++) {
253 a_pt = _comp_bezier_point(t_mid, cp);
254 /* check mid-point position on bezier curve versus targeted point */
255 if((a_pt > pt) != dec) {
256 t_hig = t_mid;
257 }
258 else {
259 t_low = t_mid;
260 }
261 /* define new 't' param for mid-point */
262 t_mid = (t_low + t_hig) / 2.0f;
263 }
264 /* return parameter 't' in integer range [0 ; T_FRACTION] */
265 return (uint16_t)floorf(t_mid * T_FRACTION + 0.5f);
266 }
267
268 /**
269 * Gives relative coords of the control points
270 * for the sub-arc starting at angle with given angle span
271 */
_get_subarc_control_points(vg_arc * arc,int32_t span)272 static void _get_subarc_control_points(vg_arc * arc, int32_t span)
273 {
274 vg_arc fullarc = {0};
275 fullarc.angle = arc->angle;
276 fullarc.quarter = arc->quarter;
277 fullarc.rad = arc->rad;
278 _set_full_arc(&fullarc);
279
280 /* special case of full arc */
281 if(arc->angle == 90) {
282 _copy_arc(arc, &fullarc);
283 return;
284 }
285
286 /* compute 1st arc using the geometric construction of curve */
287 uint16_t t2 = TperDegree[arc->angle + span];
288
289 /* lerp for A */
290 float a2x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t2);
291 float a2y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t2);
292 /* lerp for B */
293 float b2x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t2);
294 float b2y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t2);
295 /* lerp for C */
296 float c2x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t2);
297 float c2y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t2);
298
299 /* lerp for D */
300 float d2x = _lerp(a2x, b2x, t2);
301 float d2y = _lerp(a2y, b2y, t2);
302 /* lerp for E */
303 float e2x = _lerp(b2x, c2x, t2);
304 float e2y = _lerp(b2y, c2y, t2);
305
306 float pt2x = _lerp(d2x, e2x, t2);
307 float pt2y = _lerp(d2y, e2y, t2);
308
309 /* compute sub-arc using the geometric construction of curve */
310 uint16_t t1 = TperDegree[arc->angle];
311
312 /* lerp for A */
313 float a1x = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t1);
314 float a1y = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t1);
315 /* lerp for B */
316 float b1x = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t1);
317 float b1y = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t1);
318 /* lerp for C */
319 float c1x = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t1);
320 float c1y = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t1);
321
322 /* lerp for D */
323 float d1x = _lerp(a1x, b1x, t1);
324 float d1y = _lerp(a1y, b1y, t1);
325 /* lerp for E */
326 float e1x = _lerp(b1x, c1x, t1);
327 float e1y = _lerp(b1y, c1y, t1);
328
329 float pt1x = _lerp(d1x, e1x, t1);
330 float pt1y = _lerp(d1y, e1y, t1);
331
332 /* find the 't3' parameter for point P(t1) on the sub-arc [P0 A2 D2 P(t2)] using dichotomy
333 * use position of x axis only */
334 uint16_t t3;
335 t3 = _get_bez_t_from_pos(pt1x,
336 (cubic_cont_pt) {
337 .p0 = ((float)fullarc.p0x), .p1 = a2x, .p2 = d2x, .p3 = pt2x
338 },
339 (bool)(pt2x < (float)fullarc.p0x));
340
341 /* lerp for B */
342 float b3x = _lerp(a2x, d2x, t3);
343 float b3y = _lerp(a2y, d2y, t3);
344 /* lerp for C */
345 float c3x = _lerp(d2x, pt2x, t3);
346 float c3y = _lerp(d2y, pt2y, t3);
347
348 /* lerp for E */
349 float e3x = _lerp(b3x, c3x, t3);
350 float e3y = _lerp(b3y, c3y, t3);
351
352 arc->p0x = (int32_t)floorf(0.5f + pt1x);
353 arc->p0y = (int32_t)floorf(0.5f + pt1y);
354 arc->p1x = (int32_t)floorf(0.5f + e3x);
355 arc->p1y = (int32_t)floorf(0.5f + e3y);
356 arc->p2x = (int32_t)floorf(0.5f + c3x);
357 arc->p2y = (int32_t)floorf(0.5f + c3y);
358 arc->p3x = (int32_t)floorf(0.5f + pt2x);
359 arc->p3y = (int32_t)floorf(0.5f + pt2y);
360 }
361
362 /**
363 * Gives relative coords of the control points
364 */
_get_arc_control_points(vg_arc * arc,bool start)365 static void _get_arc_control_points(vg_arc * arc, bool start)
366 {
367 vg_arc fullarc = {0};
368 fullarc.angle = arc->angle;
369 fullarc.quarter = arc->quarter;
370 fullarc.rad = arc->rad;
371 _set_full_arc(&fullarc);
372
373 /* special case of full arc */
374 if(arc->angle == 90) {
375 _copy_arc(arc, &fullarc);
376 return;
377 }
378
379 /* compute sub-arc using the geometric construction of curve */
380 uint16_t t = TperDegree[arc->angle];
381 /* lerp for A */
382 float ax = _lerp((float)fullarc.p0x, (float)fullarc.p1x, t);
383 float ay = _lerp((float)fullarc.p0y, (float)fullarc.p1y, t);
384 /* lerp for B */
385 float bx = _lerp((float)fullarc.p1x, (float)fullarc.p2x, t);
386 float by = _lerp((float)fullarc.p1y, (float)fullarc.p2y, t);
387 /* lerp for C */
388 float cx = _lerp((float)fullarc.p2x, (float)fullarc.p3x, t);
389 float cy = _lerp((float)fullarc.p2y, (float)fullarc.p3y, t);
390
391 /* lerp for D */
392 float dx = _lerp(ax, bx, t);
393 float dy = _lerp(ay, by, t);
394 /* lerp for E */
395 float ex = _lerp(bx, cx, t);
396 float ey = _lerp(by, cy, t);
397
398 /* sub-arc's control points are tangents of DeCasteljau's algorithm */
399 if(start) {
400 arc->p0x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
401 arc->p0y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
402 arc->p1x = (int32_t)floorf(0.5f + ex);
403 arc->p1y = (int32_t)floorf(0.5f + ey);
404 arc->p2x = (int32_t)floorf(0.5f + cx);
405 arc->p2y = (int32_t)floorf(0.5f + cy);
406 arc->p3x = fullarc.p3x;
407 arc->p3y = fullarc.p3y;
408 }
409 else {
410 arc->p0x = fullarc.p0x;
411 arc->p0y = fullarc.p0y;
412 arc->p1x = (int32_t)floorf(0.5f + ax);
413 arc->p1y = (int32_t)floorf(0.5f + ay);
414 arc->p2x = (int32_t)floorf(0.5f + dx);
415 arc->p2y = (int32_t)floorf(0.5f + dy);
416 arc->p3x = (int32_t)floorf(0.5f + _lerp(dx, ex, t));
417 arc->p3y = (int32_t)floorf(0.5f + _lerp(dy, ey, t));
418 }
419 }
420
421 /**
422 * Add the arc control points into the path data for vglite,
423 * taking into account the real center of the arc (translation).
424 * arc_path: (in/out) the path data array for vglite
425 * pidx: (in/out) index of last element added in arc_path
426 * q_arc: (in) the arc data containing control points
427 * center: (in) the center of the circle in draw coordinates
428 * cw: (in) true if arc is clockwise
429 */
_add_split_arc_path(int32_t * arc_path,int * pidx,vg_arc * q_arc,const lv_point_t * center,bool cw)430 static void _add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, const lv_point_t * center, bool cw)
431 {
432 /* assumes first control point already in array arc_path[] */
433 int idx = *pidx;
434 if(cw) {
435 #if BEZIER_DBG_CONTROL_POINTS
436 arc_path[idx++] = VLC_OP_LINE;
437 arc_path[idx++] = q_arc->p1x + center->x;
438 arc_path[idx++] = q_arc->p1y + center->y;
439 arc_path[idx++] = VLC_OP_LINE;
440 arc_path[idx++] = q_arc->p2x + center->x;
441 arc_path[idx++] = q_arc->p2y + center->y;
442 arc_path[idx++] = VLC_OP_LINE;
443 arc_path[idx++] = q_arc->p3x + center->x;
444 arc_path[idx++] = q_arc->p3y + center->y;
445 #else
446 arc_path[idx++] = VLC_OP_CUBIC;
447 arc_path[idx++] = q_arc->p1x + center->x;
448 arc_path[idx++] = q_arc->p1y + center->y;
449 arc_path[idx++] = q_arc->p2x + center->x;
450 arc_path[idx++] = q_arc->p2y + center->y;
451 arc_path[idx++] = q_arc->p3x + center->x;
452 arc_path[idx++] = q_arc->p3y + center->y;
453 #endif
454 }
455 else { /* reverse points order when counter-clockwise */
456 #if BEZIER_DBG_CONTROL_POINTS
457 arc_path[idx++] = VLC_OP_LINE;
458 arc_path[idx++] = q_arc->p2x + center->x;
459 arc_path[idx++] = q_arc->p2y + center->y;
460 arc_path[idx++] = VLC_OP_LINE;
461 arc_path[idx++] = q_arc->p1x + center->x;
462 arc_path[idx++] = q_arc->p1y + center->y;
463 arc_path[idx++] = VLC_OP_LINE;
464 arc_path[idx++] = q_arc->p0x + center->x;
465 arc_path[idx++] = q_arc->p0y + center->y;
466 #else
467 arc_path[idx++] = VLC_OP_CUBIC;
468 arc_path[idx++] = q_arc->p2x + center->x;
469 arc_path[idx++] = q_arc->p2y + center->y;
470 arc_path[idx++] = q_arc->p1x + center->x;
471 arc_path[idx++] = q_arc->p1y + center->y;
472 arc_path[idx++] = q_arc->p0x + center->x;
473 arc_path[idx++] = q_arc->p0y + center->y;
474 #endif
475 }
476 /* update index i n path array*/
477 *pidx = idx;
478 }
479
_add_arc_path(int32_t * arc_path,int * pidx,int32_t radius,int32_t start_angle,int32_t end_angle,const lv_point_t * center,bool cw)480 static void _add_arc_path(int32_t * arc_path, int * pidx, int32_t radius,
481 int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw)
482 {
483 /* set number of arcs to draw */
484 vg_arc q_arc;
485 int32_t start_arc_angle = start_angle % 90;
486 int32_t end_arc_angle = end_angle % 90;
487 int32_t inv_start_arc_angle = (start_arc_angle > 0) ? (90 - start_arc_angle) : 0;
488 int32_t nbarc = (end_angle - start_angle - inv_start_arc_angle - end_arc_angle) / 90;
489 q_arc.rad = radius;
490
491 /* handle special case of start & end point in the same quarter */
492 if(((start_angle / 90) == (end_angle / 90)) && (nbarc <= 0)) {
493 q_arc.quarter = (start_angle / 90) % 4;
494 q_arc.angle = start_arc_angle;
495 _get_subarc_control_points(&q_arc, end_arc_angle - start_arc_angle);
496 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
497 return;
498 }
499
500 if(cw) {
501 /* partial starting arc */
502 if(start_arc_angle > 0) {
503 q_arc.quarter = (start_angle / 90) % 4;
504 q_arc.angle = start_arc_angle;
505 /* get cubic points relative to center */
506 _get_arc_control_points(&q_arc, true);
507 /* put cubic points in arc_path */
508 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
509 }
510 /* full arcs */
511 for(int32_t q = 0; q < nbarc ; q++) {
512 q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
513 q_arc.angle = 90;
514 /* get cubic points relative to center */
515 _get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
516 /* put cubic points in arc_path */
517 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
518 }
519 /* partial ending arc */
520 if(end_arc_angle > 0) {
521 q_arc.quarter = (end_angle / 90) % 4;
522 q_arc.angle = end_arc_angle;
523 /* get cubic points relative to center */
524 _get_arc_control_points(&q_arc, false);
525 /* put cubic points in arc_path */
526 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
527 }
528
529 }
530 else { /* counter clockwise */
531
532 /* partial ending arc */
533 if(end_arc_angle > 0) {
534 q_arc.quarter = (end_angle / 90) % 4;
535 q_arc.angle = end_arc_angle;
536 /* get cubic points relative to center */
537 _get_arc_control_points(&q_arc, false);
538 /* put cubic points in arc_path */
539 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
540 }
541 /* full arcs */
542 for(int32_t q = nbarc - 1; q >= 0; q--) {
543 q_arc.quarter = (q + ((start_angle + 89) / 90)) % 4;
544 q_arc.angle = 90;
545 /* get cubic points relative to center */
546 _get_arc_control_points(&q_arc, true); /* 2nd parameter 'start' ignored */
547 /* put cubic points in arc_path */
548 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
549 }
550 /* partial starting arc */
551 if(start_arc_angle > 0) {
552 q_arc.quarter = (start_angle / 90) % 4;
553 q_arc.angle = start_arc_angle;
554 /* get cubic points relative to center */
555 _get_arc_control_points(&q_arc, true);
556 /* put cubic points in arc_path */
557 _add_split_arc_path(arc_path, pidx, &q_arc, center, cw);
558 }
559 }
560 }
561
_vglite_draw_arc(const lv_point_t * center,const lv_area_t * clip_area,const lv_draw_arc_dsc_t * dsc)562 static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_area,
563 const lv_draw_arc_dsc_t * dsc)
564 {
565 vg_lite_path_t path;
566 uint16_t start_angle = dsc->start_angle;
567 uint16_t end_angle = dsc->end_angle;
568
569 /* be sure end_angle > start_angle */
570 if(end_angle < start_angle)
571 end_angle += 360;
572
573 bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false;
574 vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
575
576 int32_t arc_path[ARC_PATH_DATA_MAX_SIZE];
577 lv_memzero(arc_path, sizeof(arc_path));
578
579 /*** Init path ***/
580 int32_t width = dsc->width; /* inner arc radius = outer arc radius - width */
581 uint16_t radius = dsc->radius;
582
583 if(width > radius)
584 width = radius;
585
586 int pidx = 0;
587 int32_t cp_x, cp_y; /* control point coords */
588
589 /* first control point of curve */
590 cp_x = radius;
591 cp_y = 0;
592 _rotate_point(start_angle, &cp_x, &cp_y);
593 arc_path[pidx++] = VLC_OP_MOVE;
594 arc_path[pidx++] = center->x + cp_x;
595 arc_path[pidx++] = center->y + cp_y;
596
597 /* draw 1-5 outer quarters */
598 _add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, center, true);
599
600 if(donut) {
601 /* close outer circle */
602 cp_x = radius;
603 cp_y = 0;
604 _rotate_point(start_angle, &cp_x, &cp_y);
605 arc_path[pidx++] = VLC_OP_LINE;
606 arc_path[pidx++] = center->x + cp_x;
607 arc_path[pidx++] = center->y + cp_y;
608 /* start inner circle */
609 cp_x = radius - width;
610 cp_y = 0;
611 _rotate_point(start_angle, &cp_x, &cp_y);
612 arc_path[pidx++] = VLC_OP_MOVE;
613 arc_path[pidx++] = center->x + cp_x;
614 arc_path[pidx++] = center->y + cp_y;
615
616 }
617 else if(dsc->rounded != 0U) { /* 1st rounded arc ending */
618 cp_x = radius - width / 2;
619 cp_y = 0;
620 _rotate_point(end_angle, &cp_x, &cp_y);
621 lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
622 _add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180),
623 &round_center, true);
624
625 }
626 else { /* 1st flat ending */
627 cp_x = radius - width;
628 cp_y = 0;
629 _rotate_point(end_angle, &cp_x, &cp_y);
630 arc_path[pidx++] = VLC_OP_LINE;
631 arc_path[pidx++] = center->x + cp_x;
632 arc_path[pidx++] = center->y + cp_y;
633 }
634
635 /* draw 1-5 inner quarters */
636 _add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, center, false);
637
638 /* last control point of curve */
639 if(donut) { /* close the loop */
640 cp_x = radius - width;
641 cp_y = 0;
642 _rotate_point(start_angle, &cp_x, &cp_y);
643 arc_path[pidx++] = VLC_OP_LINE;
644 arc_path[pidx++] = center->x + cp_x;
645 arc_path[pidx++] = center->y + cp_y;
646
647 }
648 else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */
649 cp_x = radius - width / 2;
650 cp_y = 0;
651 _rotate_point(start_angle, &cp_x, &cp_y);
652 lv_point_t round_center = {center->x + cp_x, center->y + cp_y};
653 _add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360),
654 &round_center, true);
655
656 }
657 else { /* 2nd flat ending */
658 cp_x = radius;
659 cp_y = 0;
660 _rotate_point(start_angle, &cp_x, &cp_y);
661 arc_path[pidx++] = VLC_OP_LINE;
662 arc_path[pidx++] = center->x + cp_x;
663 arc_path[pidx++] = center->y + cp_y;
664 }
665
666 arc_path[pidx++] = VLC_OP_END;
667
668 VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path,
669 (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
670 ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
671
672 lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
673 vg_lite_color_t vgcol = vglite_get_color(col32, false);
674
675 /*** Draw arc ***/
676 VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
677
678 vglite_run();
679
680 VGLITE_CHECK_ERROR(vg_lite_clear_path(&path));
681 }
682
683 #endif /*LV_USE_DRAW_VGLITE*/
684