1 /**
2  * @file lv_draw_mask.h
3  *
4  */
5 
6 #ifndef LV_DRAW_MASK_H
7 #define LV_DRAW_MASK_H
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 /*********************
14  *      INCLUDES
15  *********************/
16 #include <stdbool.h>
17 #include "../misc/lv_area.h"
18 #include "../misc/lv_color.h"
19 #include "../misc/lv_math.h"
20 
21 /*********************
22  *      DEFINES
23  *********************/
24 #define LV_MASK_ID_INV  (-1)
25 #if LV_DRAW_COMPLEX
26 # define _LV_MASK_MAX_NUM     16
27 #else
28 # define _LV_MASK_MAX_NUM     1
29 #endif
30 
31 /**********************
32  *      TYPEDEFS
33  **********************/
34 
35 enum {
36     LV_DRAW_MASK_RES_TRANSP,
37     LV_DRAW_MASK_RES_FULL_COVER,
38     LV_DRAW_MASK_RES_CHANGED,
39     LV_DRAW_MASK_RES_UNKNOWN
40 };
41 
42 typedef uint8_t lv_draw_mask_res_t;
43 
44 typedef struct {
45     void * param;
46     void * custom_id;
47 } _lv_draw_mask_saved_t;
48 
49 typedef _lv_draw_mask_saved_t _lv_draw_mask_saved_arr_t[_LV_MASK_MAX_NUM];
50 
51 #if LV_DRAW_COMPLEX == 0
lv_draw_mask_get_cnt(void)52 static inline  uint8_t lv_draw_mask_get_cnt(void)
53 {
54     return 0;
55 }
56 
lv_draw_mask_is_any(const lv_area_t * a)57 static inline bool lv_draw_mask_is_any(const lv_area_t * a)
58 {
59     LV_UNUSED(a);
60     return false;
61 }
62 
63 #endif
64 
65 #if LV_DRAW_COMPLEX
66 
67 enum {
68     LV_DRAW_MASK_TYPE_LINE,
69     LV_DRAW_MASK_TYPE_ANGLE,
70     LV_DRAW_MASK_TYPE_RADIUS,
71     LV_DRAW_MASK_TYPE_FADE,
72     LV_DRAW_MASK_TYPE_MAP,
73     LV_DRAW_MASK_TYPE_POLYGON,
74 };
75 
76 typedef uint8_t lv_draw_mask_type_t;
77 
78 enum {
79     LV_DRAW_MASK_LINE_SIDE_LEFT = 0,
80     LV_DRAW_MASK_LINE_SIDE_RIGHT,
81     LV_DRAW_MASK_LINE_SIDE_TOP,
82     LV_DRAW_MASK_LINE_SIDE_BOTTOM,
83 };
84 
85 /**
86  * A common callback type for every mask type.
87  * Used internally by the library.
88  */
89 typedef lv_draw_mask_res_t (*lv_draw_mask_xcb_t)(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
90                                                  lv_coord_t len,
91                                                  void * p);
92 
93 typedef uint8_t lv_draw_mask_line_side_t;
94 
95 typedef struct {
96     lv_draw_mask_xcb_t cb;
97     lv_draw_mask_type_t type;
98 } _lv_draw_mask_common_dsc_t;
99 
100 typedef struct {
101     /*The first element must be the common descriptor*/
102     _lv_draw_mask_common_dsc_t dsc;
103 
104     struct {
105         /*First point*/
106         lv_point_t p1;
107 
108         /*Second point*/
109         lv_point_t p2;
110 
111         /*Which side to keep?*/
112         lv_draw_mask_line_side_t side : 2;
113     } cfg;
114 
115     /*A point of the line*/
116     lv_point_t origo;
117 
118     /*X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/
119     int32_t xy_steep;
120 
121     /*Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/
122     int32_t yx_steep;
123 
124     /*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines*/
125     int32_t steep;
126 
127     /*Steepness in 1 px in 0..255 range. Used only by flat lines.*/
128     int32_t spx;
129 
130     /*1: It's a flat line? (Near to horizontal)*/
131     uint8_t flat : 1;
132 
133     /*Invert the mask. The default is: Keep the left part.
134      *It is used to select left/right/top/bottom*/
135     uint8_t inv: 1;
136 } lv_draw_mask_line_param_t;
137 
138 typedef struct {
139     /*The first element must be the common descriptor*/
140     _lv_draw_mask_common_dsc_t dsc;
141 
142     struct {
143         lv_point_t vertex_p;
144         lv_coord_t start_angle;
145         lv_coord_t end_angle;
146     } cfg;
147 
148     lv_draw_mask_line_param_t start_line;
149     lv_draw_mask_line_param_t end_line;
150     uint16_t delta_deg;
151 } lv_draw_mask_angle_param_t;
152 
153 typedef struct  {
154     uint8_t * buf;
155     lv_opa_t * cir_opa;         /*Opacity of values on the circumference of an 1/4 circle*/
156     uint16_t * x_start_on_y;        /*The x coordinate of the circle for each y value*/
157     uint16_t * opa_start_on_y;      /*The index of `cir_opa` for each y value*/
158     int32_t life;               /*How many times the entry way used*/
159     uint32_t used_cnt;          /*Like a semaphore to count the referencing masks*/
160     lv_coord_t radius;          /*The radius of the entry*/
161 } _lv_draw_mask_radius_circle_dsc_t;
162 
163 typedef _lv_draw_mask_radius_circle_dsc_t _lv_draw_mask_radius_circle_dsc_arr_t[LV_CIRCLE_CACHE_SIZE];
164 
165 typedef struct {
166     /*The first element must be the common descriptor*/
167     _lv_draw_mask_common_dsc_t dsc;
168 
169     struct {
170         lv_area_t rect;
171         lv_coord_t radius;
172         /*Invert the mask. 0: Keep the pixels inside.*/
173         uint8_t outer: 1;
174     } cfg;
175 
176     _lv_draw_mask_radius_circle_dsc_t * circle;
177 } lv_draw_mask_radius_param_t;
178 
179 typedef struct {
180     /*The first element must be the common descriptor*/
181     _lv_draw_mask_common_dsc_t dsc;
182 
183     struct {
184         lv_area_t coords;
185         lv_coord_t y_top;
186         lv_coord_t y_bottom;
187         lv_opa_t opa_top;
188         lv_opa_t opa_bottom;
189     } cfg;
190 
191 } lv_draw_mask_fade_param_t;
192 
193 typedef struct _lv_draw_mask_map_param_t {
194     /*The first element must be the common descriptor*/
195     _lv_draw_mask_common_dsc_t dsc;
196 
197     struct {
198         lv_area_t coords;
199         const lv_opa_t * map;
200     } cfg;
201 } lv_draw_mask_map_param_t;
202 
203 typedef struct {
204     /*The first element must be the common descriptor*/
205     _lv_draw_mask_common_dsc_t dsc;
206 
207     struct {
208         lv_point_t * points;
209         uint16_t point_cnt;
210     } cfg;
211 } lv_draw_mask_polygon_param_t;
212 
213 /**********************
214  * GLOBAL PROTOTYPES
215  **********************/
216 
217 /**
218  * Add a draw mask. Everything drawn after it (until removing the mask) will be affected by the mask.
219  * @param param an initialized mask parameter. Only the pointer is saved.
220  * @param custom_id a custom pointer to identify the mask. Used in `lv_draw_mask_remove_custom`.
221  * @return the an integer, the ID of the mask. Can be used in `lv_draw_mask_remove_id`.
222  */
223 int16_t lv_draw_mask_add(void * param, void * custom_id);
224 
225 //! @cond Doxygen_Suppress
226 
227 /**
228  * Apply the added buffers on a line. Used internally by the library's drawing routines.
229  * @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`.
230  * @param abs_x absolute X coordinate where the line to calculate start
231  * @param abs_y absolute Y coordinate where the line to calculate start
232  * @param len length of the line to calculate (in pixel count)
233  * @return One of these values:
234  * - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero
235  * - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged
236  * - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line
237  */
238 lv_draw_mask_res_t /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x,
239                                                                   lv_coord_t abs_y, lv_coord_t len);
240 
241 /**
242  * Apply the specified buffers on a line. Used internally by the library's drawing routines.
243  * @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`.
244  * @param abs_x absolute X coordinate where the line to calculate start
245  * @param abs_y absolute Y coordinate where the line to calculate start
246  * @param len length of the line to calculate (in pixel count)
247  * @param ids ID array of added buffers
248  * @param ids_count number of ID array
249  * @return One of these values:
250  * - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero
251  * - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged
252  * - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line
253  */
254 lv_draw_mask_res_t /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_mask_apply_ids(lv_opa_t * mask_buf, lv_coord_t abs_x,
255                                                                       lv_coord_t abs_y, lv_coord_t len,
256                                                                       const int16_t * ids, int16_t ids_count);
257 
258 //! @endcond
259 
260 /**
261  * Remove a mask with a given ID
262  * @param id the ID of the mask.  Returned by `lv_draw_mask_add`
263  * @return the parameter of the removed mask.
264  * If more masks have `custom_id` ID then the last mask's parameter will be returned
265  */
266 void * lv_draw_mask_remove_id(int16_t id);
267 
268 /**
269  * Remove all mask with a given custom ID
270  * @param custom_id a pointer used in `lv_draw_mask_add`
271  * @return return the parameter of the removed mask.
272  * If more masks have `custom_id` ID then the last mask's parameter will be returned
273  */
274 void * lv_draw_mask_remove_custom(void * custom_id);
275 
276 /**
277  * Free the data from the parameter.
278  * It's called inside `lv_draw_mask_remove_id` and `lv_draw_mask_remove_custom`
279  * Needs to be called only in special cases when the mask is not added by `lv_draw_mask_add`
280  * and not removed by `lv_draw_mask_remove_id` or `lv_draw_mask_remove_custom`
281  * @param p pointer to a mask parameter
282  */
283 void lv_draw_mask_free_param(void * p);
284 
285 /**
286  * Called by LVGL the rendering of a screen is ready to clean up
287  * the temporal (cache) data of the masks
288  */
289 void _lv_draw_mask_cleanup(void);
290 
291 //! @cond Doxygen_Suppress
292 
293 /**
294  * Count the currently added masks
295  * @return number of active masks
296  */
297 uint8_t /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_mask_get_cnt(void);
298 
299 /**
300  * Check if there is any added draw mask
301  * @param a     an area to test for affecting masks.
302  * @return true: there is t least 1 draw mask; false: there are no draw masks
303  */
304 bool lv_draw_mask_is_any(const lv_area_t * a);
305 
306 //! @endcond
307 
308 /**
309  *Initialize a line mask from two points.
310  * @param param pointer to a `lv_draw_mask_param_t` to initialize
311  * @param p1x X coordinate of the first point of the line
312  * @param p1y Y coordinate of the first point of the line
313  * @param p2x X coordinate of the second point of the line
314  * @param p2y y coordinate of the second point of the line
315  * @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep.
316  * With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept
317  * With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept
318  */
319 void lv_draw_mask_line_points_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x,
320                                    lv_coord_t p2y, lv_draw_mask_line_side_t side);
321 
322 /**
323  *Initialize a line mask from a point and an angle.
324  * @param param pointer to a `lv_draw_mask_param_t` to initialize
325  * @param px X coordinate of a point of the line
326  * @param py X coordinate of a point of the line
327  * @param angle right 0 deg, bottom: 90
328  * @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep.
329  * With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept
330  * With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept
331  */
332 void lv_draw_mask_line_angle_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t py, int16_t angle,
333                                   lv_draw_mask_line_side_t side);
334 
335 /**
336  * Initialize an angle mask.
337  * @param param pointer to a `lv_draw_mask_param_t` to initialize
338  * @param vertex_x X coordinate of the angle vertex (absolute coordinates)
339  * @param vertex_y Y coordinate of the angle vertex (absolute coordinates)
340  * @param start_angle start angle in degrees. 0 deg on the right, 90 deg, on the bottom
341  * @param end_angle end angle
342  */
343 void lv_draw_mask_angle_init(lv_draw_mask_angle_param_t * param, lv_coord_t vertex_x, lv_coord_t vertex_y,
344                              lv_coord_t start_angle, lv_coord_t end_angle);
345 
346 /**
347  * Initialize a fade mask.
348  * @param param pointer to an `lv_draw_mask_radius_param_t` to initialize
349  * @param rect coordinates of the rectangle to affect (absolute coordinates)
350  * @param radius radius of the rectangle
351  * @param inv true: keep the pixels inside the rectangle; keep the pixels outside of the rectangle
352  */
353 void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area_t * rect, lv_coord_t radius, bool inv);
354 
355 /**
356  * Initialize a fade mask.
357  * @param param pointer to a `lv_draw_mask_param_t` to initialize
358  * @param coords coordinates of the area to affect (absolute coordinates)
359  * @param opa_top opacity on the top
360  * @param y_top at which coordinate start to change to opacity to `opa_bottom`
361  * @param opa_bottom opacity at the bottom
362  * @param y_bottom at which coordinate reach `opa_bottom`.
363  */
364 void lv_draw_mask_fade_init(lv_draw_mask_fade_param_t * param, const lv_area_t * coords, lv_opa_t opa_top,
365                             lv_coord_t y_top,
366                             lv_opa_t opa_bottom, lv_coord_t y_bottom);
367 
368 /**
369  * Initialize a map mask.
370  * @param param pointer to a `lv_draw_mask_param_t` to initialize
371  * @param coords coordinates of the map (absolute coordinates)
372  * @param map array of bytes with the mask values
373  */
374 void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map);
375 
376 void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt);
377 
378 #endif /*LV_DRAW_COMPLEX*/
379 
380 /**********************
381  *      MACROS
382  **********************/
383 
384 #ifdef __cplusplus
385 } /*extern "C"*/
386 #endif
387 
388 #endif /*LV_DRAW_MASK_H*/
389