shadow fixes

This commit is contained in:
Gabor Kiss-Vamosi 2020-03-31 11:06:57 +02:00
parent 88c31521e0
commit ef7a8f3543
3 changed files with 133 additions and 69 deletions

View File

@ -144,6 +144,13 @@ typedef void * lv_anim_user_data_t;
/* 1: Enable shadow drawing*/
#define LV_USE_SHADOW 1
#if LV_USE_SHADOW
/* Allow buffering some shadow calculation
* LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer,
* where shadow size is `shadow_width + radius`
* Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#define LV_SHADOW_CACHE_SIZE 0
#endif
/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/
#define LV_USE_BLEND_MODES 1

View File

@ -215,6 +215,15 @@
#ifndef LV_USE_SHADOW
#define LV_USE_SHADOW 1
#endif
#if LV_USE_SHADOW
/* Allow buffering some shadow calculation
* LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer,
* where shadow size is `shadow_width + radius`
* Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#ifndef LV_SHADOW_CACHE_SIZE
#define LV_SHADOW_CACHE_SIZE 0
#endif
#endif
/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/
#ifndef LV_USE_BLEND_MODES
@ -295,6 +304,11 @@
#define LV_ATTRIBUTE_TASK_HANDLER
#endif
/* Define a custom attribute to `lv_disp_flush_ready` function */
#ifndef LV_ATTRIBUTE_FLUSH_READY
#define LV_ATTRIBUTE_FLUSH_READY
#endif
/* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
* E.g. __attribute__((aligned(4))) */
@ -394,10 +408,8 @@
/*Check the integrity of `lv_mem` after critical operations. (Slow)*/
#ifndef LV_USE_ASSERT_MEM_INTEGRITY
#ifndef LV_USE_ASSERT_MEM_INTEGRITY
#define LV_USE_ASSERT_MEM_INTEGRITY 0
#endif
#endif
/* Check the strings.
* Search for NULL, very long strings, invalid characters, and unnatural repetitions. (Slow)
@ -414,7 +426,7 @@
/*Check if the styles are properly initialized. (Fast)*/
#ifndef LV_USE_ASSERT_STYLE
#define LV_USE_ASSERT_STYLE 1
#define LV_USE_ASSERT_STYLE 0
#endif
#endif /*LV_USE_DEBUG*/
@ -768,7 +780,7 @@
#endif
#if LV_USE_LED
#ifndef LV_LED_BRIGHT_MIN
# define LV_LED_BRIGHT_MIN 100 /*Minimal brightness*/
# define LV_LED_BRIGHT_MIN 60 /*Minimal brightness*/
#endif
#ifndef LV_LED_BRIGHT_MAX
# define LV_LED_BRIGHT_MAX 255 /*Maximal brightness*/

View File

