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

suppor blend modes on images

This commit is contained in:
Gabor Kiss-Vamosi 2019-09-10 06:13:08 +02:00
parent 2acbc59a46
commit d0bc387c14
4 changed files with 101 additions and 20 deletions

View File

@ -438,7 +438,10 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
if(found_p == NULL) {
const lv_style_t * style = lv_obj_get_style(obj);
if(style->body.opa == LV_OPA_COVER && design_res == LV_DESIGN_RES_COVER &&
lv_obj_get_opa_scale(obj) == LV_OPA_COVER) {
lv_obj_get_opa_scale(obj) == LV_OPA_COVER &&
style->body.blend_mode == LV_BLEND_MODE_NORMAL &&
style->body.border.blend_mode == LV_BLEND_MODE_NORMAL &&
style->image.blend_mode == LV_BLEND_MODE_NORMAL) {
found_p = obj;
}
}

View File

@ -71,7 +71,7 @@ void lv_style_init(void)
/*Screen style*/
lv_style_scr.glass = 0;
lv_style_scr.body.opa = LV_OPA_TRANSP;
lv_style_scr.body.opa = LV_OPA_COVER;
lv_style_scr.body.main_color = LV_COLOR_WHITE;
lv_style_scr.body.grad_color = LV_COLOR_WHITE;
lv_style_scr.body.radius = 0;
@ -107,7 +107,7 @@ void lv_style_init(void)
lv_style_scr.image.opa = LV_OPA_COVER;
lv_style_scr.image.color = lv_color_make(0x20, 0x20, 0x20);
lv_style_scr.image.intense = LV_OPA_TRANSP;
lv_style_scr.image.blend_mode = LV_BLEND_MODE_NORMAL;
lv_style_scr.image.blend_mode = LV_BLEND_MODE_SUBTRACTIVE;
lv_style_scr.line.opa = LV_OPA_COVER;
lv_style_scr.line.color = lv_color_make(0x20, 0x20, 0x20);
@ -127,19 +127,20 @@ void lv_style_init(void)
lv_style_copy(&lv_style_plain_color, &lv_style_plain);
lv_style_plain_color.text.color = lv_color_make(0xf0, 0xf0, 0xf0);
lv_style_plain_color.image.color = lv_color_make(0xf0, 0xf0, 0xf0);
// lv_style_plain_color.image.blend_mode = LV_BLEND_MODE_SUBTRACTIVE;
lv_style_plain_color.line.color = lv_color_make(0xf0, 0xf0, 0xf0);
lv_style_plain_color.body.main_color = lv_color_make(0x55, 0x96, 0xd8);
lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color;
/*Pretty style */
lv_style_copy(&lv_style_pretty, &lv_style_plain);
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_WHITE;
lv_style_pretty.body.grad_color = LV_COLOR_BLACK;
lv_style_pretty.body.grad_color = LV_COLOR_SILVER;
lv_style_pretty.body.radius = LV_DPI / 5;
// lv_style_pretty.body.opa = LV_OPA_40;//LV_DPI / 5;
lv_style_pretty.body.border.color = lv_color_make(0x40, 0x40, 0x40);
lv_style_pretty.body.border.width = LV_DPI / 50 >= 1 ? LV_DPI / 50 : 1;
lv_style_pretty.body.border.opa = LV_OPA_30;

View File

