1 /**
2  * @file lv_draw_vg_lite_line.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../misc/lv_area_private.h"
11 #include "lv_draw_vg_lite.h"
12 
13 #if LV_USE_DRAW_VG_LITE
14 
15 #include "lv_draw_vg_lite_type.h"
16 #include "lv_vg_lite_math.h"
17 #include "lv_vg_lite_path.h"
18 #include "lv_vg_lite_utils.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 
24 #define SQ(x) ((x) * (x))
25 
26 /**********************
27  *      TYPEDEFS
28  **********************/
29 
30 /**********************
31  *  STATIC PROTOTYPES
32  **********************/
33 
34 /**********************
35  *  STATIC VARIABLES
36  **********************/
37 
38 /**********************
39  *      MACROS
40  **********************/
41 
42 /**********************
43  *   GLOBAL FUNCTIONS
44  **********************/
45 
lv_draw_vg_lite_line(lv_draw_unit_t * draw_unit,const lv_draw_line_dsc_t * dsc)46 void lv_draw_vg_lite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc)
47 {
48     float p1_x = dsc->p1.x;
49     float p1_y = dsc->p1.y;
50     float p2_x = dsc->p2.x;
51     float p2_y = dsc->p2.y;
52 
53     if(p1_x == p2_x && p1_y == p2_y)
54         return;
55 
56     float half_w = dsc->width * 0.5f;
57 
58     lv_area_t rel_clip_area;
59     rel_clip_area.x1 = (int32_t)(LV_MIN(p1_x, p2_x) - half_w);
60     rel_clip_area.x2 = (int32_t)(LV_MAX(p1_x, p2_x) + half_w);
61     rel_clip_area.y1 = (int32_t)(LV_MIN(p1_y, p2_y) - half_w);
62     rel_clip_area.y2 = (int32_t)(LV_MAX(p1_y, p2_y) + half_w);
63 
64     if(!lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_unit->clip_area)) {
65         return; /*Fully clipped, nothing to do*/
66     }
67 
68     LV_PROFILER_DRAW_BEGIN;
69 
70     lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
71 
72     int32_t dash_width = dsc->dash_width;
73     int32_t dash_gap = dsc->dash_gap;
74     int32_t dash_l = dash_width + dash_gap;
75 
76     float dx = p2_x - p1_x;
77     float dy = p2_y - p1_y;
78     float inv_dl = math_fast_inv_sqrtf(SQ(dx) + SQ(dy));
79     float w_dx = dsc->width * dy * inv_dl;
80     float w_dy = dsc->width * dx * inv_dl;
81     float w2_dx = w_dx / 2;
82     float w2_dy = w_dy / 2;
83 
84     int32_t ndash = 0;
85     if(dash_width && dash_l * inv_dl < 1.0f) {
86         ndash = (int32_t)((1.0f / inv_dl + dash_l - 1) / dash_l);
87     }
88 
89     lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_FP32);
90     lv_vg_lite_path_set_bounding_box_area(path, &rel_clip_area);
91 
92     /* head point */
93     float head_start_x = p1_x + w2_dx;
94     float head_start_y = p1_y - w2_dy;
95     float head_end_x = p1_x - w2_dx;
96     float head_end_y = p1_y + w2_dy;
97 
98     /* tail point */
99     float tail_start_x = p2_x - w2_dx;
100     float tail_start_y = p2_y + w2_dy;
101     float tail_end_x = p2_x + w2_dx;
102     float tail_end_y = p2_y - w2_dy;
103 
104     /*
105           head_start        tail_end
106               *-----------------*
107              /|                 |\
108             / |                 | \
109     arc_c *(  *p1             p2*  )* arc_c
110             \ |                 | /
111              \|                 |/
112               *-----------------*
113           head_end          tail_start
114     */
115 
116     /* move to start point */
117     lv_vg_lite_path_move_to(path, head_start_x, head_start_y);
118 
119     /* draw line head */
120     if(dsc->round_start) {
121         float arc_cx = p1_x - w2_dy;
122         float arc_cy = p1_y - w2_dx;
123 
124         /* start 90deg arc */
125         lv_vg_lite_path_append_arc_right_angle(path,
126                                                head_start_x, head_start_y,
127                                                p1_x, p1_y,
128                                                arc_cx, arc_cy);
129 
130         /* end 90deg arc */
131         lv_vg_lite_path_append_arc_right_angle(path,
132                                                arc_cx, arc_cy,
133                                                p1_x, p1_y,
134                                                head_end_x, head_end_y);
135     }
136     else {
137         lv_vg_lite_path_line_to(path, head_end_x, head_end_y);
138     }
139 
140     /* draw line body */
141     lv_vg_lite_path_line_to(path, tail_start_x, tail_start_y);
142 
143     /* draw line tail */
144     if(dsc->round_end) {
145         float arc_cx = p2_x + w2_dy;
146         float arc_cy = p2_y + w2_dx;
147         lv_vg_lite_path_append_arc_right_angle(path,
148                                                tail_start_x, tail_start_y,
149                                                p2_x, p2_y,
150                                                arc_cx, arc_cy);
151         lv_vg_lite_path_append_arc_right_angle(path,
152                                                arc_cx, arc_cy,
153                                                p2_x, p2_y,
154                                                tail_end_x, tail_end_y);
155     }
156     else {
157         lv_vg_lite_path_line_to(path, tail_end_x, tail_end_y);
158     }
159 
160     /* close draw line body */
161     lv_vg_lite_path_line_to(path, head_start_x, head_start_y);
162 
163     for(int32_t i = 0; i < ndash; i++) {
164         float start_x = p1_x - w2_dx + dx * (i * dash_l + dash_width) * inv_dl;
165         float start_y = p1_y + w2_dy + dy * (i * dash_l + dash_width) * inv_dl;
166 
167         lv_vg_lite_path_move_to(path, start_x, start_y);
168         lv_vg_lite_path_line_to(path,
169                                 p1_x + w2_dx + dx * (i * dash_l + dash_width) * inv_dl,
170                                 p1_y - w2_dy + dy * (i * dash_l + dash_width) * inv_dl);
171         lv_vg_lite_path_line_to(path,
172                                 p1_x + w2_dx + dx * (i + 1) * dash_l * inv_dl,
173                                 p1_y - w2_dy + dy * (i + 1) * dash_l * inv_dl);
174         lv_vg_lite_path_line_to(path,
175                                 p1_x - w2_dx + dx * (i + 1) * dash_l * inv_dl,
176                                 p1_y + w2_dy + dy * (i + 1) * dash_l * inv_dl);
177         lv_vg_lite_path_line_to(path, start_x, start_y);
178     }
179 
180     lv_vg_lite_path_end(path);
181 
182     vg_lite_matrix_t matrix = u->global_matrix;
183 
184     vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
185 
186     vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
187 
188     LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
189     LV_VG_LITE_ASSERT_PATH(vg_lite_path);
190     LV_VG_LITE_ASSERT_MATRIX(&matrix);
191 
192     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw");
193     LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
194                                &u->target_buffer,
195                                vg_lite_path,
196                                VG_LITE_FILL_EVEN_ODD,
197                                &matrix,
198                                VG_LITE_BLEND_SRC_OVER,
199                                color));
200     LV_PROFILER_DRAW_END_TAG("vg_lite_draw");
201 
202     lv_vg_lite_path_drop(u, path);
203 
204     LV_PROFILER_DRAW_END;
205 }
206 
207 /**********************
208  *   STATIC FUNCTIONS
209  **********************/
210 
211 #endif /*LV_USE_DRAW_VG_LITE*/
212