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
This commit is contained in:
Mariotaku
2022-01-18 19:41:45 +09:00
committed by GitHub
parent 0921dfc8cd
commit d33db6bb59
11 changed files with 627 additions and 207 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
/**********************

View File

@@ -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*/

View File

@@ -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*/

View File

@@ -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)
{

View File

@@ -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*/

View File

@@ -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,

View File

@@ -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)

View File

@@ -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

View File

@@ -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