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