1 #include "lv_draw_dave2d.h"
2 #if LV_USE_DRAW_DAVE2D
3 
4 #include "../../../misc/lv_area_private.h"
5 
6 static void dave2d_draw_border_complex(lv_draw_dave2d_unit_t * draw_unit, const lv_area_t * outer_area,
7                                        const lv_area_t * inner_area,
8                                        int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa);
9 
10 static void dave2d_draw_border_simple(lv_draw_dave2d_unit_t * draw_unit, const lv_area_t * outer_area,
11                                       const lv_area_t * inner_area,
12                                       lv_color_t color, lv_opa_t opa);
13 
lv_draw_dave2d_border(lv_draw_dave2d_unit_t * draw_unit,const lv_draw_border_dsc_t * dsc,const lv_area_t * coords)14 void lv_draw_dave2d_border(lv_draw_dave2d_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc,
15                            const lv_area_t * coords)
16 {
17     if(dsc->opa <= LV_OPA_MIN) return;
18     if(dsc->width == 0) return;
19     if(dsc->side == LV_BORDER_SIDE_NONE) return;
20 
21     int32_t coords_w = lv_area_get_width(coords);
22     int32_t coords_h = lv_area_get_height(coords);
23     int32_t rout = dsc->radius;
24     int32_t short_side = LV_MIN(coords_w, coords_h);
25     if(rout > short_side >> 1) rout = short_side >> 1;
26 
27     /*Get the inner area*/
28     lv_area_t area_inner;
29     lv_area_copy(&area_inner, coords);
30     area_inner.x1 += ((dsc->side & LV_BORDER_SIDE_LEFT) ? dsc->width : - (dsc->width + rout));
31     area_inner.x2 -= ((dsc->side & LV_BORDER_SIDE_RIGHT) ? dsc->width : - (dsc->width + rout));
32     area_inner.y1 += ((dsc->side & LV_BORDER_SIDE_TOP) ? dsc->width : - (dsc->width + rout));
33     area_inner.y2 -= ((dsc->side & LV_BORDER_SIDE_BOTTOM) ? dsc->width : - (dsc->width + rout));
34 
35     int32_t rin = rout - dsc->width;
36     if(rin < 0) rin = 0;
37 
38     if(rout == 0 && rin == 0) {
39         dave2d_draw_border_simple(draw_unit, coords, &area_inner, dsc->color, dsc->opa);
40     }
41     else {
42         dave2d_draw_border_complex(draw_unit, coords, &area_inner, rout, rin, dsc->color, dsc->opa);
43     }
44 
45 }
46 
dave2d_draw_border_simple(lv_draw_dave2d_unit_t * u,const lv_area_t * outer_area,const lv_area_t * inner_area,lv_color_t color,lv_opa_t opa)47 static void dave2d_draw_border_simple(lv_draw_dave2d_unit_t * u, const lv_area_t * outer_area,
48                                       const lv_area_t * inner_area,
49                                       lv_color_t color, lv_opa_t opa)
50 
51 {
52 
53     lv_area_t clip_area;
54     lv_area_t local_outer_area;
55     lv_area_t local_inner_area;
56     int32_t x;
57     int32_t y;
58     bool is_common;
59 
60     is_common = lv_area_intersect(&clip_area, outer_area, u->base_unit.clip_area);
61     if(!is_common) return;
62 
63 #if LV_USE_OS
64     lv_result_t  status;
65     status = lv_mutex_lock(u->pd2Mutex);
66     LV_ASSERT(LV_RESULT_OK == status);
67 #endif
68 
69     local_outer_area = *outer_area;
70     local_inner_area = *inner_area;
71 
72     x = 0 - u->base_unit.target_layer->buf_area.x1;
73     y = 0 - u->base_unit.target_layer->buf_area.y1;
74 
75     lv_area_move(&clip_area, x, y);
76     lv_area_move(&local_outer_area, x, y);
77     lv_area_move(&local_inner_area, x, y);
78 
79 #if D2_RENDER_EACH_OPERATION
80     d2_selectrenderbuffer(u->d2_handle, u->renderbuffer);
81 #endif
82     //
83     // Generate render operations
84     //
85 
86     d2_framebuffer_from_layer(u->d2_handle, u->base_unit.target_layer);
87 
88     d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color));
89     d2_setalpha(u->d2_handle, opa);
90     d2_cliprect(u->d2_handle, (d2_border)clip_area.x1, (d2_border)clip_area.y1, (d2_border)clip_area.x2,
91                 (d2_border)clip_area.y2);
92 
93     lv_area_t a;
94 
95     bool top_side = local_outer_area.y1 <= local_inner_area.y1;
96     bool bottom_side = local_outer_area.y2 >= local_inner_area.y2;
97     bool left_side = local_outer_area.x1 <= local_inner_area.x1;
98     bool right_side = local_outer_area.x2 >= local_inner_area.x2;
99 
100     /*Top*/
101     a.x1 = local_outer_area.x1;
102     a.x2 = local_outer_area.x2;
103     a.y1 = local_outer_area.y1;
104     a.y2 = local_inner_area.y1 - 1;
105     if(top_side) {
106         d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
107                      (d2_point)D2_FIX4(a.y1),
108                      (d2_point)D2_FIX4(lv_area_get_width(&a)),
109                      (d2_point)D2_FIX4(lv_area_get_height(&a)));
110     }
111 
112     /*Bottom*/
113     a.y1 = local_inner_area.y2 + 1;
114     a.y2 = local_outer_area.y2;
115     if(bottom_side) {
116         d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
117                      (d2_point)D2_FIX4(a.y1),
118                      (d2_point)D2_FIX4(lv_area_get_width(&a)),
119                      (d2_point)D2_FIX4(lv_area_get_height(&a)));
120     }
121 
122     /*Left*/
123     a.x1 = local_outer_area.x1;
124     a.x2 = local_inner_area.x1 - 1;
125     a.y1 = (top_side) ? local_inner_area.y1 : local_outer_area.y1;
126     a.y2 = (bottom_side) ? local_inner_area.y2 : local_outer_area.y2;
127     if(left_side) {
128         d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
129                      (d2_point)D2_FIX4(a.y1),
130                      (d2_point)D2_FIX4(lv_area_get_width(&a)),
131                      (d2_point)D2_FIX4(lv_area_get_height(&a)));
132     }
133 
134     /*Right*/
135     a.x1 = local_inner_area.x2 + 1;
136     a.x2 = local_outer_area.x2;
137     if(right_side) {
138         d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1),
139                      (d2_point)D2_FIX4(a.y1),
140                      (d2_point)D2_FIX4(lv_area_get_width(&a)),
141                      (d2_point)D2_FIX4(lv_area_get_height(&a)));
142     }
143 
144     //
145     // Execute render operations
146     //
147 #if D2_RENDER_EACH_OPERATION
148     d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0);
149     d2_flushframe(u->d2_handle);
150 #endif
151 
152 #if LV_USE_OS
153     status = lv_mutex_unlock(u->pd2Mutex);
154     LV_ASSERT(LV_RESULT_OK == status);
155 #endif
156 }
157 
dave2d_draw_border_complex(lv_draw_dave2d_unit_t * u,const lv_area_t * orig_outer_area,const lv_area_t * orig_inner_area,int32_t rout,int32_t rin,lv_color_t color,lv_opa_t opa)158 static void dave2d_draw_border_complex(lv_draw_dave2d_unit_t * u, const lv_area_t * orig_outer_area,
159                                        const lv_area_t * orig_inner_area,
160                                        int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa)
161 {
162     /*Get clipped draw area which is the real draw area.
163      *It is always the same or inside `coords`*/
164     lv_area_t draw_area;
165     lv_area_t outer_area;
166     lv_area_t inner_area;
167     int32_t x;
168     int32_t y;
169     d2_s32 result;
170     d2_u32 flags = 0;
171 
172     outer_area = *orig_outer_area;
173     inner_area = *orig_inner_area;
174 
175     if(!lv_area_intersect(&draw_area, &outer_area, u->base_unit.clip_area)) return;
176 
177 #if LV_USE_OS
178     lv_result_t  status;
179     status = lv_mutex_lock(u->pd2Mutex);
180     LV_ASSERT(LV_RESULT_OK == status);
181 #endif
182 
183     x = 0 - u->base_unit.target_layer->buf_area.x1;
184     y = 0 - u->base_unit.target_layer->buf_area.y1;
185 
186     lv_area_move(&draw_area, x, y);
187     lv_area_move(&outer_area, x, y);
188     lv_area_move(&inner_area, x, y);
189 
190 #if D2_RENDER_EACH_OPERATION
191     d2_selectrenderbuffer(u->d2_handle, u->renderbuffer);
192 #endif
193     //
194     // Generate render operations
195     //
196 
197     d2_framebuffer_from_layer(u->d2_handle, u->base_unit.target_layer);
198 
199     d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color));
200     d2_setalpha(u->d2_handle, opa);
201     d2_cliprect(u->d2_handle, (d2_border)draw_area.x1, (d2_border)draw_area.y1, (d2_border)draw_area.x2,
202                 (d2_border)draw_area.y2);
203 
204     lv_area_t blend_area;
205     /*Calculate the x and y coordinates where the straight parts area are */
206     lv_area_t core_area;
207     core_area.x1 = LV_MAX(outer_area.x1 + rout, inner_area.x1);
208     core_area.x2 = LV_MIN(outer_area.x2 - rout, inner_area.x2);
209     core_area.y1 = LV_MAX(outer_area.y1 + rout, inner_area.y1);
210     core_area.y2 = LV_MIN(outer_area.y2 - rout, inner_area.y2);
211 
212     bool top_side = outer_area.y1 <= inner_area.y1;
213     bool bottom_side = outer_area.y2 >= inner_area.y2;
214 
215     /*No masks*/
216     bool left_side = outer_area.x1 <= inner_area.x1;
217     bool right_side = outer_area.x2 >= inner_area.x2;
218 
219     /*Draw the straight lines first */
220     if(top_side) {
221         blend_area.x1 = core_area.x1;
222         blend_area.x2 = core_area.x2;
223         blend_area.y1 = outer_area.y1;
224         blend_area.y2 = inner_area.y1 - 1;
225         d2_renderbox(u->d2_handle,
226                      (d2_point)D2_FIX4(blend_area.x1),
227                      (d2_point)D2_FIX4(blend_area.y1),
228                      (d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
229                      (d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
230     }
231 
232     if(bottom_side) {
233         blend_area.x1 = core_area.x1;
234         blend_area.x2 = core_area.x2;
235         blend_area.y1 = inner_area.y2 + 1;
236         blend_area.y2 = outer_area.y2;
237         d2_renderbox(u->d2_handle,
238                      (d2_point)D2_FIX4(blend_area.x1),
239                      (d2_point)D2_FIX4(blend_area.y1),
240                      (d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
241                      (d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
242     }
243 
244     if(left_side) {
245         blend_area.x1 = outer_area.x1;
246         blend_area.x2 = inner_area.x1 - 1;
247         blend_area.y1 = core_area.y1;
248         blend_area.y2 = core_area.y2;
249         d2_renderbox(u->d2_handle,
250                      (d2_point)D2_FIX4(blend_area.x1),
251                      (d2_point)D2_FIX4(blend_area.y1),
252                      (d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
253                      (d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
254     }
255 
256     if(right_side) {
257         blend_area.x1 = inner_area.x2 + 1;
258         blend_area.x2 = outer_area.x2;
259         blend_area.y1 = core_area.y1;
260         blend_area.y2 = core_area.y2;
261         d2_renderbox(u->d2_handle,
262                      (d2_point)D2_FIX4(blend_area.x1),
263                      (d2_point)D2_FIX4(blend_area.y1),
264                      (d2_point)D2_FIX4(lv_area_get_width(&blend_area)),
265                      (d2_point)D2_FIX4(lv_area_get_height(&blend_area)));
266     }
267 
268     /*Draw the corners*/
269     int32_t blend_w;
270     /*Left corners*/
271     blend_area.x1 = draw_area.x1;
272     blend_area.x2 = LV_MIN(draw_area.x2, core_area.x1 - 1);
273 
274     blend_w = lv_area_get_width(&blend_area);
275 
276     if(blend_w > 0) {
277         d2_s32 aa;
278         aa = d2_getantialiasing(u->d2_handle);
279         d2_setantialiasing(u->d2_handle, 0); //Don't blend with the background according to coverage value
280 
281         if(left_side || top_side) {
282             lv_area_t arc_area;
283             lv_area_t clip_arc;
284 
285             arc_area.x1 = core_area.x1 - rout;
286             arc_area.y1 = core_area.y1 - rout;
287             arc_area.x2 = core_area.x1;
288             arc_area.y2 = core_area.y1;
289 
290             if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
291                 d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
292                             (d2_border)clip_arc.y2);
293                 result = d2_renderwedge(u->d2_handle,
294                                         (d2_point)D2_FIX4(core_area.x1),
295                                         (d2_point) D2_FIX4(core_area.y1),
296                                         (d2_width) D2_FIX4(rout),
297                                         (d2_width) D2_FIX4((rout - rin)),
298                                         (d2_s32) D2_FIX16(0), // 180 Degrees
299                                         (d2_s32)  D2_FIX16((int16_t) -1),
300                                         (d2_s32)  D2_FIX16((int16_t) -1),//( 270 Degrees
301                                         (d2_s32) D2_FIX16(0),
302                                         flags);
303                 LV_ASSERT(D2_OK == result);
304             }
305 
306         }
307 
308         if(left_side || bottom_side) {
309             lv_area_t arc_area;
310             lv_area_t clip_arc;
311 
312             arc_area.x1 = core_area.x1 - rout;
313             arc_area.y1 = core_area.y2;
314             arc_area.x2 = core_area.x1;
315             arc_area.y2 = core_area.y2 + rout;
316 
317             if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
318 
319                 d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
320                             (d2_border)clip_arc.y2);
321                 result = d2_renderwedge(u->d2_handle,
322                                         (d2_point)D2_FIX4(core_area.x1),
323                                         (d2_point) D2_FIX4(core_area.y2),
324                                         (d2_width) D2_FIX4(rout),
325                                         (d2_width) D2_FIX4((rout - rin)),
326                                         (d2_s32) D2_FIX16((int16_t) -1), //90 degrees
327                                         (d2_s32)  D2_FIX16(0),
328                                         (d2_s32)  D2_FIX16(0), //180 degrees
329                                         (d2_s32) D2_FIX16(1),
330                                         flags);
331                 LV_ASSERT(D2_OK == result);
332             }
333         }
334 
335         /*Right corners*/
336         blend_area.x1 = LV_MAX(draw_area.x1, blend_area.x2 + 1);    /*To not overlap with the left side*/
337         blend_area.x1 = LV_MAX(draw_area.x1, core_area.x2 + 1);
338 
339         blend_area.x2 = draw_area.x2;
340         blend_w = lv_area_get_width(&blend_area);
341 
342         if(blend_w > 0) {
343             if(right_side || top_side) {
344 
345                 lv_area_t arc_area;
346                 lv_area_t clip_arc;
347 
348                 arc_area.x1 = core_area.x2;
349                 arc_area.y1 = core_area.y1 - rout;
350                 arc_area.x2 = core_area.x2 + rout;
351                 arc_area.y2 = core_area.y1;
352 
353                 if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
354 
355                     d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
356                                 (d2_border)clip_arc.y2);
357                     result = d2_renderwedge(u->d2_handle,
358                                             (d2_point)D2_FIX4(core_area.x2),
359                                             (d2_point) D2_FIX4(core_area.y1),
360                                             (d2_width) D2_FIX4(rout),
361                                             (d2_width) D2_FIX4((rout - rin)),
362                                             (d2_s32) D2_FIX16((int16_t)1), // 270 Degrees
363                                             (d2_s32)  D2_FIX16(0),
364                                             (d2_s32)  D2_FIX16(0),// 0 degrees
365                                             (d2_s32) D2_FIX16(-1),
366                                             flags);
367                     LV_ASSERT(D2_OK == result);
368                 }
369 
370             }
371 
372             if(right_side || bottom_side) {
373                 lv_area_t arc_area;
374                 lv_area_t clip_arc;
375 
376                 arc_area.x1 = core_area.x2;
377                 arc_area.y1 = core_area.y2;
378                 arc_area.x2 = core_area.x2 + rout;
379                 arc_area.y2 = core_area.y2 + rout;
380 
381                 if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) {
382 
383                     d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2,
384                                 (d2_border)clip_arc.y2);
385                     result = d2_renderwedge(u->d2_handle,
386                                             (d2_point)D2_FIX4(core_area.x2),
387                                             (d2_point) D2_FIX4(core_area.y2),
388                                             (d2_width) D2_FIX4(rout),
389                                             (d2_width) D2_FIX4((rout - rin)),
390                                             (d2_s32) D2_FIX16(0),// 0 degrees
391                                             (d2_s32)  D2_FIX16(1),
392                                             (d2_s32)  D2_FIX16(1),// 90 degrees
393                                             (d2_s32) D2_FIX16(0),
394                                             flags);
395                     LV_ASSERT(D2_OK == result);
396                 }
397             }
398         }
399         d2_setantialiasing(u->d2_handle, aa); //restore original setting
400     }
401 
402     //
403     // Execute render operations
404     //
405 #if D2_RENDER_EACH_OPERATION
406     d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0);
407     d2_flushframe(u->d2_handle);
408 #endif
409 
410 #if LV_USE_OS
411     status = lv_mutex_unlock(u->pd2Mutex);
412     LV_ASSERT(LV_RESULT_OK == status);
413 #endif
414 
415 }
416 
417 #endif /*LV_USE_DRAW_DAVE2D*/
418