@ -47,6 +47,10 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons
const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t opa,
const lv_opa_t * mask, lv_draw_mask_res_t mask_res);
static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area,
const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t opa,
const lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_blend_mode_t mode);
static inline lv_color_t color_blend_true_color_additive(lv_color_t bg, lv_color_t fg, lv_opa_t opa);
static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
@ -151,8 +155,9 @@ void lv_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area, const
}
else if(mode == LV_BLEND_MODE_NORMAL) {
map_normal(disp_area, disp_buf, &draw_area, map_area, map_buf, opa, mask, mask_res);
} else {
map_blended(disp_area, disp_buf, &draw_area, map_area, map_buf, opa, mask, mask_res, mode);
}
}
@ -419,7 +424,7 @@ static void fill_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, co
for(x = draw_area->x1; x <= draw_area->x2; x++) {
if(mask_tmp[x] == 0) continue;
if(mask_tmp[x] != last_mask || last_dest_color.full != disp_buf_tmp[x].full) {
lv_opa_t opa_tmp = (uint16_t)((uint16_t)mask_tmp[x] * opa) >> 8;
lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : (uint16_t)((uint16_t)mask_tmp[x] * opa) >> 8;
last_res_color = blend_fp(color, disp_buf_tmp[x], opa_tmp);
last_mask = mask_tmp[x];
@ -625,6 +630,80 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons
}
}
static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area,
const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t opa,
const lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_blend_mode_t mode)
{
/*Get the width of the `disp_area` it will be used to go to the next line*/
lv_coord_t disp_w = lv_area_get_width(disp_area);
/*Get the width of the `draw_area` it will be used to go to the next line of the mask*/
lv_coord_t draw_area_w = lv_area_get_width(draw_area);
/*Get the width of the `mask_area` it will be used to go to the next line*/
lv_coord_t map_w = lv_area_get_width(map_area);
/*Create a temp. disp_buf which always point to current line to draw*/
lv_color_t * disp_buf_tmp = disp_buf + disp_w * draw_area->y1;
/*Create a temp. map_buf which always point to current line to draw*/
const lv_color_t * map_buf_tmp = map_buf + map_w * (draw_area->y1 - (map_area->y1 - disp_area->y1));
lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t);
switch (mode) {
case LV_BLEND_MODE_ADDITIVE:
blend_fp = color_blend_true_color_additive;
break;
case LV_BLEND_MODE_SUBTRACTIVE:
blend_fp = color_blend_true_color_subtractive;
break;
default:
LV_LOG_WARN("fill_blended: unsupported blend mode");
return;
break;
}
lv_coord_t x;
lv_coord_t y;
/*Simple fill (maybe with opacity), no masking*/
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) {
/*Go to the first px of the row*/
map_buf_tmp += (draw_area->x1 - (map_area->x1 - disp_area->x1));
/*The map will be indexed from `draw_area->x1` so compensate it.*/
map_buf_tmp -= draw_area->x1;
for(y = draw_area->y1; y <= draw_area->y2; y++) {
for(x = draw_area->x1; x <= draw_area->x2; x++) {
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa);
}
disp_buf_tmp += disp_w;
map_buf_tmp += map_w;
}
}
/*Masked*/
else {
/* The mask is relative to the clipped area.
* In the cycles below mask will be indexed from `draw_area.x1`
* but it corresponds to zero index. So prepare `mask_tmp` accordingly. */
const lv_opa_t * mask_tmp = mask - draw_area->x1;
map_buf_tmp -= draw_area->x1;
for(y = draw_area->y1; y <= draw_area->y2; y++) {
for(x = draw_area->x1; x <= draw_area->x2; x++) {
if(mask_tmp[x] == 0) continue;
lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8);
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp);
}
disp_buf_tmp += disp_w;
mask_tmp += draw_area_w;
map_buf_tmp += map_w;
}
}
}
static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
{

View File

@ -27,7 +27,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
const lv_style_t * style, lv_opa_t opa_scale);
static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, const uint8_t * map_p, lv_opa_t opa,
bool chroma_key, bool alpha_byte, lv_color_t recolor, lv_opa_t recolor_opa);
bool chroma_key, bool alpha_byte, const lv_style_t * style);
/**********************
* STATIC VARIABLES
@ -504,8 +504,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
/* The decoder open could open the image and gave the entire uncompressed image.
* Just draw it!*/
else if(cdsc->dec_dsc.img_data) {
lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style->image.color,
style->image.intense);
lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style);
}
/* The whole uncompressed image is not available. Try to read it line-by-line*/
else {
@ -527,7 +526,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
LV_LOG_WARN("Image draw can't read the line");
return LV_RES_INV;
}
lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style);
line.y1++;
line.y2++;
y++;
@ -545,11 +544,10 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
* @param opa opacity of the map
* @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
* @param alpha_byte true: extra alpha byte is inserted for every pixel
* @param recolor mix the pixels with this color
* @param recolor_opa the intense of recoloring
* @param style style of the image
*/
static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, const uint8_t * map_p, lv_opa_t opa,
bool chroma_key, bool alpha_byte, lv_color_t recolor, lv_opa_t recolor_opa)
bool chroma_key, bool alpha_byte, const lv_style_t * style)
{
if(opa < LV_OPA_MIN) return;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
@ -578,8 +576,8 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
uint8_t other_mask_cnt = lv_draw_mask_get_cnt();
/*The simplest case just copy the pixels into the VDB*/
if(other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) {
lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, LV_OPA_COVER, LV_BLEND_MODE_NORMAL);
if(other_mask_cnt == 0 && chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && style->image.intense == LV_OPA_TRANSP) {
lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, LV_OPA_COVER, style->image.blend_mode);
}
/*In the other cases every pixel need to be checked one-by-one*/
else {
@ -646,8 +644,8 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
}
}
if(recolor_opa != 0) {
c = lv_color_mix(recolor, c, recolor_opa);
if(style->image.intense != 0) {
c = lv_color_mix(style->image.color, c, style->image.intense);
}
map2[px_i].full = c.full;
@ -669,7 +667,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
if(px_i + lv_area_get_width(&draw_area) < sizeof(mask_buf)) {
blend_area.y2 ++;
} else {
lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, opa, LV_BLEND_MODE_NORMAL);
lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, opa, style->image.blend_mode);
blend_area.y1 = blend_area.y2 + 1;
blend_area.y2 = blend_area.y1;
@ -686,7 +684,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
/*Flush the last part*/
if(blend_area.y1 != blend_area.y2) {
blend_area.y2--;
lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, opa, LV_BLEND_MODE_NORMAL);
lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, opa, style->image.blend_mode);
}
}