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