1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00

lv_blend_fill simplify API + shadow drawing experiments

This commit is contained in:
Gabor Kiss-Vamosi 2019-08-29 10:07:22 +02:00
parent 3cbc86fedb
commit e4d7626ca2
5 changed files with 229 additions and 80 deletions

View File

@ -51,14 +51,21 @@
* @param opa
* @param mode
*/
void lv_blend_fill(const lv_area_t * disp_area, const lv_area_t * clip_area, const lv_area_t * fill_area,
lv_color_t * disp_buf, lv_img_cf_t cf, lv_color_t color,
lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode)
void lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area,
lv_color_t color, lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa,
lv_blend_mode_t mode)
{
/*Do not draw transparent things*/
if(opa < LV_OPA_MIN) return;
if(mask_res == LV_MASK_RES_FULL_TRANSP) return;
lv_disp_t * disp = lv_refr_get_disp_refreshing();
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
const lv_area_t * disp_area = &vdb->area;
lv_color_t * disp_buf = vdb->buf_act;
lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR;
/* Get clipped fill area which is the real draw area.
* It is always the same or inside `fill_area` */
lv_area_t draw_area;

View File

@ -34,9 +34,9 @@ typedef enum {
* GLOBAL PROTOTYPES
**********************/
void lv_blend_fill(const lv_area_t * disp_area, const lv_area_t * clip_area, const lv_area_t * fill_area,
lv_color_t * disp_buf, lv_img_cf_t cf, lv_color_t color,
lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode);
void lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area,
lv_color_t color, lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa,
lv_blend_mode_t mode);
void lv_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area, const lv_color_t * map_buf,

View File

@ -384,9 +384,9 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const
if(mask_p + (row_end - row_start) < sizeof(mask_buf)) {
fill_area.y2 ++;
} else {
lv_blend_fill(&vdb->area, clip_area, &fill_area,
vdb->buf_act, LV_IMG_CF_TRUE_COLOR, color,
mask_buf, LV_MASK_RES_CHANGED, opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip_area, &fill_area,
color, mask_buf, LV_MASK_RES_CHANGED, opa,
LV_BLIT_MODE_NORMAL);
fill_area.y1 = fill_area.y2 + 1;
fill_area.y2 = fill_area.y1;
@ -402,9 +402,9 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, const
/*Flush the last part*/
if(fill_area.y1 != fill_area.y2) {
fill_area.y2--;
lv_blend_fill(&vdb->area, clip_area, &fill_area,
vdb->buf_act, LV_IMG_CF_TRUE_COLOR, color,
mask_buf, LV_MASK_RES_CHANGED, opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip_area, &fill_area,
color, mask_buf, LV_MASK_RES_CHANGED, opa,
LV_BLIT_MODE_NORMAL);
mask_p = 0;
}
}

View File

@ -94,9 +94,9 @@ static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2,
/*If there is no mask then simply draw a rectangle*/
if(other_mask_cnt == 0) {
lv_blend_fill(disp_area, clip, &draw_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->line.color,
NULL, LV_MASK_RES_FULL_COVER, style->line.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &draw_area,
style->line.color, NULL, LV_MASK_RES_FULL_COVER, style->line.opa,
LV_BLIT_MODE_NORMAL);
}
/*If there other mask apply it*/
else {
@ -128,9 +128,9 @@ static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2,
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->line.color,
mask_buf, mask_res, style->line.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
style->line.color, mask_buf, mask_res, style->line.opa,
LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;
@ -166,9 +166,9 @@ static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2,
/*If there is no mask then simply draw a rectangle*/
if(other_mask_cnt == 0) {
lv_blend_fill(disp_area, clip, &draw_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->line.color,
NULL, LV_MASK_RES_FULL_COVER, style->line.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &draw_area,
style->line.color, NULL, LV_MASK_RES_FULL_COVER, style->line.opa,
LV_BLIT_MODE_NORMAL);
}
/*If there other mask apply it*/
else {
@ -200,9 +200,9 @@ static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2,
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->line.color,
mask_buf, mask_res, style->line.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
style->line.color, mask_buf, mask_res, style->line.opa,
LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;
@ -320,9 +320,9 @@ static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2,
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->line.color,
mask_buf, mask_res, style->line.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
style->line.color, mask_buf, mask_res, style->line.opa,
LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;

View File

@ -25,6 +25,8 @@
* STATIC PROTOTYPES
**********************/
static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_style_t * style, lv_opa_t opa_scale);
static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const lv_style_t * style, lv_opa_t opa_scale);
static void shadow_draw_corner_buf(lv_opa_t * sh_buf, lv_coord_t s, lv_coord_t r);
/**********************
* STATIC VARIABLES
@ -49,9 +51,10 @@ void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_sty
{
if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return;
draw_bg(coords, clip, style, opa_scale);
draw_shadow(coords, clip, style, opa_scale);
}
@ -100,9 +103,9 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
/*Most simple case: just a plain rectangle*/
if(other_mask_cnt == 0 && rout == 0 && style->body.main_color.full == style->body.grad_color.full) {
lv_blend_fill(disp_area, clip, coords,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.main_color,
NULL, LV_MASK_RES_FULL_COVER, style->body.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, coords,
style->body.main_color, NULL, LV_MASK_RES_FULL_COVER, style->body.opa,
LV_BLIT_MODE_NORMAL);
}
/*More complex case: there is a radius, gradient or mask.*/
else {
@ -131,7 +134,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
/*In not corner areas apply the mask only if required*/
if(y > coords->y1 + rout + 1 &&
y < coords->y2 - rout - 1) {
y < coords->y2 - rout - 1) {
mask_res = LV_MASK_RES_FULL_COVER;
if(other_mask_cnt != 0) {
memset(mask_buf, LV_OPA_COVER, draw_area_w);
@ -153,8 +156,8 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
/* If there is not other mask and drawing the corner area split the drawing to corners and middle area
* because it the middle mask shuldn't be taken into account (therefore its faster)*/
if(other_mask_cnt == 0 &&
(y < coords->y1 + rout + 1 ||
y > coords->y2 - rout - 1)) {
(y < coords->y1 + rout + 1 ||
y > coords->y2 - rout - 1)) {
lv_area_t fill_area2;
fill_area2.x1 = coords->x1;
@ -162,30 +165,26 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
fill_area2.y1 = fill_area.y1;
fill_area2.y2 = fill_area.y2;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, grad_color,
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
grad_color, mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
fill_area2.x1 = coords->x1 + rout + 1;
fill_area2.x2 = coords->x2 - rout - 1;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, grad_color,
NULL, LV_MASK_RES_FULL_COVER, style->body.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
grad_color, NULL, LV_MASK_RES_FULL_COVER, style->body.opa, LV_BLIT_MODE_NORMAL);
fill_area2.x1 = coords->x2 - rout;
fill_area2.x2 = coords->x2;
lv_coord_t mask_ofs = (coords->x2 - rout) - (vdb->area.x1 + draw_area.x1);
if(mask_ofs < 0) mask_ofs = 0;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, grad_color,
mask_buf + mask_ofs, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
grad_color, mask_buf + mask_ofs, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
} else {
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, grad_color,
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
grad_color,mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
}
fill_area.y1++;
fill_area.y2++;
@ -239,27 +238,24 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
fill_area2.y1 = fill_area.y1;
fill_area2.y2 = fill_area.y2;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
if(fill_area2.y2 < coords->y1 + style->body.border.width) {
fill_area2.x1 = coords->x1 + rout + 1;
fill_area2.x2 = coords->x2 - rout - 1;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
}
fill_area2.x1 = coords->x2 - rout;
fill_area2.x2 = coords->x2;
lv_coord_t mask_ofs = (coords->x2 - rout) - (vdb->area.x1 + draw_area.x1);
if(mask_ofs < 0) mask_ofs = 0;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
mask_buf + mask_ofs, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, mask_buf + mask_ofs, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;
@ -271,59 +267,54 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
fill_area.y1 = disp_area->y1 + lower_corner_end;
fill_area.y2 = fill_area.y1;
for(h = lower_corner_end; h <= draw_area.y2; h++) {
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
lv_area_t fill_area2;
lv_area_t fill_area2;
fill_area2.x1 = coords->x1;
fill_area2.x2 = coords->x1 + rout;
fill_area2.y1 = fill_area.y1;
fill_area2.y2 = fill_area.y2;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
if(fill_area2.y2 > coords->y2 - style->body.border.width) {
fill_area2.x1 = coords->x1 + rout + 1;
fill_area2.x2 = coords->x2 - rout - 1;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
}
fill_area2.x1 = coords->x2 - rout;
fill_area2.x2 = coords->x2;
lv_coord_t mask_ofs = (coords->x2 - rout) - (vdb->area.x1 + draw_area.x1);
if(mask_ofs < 0) mask_ofs = 0;
lv_blend_fill(disp_area, clip, &fill_area2,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
mask_buf + mask_ofs, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area2,
style->body.border.color, mask_buf + mask_ofs, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;
}
fill_area.y1++;
fill_area.y2++;
}
/*Draw the left vertical border part*/
/*Draw the left vertical border part*/
fill_area.x1 = coords->x1;
fill_area.x2 = coords->x1 + border_width - 1;
fill_area.y1 = coords->y1 + corner_size + 1;
fill_area.y2 = coords->y2 - corner_size - 1;
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
style->body.border.color, NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
/*Draw the right vertical border*/
fill_area.x1 = coords->x2 - border_width + 1;
fill_area.x2 = coords->x2;
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill(clip, &fill_area,
style->body.border.color, NULL, LV_MASK_RES_FULL_COVER, style->body.border.opa, LV_BLIT_MODE_NORMAL);
}
/*Process line by line if there is other mask too*/
else {
@ -335,9 +326,8 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
memset(mask_buf, LV_OPA_COVER, draw_area_w);
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w);
lv_blend_fill(disp_area, clip, &fill_area,
disp_buf, LV_IMG_CF_TRUE_COLOR, style->body.border.color,
mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
lv_blend_fill( clip, &fill_area,
style->body.border.color, mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
fill_area.y1++;
fill_area.y2++;
@ -349,3 +339,155 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
lv_mask_remove_id(mask_rout_id);
}
static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, const lv_style_t * style, lv_opa_t opa_scale)
{
if(style->body.shadow.width == 0) return;
// lv_area_t c2;
// c2.x1 = 20;
// c2.x2 = 80;
// c2.y1 = 20;
// c2.y2 = 80;
//
// coords = &c2;
lv_opa_t opa = style->body.opa;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
lv_disp_t * disp = lv_refr_get_disp_refreshing();
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
/* Get clipped fill area which is the real draw area.
* It is always the same or inside `fill_area` */
lv_area_t draw_area;
bool is_common;
is_common = lv_area_intersect(&draw_area, coords, clip);
if(is_common == false) return;
const lv_area_t * disp_area = &vdb->area;
lv_color_t * disp_buf = vdb->buf_act;
/* Now `draw_area` has absolute coordinates.
* Make it relative to `disp_area` to simplify draw to `disp_buf`*/
draw_area.x1 -= disp_area->x1;
draw_area.y1 -= disp_area->y1;
draw_area.x2 -= disp_area->x1;
draw_area.y2 -= disp_area->y1;
lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
/*Create a mask if there is a radius*/
lv_opa_t mask_buf[LV_HOR_RES_MAX];
/*Draw a radius into the shadow buffer*/
int16_t mask_rout_id = LV_MASK_ID_INV;
uint8_t other_mask_cnt = lv_mask_get_cnt();
/*Get the real radius*/
lv_coord_t rout = style->body.radius;
lv_coord_t short_side = LV_MATH_MIN(lv_area_get_width(coords), lv_area_get_height(coords));
if(rout > short_side >> 1) rout = short_side >> 1;
lv_coord_t corner_size = rout + 2 * style->body.shadow.width;
lv_opa_t sh_buf[corner_size * corner_size];
shadow_draw_corner_buf(sh_buf, style->body.shadow.width, rout);
lv_area_t a;
a.x1 = coords->x1;
a.x2 = coords->x1 + corner_size-1;
a.y1 = coords->y1;
a.y2 = a.y1;
lv_opa_t * sh_buf_tmp = sh_buf;
lv_coord_t y;
for(y = 0; y < corner_size; y++) {
lv_blend_fill(clip, &a,
LV_COLOR_BLACK, sh_buf_tmp, LV_MASK_RES_CHANGED, LV_OPA_COVER, LV_BLIT_MODE_NORMAL);
a.y1++;
a.y2++;
sh_buf_tmp += corner_size;
}
}
#define SHADOW_UPSACALE_SHIFT 10
static void shadow_draw_corner_buf(lv_opa_t * sh_buf, lv_coord_t sw, lv_coord_t r)
{
lv_coord_t size = sw + sw + r;
lv_area_t sh_area;
sh_area.x1 = -100;
sh_area.y1 = sw;
sh_area.x2 = sw+r-1; /*make the end far to not draw the other radius*/
sh_area.y2 = 100;
lv_mask_param_t mask_param;
lv_mask_radius_init(&mask_param, &sh_area, r, false);
int16_t mask_id = lv_mask_add(lv_mask_radius, &mask_param, NULL);
/*Initialize the shadow buffer*/
lv_mask_res_t mask_res;
lv_opa_t * sh_buf_tmp = sh_buf;
lv_coord_t y;
lv_opa_t mask_line[size];
lv_coord_t s_left = sw >> 1;
lv_coord_t s_right = (sw >> 1);
if((sw & 1) == 0) s_left--;
for(y = 0; y < size; y++) {
memset(mask_line, 0xFF, size);
mask_res = lv_mask_apply(mask_line, 0, y, size);
if(mask_res == LV_MASK_RES_FULL_TRANSP) {
memset(sh_buf_tmp, 0x00, size);
}
/*Horizontal blur*/
else {
lv_coord_t x;
int32_t last_val = 255 << SHADOW_UPSACALE_SHIFT;
int32_t chg = 0;
for(x = 0; x < size; x++) {
if(chg) last_val += chg/sw;
sh_buf_tmp[x] = last_val >> SHADOW_UPSACALE_SHIFT;
/*Forget the left pixel*/
chg = 0;
uint32_t left_val;
if(x - s_left <= 0) left_val = 255;
else left_val = mask_line[x - s_left];
chg -= (left_val << SHADOW_UPSACALE_SHIFT);
/*Add the right pixel*/
uint32_t right_val = 0;
if(x + s_right + 1 < size) right_val = mask_line[x + s_right + 1];
chg += (right_val << SHADOW_UPSACALE_SHIFT);
}
}
sh_buf_tmp += size;
}
lv_mask_remove_id(mask_id);
}