1 /**
2  * @file lv_draw_vglite_fill.c
3  *
4  */
5 
6 /**
7  * Copyright 2020-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 
25 /*********************
26  *      DEFINES
27  *********************/
28 
29 /**********************
30  *      TYPEDEFS
31  **********************/
32 
33 /**********************
34  *  STATIC PROTOTYPES
35  **********************/
36 
37 /**
38  * Fill area, with optional opacity.
39  *
40  * @param[in] dest_area Area with relative coordinates of destination buffer
41  * @param[in] dsc Description of the area to fill (color, opa)
42  *
43  */
44 static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * dsc);
45 
46 /**
47  * Draw rectangle background with effects (rounded corners, gradient)
48  *
49  * @param[in] coords Coordinates of the rectangle background (relative to dest buff)
50  * @param[in] clip_area Clip area with relative coordinates to dest buff
51  * @param[in] dsc Description of the rectangle background
52  *
53  */
54 static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_area,
55                               const lv_draw_fill_dsc_t * dsc);
56 
57 /**********************
58  *  STATIC VARIABLES
59  **********************/
60 
61 /**********************
62  *      MACROS
63  **********************/
64 
65 /**********************
66  *   GLOBAL FUNCTIONS
67  **********************/
68 
lv_draw_vglite_fill(lv_draw_unit_t * draw_unit,const lv_draw_fill_dsc_t * dsc,const lv_area_t * coords)69 void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
70                          const lv_area_t * coords)
71 {
72     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
73         return;
74 
75     lv_layer_t * layer = draw_unit->target_layer;
76     lv_area_t relative_coords;
77     lv_area_copy(&relative_coords, coords);
78     lv_area_move(&relative_coords, -layer->buf_area.x1, -layer->buf_area.y1);
79 
80     lv_area_t clip_area;
81     lv_area_copy(&clip_area, draw_unit->clip_area);
82     lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
83 
84     lv_area_t clipped_coords;
85     if(!lv_area_intersect(&clipped_coords, &relative_coords, &clip_area))
86         return; /*Fully clipped, nothing to do*/
87 
88     /*
89      * Most simple case: just a plain rectangle (no radius, no gradient)
90      */
91     if((dsc->radius == 0) && (dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE))
92         _vglite_fill(&clipped_coords, dsc);
93     else
94         _vglite_draw_rect(&relative_coords, &clip_area, dsc);
95 }
96 
97 /**********************
98  *   STATIC FUNCTIONS
99  **********************/
100 
_vglite_fill(const lv_area_t * dest_area,const lv_draw_fill_dsc_t * dsc)101 static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * dsc)
102 {
103     vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
104 
105     lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa);
106     vg_lite_color_t vgcol = vglite_get_color(col32, false);
107 
108     if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) {   /*Opaque fill*/
109         vg_lite_rectangle_t rect = {
110             .x = dest_area->x1,
111             .y = dest_area->y1,
112             .width = lv_area_get_width(dest_area),
113             .height = lv_area_get_height(dest_area)
114         };
115 
116         VGLITE_CHECK_ERROR(vg_lite_clear(vgbuf, &rect, vgcol));
117 
118         vglite_run();
119     }
120     else {   /*fill with transparency*/
121 
122         vg_lite_path_t path;
123         int32_t path_data[] = { /*VG rectangular path*/
124             VLC_OP_MOVE, dest_area->x1,  dest_area->y1,
125             VLC_OP_LINE, dest_area->x2 + 1,  dest_area->y1,
126             VLC_OP_LINE, dest_area->x2 + 1,  dest_area->y2 + 1,
127             VLC_OP_LINE, dest_area->x1,  dest_area->y2 + 1,
128             VLC_OP_LINE, dest_area->x1,  dest_area->y1,
129             VLC_OP_END
130         };
131 
132         VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_MEDIUM, sizeof(path_data), path_data,
133                                              (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1,
134                                              ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f));
135 
136         /*Draw rectangle*/
137         VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
138 
139         vglite_run();
140 
141         VGLITE_CHECK_ERROR(vg_lite_clear_path(&path));
142     }
143 }
144 
_vglite_draw_rect(const lv_area_t * coords,const lv_area_t * clip_area,const lv_draw_fill_dsc_t * dsc)145 static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_area,
146                               const lv_draw_fill_dsc_t * dsc)
147 {
148     int32_t width = lv_area_get_width(coords);
149     int32_t height = lv_area_get_height(coords);
150     int32_t radius = dsc->radius;
151     lv_opa_t opa = dsc->opa;
152     vg_lite_buffer_t * vgbuf = vglite_get_dest_buf();
153 
154     if(dsc->radius < 0)
155         return;
156 
157     /*** Init path ***/
158     int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
159     uint32_t path_data_size;
160     vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
161     vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM;
162 
163     vg_lite_path_t path;
164     VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
165                                          (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
166                                          ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f));
167 
168     /*** Init Color ***/
169     lv_color32_t col32 = lv_color_to_32(dsc->color, opa);
170     vg_lite_color_t vgcol = vglite_get_color(col32, false);
171 
172     vg_lite_linear_gradient_t gradient;
173     bool has_gradient = (dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE);
174 
175     /*** Init Gradient ***/
176     if(has_gradient) {
177         vg_lite_matrix_t * grad_matrix;
178 
179         vg_lite_uint32_t colors[LV_GRADIENT_MAX_STOPS];
180         vg_lite_uint32_t stops[LV_GRADIENT_MAX_STOPS];
181         lv_color32_t col32[LV_GRADIENT_MAX_STOPS];
182 
183         /* Gradient setup */
184         vg_lite_uint32_t cnt = LV_MAX(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS);
185         lv_opa_t opa;
186 
187         for(uint8_t i = 0; i < cnt; i++) {
188             stops[i] = dsc->grad.stops[i].frac;
189 
190             opa = LV_OPA_MIX2(dsc->grad.stops[i].opa, dsc->opa);
191 
192             col32[i] = lv_color_to_32(dsc->grad.stops[i].color, opa);
193             colors[i] = vglite_get_color(col32[i], true);
194         }
195 
196         lv_memzero(&gradient, sizeof(vg_lite_linear_gradient_t));
197 
198         VGLITE_CHECK_ERROR(vg_lite_init_grad(&gradient));
199 
200         VGLITE_CHECK_ERROR(vg_lite_set_grad(&gradient, cnt, colors, stops));
201 
202         VGLITE_CHECK_ERROR(vg_lite_update_grad(&gradient));
203 
204         grad_matrix = vg_lite_get_grad_matrix(&gradient);
205         vg_lite_identity(grad_matrix);
206         vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix);
207 
208         if(dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
209             vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix);
210             vg_lite_rotate(90.0f, grad_matrix);
211         }
212         else {   /*LV_GRAD_DIR_HOR*/
213             vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix);
214         }
215 
216         VGLITE_CHECK_ERROR(vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, NULL, &gradient,
217                                                  VG_LITE_BLEND_SRC_OVER));
218     }
219     else {
220         VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, NULL, VG_LITE_BLEND_SRC_OVER, vgcol));
221     }
222 
223     vglite_run();
224 
225     VGLITE_CHECK_ERROR(vg_lite_clear_path(&path));
226 
227     if(has_gradient)
228         VGLITE_CHECK_ERROR(vg_lite_clear_grad(&gradient));
229 }
230 
231 #endif /*LV_USE_DRAW_VGLITE*/
232