@ -19,7 +19,6 @@
*********************/
#define SHADOW_UPSACALE_SHIFT 6
#define SHADOW_ENHANCE 1
#define SHADOW_CACHE_SIZE 100
#define SPLIT_LIMIT 50
/**********************
@ -31,20 +30,24 @@
**********************/
static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static void draw_border(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static inline lv_color_t grad_get(lv_draw_rect_dsc_t * dsc, lv_coord_t s, lv_coord_t i);
#if LV_USE_SHADOW
static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static void shadow_draw_corner_buf(const lv_area_t * coords, uint16_t * sh_buf, lv_coord_t s, lv_coord_t r);
static void shadow_blur_corner(lv_coord_t size, lv_coord_t sw, uint16_t * sh_ups_buf);
#endif
static void draw_pattern(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
static void draw_value(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
static uint8_t sh_cache[SHADOW_CACHE_SIZE * SHADOW_CACHE_SIZE];
#if LV_USE_SHADOW && LV_SHADOW_CACHE_SIZE
static uint8_t sh_cache[LV_SHADOW_CACHE_SIZE * LV_SHADOW_CACHE_SIZE];
static int32_t sh_cache_size = -1;
static int32_t sh_cache_r = -1;
#endif
/**********************
* MACROS
@ -85,8 +88,10 @@ void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc)
{
if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return;
#if LV_USE_SHADOW
draw_shadow(coords, clip, dsc);
#endif
draw_outline(coords, clip, dsc);
draw_bg(coords, clip, dsc);
draw_pattern(coords, clip, dsc);
@ -558,7 +563,7 @@ static inline lv_color_t grad_get(lv_draw_rect_dsc_t * dsc, lv_coord_t s, lv_coo
lv_opa_t mix = (i * 255) / d;
return lv_color_mix(dsc->bg_grad_color, dsc->bg_color, mix);
}
#if LV_USE_SHADOW
static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc)
{
/*Check whether the shadow is visible*/
@ -629,19 +634,30 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
lv_opa_t * sh_buf;
#if LV_SHADOW_CACHE_SIZE
if(sh_cache_size == corner_size && sh_cache_r == r_sh) {
/*Use the cache if available*/
sh_buf = lv_mem_buf_get(corner_size * corner_size);
lv_memcpy(sh_buf, sh_cache, corner_size * corner_size);
} else {
/*A larger buffer is required for calculation */
sh_buf = lv_mem_buf_get(corner_size * corner_size * sizeof(uint16_t));
shadow_draw_corner_buf(&sh_rect_area, (uint16_t *)sh_buf, dsc->shadow_width, r_sh);
/*Cache the corner if it fits into the cache size*/
if(corner_size * corner_size < sizeof(sh_cache)) {
lv_memcpy(sh_cache, sh_buf, corner_size * corner_size);
sh_cache_size = corner_size;
sh_cache_r = r_sh;
}
}
#else
sh_buf = lv_mem_buf_get(corner_size * corner_size * sizeof(uint16_t));
shadow_draw_corner_buf(&sh_rect_area, (uint16_t *)sh_buf, dsc->shadow_width, r_sh);
#endif
lv_coord_t h_half = sh_area.y1 + lv_area_get_height(&sh_area) / 2;
lv_coord_t w_half = sh_area.x1 + lv_area_get_width(&sh_area) / 2;
bool simple_mode = true;
if(lv_draw_mask_get_cnt() > 0) simple_mode = false;
@ -670,29 +686,34 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
lv_area_t ca;
bool has_com = lv_area_intersect(&ca, &a, clip);
if(has_com) {
/*Avoid overlap in the middle with large radius*/
if(ca.y2 > h_half) ca.y2 = h_half;
if(ca.x1 <= w_half) ca.x1 = w_half + 1;
lv_coord_t h = lv_area_get_height(&ca);
lv_coord_t w = lv_area_get_width(&ca);
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (ca.y1 - a.y1);
if(w > 0) {
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (ca.y1 - a.y1);
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y2 = fa.y1;
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y2 = fa.y1;
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1++;
fa.y2++;
sh_buf_tmp += corner_size;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1++;
fa.y2++;
sh_buf_tmp += corner_size;
}
}
}
/*Draw the bottom right corner*/
a.x2 = sh_area.x2;
a.x1 = a.x2 - corner_size + 1;
@ -701,25 +722,32 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
has_com = lv_area_intersect(&ca, &a, clip);
if(has_com) {
/*Avoid overlap in the middle with large radius*/
if(ca.y1 <= h_half) ca.y1 = h_half + 1;
if(ca.x1 <= w_half) ca.x1 = w_half + 1;
lv_coord_t h = lv_area_get_height(&ca);
lv_coord_t w = lv_area_get_width(&ca);
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (a.y2 - ca.y2);
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y1 = fa.y2; /*Fill from bottom to top*/
if(w > 0) {
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (a.y2 - ca.y2);
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y1 = fa.y2; /*Fill from bottom to top*/
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1--;
fa.y2--;
sh_buf_tmp += corner_size;
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1--;
fa.y2--;
sh_buf_tmp += corner_size;
}
}
}
@ -783,25 +811,31 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
has_com = lv_area_intersect(&ca, &a, clip);
if(has_com) {
/*Avoid overlap in the middle with large radius*/
if(ca.y2 > h_half) ca.y2 = h_half;
if(ca.x2 > w_half) ca.x2 = w_half;
lv_coord_t h = lv_area_get_height(&ca);
lv_coord_t w = lv_area_get_width(&ca);
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (ca.y1 - a.y1);
if(w > 0) {
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (ca.y1 - a.y1);
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y2 = fa.y1;
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y2 = fa.y1;
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1++;
fa.y2++;
sh_buf_tmp += corner_size;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1++;
fa.y2++;
sh_buf_tmp += corner_size;
}
}
}
@ -813,29 +847,34 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
has_com = lv_area_intersect(&ca, &a, clip);
if(has_com) {
/*Avoid overlap in the middle with large radius*/
if(ca.y1 <= h_half) ca.y1 = h_half + 1;
if(ca.x2 > w_half) ca.x2 = w_half;
lv_coord_t h = lv_area_get_height(&ca);
lv_coord_t w = lv_area_get_width(&ca);
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (a.y2 - ca.y2);
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y1 = fa.y2; /*Fill from bottom to top*/
if(w > 0) {
sh_buf_tmp = sh_buf + (ca.x1 - a.x1);
sh_buf_tmp += corner_size * (a.y2 - ca.y2);
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_area_t fa;
lv_area_copy(&fa, &ca);
fa.y1 = fa.y2; /*Fill from bottom to top*/
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
for(y = 0; y < h; y++) {
lv_memcpy(mask_buf, sh_buf_tmp, w);
mask_res = lv_draw_mask_apply(mask_buf, fa.x1, fa.y1, w);
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED;
lv_blend_fill(clip, &fa, dsc->shadow_color, mask_buf,
mask_res, opa, dsc->shadow_blend_mode);
fa.y1--;
fa.y2--;
sh_buf_tmp += corner_size;
}
fa.y1--;
fa.y2--;
sh_buf_tmp += corner_size;
}
}
}
/*Fill the left side*/
a.x1 = sh_area.x1;
a.x2 = a.x1 + corner_size - 1;
@ -953,7 +992,6 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
}
}
/*Draw the middle area*/
a.x1 = sh_area.x1 + corner_size;
a.x2 = sh_area.x2 - corner_size;
@ -986,6 +1024,13 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra
lv_mem_buf_release(sh_buf);
}
/**
* Calculate a blurred corner
* @param coords Coordinates of the shadow
* @param sh_buf a buffer to store the result. It's size should be `(sw + r)^2 * 2`
* @param sw shadow width
* @param r radius
*/
static void shadow_draw_corner_buf(const lv_area_t * coords, uint16_t * sh_buf, lv_coord_t sw, lv_coord_t r)
{
int32_t sw_ori = sw;
@ -1140,7 +1185,7 @@ static void shadow_blur_corner(lv_coord_t size, lv_coord_t sw, uint16_t * sh_ups
lv_mem_buf_release(sh_ups_blur_buf);
}
#endif
static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, lv_draw_rect_dsc_t * dsc)
{