From d33db6bb59dc25147f6f8581558fd2c2d6c948b7 Mon Sep 17 00:00:00 2001 From: Mariotaku Date: Tue, 18 Jan 2022 19:41:45 +0900 Subject: [PATCH] feat(sdl): support rounded images (#3012) * added radius mask for rounded img * improved mask composite improved image zoom fidelity * implementing sdl image radius * low performance radius img drawing * improved rounded image performance * improved rounded image performance * improved rounded image blending * pixel perfect rounded image for SDL * accurate drawing only * supports rounded img for rect as well * fixed mask check when zoomed * surrounded rounded mask in lv_img with draw_complex check * updated docs * fixed build issue * aware of clip_corner property * reverted lv_img.c * updated docs --- docs/widgets/core/img.md | 8 +- src/draw/sdl/lv_draw_sdl_composite.c | 6 +- src/draw/sdl/lv_draw_sdl_composite.h | 1 + src/draw/sdl/lv_draw_sdl_img.c | 428 ++++++++++++++++++----- src/draw/sdl/lv_draw_sdl_img.h | 72 ++++ src/draw/sdl/lv_draw_sdl_rect.c | 219 ++++++------ src/draw/sdl/lv_draw_sdl_rect.h | 75 ++++ src/draw/sdl/lv_draw_sdl_texture_cache.h | 1 + src/draw/sdl/lv_draw_sdl_utils.c | 12 +- src/misc/lv_area.c | 5 + src/misc/lv_area.h | 7 + 11 files changed, 627 insertions(+), 207 deletions(-) create mode 100644 src/draw/sdl/lv_draw_sdl_img.h create mode 100644 src/draw/sdl/lv_draw_sdl_rect.h diff --git a/docs/widgets/core/img.md b/docs/widgets/core/img.md index 82d1f8d2f..da98e9d58 100644 --- a/docs/widgets/core/img.md +++ b/docs/widgets/core/img.md @@ -100,7 +100,13 @@ It also means the layouts are not affected the by the transformations. If you need the object size to be updated to the transformed size set `lv_img_set_size_mode(img, LV_IMG_SIZE_MODE_REAL)`. (The previous mode is the default and called `LV_IMG_SIZE_MODE_VIRTUAL`). In this case if the width/height of the object is set to `LV_SIZE_CONTENT` the object's size will be set to the zoomed and rotated size. -If an explicit size is set then the overflowing content will be cropped. +If an explicit size is set then the overflowing content will be cropped. + +### Rounded image + +You can use `lv_obj_set_style_radius` to set radius to an image, and enable `lv_obj_set_style_clip_corner` to clip the +content to rounded rectangle or circular shape. Please note this will have some negative performance impact to CPU +based renderers. ## Events No special events are sent by image objects. diff --git a/src/draw/sdl/lv_draw_sdl_composite.c b/src/draw/sdl/lv_draw_sdl_composite.c index 91665aed8..1ee843f7a 100644 --- a/src/draw/sdl/lv_draw_sdl_composite.c +++ b/src/draw/sdl/lv_draw_sdl_composite.c @@ -146,21 +146,21 @@ void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_ SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); break; case LV_BLEND_MODE_ADDITIVE: - SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_ADD); + SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_ADD); break; #if LV_GPU_SDL_CUSTOM_BLEND_MODE case LV_BLEND_MODE_SUBTRACTIVE: { SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT, SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT); - SDL_SetRenderDrawBlendMode(ctx->renderer, mode); + SDL_SetTextureBlendMode(internals->composition, mode); break; } case LV_BLEND_MODE_MULTIPLY: { SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_DST_ALPHA, SDL_BLENDOPERATION_ADD); - SDL_SetRenderDrawBlendMode(ctx->renderer, mode); + SDL_SetTextureBlendMode(internals->composition, mode); break; } #endif diff --git a/src/draw/sdl/lv_draw_sdl_composite.h b/src/draw/sdl/lv_draw_sdl_composite.h index 89c5a5c5a..3050815d7 100644 --- a/src/draw/sdl/lv_draw_sdl_composite.h +++ b/src/draw/sdl/lv_draw_sdl_composite.h @@ -34,6 +34,7 @@ typedef enum lv_draw_sdl_composite_texture_id_t { LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET1, } lv_draw_sdl_composite_texture_id_t; /********************** diff --git a/src/draw/sdl/lv_draw_sdl_img.c b/src/draw/sdl/lv_draw_sdl_img.c index 743675c8e..c6782386e 100644 --- a/src/draw/sdl/lv_draw_sdl_img.c +++ b/src/draw/sdl/lv_draw_sdl_img.c @@ -15,9 +15,13 @@ #include "../lv_img_cache.h" #include "../lv_draw_mask.h" #include "../../misc/lv_lru.h" +#include "../../misc/lv_gc.h" +#include "lv_draw_sdl_img.h" #include "lv_draw_sdl_utils.h" #include "lv_draw_sdl_texture_cache.h" +#include "lv_draw_sdl_composite.h" +#include "lv_draw_sdl_rect.h" /********************* * DEFINES @@ -26,10 +30,28 @@ /********************** * TYPEDEFS **********************/ -typedef struct sdl_img_header_t { - lv_img_header_t base; - SDL_Rect rect; -} sdl_img_header_t; + +typedef struct { + lv_sdl_cache_key_magic_t magic; + const SDL_Texture * texture; + lv_coord_t w, h, radius; +} lv_draw_img_rounded_key_t; + +enum { + ROUNDED_IMG_PART_LEFT = 0, + ROUNDED_IMG_PART_HCENTER = 1, + ROUNDED_IMG_PART_RIGHT = 2, + ROUNDED_IMG_PART_TOP = 3, + ROUNDED_IMG_PART_VCENTER = 4, + ROUNDED_IMG_PART_BOTTOM = 5, +}; + +enum { + ROUNDED_IMG_CORNER_TOP_LEFT = 0, + ROUNDED_IMG_CORNER_TOP_RIGHT = 1, + ROUNDED_IMG_CORNER_BOTTOM_RIGHT = 2, + ROUNDED_IMG_CORNER_BOTTOM_LEFT = 3, +}; /********************** * STATIC PROTOTYPES @@ -39,6 +61,23 @@ static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_ static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc); +static bool check_mask_simple_radius(const lv_area_t * coords, lv_coord_t * radius); + +static void draw_img_simple(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, + const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip); + +static void draw_img_rounded(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, + const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip, + lv_coord_t radius); + +static SDL_Texture * img_rounded_frag_obtain(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, + const lv_draw_sdl_img_header_t * header, int w, int h, lv_coord_t radius); + +static lv_draw_img_rounded_key_t rounded_key_create(const SDL_Texture * texture, lv_coord_t w, lv_coord_t h, + lv_coord_t radius); + +static void calc_draw_part(SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, const lv_area_t * coords, + const lv_area_t * clip, SDL_Rect * clipped_src, SDL_Rect * clipped_dst); /********************** * STATIC VARIABLES **********************/ @@ -47,6 +86,9 @@ static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img * MACROS **********************/ + +static void apply_recolor_opa(SDL_Texture * texture, const lv_draw_img_dsc_t * draw_dsc); + /********************** * GLOBAL FUNCTIONS **********************/ @@ -56,114 +98,123 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t { const lv_area_t * clip = draw_ctx->clip_area; lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; - SDL_Renderer * renderer = ctx->renderer; size_t key_size; lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(src, draw_dsc->frame_id, &key_size); bool texture_found = false; - sdl_img_header_t * header = NULL; + lv_draw_sdl_img_header_t * header = NULL; SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &texture_found, (void **) &header); if(!texture_found) { - _lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id); - lv_draw_sdl_cache_flag_t tex_flags = 0; - SDL_Rect rect; - SDL_memset(&rect, 0, sizeof(SDL_Rect)); - if(cdsc) { - lv_img_decoder_dsc_t * dsc = &cdsc->dec_dsc; - if(dsc->user_data && SDL_memcmp(dsc->user_data, LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD, 8) == 0) { - lv_draw_sdl_dec_dsc_userdata_t * ptr = (lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data; - texture = ptr->texture; - rect = ptr->rect; - if(ptr->texture_managed) { - tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED; - } - ptr->texture_referenced = true; - } - else { - texture = upload_img_texture(renderer, dsc); - } -#if LV_IMG_CACHE_DEF_SIZE == 0 - lv_img_decoder_close(dsc); -#endif - } - if(texture && cdsc) { - header = SDL_malloc(sizeof(sdl_img_header_t)); - SDL_memcpy(&header->base, &cdsc->dec_dsc.header, sizeof(lv_img_header_t)); - header->rect = rect; - lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_size, texture, header, SDL_free, tex_flags); - } - else { - lv_draw_sdl_texture_cache_put(ctx, key, key_size, NULL); - } + lv_draw_sdl_img_load_texture(ctx, key, key_size, src, draw_dsc->frame_id, &texture, &header); } SDL_free(key); if(!texture) { return LV_RES_INV; } - SDL_Rect clip_rect, coords_rect; - lv_area_to_sdl_rect(clip, &clip_rect); - lv_area_to_sdl_rect(coords, &coords_rect); - lv_area_zoom_to_sdl_rect(coords, &coords_rect, draw_dsc->zoom, &draw_dsc->pivot); + lv_area_t zoomed_cords; + _lv_img_buf_get_transformed_area(&zoomed_cords, lv_area_get_width(coords), lv_area_get_height(coords), 0, + draw_dsc->zoom, &draw_dsc->pivot); + lv_area_move(&zoomed_cords, coords->x1, coords->y1); - SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y}; - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_Rect clipped_src = {0, 0, 0, 0}, clipped_dst = coords_rect; - const SDL_Rect * src_rect = NULL, *dst_rect = &clipped_dst; + /* When in > 0, draw simple radius */ + lv_coord_t radius = 0; + /* Coords will be translated so coords will start at (0,0) */ + lv_area_t t_coords = zoomed_cords, t_clip = *clip, apply_area; - if(_lv_area_is_in(coords, clip, 0)) { - /*Image needs to be fully drawn*/ - src_rect = SDL_RectEmpty(&header->rect) ? NULL : &header->rect; + if(!check_mask_simple_radius(&t_coords, &radius)) { + lv_draw_sdl_composite_begin(ctx, &zoomed_cords, clip, NULL, draw_dsc->blend_mode, + &t_coords, &t_clip, &apply_area); } - else if(draw_dsc->angle == 0) { - /*Image needs to be partly drawn, and we calculate the area to draw manually*/ + + SDL_Rect clip_rect, coords_rect; + lv_area_to_sdl_rect(&t_clip, &clip_rect); + lv_area_to_sdl_rect(&t_coords, &coords_rect); + + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + + if(radius > 0) { + draw_img_rounded(ctx, texture, header, draw_dsc, &t_coords, &t_clip, radius); + } + else { + draw_img_simple(ctx, texture, header, draw_dsc, &t_coords, &t_clip); + } + + lv_draw_sdl_composite_end(ctx, &apply_area, draw_dsc->blend_mode); + + return LV_RES_OK; +} + +static void calc_draw_part(SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, const lv_area_t * coords, + const lv_area_t * clip, SDL_Rect * clipped_src, SDL_Rect * clipped_dst) +{ + double x = 0, y = 0, w, h; + if(SDL_RectEmpty(&header->rect)) { Uint32 format = 0; - int access = 0, w, h; - if(SDL_RectEmpty(&header->rect)) { - SDL_QueryTexture(texture, &format, &access, &w, &h); + int access = 0, tw, th; + SDL_QueryTexture(texture, &format, &access, &tw, &th); + w = tw; + h = th; + } + else { + x = header->rect.x; + y = header->rect.y; + w = header->rect.w; + h = header->rect.h; + } + if(clip) { + lv_area_t clipped_area; + _lv_area_intersect(&clipped_area, coords, clip); + lv_area_to_sdl_rect(&clipped_area, clipped_dst); + } + else { + lv_area_to_sdl_rect(coords, clipped_dst); + } + lv_coord_t coords_w = lv_area_get_width(coords), coords_h = lv_area_get_height(coords); + clipped_src->x = (int)(x + (clipped_dst->x - coords->x1) * w / coords_w); + clipped_src->y = (int)(y + (clipped_dst->y - coords->y1) * h / coords_h); + clipped_src->w = (int)(w - (coords_w - clipped_dst->w) * w / coords_w); + clipped_src->h = (int)(h - (coords_h - clipped_dst->h) * h / coords_h); +} + +bool lv_draw_sdl_img_load_texture(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_cache_key_head_img_t * key, size_t key_size, + const void * src, int32_t frame_id, SDL_Texture ** texture, + lv_draw_sdl_img_header_t ** header) +{ + _lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, lv_color_white(), frame_id); + lv_draw_sdl_cache_flag_t tex_flags = 0; + SDL_Rect rect; + SDL_memset(&rect, 0, sizeof(SDL_Rect)); + if(cdsc) { + lv_img_decoder_dsc_t * dsc = &cdsc->dec_dsc; + if(dsc->user_data && SDL_memcmp(dsc->user_data, LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD, 8) == 0) { + lv_draw_sdl_dec_dsc_userdata_t * ptr = (lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data; + *texture = ptr->texture; + rect = ptr->rect; + if(ptr->texture_managed) { + tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED; + } + ptr->texture_referenced = true; } else { - w = header->rect.w; - h = header->rect.h; + *texture = upload_img_texture(ctx->renderer, dsc); } - SDL_IntersectRect(&clip_rect, &coords_rect, &clipped_dst); - clipped_src.x = header->rect.x + (clipped_dst.x - coords_rect.x) * w / coords_rect.w; - clipped_src.y = header->rect.y + (clipped_dst.y - coords_rect.y) * h / coords_rect.h; - clipped_src.w = w - (coords_rect.w - clipped_dst.w) * w / coords_rect.w; - clipped_src.h = h - (coords_rect.h - clipped_dst.h) * h / coords_rect.h; - src_rect = &clipped_src; +#if LV_IMG_CACHE_DEF_SIZE == 0 + lv_img_decoder_close(dsc); +#endif + } + if(texture && cdsc) { + *header = SDL_malloc(sizeof(lv_draw_sdl_img_header_t)); + SDL_memcpy(&(*header)->base, &cdsc->dec_dsc.header, sizeof(lv_img_header_t)); + (*header)->rect = rect; + lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_size, *texture, *header, SDL_free, tex_flags); } else { - /*Image needs to be rotated, so we have to use clip rect which is slower*/ - SDL_RenderSetClipRect(renderer, &clip_rect); + lv_draw_sdl_texture_cache_put(ctx, key, key_size, NULL); + return false; } - - SDL_Color recolor; - lv_color_to_sdl_color(&draw_dsc->recolor, &recolor); - if(draw_dsc->recolor_opa == LV_OPA_COVER) { - /* Draw fully recolored image*/ - SDL_SetTextureColorMod(texture, draw_dsc->recolor.ch.red, recolor.g, recolor.b); - SDL_SetTextureAlphaMod(texture, draw_dsc->opa); - SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); - } - else if(draw_dsc->recolor_opa > LV_OPA_TRANSP) { - /* Draw blended. src: origA, dst: origA * recolorA */ - SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF); - SDL_SetTextureAlphaMod(texture, draw_dsc->opa); - SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); - SDL_SetTextureColorMod(texture, recolor.r, recolor.g, recolor.b); - SDL_SetTextureAlphaMod(texture, draw_dsc->opa * draw_dsc->recolor_opa / 255); - SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); - } - else { - /* Draw with no recolor */ - SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF); - SDL_SetTextureAlphaMod(texture, draw_dsc->opa); - SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); - } - SDL_RenderSetClipRect(renderer, NULL); - return LV_RES_OK; + return true; } /********************** @@ -175,9 +226,9 @@ static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_ if(!dsc->img_data) { return upload_img_texture_fallback(renderer, dsc); } - bool chroma_keyed = dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; - uint32_t h = dsc->header.h; - uint32_t w = dsc->header.w; + bool chroma_keyed = dsc->header.cf == (uint32_t) LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; + int h = (int) dsc->header.h; + int w = (int) dsc->header.w; void * data = (void *) dsc->img_data; Uint32 rmask = 0x00FF0000; Uint32 gmask = 0x0000FF00; @@ -196,8 +247,8 @@ static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_ static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc) { - lv_coord_t h = dsc->header.h; - lv_coord_t w = dsc->header.w; + lv_coord_t h = (lv_coord_t) dsc->header.h; + lv_coord_t w = (lv_coord_t) dsc->header.w; uint8_t * data = lv_mem_buf_get(w * h * sizeof(lv_color_t)); for(lv_coord_t y = 0; y < h; y++) { lv_img_decoder_read_line(dsc, 0, y, w, &data[y * w * sizeof(lv_color_t)]); @@ -215,5 +266,194 @@ static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img return texture; } +/** + * Check if there is only one radius mask + * @param radius Set to radius value if the only mask is a radius mask + * @return true if the only mask is a radius mask + */ +static bool check_mask_simple_radius(const lv_area_t * coords, lv_coord_t * radius) +{ + if(lv_draw_mask_get_cnt() != 1) return false; + for(uint8_t i = 0; i < _LV_MASK_MAX_NUM; i++) { + _lv_draw_mask_common_dsc_t * param = LV_GC_ROOT(_lv_draw_mask_list[i]).param; + if(param->type == LV_DRAW_MASK_TYPE_RADIUS) { + lv_draw_mask_radius_param_t * rparam = (lv_draw_mask_radius_param_t *) param; + if(rparam->cfg.outer) return false; + if(!_lv_area_is_equal(&rparam->cfg.rect, coords)) return false; + *radius = rparam->cfg.radius; + return true; + } + } + return false; +} + +static void draw_img_simple(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, + const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip) +{ + apply_recolor_opa(texture, draw_dsc); + SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y}; + + /*Image needs to be rotated, so we have to use clip rect which is slower*/ + if(draw_dsc->angle != 0) { + /* No radius, set clip here */ + SDL_Rect clip_rect; + lv_area_to_sdl_rect(clip, &clip_rect); + SDL_RenderSetClipRect(ctx->renderer, &clip_rect); + } + SDL_Rect src_rect, dst_rect; + calc_draw_part(texture, header, coords, clip, &src_rect, &dst_rect); + SDL_RenderCopyEx(ctx->renderer, texture, &src_rect, &dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); + if(draw_dsc->angle != 0) { + SDL_RenderSetClipRect(ctx->renderer, NULL); + } +} + + +static void draw_img_rounded(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, const lv_draw_sdl_img_header_t * header, + const lv_draw_img_dsc_t * draw_dsc, const lv_area_t * coords, const lv_area_t * clip, + lv_coord_t radius) +{ + const int w = lv_area_get_width(coords), h = lv_area_get_height(coords); + lv_coord_t real_radius = LV_MIN3(radius, w, h); + SDL_Texture * frag = img_rounded_frag_obtain(ctx, texture, header, w, h, real_radius); + apply_recolor_opa(frag, draw_dsc); + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, frag, real_radius, coords, clip, true); + + apply_recolor_opa(texture, draw_dsc); + + SDL_Rect src_rect, dst_rect; + /* Draw 3 parts */ + lv_area_t clip_tmp, part; + calc_draw_part(texture, header, coords, NULL, &src_rect, &dst_rect); + for(int i = w > h ? ROUNDED_IMG_PART_LEFT : ROUNDED_IMG_PART_TOP, j = i + 3; i <= j; i++) { + switch(i) { + case ROUNDED_IMG_PART_LEFT: + lv_area_set(&part, coords->x1, coords->y1 + radius, coords->x1 + radius - 1, coords->y2 - radius); + break; + case ROUNDED_IMG_PART_HCENTER: + lv_area_set(&part, coords->x1 + radius, coords->y1, coords->x2 - radius, coords->y2); + break; + case ROUNDED_IMG_PART_RIGHT: + lv_area_set(&part, coords->x2 - radius + 1, coords->y1 + radius, coords->x2, coords->y2 - radius); + break; + case ROUNDED_IMG_PART_TOP: + lv_area_set(&part, coords->x1 + radius, coords->y1, coords->x2 - radius, coords->y1 + radius - 1); + break; + case ROUNDED_IMG_PART_VCENTER: + lv_area_set(&part, coords->x1 + radius, coords->y2 - radius + 1, coords->x2 - radius, coords->y2); + break; + case ROUNDED_IMG_PART_BOTTOM: + lv_area_set(&part, coords->x1, coords->y1 + radius, coords->x2, coords->y2 - radius); + break; + default: + break; + } + if(!_lv_area_intersect(&clip_tmp, &part, clip)) continue; + SDL_Rect clip_rect; + lv_area_to_sdl_rect(&clip_tmp, &clip_rect); + SDL_RenderSetClipRect(ctx->renderer, &clip_rect); + SDL_RenderCopy(ctx->renderer, texture, &src_rect, &dst_rect); + } + SDL_RenderSetClipRect(ctx->renderer, NULL); +} + +static void apply_recolor_opa(SDL_Texture * texture, const lv_draw_img_dsc_t * draw_dsc) +{ + if(draw_dsc->recolor_opa > LV_OPA_TRANSP) { + /* Draw with mixed recolor */ + lv_color_t recolor = lv_color_mix(draw_dsc->recolor, lv_color_white(), draw_dsc->recolor_opa); + SDL_SetTextureColorMod(texture, recolor.ch.red, recolor.ch.green, recolor.ch.blue); + } + else { + /* Draw with no recolor */ + SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF); + } + SDL_SetTextureAlphaMod(texture, draw_dsc->opa); +} + +static SDL_Texture * img_rounded_frag_obtain(lv_draw_sdl_ctx_t * ctx, SDL_Texture * texture, + const lv_draw_sdl_img_header_t * header, int w, int h, lv_coord_t radius) +{ + lv_draw_img_rounded_key_t key = rounded_key_create(texture, w, h, radius); + SDL_Texture * mask_frag = lv_draw_sdl_rect_bg_frag_obtain(ctx, radius); + SDL_Texture * img_frag = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(img_frag == NULL) { + const lv_coord_t full_frag_size = radius * 2 + 3; + img_frag = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, + full_frag_size, full_frag_size); + SDL_SetTextureBlendMode(img_frag, SDL_BLENDMODE_BLEND); + SDL_Texture * old_target = SDL_GetRenderTarget(ctx->renderer); + SDL_SetRenderTarget(ctx->renderer, img_frag); + SDL_SetRenderDrawColor(ctx->renderer, 0, 0, 0, 0); + SDL_RenderClear(ctx->renderer); + + lv_area_t coords = {0, 0, w - 1, h - 1}, clip; + lv_area_t frag_coords = {0, 0, full_frag_size - 1, full_frag_size - 1}; + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, mask_frag, radius, &frag_coords, NULL, false); + + SDL_SetTextureAlphaMod(texture, 0xFF); + SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF); +#if LV_GPU_SDL_CUSTOM_BLEND_MODE + SDL_BlendMode blend_mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, + SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_DST_ALPHA, + SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD); + SDL_SetTextureBlendMode(texture, blend_mode); +#else + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD); +#endif + SDL_Rect srcrect, cliprect, dstrect = {0, 0, radius, radius}; + + cliprect.w = cliprect.h = radius; + for(int i = 0; i <= ROUNDED_IMG_CORNER_BOTTOM_LEFT; i++) { + switch(i) { + case ROUNDED_IMG_CORNER_TOP_LEFT: + cliprect.x = 0; + cliprect.y = 0; + lv_area_align(&frag_coords, &coords, LV_ALIGN_TOP_LEFT, 0, 0); + break; + case ROUNDED_IMG_CORNER_TOP_RIGHT: + cliprect.x = full_frag_size - radius; + cliprect.y = 0; + lv_area_align(&frag_coords, &coords, LV_ALIGN_TOP_RIGHT, 0, 0); + break; + case ROUNDED_IMG_CORNER_BOTTOM_RIGHT: + cliprect.x = full_frag_size - radius; + cliprect.y = full_frag_size - radius; + lv_area_align(&frag_coords, &coords, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + break; + case ROUNDED_IMG_CORNER_BOTTOM_LEFT: + cliprect.x = 0; + cliprect.y = full_frag_size - radius; + lv_area_align(&frag_coords, &coords, LV_ALIGN_BOTTOM_LEFT, 0, 0); + break; + default: + break; + } + calc_draw_part(texture, header, &coords, NULL, &srcrect, &dstrect); + SDL_RenderSetClipRect(ctx->renderer, &cliprect); + SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect); + } + SDL_RenderSetClipRect(ctx->renderer, NULL); + + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + + SDL_SetRenderTarget(ctx->renderer, old_target); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), img_frag); + } + return img_frag; +} + +static lv_draw_img_rounded_key_t rounded_key_create(const SDL_Texture * texture, lv_coord_t w, lv_coord_t h, + lv_coord_t radius) +{ + lv_draw_img_rounded_key_t key; + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_IMG_ROUNDED_CORNERS; + key.texture = texture; + key.w = w; + key.h = h; + key.radius = radius; + return key; +} #endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_img.h b/src/draw/sdl/lv_draw_sdl_img.h new file mode 100644 index 000000000..0e2702772 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_img.h @@ -0,0 +1,72 @@ +/** + * @file lv_draw_sdl_img.h + * + */ + +#ifndef LV_DRAW_SDL_IMG_H +#define LV_DRAW_SDL_IMG_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" + +#include "lv_draw_sdl_texture_cache.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct lv_draw_sdl_img_header_t { + lv_img_header_t base; + SDL_Rect rect; +} lv_draw_sdl_img_header_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ +bool lv_draw_sdl_img_load_texture(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_cache_key_head_img_t * key, size_t key_size, + const void * src, int32_t frame_id, SDL_Texture ** texture, + lv_draw_sdl_img_header_t ** header); +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_IMG_H*/ diff --git a/src/draw/sdl/lv_draw_sdl_rect.c b/src/draw/sdl/lv_draw_sdl_rect.c index 99b91ebcd..4df113efb 100644 --- a/src/draw/sdl/lv_draw_sdl_rect.c +++ b/src/draw/sdl/lv_draw_sdl_rect.c @@ -21,6 +21,7 @@ #include "lv_draw_sdl_composite.h" #include "lv_draw_sdl_mask.h" #include "lv_draw_sdl_stack_blur.h" +#include "lv_draw_sdl_img.h" /********************* * DEFINES @@ -72,9 +73,6 @@ static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer const lv_area_t * clip, lv_coord_t rout, lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); -static void frag_render_corners(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, - const lv_area_t * coords, const lv_area_t * clip, bool full); - static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords, const lv_area_t * clipped, bool full); @@ -143,6 +141,103 @@ void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode); } +SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius) +{ + lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, radius); + lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1}; + lv_area_t coords_frag = {0, 0, radius - 1, radius - 1}; + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(texture == NULL) { + lv_draw_mask_radius_param_t mask_rout_param; + lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false); + int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); + texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1); + lv_draw_mask_remove_id(mask_id); + SDL_assert(texture); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); + } + return texture; +} + +void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size, + const lv_area_t * coords, const lv_area_t * clip, bool full) +{ + if(!clip) clip = coords; + lv_area_t corner_area, dst_area; + /* Upper left */ + corner_area.x1 = coords->x1; + corner_area.y1 = coords->y1; + corner_area.x2 = coords->x1 + frag_size - 1; + corner_area.y2 = coords->y1 + frag_size - 1; + if(_lv_area_intersect(&dst_area, &corner_area, clip)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); + SDL_Rect src_rect = {sx, sy, dw, dh}; + SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); + } + /* Upper right, clip right edge if too big */ + corner_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size); + corner_area.x2 = coords->x2; + if(_lv_area_intersect(&dst_area, &corner_area, clip)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); + if(full) { + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), + sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); + SDL_Rect src_rect = {frag_size + 3 + sx, sy, dw, dh}; + SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); + } + else { + SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, dst_area.y1 - corner_area.y1, dw, dh}; + SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); + } + } + /* Lower right, clip bottom edge if too big */ + corner_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size); + corner_area.y2 = coords->y2; + if(_lv_area_intersect(&dst_area, &corner_area, clip)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); + if(full) { + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), + sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); + SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 3 + sy, dw, dh}; + SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); + } + else { + SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, corner_area.y2 - dst_area.y2, dw, dh}; + SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL); + } + } + /* Lower left, right edge should not be clip */ + corner_area.x1 = coords->x1; + corner_area.x2 = coords->x1 + frag_size - 1; + if(_lv_area_intersect(&dst_area, &corner_area, clip)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); + if(full) { + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), + sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); + SDL_Rect src_rect = {sx, frag_size + 3 + sy, dw, dh}; + SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); + } + else { + SDL_Rect src_rect = {dst_area.x1 - corner_area.x1, corner_area.y2 - dst_area.y2, dw, dh}; + SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL); + } + } +} + + /********************** * STATIC FUNCTIONS **********************/ @@ -167,29 +262,15 @@ static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, con /*A small texture with a quarter of the rect is enough*/ lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords); - lv_coord_t frag_size = LV_MIN3(bg_w / 2, bg_h / 2, radius); - lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, frag_size); - lv_area_t coords_frag; - lv_area_copy(&coords_frag, coords); - lv_area_set_width(&coords_frag, frag_size); - lv_area_set_height(&coords_frag, frag_size); - SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); - if(texture == NULL) { - lv_draw_mask_radius_param_t mask_rout_param; - lv_draw_mask_radius_init(&mask_rout_param, coords, radius, false); - int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); - texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1); - lv_draw_mask_remove_id(mask_id); - SDL_assert(texture); - lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); - } + lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius); + SDL_Texture * texture = lv_draw_sdl_rect_bg_frag_obtain(ctx, real_radius); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(texture, dsc->bg_opa); SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b); - frag_render_corners(ctx->renderer, texture, frag_size, coords, draw_area, false); - frag_render_borders(ctx->renderer, texture, frag_size, coords, draw_area, false); - frag_render_center(ctx->renderer, texture, frag_size, coords, draw_area, false); + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, real_radius, coords, draw_area, false); + frag_render_borders(ctx->renderer, texture, real_radius, coords, draw_area, false); + frag_render_center(ctx->renderer, texture, real_radius, coords, draw_area, false); } static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, @@ -238,6 +319,14 @@ static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const img_dsc.recolor = dsc->bg_img_recolor; img_dsc.recolor_opa = dsc->bg_img_recolor_opa; img_dsc.opa = dsc->bg_img_opa; + img_dsc.frame_id = 0; + + int16_t radius_mask_id = LV_MASK_ID_INV; + lv_draw_mask_radius_param_t radius_param; + if(dsc->radius > 0) { + lv_draw_mask_radius_init(&radius_param, coords, dsc->radius, false); + radius_mask_id = lv_draw_mask_add(&radius_param, NULL); + } /*Center align*/ if(dsc->bg_img_tiled == false) { @@ -263,6 +352,11 @@ static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const } } } + + if(radius_mask_id != LV_MASK_ID_INV) { + lv_draw_mask_remove_id(radius_mask_id); + lv_draw_mask_free_param(&radius_param); + } } } @@ -338,7 +432,7 @@ static void draw_shadow(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const SDL_SetTextureAlphaMod(texture, opa); SDL_SetTextureColorMod(texture, shadow_color.r, shadow_color.g, shadow_color.b); - frag_render_corners(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false); + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, blur_frag_size, &shadow_area, clip, false); frag_render_borders(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false); frag_render_center(ctx->renderer, texture, blur_frag_size, &shadow_area, clip, false); } @@ -460,87 +554,10 @@ static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer SDL_SetTextureAlphaMod(texture, opa); SDL_SetTextureColorMod(texture, color_sdl.r, color_sdl.g, color_sdl.b); - frag_render_corners(renderer, texture, frag_size, outer_area, clip, true); + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, texture, frag_size, outer_area, clip, true); frag_render_borders(renderer, texture, frag_size, outer_area, clip, true); } -static void frag_render_corners(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, - const lv_area_t * coords, const lv_area_t * clipped, bool full) -{ - lv_area_t corner_area, dst_area; - /* Upper left */ - corner_area.x1 = coords->x1; - corner_area.y1 = coords->y1; - corner_area.x2 = coords->x1 + frag_size - 1; - corner_area.y2 = coords->y1 + frag_size - 1; - if(_lv_area_intersect(&dst_area, &corner_area, clipped)) { - SDL_Rect dst_rect; - lv_area_to_sdl_rect(&dst_area, &dst_rect); - - lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); - lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {sx, sy, dw, dh}; - SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); - } - /* Upper right, clip right edge if too big */ - corner_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size); - corner_area.x2 = coords->x2; - if(_lv_area_intersect(&dst_area, &corner_area, clipped)) { - SDL_Rect dst_rect; - lv_area_to_sdl_rect(&dst_area, &dst_rect); - - lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); - if(full) { - lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), - sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, sy, dw, dh}; - SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); - } - else { - SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, dst_area.y1 - corner_area.y1, dw, dh}; - SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); - } - } - /* Lower right, clip bottom edge if too big */ - corner_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size); - corner_area.y2 = coords->y2; - if(_lv_area_intersect(&dst_area, &corner_area, clipped)) { - SDL_Rect dst_rect; - lv_area_to_sdl_rect(&dst_area, &dst_rect); - - lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); - if(full) { - lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), - sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 3 + sy, dw, dh}; - SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); - } - else { - SDL_Rect src_rect = {corner_area.x2 - dst_area.x2, corner_area.y2 - dst_area.y2, dw, dh}; - SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL); - } - } - /* Lower left, right edge should not be clipped */ - corner_area.x1 = coords->x1; - corner_area.x2 = coords->x1 + frag_size - 1; - if(_lv_area_intersect(&dst_area, &corner_area, clipped)) { - SDL_Rect dst_rect; - lv_area_to_sdl_rect(&dst_area, &dst_rect); - - lv_coord_t dw = lv_area_get_width(&dst_area), dh = lv_area_get_height(&dst_area); - if(full) { - lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), - sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {sx, frag_size + 3 + sy, dw, dh}; - SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); - } - else { - SDL_Rect src_rect = {dst_area.x1 - corner_area.x1, corner_area.y2 - dst_area.y2, dw, dh}; - SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL); - } - } -} - static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords, const lv_area_t * clipped, bool full) { diff --git a/src/draw/sdl/lv_draw_sdl_rect.h b/src/draw/sdl/lv_draw_sdl_rect.h new file mode 100644 index 000000000..1e9be3445 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_rect.h @@ -0,0 +1,75 @@ +/** + * @file lv_draw_sdl_rect.h + * + */ + +#ifndef LV_DRAW_SDL_RECT_H +#define LV_DRAW_SDL_RECT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" + +#include "lv_draw_sdl_texture_cache.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct lv_draw_sdl_rect_header_t { + lv_img_header_t base; + SDL_Rect rect; +} lv_draw_sdl_rect_header_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius); + +void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size, + const lv_area_t * coords, const lv_area_t * clip, bool full); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_RECT_H*/ diff --git a/src/draw/sdl/lv_draw_sdl_texture_cache.h b/src/draw/sdl/lv_draw_sdl_texture_cache.h index 337c1e3d2..dc8b578e6 100644 --- a/src/draw/sdl/lv_draw_sdl_texture_cache.h +++ b/src/draw/sdl/lv_draw_sdl_texture_cache.h @@ -45,6 +45,7 @@ typedef struct { typedef enum { LV_GPU_CACHE_KEY_MAGIC_ARC = 0x01, LV_GPU_CACHE_KEY_MAGIC_IMG = 0x11, + LV_GPU_CACHE_KEY_MAGIC_IMG_ROUNDED_CORNERS = 0x12, LV_GPU_CACHE_KEY_MAGIC_LINE = 0x21, LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31, LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32, diff --git a/src/draw/sdl/lv_draw_sdl_utils.c b/src/draw/sdl/lv_draw_sdl_utils.c index 3bbbfdbdd..3ca0fad45 100644 --- a/src/draw/sdl/lv_draw_sdl_utils.c +++ b/src/draw/sdl/lv_draw_sdl_utils.c @@ -98,14 +98,10 @@ void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoo lv_area_to_sdl_rect(in, out); return; } - int h = in->y2 - in->y1 + 1; - int w = in->x2 - in->x1 + 1; - int sh = h * zoom >> 8; - int sw = w * zoom >> 8; - out->x = in->x1 - (sw / 2 - pivot->x); - out->y = in->y1 - (sh / 2 - pivot->y); - out->w = sw; - out->h = sh; + lv_area_t tmp; + _lv_img_buf_get_transformed_area(&tmp, lv_area_get_width(in), lv_area_get_height(in), 0, zoom, pivot); + lv_area_move(&tmp, in->x1, in->y1); + lv_area_to_sdl_rect(&tmp, out); } SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp) diff --git a/src/misc/lv_area.c b/src/misc/lv_area.c index 08a8f16e1..7c66a9b33 100644 --- a/src/misc/lv_area.c +++ b/src/misc/lv_area.c @@ -319,6 +319,11 @@ bool _lv_area_is_out(const lv_area_t * aout_p, const lv_area_t * aholder_p, lv_c return true; } +bool _lv_area_is_equal(const lv_area_t * a, const lv_area_t * b) +{ + return a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y1 && a->y2 == b->y2; +} + /** * Align an area to an other * @param base an are where the other will be aligned diff --git a/src/misc/lv_area.h b/src/misc/lv_area.h index 7407b16f9..542d86bc5 100644 --- a/src/misc/lv_area.h +++ b/src/misc/lv_area.h @@ -221,6 +221,13 @@ bool _lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p, lv_coo */ bool _lv_area_is_out(const lv_area_t * aout_p, const lv_area_t * aholder_p, lv_coord_t radius); +/** + * Check if 2 area is the same + * @param a pointer to an area + * @param b pointer to another area + */ +bool _lv_area_is_equal(const lv_area_t * a, const lv_area_t * b); + /** * Align an area to an other * @param base an are where the other will be aligned