From 1b5b2bfb4f18ac1a0e3890c62034931367b77030 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 21 Aug 2019 15:44:35 +0200 Subject: [PATCH] add real draw functions --- src/lv_core/lv_style.c | 2 +- src/lv_draw/lv_blend.c | 79 +++ src/lv_draw/{lv_blit.h => lv_blend.h} | 9 +- src/lv_draw/lv_blit.c | 46 -- src/lv_draw/lv_draw_line.c | 895 ++++++++------------------ src/lv_draw/lv_draw_rect.c | 133 ++-- src/lv_draw/lv_mask.c | 233 ++++--- src/lv_draw/lv_mask.h | 48 +- src/lv_misc/lv_color.h | 4 +- 9 files changed, 623 insertions(+), 826 deletions(-) create mode 100644 src/lv_draw/lv_blend.c rename src/lv_draw/{lv_blit.h => lv_blend.h} (67%) delete mode 100644 src/lv_draw/lv_blit.c diff --git a/src/lv_core/lv_style.c b/src/lv_core/lv_style.c index 98cab4045..f5241fb77 100644 --- a/src/lv_core/lv_style.c +++ b/src/lv_core/lv_style.c @@ -126,7 +126,7 @@ void lv_style_init(void) lv_style_pretty.text.color = lv_color_make(0x20, 0x20, 0x20); lv_style_pretty.image.color = lv_color_make(0x20, 0x20, 0x20); lv_style_pretty.line.color = lv_color_make(0x20, 0x20, 0x20); - lv_style_pretty.body.main_color = LV_COLOR_RED; + lv_style_pretty.body.main_color = LV_COLOR_WHITE; lv_style_pretty.body.grad_color = LV_COLOR_SILVER; lv_style_pretty.body.radius = LV_DPI / 15; lv_style_pretty.body.border.color = lv_color_make(0x40, 0x40, 0x40); diff --git a/src/lv_draw/lv_blend.c b/src/lv_draw/lv_blend.c new file mode 100644 index 000000000..ef1cc43e1 --- /dev/null +++ b/src/lv_draw/lv_blend.c @@ -0,0 +1,79 @@ +/** + * @file lv_blend.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_blend.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_blend_color(lv_color_t * dest_buf, lv_img_cf_t dest_cf, lv_coord_t len, + lv_color_t color, lv_img_cf_t src_cf, + lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode) +{ + if(opa < LV_OPA_MIN) return; + if(mask_res == LV_MASK_RES_FULL_TRANSP) return; + + lv_coord_t i; + if(dest_cf == LV_IMG_CF_TRUE_COLOR && src_cf == LV_IMG_CF_TRUE_COLOR) { + /*Simple fill (maybe with opacity), no masking*/ + if(mask_res == LV_MASK_RES_FULL_COVER) { + if(opa > LV_OPA_MAX) { + for(i = 0; i < len; i++) { + dest_buf[i].full = color.full; + } + } + else { + for(i = 0; i < len; i++) { + dest_buf[i] = lv_color_mix(color, dest_buf[i], opa); + } + } + } + /*Masked*/ + else { + /*Only the mask matters*/ + if(opa > LV_OPA_MAX) { + for(i = 0; i < len; i++) { + dest_buf[i] = lv_color_mix(color, dest_buf[i], mask[i]); + } + } else { + for(i = 0; i < len; i++) { + if(mask[i] > LV_OPA_MAX) { + dest_buf[i] = lv_color_mix(color, dest_buf[i], opa); + } else { + dest_buf[i] = lv_color_mix(color, dest_buf[i], (mask[i] * opa) >> 8); + } + } + } + } + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/src/lv_draw/lv_blit.h b/src/lv_draw/lv_blend.h similarity index 67% rename from src/lv_draw/lv_blit.h rename to src/lv_draw/lv_blend.h index 8693e6c0d..a745ec6d7 100644 --- a/src/lv_draw/lv_blit.h +++ b/src/lv_draw/lv_blend.h @@ -15,6 +15,8 @@ extern "C" { *********************/ #include "../lv_misc/lv_color.h" #include "../lv_misc/lv_area.h" +#include "lv_img_decoder.h" +#include "lv_mask.h" /********************* * DEFINES @@ -26,12 +28,15 @@ extern "C" { typedef enum { LV_BLIT_MODE_NORMAL, LV_BLIT_MODE_ADDITIVE, -}lv_blit_mode_t; +}lv_blend_mode_t; /********************** * GLOBAL PROTOTYPES **********************/ -void lv_blit_color(lv_color_t * dest_buf, lv_color_t * bg_buf, lv_coord_t len, lv_color_t color, lv_blit_mode_t mode); + +void lv_blend_color(lv_color_t * dest_buf, lv_img_cf_t dest_cf, lv_coord_t len, + lv_color_t color, lv_img_cf_t src_cf, + lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode); /********************** * MACROS diff --git a/src/lv_draw/lv_blit.c b/src/lv_draw/lv_blit.c deleted file mode 100644 index d102f4299..000000000 --- a/src/lv_draw/lv_blit.c +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file lv_blit.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_blit.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_blit_color(lv_color_t * dest_buf, lv_color_t * bg_buf, lv_coord_t len, lv_color_t color, lv_blit_mode_t mode) -{ - uint32_t i; - for(i = 0; i < len; i++) { - dest_buf[i].full = color.full; - } -} - - -/********************** - * STATIC FUNCTIONS - **********************/ diff --git a/src/lv_draw/lv_draw_line.c b/src/lv_draw/lv_draw_line.c index 84041ad28..a20fe0a0c 100644 --- a/src/lv_draw/lv_draw_line.c +++ b/src/lv_draw/lv_draw_line.c @@ -9,6 +9,8 @@ #include #include #include "lv_draw.h" +#include "lv_mask.h" +#include "lv_blend.h" #include "../lv_core/lv_refr.h" #include "../lv_misc/lv_math.h" @@ -20,111 +22,16 @@ * TYPEDEFS **********************/ - -/* - * 8192 -8193 -8196 -8201 -8208 -8217 -8228 -8241 -8256 -8273 -8291 -8312 -8335 -8359 -8386 -8414 -8444 -8476 -8510 -8545 -8583 -8622 -8662 -8705 -8749 -8795 -8842 -8891 -8942 -8994 -9047 -9102 -9159 -9217 -9276 -9337 -9399 -9462 -9527 -9593 -9660 -9729 -9798 -9869 -9941 -10014 -10088 -10164 -10240 -10317 -10396 -10475 -10555 -10636 -10718 -10801 -10885 -10970 -11056 -11142 -11229 -11317 -11406 -11495 -11585 - * - * - * */ - -typedef struct -{ - lv_point_t p1; - lv_point_t p2; - lv_point_t p_act; - lv_coord_t dx; - lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/ - lv_coord_t dy; - lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/ - lv_coord_t err; - lv_coord_t e2; - bool hor; /*Rather horizontal or vertical*/ -} line_draw_t; - -typedef struct -{ - lv_coord_t width; - lv_coord_t width_1; - lv_coord_t width_half; -} line_width_t; - /********************** * STATIC PROTOTYPES **********************/ -static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, - lv_opa_t opa_scale); -static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, - lv_opa_t opa_scale); -static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, - lv_opa_t opa_scale); -static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2); -static bool line_next(line_draw_t * line); -static bool line_next_y(line_draw_t * line); -static bool line_next_x(line_draw_t * line); +static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale); +static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale); +static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale); + /********************** * STATIC VARIABLES @@ -146,563 +53,285 @@ static bool line_next_x(line_draw_t * line); * @param style pointer to a line's style * @param opa_scale scale down all opacities by the factor */ -void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, - const lv_style_t * style, lv_opa_t opa_scale) +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale) { - if(style->line.width == 0) return; if(point1->x == point2->x && point1->y == point2->y) return; - /*Return if the points are out of the mask*/ - if(point1->x < mask->x1 - style->line.width && point2->x < mask->x1 - style->line.width) return; - if(point1->x > mask->x2 + style->line.width && point2->x > mask->x2 + style->line.width) return; - if(point1->y < mask->y1 - style->line.width && point2->y < mask->y1 - style->line.width) return; - if(point1->y > mask->y2 + style->line.width && point2->y > mask->y2 + style->line.width) return; - - line_draw_t main_line; - lv_point_t p1; - lv_point_t p2; - - /*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/ - - if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) { - - /*Steps less in y then x -> rather horizontal*/ - if(point1->x < point2->x) { - p1.x = point1->x; - p1.y = point1->y; - p2.x = point2->x; - p2.y = point2->y; - } else { - p1.x = point2->x; - p1.y = point2->y; - p2.x = point1->x; - p2.y = point1->y; - } - } else { - /*Steps less in x then y -> rather vertical*/ - if(point1->y < point2->y) { - p1.x = point1->x; - p1.y = point1->y; - p2.x = point2->x; - p2.y = point2->y; - } else { - p1.x = point2->x; - p1.y = point2->y; - p2.x = point1->x; - p2.y = point1->y; - } - } - - line_init(&main_line, &p1, &p2); - - /*Special case draw a horizontal line*/ - if(main_line.p1.y == main_line.p2.y) { - line_draw_hor(&main_line, mask, style, opa_scale); - } - /*Special case draw a vertical line*/ - else if(main_line.p1.x == main_line.p2.x) { - line_draw_ver(&main_line, mask, style, opa_scale); - } - /*Arbitrary skew line*/ - else { - bool dir_ori = false; -#if LV_ANTIALIAS - bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing()); - if(aa) { - lv_point_t p_tmp; - - if(main_line.hor) { - if(main_line.p1.y < main_line.p2.y) { - dir_ori = true; - p_tmp.x = main_line.p2.x; - p_tmp.y = main_line.p2.y - 1; - line_init(&main_line, &p1, &p_tmp); - main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ - } else if(main_line.p1.y > main_line.p2.y) { - dir_ori = false; - p_tmp.x = main_line.p2.x; - p_tmp.y = main_line.p2.y + 1; - line_init(&main_line, &p1, &p_tmp); - main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/ - } - } else { - if(main_line.p1.x < main_line.p2.x) { - dir_ori = true; - p_tmp.x = main_line.p2.x - 1; - p_tmp.y = main_line.p2.y; - line_init(&main_line, &p1, &p_tmp); - main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ - } else if(main_line.p1.x > main_line.p2.x) { - dir_ori = false; - p_tmp.x = main_line.p2.x + 1; - p_tmp.y = main_line.p2.y; - line_init(&main_line, &p1, &p_tmp); - main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/ - } - } - } -#endif - line_draw_skew(&main_line, dir_ori, mask, style, opa_scale); - } + if(point1->y == point2->y) draw_line_hor(point1, point2, clip, style, opa_scale); + else if(point1->x == point2->x) draw_line_ver(point1, point2, clip, style, opa_scale); + else draw_line_skew(point1, point2, clip, style, opa_scale); } /********************** * STATIC FUNCTIONS **********************/ -static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) +static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale) { - lv_coord_t width = style->line.width - 1; - lv_coord_t width_half = width >> 1; - lv_coord_t width_1 = width & 0x1; - lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8; + lv_opa_t opa = style->body.opa; - lv_area_t act_area; - act_area.x1 = main_line->p1.x; - act_area.x2 = main_line->p2.x; - act_area.y1 = main_line->p1.y - width_half - width_1; - act_area.y2 = main_line->p2.y + width_half; + /*Keep the great y in p1*/ + lv_point_t p1; + lv_point_t p2; + if(point1->y < point2->y) { + p1.y = point1->y; + p2.y = point2->y; + p1.x = point1->x; + p2.x = point2->x; + } else { + p1.y = point2->y; + p2.y = point1->y; + p1.x = point2->x; + p2.x = point1->x; + } - lv_area_t draw_area; - draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); - draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); - draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); - draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); - lv_draw_fill(&draw_area, mask, style->line.color, opa); + lv_coord_t xdiff = p2.x - p1.x; + lv_coord_t ydiff = p2.y - p1.y; + + lv_coord_t w = style->line.width - 1; + lv_coord_t w_half0 = w >> 1; + lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ + + lv_area_t draw_a; + draw_a.x1 = LV_MATH_MIN(p1.x, p2.x); + draw_a.x2 = LV_MATH_MAX(p1.x, p2.x); + draw_a.y1 = LV_MATH_MIN(p1.y, p2.y) - w_half1; + draw_a.y2 = LV_MATH_MAX(p1.y, p2.y) + w_half0; + + /* Get the union of `coords` and `clip`*/ + /* `clip` is already truncated to the `vdb` size + * in 'lv_refr_area' function */ + bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip); + + /*If there are common part of `clip` and `vdb` then draw*/ + if(union_ok == false) return; + + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); + + /*Store the coordinates of the `draw_a` relative to the VDB */ + lv_area_t draw_rel_a; + draw_rel_a.x1 = draw_a.x1 - vdb->area.x1; + draw_rel_a.y1 = draw_a.y1 - vdb->area.y1; + draw_rel_a.x2 = draw_a.x2 - vdb->area.x1; + draw_rel_a.y2 = draw_a.y2 - vdb->area.y1; + + uint32_t vdb_width = lv_area_get_width(&vdb->area); + uint32_t draw_a_width = lv_area_get_width(&draw_rel_a); + + /*Move the vdb_buf_tmp to the first row*/ + lv_color_t * vdb_buf_tmp = vdb->buf_act; + vdb_buf_tmp += vdb_width * draw_rel_a.y1; + + lv_opa_t mask_buf[LV_HOR_RES_MAX]; + + /*Draw line by line*/ + lv_coord_t h; + lv_mask_res_t mask_res; + /*Fill the first row with 'color'*/ + for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { + memset(mask_buf, LV_OPA_COVER, draw_a_width); + mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width); + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + style->line.color, LV_IMG_CF_TRUE_COLOR, + mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL); + vdb_buf_tmp += vdb_width; + } } -static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale) + +static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale) { - lv_coord_t width = style->line.width - 1; - lv_coord_t width_half = width >> 1; - lv_coord_t width_1 = width & 0x1; - lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8; + lv_opa_t opa = style->body.opa; - lv_area_t act_area; - act_area.x1 = main_line->p1.x - width_half; - act_area.x2 = main_line->p2.x + width_half + width_1; - act_area.y1 = main_line->p1.y; - act_area.y2 = main_line->p2.y; + /*Keep the great y in p1*/ + lv_point_t p1; + lv_point_t p2; + if(point1->y < point2->y) { + p1.y = point1->y; + p2.y = point2->y; + p1.x = point1->x; + p2.x = point2->x; + } else { + p1.y = point2->y; + p2.y = point1->y; + p1.x = point2->x; + p2.x = point1->x; + } - lv_area_t draw_area; - draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2); - draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2); - draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2); - draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2); - lv_draw_fill(&draw_area, mask, style->line.color, opa); + lv_coord_t w = style->line.width - 1; + lv_coord_t w_half0 = w >> 1; + lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ + + lv_area_t draw_a; + draw_a.x1 = LV_MATH_MIN(p1.x, p2.x) - w_half0; + draw_a.x2 = LV_MATH_MAX(p1.x, p2.x) + w_half1; + draw_a.y1 = LV_MATH_MIN(p1.y, p2.y); + draw_a.y2 = LV_MATH_MAX(p1.y, p2.y); + + /* Get the union of `coords` and `clip`*/ + /* `clip` is already truncated to the `vdb` size + * in 'lv_refr_area' function */ + bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip); + + /*If there are common part of `clip` and `vdb` then draw*/ + if(union_ok == false) return; + + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); + + /*Store the coordinates of the `draw_a` relative to the VDB */ + lv_area_t draw_rel_a; + draw_rel_a.x1 = draw_a.x1 - vdb->area.x1; + draw_rel_a.y1 = draw_a.y1 - vdb->area.y1; + draw_rel_a.x2 = draw_a.x2 - vdb->area.x1; + draw_rel_a.y2 = draw_a.y2 - vdb->area.y1; + + uint32_t vdb_width = lv_area_get_width(&vdb->area); + uint32_t draw_a_width = lv_area_get_width(&draw_rel_a); + + /*Move the vdb_buf_tmp to the first row*/ + lv_color_t * vdb_buf_tmp = vdb->buf_act; + vdb_buf_tmp += vdb_width * draw_rel_a.y1; + + lv_opa_t mask_buf[LV_HOR_RES_MAX]; + + /*Draw the background line by line*/ + lv_coord_t h; + lv_mask_res_t mask_res; + /*Fill the first row with 'color'*/ + for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { + memset(mask_buf, LV_OPA_COVER, draw_a_width); + mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width); + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + style->line.color, LV_IMG_CF_TRUE_COLOR, + mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL); + vdb_buf_tmp += vdb_width; + } } -static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style, - lv_opa_t opa_scale) + +static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, + const lv_style_t * style, lv_opa_t opa_scale) { + lv_opa_t opa = style->body.opa; - lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8; -#if LV_ANTIALIAS - bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing()); -#endif - lv_point_t vect_main, vect_norm; - vect_main.x = main_line->p2.x - main_line->p1.x; - vect_main.y = main_line->p2.y - main_line->p1.y; + /*Keep the great y in p1*/ + lv_point_t p1; + lv_point_t p2; + if(point1->y < point2->y) { + p1.y = point1->y; + p2.y = point2->y; + p1.x = point1->x; + p2.x = point2->x; + } else { + p1.y = point2->y; + p2.y = point1->y; + p1.x = point2->x; + p2.x = point1->x; + } - if(main_line->hor) { - if(main_line->p1.y < main_line->p2.y + dir_ori) { - vect_norm.x = -vect_main.y; - vect_norm.y = vect_main.x; + lv_coord_t xdiff = p2.x - p1.x; + lv_coord_t ydiff = p2.y - p1.y; + bool flat = LV_MATH_ABS(xdiff) > LV_MATH_ABS(ydiff) ? true : false; + + static const uint8_t wcorr[] = { + 128, 128, 128, 129, 129, 130, 130, 131, + 132, 133, 134, 135, 137, 138, 140, 141, + 143, 145, 147, 149, 151, 153, 155, 158, + 160, 162, 165, 167, 170, 173, 175, 178, + 181, + }; + + lv_coord_t w = style->line.width; + lv_coord_t wcorr_i = 0; + if(flat) wcorr_i = (LV_MATH_ABS(ydiff) << 5) / LV_MATH_ABS(xdiff); + else wcorr_i = (LV_MATH_ABS(xdiff) << 5) / LV_MATH_ABS(ydiff); + + w = (w * wcorr[wcorr_i]) >> 7; + printf("w:%d\n", w); + lv_coord_t w_half0 = w >> 1; + lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ + + lv_area_t draw_a; + draw_a.x1 = LV_MATH_MIN(p1.x, p2.x) - w; + draw_a.x2 = LV_MATH_MAX(p1.x, p2.x) + w; + draw_a.y1 = LV_MATH_MIN(p1.y, p2.y) - w; + draw_a.y2 = LV_MATH_MAX(p1.y, p2.y) + w; + + /* Get the union of `coords` and `clip`*/ + /* `clip` is already truncated to the `vdb` size + * in 'lv_refr_area' function */ + bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip); + + /*If there are common part of `clip` and `vdb` then draw*/ + if(union_ok == false) return; + + lv_mask_param_t mask_left_param; + lv_mask_param_t mask_right_param; + lv_mask_param_t mask_top_param; + lv_mask_param_t mask_bottom_param; + + if(flat) { + if(xdiff > 0) { + lv_mask_line_points_init(&mask_left_param, p1.x, p1.y - w_half0, p2.x, p2.y - w_half0, LV_LINE_MASK_SIDE_LEFT); + lv_mask_line_points_init(&mask_right_param, p1.x, p1.y + w_half1, p2.x, p2.y + w_half1, LV_LINE_MASK_SIDE_RIGHT); } else { - vect_norm.x = vect_main.y; - vect_norm.y = -vect_main.x; + lv_mask_line_points_init(&mask_left_param, p1.x, p1.y + w_half0, p2.x, p2.y + w_half0, LV_LINE_MASK_SIDE_LEFT); + lv_mask_line_points_init(&mask_right_param, p1.x, p1.y - w_half1, p2.x, p2.y - w_half1, LV_LINE_MASK_SIDE_RIGHT); } } else { - if(main_line->p1.x < main_line->p2.x + dir_ori) { - vect_norm.x = vect_main.y; - vect_norm.y = -vect_main.x; - } else { - vect_norm.x = -vect_main.y; - vect_norm.y = vect_main.x; - } + lv_mask_line_points_init(&mask_left_param, p1.x + w_half0, p1.y, p2.x + w_half0, p2.y, LV_LINE_MASK_SIDE_LEFT); + lv_mask_line_points_init(&mask_right_param, p1.x - w_half1, p1.y, p2.x - w_half1, p2.y, LV_LINE_MASK_SIDE_RIGHT); + + } + /*Use the normal vector for the endings*/ + lv_mask_line_points_init(&mask_top_param, p1.x, p1.y, p1.x - ydiff, p1.y + xdiff, LV_LINE_MASK_SIDE_BOTTOM); + lv_mask_line_points_init(&mask_bottom_param, p2.x, p2.y,p2.x - ydiff, p2.y + xdiff, LV_LINE_MASK_SIDE_TOP); + + int16_t mask_left_id = lv_mask_add(lv_mask_line, &mask_left_param, NULL); + int16_t mask_right_id = lv_mask_add(lv_mask_line, &mask_right_param, NULL); + int16_t mask_top_id = lv_mask_add(lv_mask_line, &mask_top_param, NULL); + int16_t mask_bottom_id = lv_mask_add(lv_mask_line, &mask_bottom_param, NULL); + + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + lv_disp_buf_t * vdb = lv_disp_get_buf(disp); + + /*Store the coordinates of the `draw_a` relative to the VDB */ + lv_area_t draw_rel_a; + draw_rel_a.x1 = draw_a.x1 - vdb->area.x1; + draw_rel_a.y1 = draw_a.y1 - vdb->area.y1; + draw_rel_a.x2 = draw_a.x2 - vdb->area.x1; + draw_rel_a.y2 = draw_a.y2 - vdb->area.y1; + + uint32_t vdb_width = lv_area_get_width(&vdb->area); + uint32_t draw_a_width = lv_area_get_width(&draw_rel_a); + + /*Move the vdb_buf_tmp to the first row*/ + lv_color_t * vdb_buf_tmp = vdb->buf_act; + vdb_buf_tmp += vdb_width * draw_rel_a.y1; + + lv_opa_t mask_buf[LV_HOR_RES_MAX]; + + /*Draw the background line by line*/ + lv_coord_t h; + lv_mask_res_t mask_res; + /*Fill the first row with 'color'*/ + for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { + memset(mask_buf, LV_OPA_COVER, draw_a_width); + mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width); + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + style->line.color, LV_IMG_CF_TRUE_COLOR, + mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL); + vdb_buf_tmp += vdb_width; } - /* In case of a short but tick line the perpendicular ending is longer then the real line. - * it would break the calculations so make the normal vector larger*/ - vect_norm.x = vect_norm.x << 4; - vect_norm.y = vect_norm.y << 4; - - lv_coord_t width; - width = style->line.width; - - /* The pattern stores the points of the line ending. It has the good direction and length. - * The worth case is the 45° line where pattern can have 1.41 x `width` points*/ - - lv_coord_t pattern_size = width * 2; - lv_point_t * pattern = lv_draw_get_buf(pattern_size * sizeof(lv_point_t)); - lv_coord_t i = 0; - - /*Create a perpendicular pattern (a small line)*/ - if(width != 0) { - line_draw_t pattern_line; - lv_point_t p0 = {0, 0}; - line_init(&pattern_line, &p0, &vect_norm); - - uint32_t width_sqr = width * width; - /* Run for a lot of times. Meanwhile the real width will be determined as well */ - for(i = 0; i < (lv_coord_t)pattern_size - 1; i++) { - pattern[i].x = pattern_line.p_act.x; - pattern[i].y = pattern_line.p_act.y; - - /*Finish the pattern line if it's length equal to the desired width (Use Pythagoras - * theorem)*/ - uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y; - if(sqr >= width_sqr) { - width = i; -#if LV_ANTIALIAS - if(aa) width--; -#endif - break; - } - - line_next(&pattern_line); - } - } - -#if LV_ANTIALIAS - lv_coord_t aa_last_corner; - lv_coord_t width_safe = width; - if(aa) { - if(width == 0) width_safe = 1; - - aa_last_corner = 0; - } -#endif - - lv_coord_t x_center_ofs = 0; - lv_coord_t y_center_ofs = 0; - - if(width != 0) { - x_center_ofs = pattern[width - 1].x / 2; - y_center_ofs = pattern[width - 1].y / 2; - } else { - if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y--; - if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x--; - } - - /* Make the coordinates relative to the center */ - for(i = 0; i < width; i++) { - pattern[i].x -= x_center_ofs; - pattern[i].y -= y_center_ofs; -#if LV_ANTIALIAS - if(aa) { - if(i != 0) { - if(main_line->hor) { - if(pattern[i - 1].x != pattern[i].x) { - lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y; - if(main_line->sy < 0) { - lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, - main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, seg_w, mask, - style->line.color, opa); - - lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, - main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, -seg_w, mask, - style->line.color, opa); - } else { - lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, - main_line->p1.y + pattern[aa_last_corner].y, seg_w, mask, - style->line.color, opa); - - lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, - main_line->p2.y + pattern[aa_last_corner].y, -seg_w, mask, - style->line.color, opa); - } - aa_last_corner = i; - } - } else { - if(pattern[i - 1].y != pattern[i].y) { - lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x; - if(main_line->sx < 0) { - lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1, - main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask, - style->line.color, opa); - - lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1, - main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask, - style->line.color, opa); - } else { - lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, - main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask, - style->line.color, opa); - - lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, - main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask, - style->line.color, opa); - } - aa_last_corner = i; - } - } - } - } -#endif - } - -#if LV_ANTIALIAS - /*Add the last part of anti-aliasing for the perpendicular ending*/ - if(width != 0 && aa) { /*Due to rounding error with very thin lines it looks ugly*/ - if(main_line->hor) { - lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y; - if(main_line->sy < 0) { - lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, - main_line->p1.y + pattern[aa_last_corner].y + seg_w, seg_w + main_line->sy, mask, - style->line.color, opa); - - lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, - main_line->p2.y + pattern[aa_last_corner].y + seg_w, -(seg_w + main_line->sy), mask, - style->line.color, opa); - - } else { - lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1, - main_line->p1.y + pattern[aa_last_corner].y, seg_w + main_line->sy, mask, - style->line.color, opa); - - lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1, - main_line->p2.y + pattern[aa_last_corner].y, -(seg_w + main_line->sy), mask, - style->line.color, opa); - } - } else { - lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x; - if(main_line->sx < 0) { - lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w, - main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask, - style->line.color, opa); - - lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w, - main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask, - style->line.color, opa); - - } else { - lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x, - main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask, - style->line.color, opa); - - lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x, - main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask, - style->line.color, opa); - } - } - } -#endif - -#if LV_ANTIALIAS - - /*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/ - lv_coord_t aa_shift1 = 0; - lv_coord_t aa_shift2 = 0; - if(aa) { - if(main_line->hor == false) { - if(main_line->sx < 0) { - aa_shift1 = -1; - aa_shift2 = width == 0 ? 0 : aa_shift1; - } else { - aa_shift2 = 1; - aa_shift1 = width == 0 ? 0 : aa_shift2; - } - } else { - if(main_line->sy < 0) { - aa_shift1 = -1; - aa_shift2 = width == 0 ? 0 : aa_shift1; - } else { - aa_shift2 = 1; - aa_shift1 = width == 0 ? 0 : aa_shift2; - } - } - } -#endif - - volatile lv_point_t prev_p; - prev_p.x = main_line->p1.x; - prev_p.y = main_line->p1.y; - lv_area_t draw_area; - bool first_run = true; - - if(main_line->hor) { - while(line_next_y(main_line)) { - for(i = 0; i < width; i++) { - draw_area.x1 = prev_p.x + pattern[i].x; - draw_area.y1 = prev_p.y + pattern[i].y; - draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1; - draw_area.y2 = draw_area.y1; - lv_draw_fill(&draw_area, mask, style->line.color, opa); - - /* Fill the gaps - * When stepping in y one pixel remains empty on every corner (don't do this on the - * first segment ) */ - if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { - lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); - } - } - -#if LV_ANTIALIAS - if(aa) { - lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, - -(main_line->p_act.x - prev_p.x), mask, style->line.color, opa); - lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, - prev_p.y + pattern[width_safe - 1].y + aa_shift2, main_line->p_act.x - prev_p.x, - mask, style->line.color, opa); - } -#endif - - first_run = false; - - prev_p.x = main_line->p_act.x; - prev_p.y = main_line->p_act.y; - } - - for(i = 0; i < width; i++) { - draw_area.x1 = prev_p.x + pattern[i].x; - draw_area.y1 = prev_p.y + pattern[i].y; - draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x; - draw_area.y2 = draw_area.y1; - lv_draw_fill(&draw_area, mask, style->line.color, opa); - - /* Fill the gaps - * When stepping in y one pixel remains empty on every corner */ - if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) { - lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa); - } - } - -#if LV_ANTIALIAS - if(aa) { - lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1, - -(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa); - lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2, - main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa); - } -#endif - } - /*Rather a vertical line*/ - else { - - while(line_next_x(main_line)) { - for(i = 0; i < width; i++) { - draw_area.x1 = prev_p.x + pattern[i].x; - draw_area.y1 = prev_p.y + pattern[i].y; - draw_area.x2 = draw_area.x1; - draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1; - - lv_draw_fill(&draw_area, mask, style->line.color, opa); - - /* Fill the gaps - * When stepping in x one pixel remains empty on every corner (don't do this on the - * first segment ) */ - if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { - lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); - } - } - -#if LV_ANTIALIAS - if(aa) { - lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, - -(main_line->p_act.y - prev_p.y), mask, style->line.color, opa); - lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, - prev_p.y + pattern[width_safe - 1].y, main_line->p_act.y - prev_p.y, mask, - style->line.color, opa); - } -#endif - - first_run = false; - - prev_p.x = main_line->p_act.x; - prev_p.y = main_line->p_act.y; - } - - /*Draw the last part*/ - for(i = 0; i < width; i++) { - draw_area.x1 = prev_p.x + pattern[i].x; - draw_area.y1 = prev_p.y + pattern[i].y; - draw_area.x2 = draw_area.x1; - draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y; - - lv_draw_fill(&draw_area, mask, style->line.color, opa); - - /* Fill the gaps - * When stepping in x one pixel remains empty on every corner */ - if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) { - lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa); - } - } - -#if LV_ANTIALIAS - if(aa) { - lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y, - -(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa); - lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y, - main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa); - } -#endif - } -} - -static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2) -{ - line->p1.x = p1->x; - line->p1.y = p1->y; - line->p2.x = p2->x; - line->p2.y = p2->y; - - line->dx = LV_MATH_ABS(line->p2.x - line->p1.x); - line->sx = line->p1.x < line->p2.x ? 1 : -1; - line->dy = LV_MATH_ABS(line->p2.y - line->p1.y); - line->sy = line->p1.y < line->p2.y ? 1 : -1; - line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2; - line->e2 = 0; - line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/ - - line->p_act.x = line->p1.x; - line->p_act.y = line->p1.y; -} - -static bool line_next(line_draw_t * line) -{ - if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false; - line->e2 = line->err; - if(line->e2 > -line->dx) { - line->err -= line->dy; - line->p_act.x += line->sx; - } - if(line->e2 < line->dy) { - line->err += line->dx; - line->p_act.y += line->sy; - } - return true; -} - -/** - * Iterate until step one in y direction. - * @param line - * @return - */ -static bool line_next_y(line_draw_t * line) -{ - lv_coord_t last_y = line->p_act.y; - - do { - if(!line_next(line)) return false; - } while(last_y == line->p_act.y); - - return true; -} - -/** - * Iterate until step one in x direction. - * @param line - * @return - */ -static bool line_next_x(line_draw_t * line) -{ - lv_coord_t last_x = line->p_act.x; - - do { - if(!line_next(line)) return false; - } while(last_x == line->p_act.x); - - return true; + lv_mask_remove_id(mask_left_id); + lv_mask_remove_id(mask_right_id); + lv_mask_remove_id(mask_top_id); + lv_mask_remove_id(mask_bottom_id); } diff --git a/src/lv_draw/lv_draw_rect.c b/src/lv_draw/lv_draw_rect.c index e3ea80e57..5eedbd8dc 100644 --- a/src/lv_draw/lv_draw_rect.c +++ b/src/lv_draw/lv_draw_rect.c @@ -6,11 +6,11 @@ /********************* * INCLUDES *********************/ +#include #include "lv_draw_rect.h" #include "../lv_misc/lv_circ.h" #include "../lv_misc/lv_math.h" #include "../lv_core/lv_refr.h" -#include "lv_blit.h" #include "lv_mask.h" /********************* @@ -63,7 +63,6 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s { lv_opa_t opa = style->body.opa; - if(opa < LV_OPA_MIN) return; if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; lv_area_t draw_a; @@ -87,81 +86,97 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s draw_rel_a.x2 = draw_a.x2 - vdb->area.x1; draw_rel_a.y2 = draw_a.y2 - vdb->area.y1; - lv_color_t * vdb_buf_tmp = vdb->buf_act; uint32_t vdb_width = lv_area_get_width(&vdb->area); uint32_t draw_a_width = lv_area_get_width(&draw_rel_a); /*Move the vdb_buf_tmp to the first row*/ + lv_color_t * vdb_buf_tmp = vdb->buf_act; vdb_buf_tmp += vdb_width * draw_rel_a.y1; - - lv_color_t line_buf[LV_HOR_RES_MAX]; lv_opa_t mask_buf[LV_HOR_RES_MAX]; - lv_mask_line_param_t line_mask_param1; -// lv_mask_line_points_init(&line_mask_param1, 100, 0, -50, 100, LV_LINE_MASK_SIDE_LEFT); - lv_mask_line_angle_init(&line_mask_param1, 0, 0, 60, LV_LINE_MASK_SIDE_LEFT); + lv_coord_t short_side = LV_MATH_MIN(lv_area_get_width(coords), lv_area_get_height(coords)); + lv_coord_t rout = style->body.radius; + if(rout > short_side >> 1) rout = short_side >> 1; - lv_mask_line_param_t line_mask_param2; - lv_mask_line_points_init(&line_mask_param2, 100, 0, 0, 100, LV_LINE_MASK_SIDE_LEFT); -// lv_mask_line_angle_init(&line_mask_param2, 0, 0, 45, LV_LINE_MASK_SIDE_LEFT); + /*Create the outer mask*/ + lv_mask_param_t mask_rout_param; + lv_mask_radius_init(&mask_rout_param, coords, rout, false); + int16_t mask_rout_id = lv_mask_add(lv_mask_radius, &mask_rout_param, NULL); + lv_area_t t; + t.x1 = 10; + t.y1 = 20; + t.x2 = 30; + t.y2 = 50; + lv_mask_param_t tp; + lv_mask_radius_init(&tp, &t, 5, false); +// int16_t tpid = lv_mask_add(lv_mask_radius, &tp, NULL); - lv_mask_radius_param_t param1; - lv_area_copy(¶m1.rect, coords); - param1.radius = 50; - param1.inv = 0; - - lv_coord_t w = 20; - lv_mask_radius_param_t param2; - lv_area_copy(¶m2.rect, coords); - param2.rect.x1 += w; - param2.rect.x2 -= w; - param2.rect.y1 += w; - param2.rect.y2 -= w; - param2.radius = param1.radius - w; - param2.inv = 1; - - - lv_mask_angle_param_t pa; - lv_mask_angle_init(&pa, coords->x1 + lv_area_get_width(coords) / 2, coords->y1 + lv_area_get_height(coords) / 2, 60, 30); -// lv_mask_angle_init(&pa, 0, 0, 60, 30); - -// line_mask_param1.origo.x = 0; -// line_mask_param1.origo.y = 0; -// line_mask_param1.steep = 300; -// line_mask_param1.flat = 1; -// line_mask_param1.side = LV_LINE_MASK_SIDE_RIGHT; -// line_mask_param1.inv = 0; - - - /*Fill with a color line-by-line*/ + /*Draw the background line by line*/ lv_coord_t h; + lv_mask_res_t mask_res; + lv_color_t grad_color; + /*Fill the first row with 'color'*/ - for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { + if(opa >= LV_OPA_MIN) { + for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { - if(style->body.main_color.full != style->body.grad_color.full) { - // 3 - lv_blit_color(line_buf, &vdb_buf_tmp[draw_rel_a.x1], draw_a_width, style->body.main_color, LV_BLIT_MODE_NORMAL); + lv_opa_t mix = ((uint32_t)((uint32_t)h + vdb->area.y1-coords->y1)*255) / lv_area_get_height(coords); + grad_color = lv_color_mix(style->body.grad_color, style->body.main_color, mix); + + if(style->body.main_color.full != style->body.grad_color.full) { + memset(mask_buf, LV_OPA_COVER, draw_a_width); + mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width); + + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + grad_color, LV_IMG_CF_TRUE_COLOR, + mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL); + } else { + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + style->body.main_color, LV_IMG_CF_TRUE_COLOR, + NULL, LV_MASK_RES_FULL_COVER, style->body.opa, LV_BLIT_MODE_NORMAL); + } + + vdb_buf_tmp += vdb_width; + } + } + + + /*Draw the border if any*/ + lv_coord_t border_width = style->body.border.width; + if(border_width) { + /*Move the vdb_buf_tmp to the first row*/ + vdb_buf_tmp = vdb->buf_act; + vdb_buf_tmp += vdb_width * draw_rel_a.y1; + + lv_mask_param_t mask_rsmall_param; + lv_coord_t rin = rout - border_width; + if(rin < 0) rin = 0; + lv_area_t area_small; + lv_area_copy(&area_small, coords); + area_small.x1 += border_width; + area_small.x2 -= border_width; + area_small.y1 += border_width; + area_small.y2 -= border_width; + lv_mask_radius_init(&mask_rsmall_param, &area_small, style->body.radius - border_width, true); + int16_t mask_rsmall_id = lv_mask_add(lv_mask_radius, &mask_rsmall_param, NULL); + + /*Fill the first row with 'color'*/ + for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) { memset(mask_buf, LV_OPA_COVER, draw_a_width); -// lv_mask_line(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &line_mask_param1); -// lv_mask_line(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &line_mask_param2); + mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width); - //4 - lv_mask_radius(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, ¶m1); - lv_mask_radius(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, ¶m2); + lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width, + style->body.border.color, LV_IMG_CF_TRUE_COLOR, + mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL); - lv_mask_angle(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &pa); - - //9 - lv_mask_apply(&vdb_buf_tmp[draw_rel_a.x1], line_buf, mask_buf, draw_a_width); -// memcpy(&vdb_buf_tmp[draw_rel_a.x1], line_buf, draw_a_width * sizeof(lv_color_t)); - } else { - //1 - lv_blit_color(&vdb_buf_tmp[draw_rel_a.x1], &vdb_buf_tmp[draw_rel_a.x1], draw_a_width, style->body.main_color, LV_BLIT_MODE_NORMAL); -// memcpy(&vdb_buf_tmp[draw_rel_a.x1], line_buf, draw_a_width * sizeof(lv_color_t)); + vdb_buf_tmp += vdb_width; } - vdb_buf_tmp += vdb_width; + lv_mask_remove_id(mask_rsmall_id); } + + lv_mask_remove_id(mask_rout_id); +// lv_mask_remove_id(tpid); } diff --git a/src/lv_draw/lv_mask.c b/src/lv_draw/lv_mask.c index a40785007..844f7c85f 100644 --- a/src/lv_draw/lv_mask.c +++ b/src/lv_draw/lv_mask.c @@ -8,26 +8,36 @@ *********************/ #include "lv_mask.h" #include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_log.h" /********************* * DEFINES *********************/ +#define LV_MASK_MAX_NUM 8 /********************** * TYPEDEFS **********************/ +typedef struct +{ + lv_mask_cb_t cb; + lv_mask_param_t param; + void * custom_id; +}lv_mask_saved_t; + /********************** * STATIC PROTOTYPES **********************/ -static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p); -static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p); +static lv_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p); +static lv_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p); static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new); /********************** * STATIC VARIABLES **********************/ +static lv_mask_saved_t mask_list[LV_MASK_MAX_NUM]; /********************** * MACROS @@ -37,20 +47,64 @@ static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new); * GLOBAL FUNCTIONS **********************/ - -void lv_mask_apply(lv_color_t * dest_buf, lv_color_t * src_buf, lv_opa_t * mask_buf, lv_coord_t len) +int16_t lv_mask_add(lv_mask_cb_t mask_cb, lv_mask_param_t * param, void * custom_id) { - lv_coord_t i; - for(i = 0; i < len; i++) { -// if(mask_buf[i] > LV_OPA_MAX) dest_buf[i] = src_buf[i]; -// else if(mask_buf[i] > LV_OPA_MIN) dest_buf[i] = lv_color_mix(src_buf[i], dest_buf[i], mask_buf[i]); - dest_buf[i] = lv_color_mix(src_buf[i], dest_buf[i], mask_buf[i]); + /*Search a free entry*/ + uint8_t i; + for(i = 0; i < LV_MASK_MAX_NUM; i++) { + if(mask_list[i].cb == NULL) break; } + + if(i >= LV_MASK_MAX_NUM) { + LV_LOG_WARN("lv_mask_add: no place to add the mask"); + return LV_MASK_ID_INV; + } + + mask_list[i].cb = mask_cb; + memcpy(&mask_list[i].param, param, sizeof(lv_mask_param_t)); + mask_list[i].custom_id = custom_id; + + return i; } -void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side) +lv_mask_res_t lv_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len) { + + bool changed = false; + lv_mask_res_t res; + uint8_t i; + for(i = 0; i < LV_MASK_MAX_NUM; i++) { + if(mask_list[i].cb) { + res = mask_list[i].cb(mask_buf, abs_x, abs_y, len, (void*)&mask_list[i].param); + if(res == LV_MASK_RES_FULL_TRANSP) return LV_MASK_RES_FULL_TRANSP; + else if(res == LV_MASK_RES_CHANGED) changed = true; + } + } + + return changed ? LV_MASK_RES_CHANGED : LV_MASK_RES_FULL_COVER; +} + +void lv_mask_remove_id(int16_t id) +{ + if(id != LV_MASK_ID_INV) { + mask_list[id].cb = NULL; + } +} + +void lv_mask_remove_custom(void * custom_id) +{ + uint8_t i; + for(i = 0; i < LV_MASK_MAX_NUM; i++) { + if(mask_list[i].custom_id == custom_id) { + mask_list[i].cb = NULL; + } + } +} + +void lv_mask_line_points_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side) +{ + lv_mask_line_param_t * p = ¶m->line; memset(p, 0x00, sizeof(lv_mask_line_param_t)); if(p1y > p2y) { @@ -107,13 +161,13 @@ void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord if(p->side == LV_LINE_MASK_SIDE_LEFT) p->inv = 0; else if(p->side == LV_LINE_MASK_SIDE_RIGHT) p->inv = 1; else if(p->side == LV_LINE_MASK_SIDE_TOP) { - if(p->steep > 0) p->inv = 0; - else p->inv = 1; - } - else if(p->side == LV_LINE_MASK_SIDE_BOTTOM) { if(p->steep > 0) p->inv = 1; else p->inv = 0; } + else if(p->side == LV_LINE_MASK_SIDE_BOTTOM) { + if(p->steep > 0) p->inv = 0; + else p->inv = 1; + } p->spx = p->steep >> 2; if(p->steep < 0) p->spx = -p->spx; @@ -127,8 +181,11 @@ void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord * @param deg right 0 deg, bottom: 90 * @param side */ -void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side) +void lv_mask_line_angle_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side) { + + lv_mask_angle_param_t * p = ¶m->angle; + /* Find an optimal degree. * lv_mask_line_points_init will swap the points to keep the smaller y in p1 * Theoretically a line with `deg` or `deg+180` is the same only the points are swapped @@ -147,9 +204,9 @@ void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_ lv_mask_line_points_init(p, p1x, p1y, p2x, p2y, side); } -void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, void * param) +lv_mask_res_t lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param) { - lv_mask_line_param_t * p = (lv_mask_line_param_t *)param; + lv_mask_line_param_t * p = ¶m->line; /*Make to points relative to the origo*/ abs_y -= p->origo.y; @@ -160,44 +217,48 @@ void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_co /*Horizontal*/ if(p->flat) { /*Non sense: Can't be on the right/left of a horizontal line*/ - if(p->side == LV_LINE_MASK_SIDE_LEFT || p->side == LV_LINE_MASK_SIDE_RIGHT) return; - else if(p->side == LV_LINE_MASK_SIDE_TOP && abs_y+1 < p->origo.y) return; - else if(p->side == LV_LINE_MASK_SIDE_BOTTOM && abs_y > p->origo.y) return; + if(p->side == LV_LINE_MASK_SIDE_LEFT || p->side == LV_LINE_MASK_SIDE_RIGHT) return LV_MASK_RES_FULL_COVER; + else if(p->side == LV_LINE_MASK_SIDE_TOP && abs_y+1 < p->origo.y) return LV_MASK_RES_FULL_COVER; + else if(p->side == LV_LINE_MASK_SIDE_BOTTOM && abs_y > p->origo.y) return LV_MASK_RES_FULL_COVER; else { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } /*Vertical*/ else { /*Non sense: Can't be on the top/bottom of a vertical line*/ - if(p->side == LV_LINE_MASK_SIDE_TOP || p->side == LV_LINE_MASK_SIDE_BOTTOM) return; - else if(p->side == LV_LINE_MASK_SIDE_RIGHT && abs_x > 0) return; + if(p->side == LV_LINE_MASK_SIDE_TOP || p->side == LV_LINE_MASK_SIDE_BOTTOM) return LV_MASK_RES_FULL_COVER; + else if(p->side == LV_LINE_MASK_SIDE_RIGHT && abs_x > 0) return LV_MASK_RES_FULL_COVER; else if(p->side == LV_LINE_MASK_SIDE_LEFT) { - if(abs_x + len < 0) return; + if(abs_x + len < 0) return LV_MASK_RES_FULL_COVER; else { int32_t k = - abs_x; if(k < 0) k = 0; if(k >= 0 && k < len) memset(&mask_buf[k], 0x00, len - k); - return; + return LV_MASK_RES_CHANGED; } } else { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } } + lv_mask_res_t res; if(p->flat) { - line_mask_flat(mask_buf, abs_x, abs_y, len, p); + res = line_mask_flat(mask_buf, abs_x, abs_y, len, p); } else { - line_mask_steep(mask_buf, abs_x, abs_y, len, p); + res = line_mask_steep(mask_buf, abs_x, abs_y, len, p); } + + return res; } -void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origo_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle) + +void lv_mask_angle_init(lv_mask_param_t * param, lv_coord_t origo_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle) { + lv_mask_angle_param_t * p = ¶m->line; + lv_line_mask_side_t start_side; lv_line_mask_side_t end_side; @@ -224,13 +285,14 @@ void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origo_x, lv_coord_ } } - lv_mask_line_angle_init(&p->start_line, origo_x, origo_y, start_angle, start_side); - lv_mask_line_angle_init(&p->end_line, origo_x, origo_y, end_angle, end_side); + lv_mask_line_angle_init((lv_mask_param_t*)&p->start_line, origo_x, origo_y, start_angle, start_side); + lv_mask_line_angle_init((lv_mask_param_t*)&p->end_line, origo_x, origo_y, end_angle, end_side); } -void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_angle_param_t * p) +lv_mask_res_t lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param) { + lv_mask_angle_param_t * p = ¶m->line; // if(p->delta_deg <= 180) { // if((p->start_angle <= 180 && abs_y >= p->origo.y) || // (p->start_angle >= 180 && abs_y <= p->origo.y)) { @@ -238,7 +300,7 @@ void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_c if(abs_y < p->origo.y) { // memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_COVER; } @@ -251,36 +313,68 @@ void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_c int32_t dist = (end_angle_first - start_angle_last) >> 1; - + lv_mask_res_t res1 = LV_MASK_RES_FULL_COVER; + lv_mask_res_t res2 = LV_MASK_RES_FULL_COVER; int32_t tmp = start_angle_last + dist - rel_x; if(tmp > len) tmp = len; if(tmp > 0) { - lv_mask_line(&mask_buf[0], abs_x, abs_y, tmp, &p->start_line); + res1 = lv_mask_line(&mask_buf[0], abs_x, abs_y, tmp, (lv_mask_param_t*)&p->start_line); + if(res1 == LV_MASK_RES_FULL_TRANSP) { + memset(&mask_buf[0], 0x00, tmp); + } } if(tmp > len) tmp = len; if(tmp < 0) tmp = 0; - lv_mask_line(&mask_buf[tmp], abs_x+tmp, abs_y, len-tmp, &p->end_line); - + res2 = lv_mask_line(&mask_buf[tmp], abs_x+tmp, abs_y, len-tmp, (lv_mask_param_t*)&p->end_line); + if(res2 == LV_MASK_RES_FULL_TRANSP) { + memset(&mask_buf[tmp], 0x00, len-tmp); + } + if(res1 == res2) return res1; + else return LV_MASK_RES_CHANGED; } - -void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_radius_param_t * p) +void lv_mask_radius_init(lv_mask_param_t * param, lv_area_t * rect, lv_coord_t radius, bool inv) { + lv_mask_radius_param_t * p = ¶m->radius; + + lv_area_copy(&p->rect, rect); + p->radius = radius; + p->inv = inv ? 1 : 0; +} + +lv_mask_res_t lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param) +{ + lv_mask_radius_param_t * p = ¶m->radius; + if(p->inv == 0) { if(abs_y < p->rect.y1 || abs_y > p->rect.y2) { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } else { if(abs_y < p->rect.y1 || abs_y > p->rect.y2) { - return; + return LV_MASK_RES_FULL_COVER; } } + if((abs_x >= p->rect.x1 + p->radius && abs_x + len <= p->rect.x2 - p->radius) || (abs_y >= p->rect.y1 + p->radius && abs_y <= p->rect.y2 - p->radius+1)) { - if(p->inv == 0) return; + if(p->inv == 0) { + /*Remove the edges*/ + int32_t last = p->rect.x1 - abs_x; + if(last > len) last = len; + if(last >= 0) { + memset(&mask_buf[0], 0x00, last); + } + + int32_t first = p->rect.x2 - abs_x + 1; + if(first < len) { + memset(&mask_buf[first], 0x00, len-first); + } + + return LV_MASK_RES_CHANGED; + } else { int32_t first = p->rect.x1 - abs_x; if(first < 0) first = 0; @@ -292,12 +386,9 @@ void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_ } } } - return; + return LV_MASK_RES_CHANGED; } - - - int32_t k = p->rect.x1 -abs_x; /*First relevant coordinate on the of the mask*/ lv_coord_t w = lv_area_get_width(&p->rect); lv_coord_t h = lv_area_get_height(&p->rect); @@ -446,18 +537,16 @@ void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_ if(kr < len) memset(&mask_buf[kr], 0x00, len - kr); } } - - return; } + + return LV_MASK_RES_CHANGED; } - - /********************** * STATIC FUNCTIONS **********************/ -static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p) +static lv_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p) { lv_coord_t y_at_x; @@ -468,19 +557,17 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs if(p->yx_steep > 0) { if(y_at_x > abs_y) { if(p->inv) { - return; + return LV_MASK_RES_FULL_COVER; } else { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } } else { if(y_at_x < abs_y) { if(p->inv) { - return; + return LV_MASK_RES_FULL_COVER; } else { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } } @@ -491,19 +578,17 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs if(p->yx_steep > 0) { if(y_at_x < abs_y) { if(p->inv) { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } else { - return; + return LV_MASK_RES_FULL_COVER; } } } else { if(y_at_x > abs_y) { if(p->inv) { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } else { - return; + return LV_MASK_RES_FULL_COVER; } } } @@ -562,9 +647,11 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs memset(&mask_buf[k], 0x00, len - k); } } + + return LV_MASK_RES_CHANGED; } -static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p) +static lv_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p) { int32_t k; lv_coord_t x_at_y; @@ -574,10 +661,9 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab if(p->xy_steep > 0) x_at_y++; if(x_at_y < abs_x) { if(p->inv) { - return; + return LV_MASK_RES_FULL_COVER; } else { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } } @@ -586,10 +672,9 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab x_at_y = (int32_t)((int32_t)p->xy_steep * (abs_y)) >> 10; if(x_at_y > abs_x + len) { if(p->inv) { - memset(mask_buf, 0x00, len); - return; + return LV_MASK_RES_FULL_TRANSP; } else { - return; + return LV_MASK_RES_FULL_COVER; } } @@ -690,6 +775,8 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab } } + + return LV_MASK_RES_CHANGED; } static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new) diff --git a/src/lv_draw/lv_mask.h b/src/lv_draw/lv_mask.h index 5a23483e8..17a185feb 100644 --- a/src/lv_draw/lv_mask.h +++ b/src/lv_draw/lv_mask.h @@ -20,10 +20,21 @@ extern "C" { /********************* * DEFINES *********************/ +#define LV_MASK_ID_INV (-1) /********************** * TYPEDEFS **********************/ + +enum { + LV_MASK_RES_FULL_COVER, + LV_MASK_RES_FULL_TRANSP, + LV_MASK_RES_CHANGED, +}; + +typedef uint8_t lv_mask_res_t; + + enum { LV_LINE_MASK_SIDE_LEFT = 0, LV_LINE_MASK_SIDE_RIGHT, @@ -36,13 +47,13 @@ typedef uint8_t lv_line_mask_side_t; typedef struct { lv_point_t origo; /* X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/ - lv_coord_t xy_steep; + int32_t xy_steep; /* Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/ - lv_coord_t yx_steep; + int32_t yx_steep; /*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines */ - lv_coord_t steep; + int32_t steep; /*Steepness in 1 px in 0..255 range. Used only by flat lines. */ int32_t spx; @@ -68,7 +79,6 @@ typedef struct { uint16_t delta_deg; }lv_mask_angle_param_t; - typedef struct { lv_area_t rect; lv_coord_t radius; @@ -77,18 +87,36 @@ typedef struct { uint8_t inv:1; }lv_mask_radius_param_t; + +typedef union { + lv_mask_line_param_t line; + lv_mask_radius_param_t radius; + lv_mask_angle_param_t angle; +}lv_mask_param_t; + +typedef lv_mask_res_t (*lv_mask_cb_t)(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * p); + /********************** * GLOBAL PROTOTYPES **********************/ -void lv_mask_apply(lv_color_t * dest_buf, lv_color_t * src_buf, lv_opa_t * mask_buf, lv_coord_t len); -void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side); -void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side); -void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, void * param); +int16_t lv_mask_add(lv_mask_cb_t mask_cb, lv_mask_param_t * param, void * custom_id); +void lv_mask_remove_id(int16_t id); +void lv_mask_remove_custom(void * custom_id); + +lv_mask_res_t lv_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len); + +void lv_mask_line_points_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side); +void lv_mask_line_angle_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side); +lv_mask_res_t lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param); -void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origio_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle); -void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_angle_param_t * p); +void lv_mask_radius_init(lv_mask_param_t * param, lv_area_t * rect, lv_coord_t radius, bool inv); +lv_mask_res_t lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param); + +void lv_mask_angle_init(lv_mask_param_t * param, lv_coord_t origio_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle); +lv_mask_res_t lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param); + /********************** * MACROS diff --git a/src/lv_misc/lv_color.h b/src/lv_misc/lv_color.h index a73ab8c88..cf494f494 100644 --- a/src/lv_misc/lv_color.h +++ b/src/lv_misc/lv_color.h @@ -75,8 +75,8 @@ enum { LV_OPA_COVER = 255, }; -#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/ -#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/ +#define LV_OPA_MIN 5 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 250 /*Opacities above this will fully cover*/ #if LV_COLOR_DEPTH == 1 #define LV_COLOR_SIZE 8