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