diff --git a/examples/event/lv_example_event.h b/examples/event/lv_example_event.h index 66c9c0d99..591f4f947 100644 --- a/examples/event/lv_example_event.h +++ b/examples/event/lv_example_event.h @@ -28,6 +28,7 @@ extern "C" { void lv_example_event_1(void); void lv_example_event_2(void); void lv_example_event_3(void); +void lv_example_event_4(void); /********************** * MACROS diff --git a/examples/event/lv_example_event_4.c b/examples/event/lv_example_event_4.c new file mode 100644 index 000000000..8094dedf7 --- /dev/null +++ b/examples/event/lv_example_event_4.c @@ -0,0 +1,65 @@ +#include "../lv_examples.h" + +#if LV_BUILD_EXAMPLES + +static int n = 3; +static lv_obj_t * label = NULL; + +static void timer_cb(lv_timer_t * timer) +{ + if (n < 3 || n > 32) { + n = 3; + } else { + static uint32_t old_tick = 0; + uint32_t tick = lv_tick_get(); + if (!old_tick) { + old_tick = tick; + } + if (tick - old_tick > 3000) { + n++; + lv_label_set_text_fmt(label, "%d sides", n); + old_tick = tick; + } + } + lv_obj_invalidate(timer->user_data); +} + +static void event_cb(lv_event_t * e) +{ + /*The original target of the event. Can be the buttons or the container*/ + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); + lv_draw_rect_dsc_t draw_dsc; + lv_draw_rect_dsc_init(&draw_dsc); + draw_dsc.bg_color = lv_palette_main(LV_PALETTE_LIGHT_GREEN); + draw_dsc.bg_opa = LV_OPA_COVER; + lv_point_t points[32]; + int i, r = 150; + uint32_t tick = lv_tick_get(); + for (i = 0; i < n; i++) { + int angle = i * 360 / n + ((tick % 36000) / 100); + lv_coord_t x = 150 + (r * lv_trigo_cos(angle) >> LV_TRIGO_SHIFT), y = + 150 + (r * lv_trigo_sin(angle) >> LV_TRIGO_SHIFT); + points[i].x = x; + points[i].y = y; + } + lv_draw_polygon(draw_ctx, &draw_dsc, points, n); +} + +/** + * Demonstrate event bubbling + */ +void lv_example_event_4(void) +{ + + lv_obj_t * cont = lv_obj_create(lv_scr_act()); + lv_obj_remove_style_all(cont); + lv_obj_set_size(cont, 300, 300); + label = lv_label_create(cont); + lv_label_set_text_fmt(label, "%d sides", n); + lv_obj_center(label); + + lv_obj_add_event_cb(cont, event_cb, LV_EVENT_DRAW_MAIN, NULL); + lv_timer_create(timer_cb, 17, cont); +} + +#endif diff --git a/src/draw/lv_draw_mask.c b/src/draw/lv_draw_mask.c index 587913628..2c8a7e3fe 100644 --- a/src/draw/lv_draw_mask.c +++ b/src/draw/lv_draw_mask.c @@ -41,6 +41,9 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_fade(lv_opa_t * mas LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_map(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_draw_mask_map_param_t * param); +LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_polygon(lv_opa_t * mask_buf, lv_coord_t abs_x, + lv_coord_t abs_y, lv_coord_t len, + lv_draw_mask_polygon_param_t * param); LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, @@ -219,6 +222,10 @@ void lv_draw_mask_free_param(void * p) } } } + else if(pdsc->type == LV_DRAW_MASK_TYPE_POLYGON) { + lv_draw_mask_polygon_param_t * poly_p = (lv_draw_mask_polygon_param_t *) p; + lv_mem_free(poly_p->cfg.points); + } } void _lv_draw_mask_cleanup(void) @@ -560,6 +567,31 @@ void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * c param->dsc.type = LV_DRAW_MASK_TYPE_MAP; } +void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt) +{ + /*Join adjacent points if they are on the same coordinate*/ + lv_point_t * p = lv_mem_alloc(point_cnt * sizeof(lv_point_t)); + if(p == NULL) return; + uint16_t i; + uint16_t pcnt = 0; + p[0] = points[0]; + for(i = 0; i < point_cnt - 1; i++) { + if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) { + p[pcnt] = points[i]; + pcnt++; + } + } + /*The first and the last points are also adjacent*/ + if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) { + p[pcnt] = points[point_cnt - 1]; + pcnt++; + } + param->cfg.points = p; + param->cfg.point_cnt = pcnt; + param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_polygon; + param->dsc.type = LV_DRAW_MASK_TYPE_POLYGON; +} + /********************** * STATIC FUNCTIONS **********************/ @@ -1218,6 +1250,79 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_map(lv_opa_t * mask return LV_DRAW_MASK_RES_CHANGED; } +LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_polygon(lv_opa_t * mask_buf, lv_coord_t abs_x, + lv_coord_t abs_y, lv_coord_t len, + lv_draw_mask_polygon_param_t * param) +{ + uint16_t i; + struct { + lv_point_t p1; + lv_point_t p2; + } lines[2], tmp; + uint16_t line_cnt = 0; + lv_memset_00(&lines, sizeof(lines)); + int psign_prev = 0; + for(i = 0; i < param->cfg.point_cnt; i++) { + lv_point_t p1 = param->cfg.points[i]; + lv_point_t p2 = param->cfg.points[i + 1 < param->cfg.point_cnt ? i + 1 : 0]; + int pdiff = p1.y - p2.y, psign = pdiff / LV_ABS(pdiff); + if(pdiff > 0) { + if(abs_y > p1.y || abs_y < p2.y) continue; + lines[line_cnt].p1 = p2; + lines[line_cnt].p2 = p1; + } + else { + if(abs_y < p1.y || abs_y > p2.y) continue; + lines[line_cnt].p1 = p1; + lines[line_cnt].p2 = p2; + } + if(psign_prev && psign_prev == psign) continue; + psign_prev = psign; + line_cnt++; + if(line_cnt == 2) break; + } + if(line_cnt != 2) return LV_DRAW_MASK_RES_TRANSP; + if(lines[0].p1.x > lines[1].p1.x || lines[0].p2.x > lines[1].p2.x) { + tmp = lines[0]; + lines[0] = lines[1]; + lines[1] = tmp; + } + lv_draw_mask_line_param_t line_p; + lv_draw_mask_line_points_init(&line_p, lines[0].p1.x, lines[0].p1.y, lines[0].p2.x, lines[0].p2.y, + LV_DRAW_MASK_LINE_SIDE_RIGHT); + if(line_p.steep == 0 && line_p.flat) { + lv_coord_t x1 = LV_MIN(lines[0].p1.x, lines[0].p2.x); + lv_coord_t x2 = LV_MAX(lines[0].p1.x, lines[0].p2.x); + for(i = 0; i < len; i++) { + mask_buf[i] = mask_mix(mask_buf[i], (abs_x + i >= x1 && abs_x + i <= x2) * 0xFF); + } + lv_draw_mask_free_param(&line_p); + return LV_DRAW_MASK_RES_CHANGED; + } + lv_draw_mask_res_t res1 = lv_draw_mask_line(mask_buf, abs_x, abs_y, len, &line_p); + lv_draw_mask_free_param(&line_p); + if(res1 == LV_DRAW_MASK_RES_TRANSP) { + return LV_DRAW_MASK_RES_TRANSP; + } + lv_draw_mask_line_points_init(&line_p, lines[1].p1.x, lines[1].p1.y, lines[1].p2.x, lines[1].p2.y, + LV_DRAW_MASK_LINE_SIDE_LEFT); + if(line_p.steep == 0 && line_p.flat) { + lv_coord_t x1 = LV_MIN(lines[1].p1.x, lines[1].p2.x); + lv_coord_t x2 = LV_MAX(lines[1].p1.x, lines[1].p2.x); + for(i = 0; i < len; i++) { + mask_buf[i] = mask_mix(mask_buf[i], (abs_x + i >= x1 && abs_x + i <= x2) * 0xFF); + } + lv_draw_mask_free_param(&line_p); + return LV_DRAW_MASK_RES_CHANGED; + } + lv_draw_mask_res_t res2 = lv_draw_mask_line(mask_buf, abs_x, abs_y, len, &line_p); + lv_draw_mask_free_param(&line_p); + if(res2 == LV_DRAW_MASK_RES_TRANSP) { + return LV_DRAW_MASK_RES_TRANSP; + } + if(res1 == LV_DRAW_MASK_RES_CHANGED || res2 == LV_DRAW_MASK_RES_CHANGED) return LV_DRAW_MASK_RES_CHANGED; + return res1; +} /** * Initialize the circle drawing * @param c pointer to a point. The coordinates will be calculated here diff --git a/src/draw/lv_draw_mask.h b/src/draw/lv_draw_mask.h index ea0624698..b6ec14f23 100644 --- a/src/draw/lv_draw_mask.h +++ b/src/draw/lv_draw_mask.h @@ -73,6 +73,7 @@ enum { LV_DRAW_MASK_TYPE_RADIUS, LV_DRAW_MASK_TYPE_FADE, LV_DRAW_MASK_TYPE_MAP, + LV_DRAW_MASK_TYPE_POLYGON, }; typedef uint8_t lv_draw_mask_type_t; @@ -204,6 +205,16 @@ typedef struct _lv_draw_mask_map_param_t { } cfg; } lv_draw_mask_map_param_t; +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_point_t * points; + uint16_t point_cnt; + } cfg; +} lv_draw_mask_polygon_param_t; + /********************** * GLOBAL PROTOTYPES @@ -368,6 +379,8 @@ void lv_draw_mask_fade_init(lv_draw_mask_fade_param_t * param, const lv_area_t * */ void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map); +void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt); + #endif /*LV_DRAW_COMPLEX*/ /********************** diff --git a/src/draw/sdl/lv_draw_sdl.c b/src/draw/sdl/lv_draw_sdl.c index 4d7fa9f50..430f3a23c 100644 --- a/src/draw/sdl/lv_draw_sdl.c +++ b/src/draw/sdl/lv_draw_sdl.c @@ -33,9 +33,10 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, uint16_t radius, uint16_t start_angle, uint16_t end_angle); -void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points, + uint16_t point_cnt); -void lv_draw_sdl_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); +void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); /********************** * TYPEDEFS @@ -61,16 +62,15 @@ void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx) { _lv_draw_sdl_utils_init(); lv_memset_00(draw_ctx, sizeof(lv_draw_sdl_ctx_t)); - lv_draw_sw_init_ctx(disp_drv, draw_ctx); draw_ctx->draw_rect = lv_draw_sdl_draw_rect; draw_ctx->draw_img = lv_draw_sdl_img_core; draw_ctx->draw_letter = lv_draw_sdl_draw_letter; draw_ctx->draw_line = lv_draw_sdl_draw_line; draw_ctx->draw_arc = lv_draw_sdl_draw_arc; + draw_ctx->draw_polygon = lv_draw_sdl_polygon; draw_ctx->draw_bg = lv_draw_sdl_draw_bg; lv_draw_sdl_ctx_t * draw_ctx_sdl = (lv_draw_sdl_ctx_t *) draw_ctx; draw_ctx_sdl->renderer = ((lv_draw_sdl_drv_param_t *) disp_drv->user_data)->renderer; - draw_ctx_sdl->base_draw.blend = lv_draw_sdl_blend; draw_ctx_sdl->internals = lv_mem_alloc(sizeof(lv_draw_sdl_context_internals_t)); lv_memset_00(draw_ctx_sdl->internals, sizeof(lv_draw_sdl_context_internals_t)); lv_draw_sdl_texture_cache_init(draw_ctx_sdl); diff --git a/src/draw/sdl/lv_draw_sdl.h b/src/draw/sdl/lv_draw_sdl.h index 0de6ebc1e..1bd744ce1 100644 --- a/src/draw/sdl/lv_draw_sdl.h +++ b/src/draw/sdl/lv_draw_sdl.h @@ -20,7 +20,8 @@ extern "C" { #include LV_GPU_SDL_INCLUDE_PATH -#include "../sw/lv_draw_sw.h" +#include "../lv_draw.h" +#include "../../core/lv_disp.h" /********************* * DEFINES @@ -46,7 +47,7 @@ typedef struct { } lv_draw_sdl_drv_param_t; typedef struct { - lv_draw_sw_ctx_t base_draw; + lv_draw_ctx_t base_draw; SDL_Renderer * renderer; struct lv_draw_sdl_context_internals_t * internals; } lv_draw_sdl_ctx_t; diff --git a/src/draw/sdl/lv_draw_sdl.mk b/src/draw/sdl/lv_draw_sdl.mk index 11f82457c..6609c38bc 100644 --- a/src/draw/sdl/lv_draw_sdl.mk +++ b/src/draw/sdl/lv_draw_sdl.mk @@ -1,12 +1,12 @@ CSRCS += lv_draw_sdl.c CSRCS += lv_draw_sdl_arc.c CSRCS += lv_draw_sdl_bg.c -CSRCS += lv_draw_sdl_blend.c CSRCS += lv_draw_sdl_composite.c CSRCS += lv_draw_sdl_img.c CSRCS += lv_draw_sdl_label.c CSRCS += lv_draw_sdl_line.c CSRCS += lv_draw_sdl_mask.c +CSRCS += lv_draw_sdl_polygon.c CSRCS += lv_draw_sdl_rect.c CSRCS += lv_draw_sdl_stack_blur.c CSRCS += lv_draw_sdl_texture_cache.c diff --git a/src/draw/sdl/lv_draw_sdl_arc.c b/src/draw/sdl/lv_draw_sdl_arc.c index 4853b5cd1..5786eaeb9 100644 --- a/src/draw/sdl/lv_draw_sdl_arc.c +++ b/src/draw/sdl/lv_draw_sdl_arc.c @@ -1,5 +1,5 @@ /** - * @file lv_templ.c + * @file lv_draw_sdl_arc.c * */ @@ -14,7 +14,6 @@ #include "lv_draw_sdl_utils.h" #include "lv_draw_sdl_texture_cache.h" #include "lv_draw_sdl_composite.h" -#include "lv_draw_sdl_mask.h" /********************* * DEFINES @@ -24,14 +23,6 @@ * TYPEDEFS **********************/ -typedef struct { - lv_sdl_cache_key_magic_t magic; - uint16_t radius; - uint16_t angle; - lv_coord_t width; - uint8_t rounded; -} lv_draw_arc_key_t; - /********************** * STATIC PROTOTYPES **********************/ @@ -44,9 +35,6 @@ typedef struct { * MACROS **********************/ -static lv_draw_arc_key_t arc_key_create(const lv_draw_arc_dsc_t * dsc, uint16_t radius, uint16_t start_angle, - uint16_t end_angle); - static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count, const int16_t * caps); @@ -60,7 +48,6 @@ void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * ds uint16_t radius, uint16_t start_angle, uint16_t end_angle) { lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; - SDL_Renderer * renderer = ctx->renderer; lv_area_t area_out; area_out.x1 = center->x - radius; @@ -154,19 +141,6 @@ void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * ds * STATIC FUNCTIONS **********************/ -static lv_draw_arc_key_t arc_key_create(const lv_draw_arc_dsc_t * dsc, uint16_t radius, uint16_t start_angle, - uint16_t end_angle) -{ - lv_draw_arc_key_t key; - lv_memset_00(&key, sizeof(lv_draw_arc_key_t)); - key.magic = LV_GPU_CACHE_KEY_MAGIC_ARC; - key.radius = radius; - key.angle = ((end_angle - start_angle) % 360 + 360) % 360; - key.width = dsc->width; - key.rounded = dsc->rounded; - return key; -} - static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count, const int16_t * caps) { @@ -233,7 +207,7 @@ static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, c int32_t cir_x; int32_t cir_y; - cir_x = ((radius - thick_half) * lv_trigo_sin(90 - angle)) >> (LV_TRIGO_SHIFT - ps); + cir_x = ((radius - thick_half) * lv_trigo_sin((int16_t)(90 - angle))) >> (LV_TRIGO_SHIFT - ps); cir_y = ((radius - thick_half) * lv_trigo_sin(angle)) >> (LV_TRIGO_SHIFT - ps); /*Actually the center of the pixel need to be calculated so apply 1/2 px offset*/ diff --git a/src/draw/sdl/lv_draw_sdl_blend.c b/src/draw/sdl/lv_draw_sdl_blend.c deleted file mode 100644 index 208eedd29..000000000 --- a/src/draw/sdl/lv_draw_sdl_blend.c +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file lv_draw_sdl_blend.c - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "../../lv_conf_internal.h" - -#if LV_USE_GPU_SDL - -#include "lv_draw_sdl_texture_cache.h" -#include "lv_draw_sdl_utils.h" -#include "lv_draw_sdl_composite.h" - -#include LV_GPU_SDL_INCLUDE_PATH - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void blend_fill(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); - -static void blend_map(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_draw_sdl_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) -{ - if(dsc->src_buf) { - blend_map((lv_draw_sdl_ctx_t *) draw_ctx, dsc); - } - else { - blend_fill((lv_draw_sdl_ctx_t *) draw_ctx, dsc); - } -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -void blend_fill(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) -{ - const lv_opa_t opa = dsc->opa; - const lv_color_t color = dsc->color; - /*Do not draw transparent things*/ - if(opa < LV_OPA_MIN) return; - - SDL_Renderer * renderer = draw_ctx->renderer; - - lv_area_t fill_area; - _lv_area_intersect(&fill_area, draw_ctx->base_draw.base_draw.clip_area, dsc->blend_area); - SDL_Rect fill_rect; - lv_area_to_sdl_rect(&fill_area, &fill_rect); - - if(dsc->mask) { - SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(draw_ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, - lv_area_get_height(&fill_area), - lv_area_get_width(&fill_area)); - SDL_Rect rect = {0, 0, lv_area_get_width(&fill_area), lv_area_get_height(&fill_area)}; - uint8_t * pixels = NULL; - int pitch; - SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch); - SDL_assert(pixels && pitch); - for(int y = 0; y < rect.h; y++) { - SDL_memset(&pixels[y * pitch], 0xFF, 4 * rect.w); - for(int x = 0; x < rect.w; x++) { - pixels[y * pitch + x * 4] = dsc->mask[y * rect.w + x]; - } - } - SDL_UnlockTexture(texture); - - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(texture, opa); - SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue); - SDL_RenderCopy(renderer, texture, &rect, &fill_rect); - } - else { - SDL_SetRenderDrawColor(renderer, color.ch.red, color.ch.green, color.ch.blue, opa); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - SDL_RenderFillRect(renderer, &fill_rect); - } -} - -void blend_map(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) -{ - const lv_opa_t opa = dsc->opa; - /*Do not draw transparent things*/ - if(opa < LV_OPA_MIN) return; - lv_coord_t sw = lv_area_get_width(dsc->blend_area), sh = lv_area_get_height(dsc->blend_area); - - SDL_Renderer * renderer = draw_ctx->renderer; - - SDL_Rect draw_area_rect; - lv_area_to_sdl_rect(draw_ctx->base_draw.base_draw.clip_area, &draw_area_rect); - - Uint32 rmask = 0x00FF0000; - Uint32 gmask = 0x0000FF00; - Uint32 bmask = 0x000000FF; - Uint32 amask = 0x00000000; - SDL_Surface * surface = SDL_CreateRGBSurfaceFrom((void *) dsc->src_buf, sw, sh, LV_COLOR_DEPTH, - sw * LV_COLOR_DEPTH / 8, rmask, gmask, bmask, amask); - if(dsc->mask) { - SDL_Texture * masked = SDL_CreateTexture(renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, - sw, sh); - SDL_Texture * mask_texture = lv_sdl_create_opa_texture(renderer, dsc->mask, sw, sh, sw); - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); - SDL_SetRenderTarget(renderer, masked); - - SDL_SetTextureAlphaMod(mask_texture, opa); - SDL_SetTextureBlendMode(mask_texture, SDL_BLENDMODE_NONE); - SDL_RenderCopy(renderer, mask_texture, NULL, NULL); - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD); - SDL_RenderCopy(renderer, texture, NULL, NULL); - - SDL_SetRenderTarget(renderer, draw_ctx->base_draw.base_draw.buf); - SDL_SetTextureBlendMode(masked, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(masked, 0xFF); - SDL_SetTextureColorMod(masked, 0xFF, 0xFF, 0xFF); - SDL_RenderCopy(renderer, masked, NULL, &draw_area_rect); - SDL_DestroyTexture(texture); - SDL_DestroyTexture(mask_texture); - SDL_DestroyTexture(masked); - } - else { - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); - SDL_SetTextureAlphaMod(texture, opa); - SDL_SetRenderTarget(renderer, draw_ctx->base_draw.base_draw.buf); - SDL_RenderCopy(renderer, texture, NULL, &draw_area_rect); - SDL_DestroyTexture(texture); - } - SDL_FreeSurface(surface); -} - -#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_composite.c b/src/draw/sdl/lv_draw_sdl_composite.c index 8dd9b3ef8..b456f2616 100644 --- a/src/draw/sdl/lv_draw_sdl_composite.c +++ b/src/draw/sdl/lv_draw_sdl_composite.c @@ -141,7 +141,7 @@ void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_ SDL_Rect dst_rect; lv_area_to_sdl_rect(apply_area, &dst_rect); - SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.base_draw.buf); + SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.buf); switch(blend_mode) { case LV_BLEND_MODE_NORMAL: SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); diff --git a/src/draw/sdl/lv_draw_sdl_img.c b/src/draw/sdl/lv_draw_sdl_img.c index 6e28489aa..702d5c5e2 100644 --- a/src/draw/sdl/lv_draw_sdl_img.c +++ b/src/draw/sdl/lv_draw_sdl_img.c @@ -26,7 +26,10 @@ /********************** * TYPEDEFS **********************/ - +typedef struct sdl_img_header_t { + lv_img_header_t base; + SDL_Rect rect; +} sdl_img_header_t; /********************** * STATIC PROTOTYPES @@ -58,15 +61,20 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t 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_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, key, key_size, &texture_found); + 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; } @@ -80,8 +88,9 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t #endif } if(texture && cdsc) { - lv_img_header_t * header = SDL_malloc(sizeof(lv_img_header_t)); - SDL_memcpy(header, &cdsc->dec_dsc.header, sizeof(lv_img_header_t)); + 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 { @@ -100,7 +109,35 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y}; SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_RenderSetClipRect(renderer, &clip_rect); + SDL_Rect clipped_src = {0, 0, 0, 0}, clipped_dst = coords_rect; + const SDL_Rect * src_rect = NULL, *dst_rect = &clipped_dst; + + if(_lv_area_is_in(coords, clip, 0)) { + /*Image needs to be fully drawn*/ + src_rect = SDL_RectEmpty(&header->rect) ? NULL : &header->rect; + } + else if(draw_dsc->angle == 0) { + /*Image needs to be partly drawn, and we calculate the area to draw manually*/ + Uint32 format = 0; + int access = 0, w, h; + if(SDL_RectEmpty(&header->rect)) { + SDL_QueryTexture(texture, &format, &access, &w, &h); + } + else { + w = header->rect.w; + h = header->rect.h; + } + SDL_IntersectRect(&clip_rect, &coords_rect, &clipped_dst); + clipped_src.x = header->rect.x + (clipped_dst.x - coords_rect.x) * w / coords_rect.x; + 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; + } + else { + /*Image needs to be rotated, so we have to use clip rect which is slower*/ + SDL_RenderSetClipRect(renderer, &clip_rect); + } SDL_Color recolor; lv_color_to_sdl_color(&draw_dsc->recolor, &recolor); @@ -108,22 +145,22 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t /* 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, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); + 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, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); + 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, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); + 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, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); + SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); } SDL_RenderSetClipRect(renderer, NULL); return LV_RES_OK; diff --git a/src/draw/sdl/lv_draw_sdl_line.c b/src/draw/sdl/lv_draw_sdl_line.c index bd24ff6fb..8dd7b2e00 100644 --- a/src/draw/sdl/lv_draw_sdl_line.c +++ b/src/draw/sdl/lv_draw_sdl_line.c @@ -1,5 +1,5 @@ /** - * @file lv_templ.c + * @file lv_draw_sdl_line.c * */ @@ -64,10 +64,10 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * } double angle = SDL_atan2(y2 - y1, x2 - x1) * 180 / M_PI; - lv_draw_line_key_t key = line_key_create(dsc, length); + lv_draw_line_key_t key = line_key_create(dsc, (lv_coord_t) length); SDL_Texture * texture = lv_draw_sdl_texture_cache_get(sdl_ctx, &key, sizeof(key), NULL); if(!texture) { - texture = line_texture_create(sdl_ctx, dsc, length); + texture = line_texture_create(sdl_ctx, dsc, (lv_coord_t) length); lv_draw_sdl_texture_cache_put(sdl_ctx, &key, sizeof(key), texture); } @@ -80,20 +80,23 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * lv_area_t t_coords = coords, t_clip = *clip, apply_area; lv_area_t extension = {dsc->width / 2, dsc->width / 2, dsc->width / 2, dsc->width / 2}; - bool has_mask = lv_draw_sdl_composite_begin(sdl_ctx, &coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip, - &apply_area); + lv_draw_sdl_composite_begin(sdl_ctx, &coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip, + &apply_area); SDL_Color color; lv_color_to_sdl_color(&dsc->color, &color); - SDL_Rect clip_rect; - lv_area_to_sdl_rect(&t_clip, &clip_rect); - SDL_RenderSetClipRect(renderer, &clip_rect); SDL_SetTextureColorMod(texture, color.r, color.g, color.b); SDL_SetTextureAlphaMod(texture, dsc->opa); - SDL_Rect srcrect = {0, 0, length + dsc->width + 2, dsc->width + 2}, + SDL_Rect srcrect = {0, 0, (int) length + dsc->width + 2, dsc->width + 2}, dstrect = {t_coords.x1 - 1 - dsc->width / 2, t_coords.y1 - 1, srcrect.w, srcrect.h}; SDL_Point center = {1 + dsc->width / 2, 1 + dsc->width / 2}; + + SDL_Rect clip_rect; + lv_area_to_sdl_rect(&t_clip, &clip_rect); + if(!SDL_RectEquals(&clip_rect, &dstrect) || angle != 0) { + SDL_RenderSetClipRect(renderer, &clip_rect); + } SDL_RenderCopyEx(renderer, texture, &srcrect, &dstrect, angle, ¢er, 0); SDL_RenderSetClipRect(renderer, NULL); diff --git a/src/draw/sdl/lv_draw_sdl_polygon.c b/src/draw/sdl/lv_draw_sdl_polygon.c new file mode 100644 index 000000000..c5df50cb9 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_polygon.c @@ -0,0 +1,133 @@ +/** + * @file lv_draw_sdl_polygon.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include "lv_draw_sdl.h" +#include "lv_draw_sdl_utils.h" +#include "lv_draw_sdl_texture_cache.h" +#include "lv_draw_sdl_composite.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +static void dump_masks(SDL_Texture * texture, const lv_area_t * coords); + +/********************** + * GLOBAL FUNCTIONS + **********************/ +void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points, + uint16_t point_cnt) +{ + if(point_cnt < 3) return; + if(points == NULL) return; + + lv_draw_mask_polygon_param_t polygon_param; + lv_draw_mask_polygon_init(&polygon_param, points, point_cnt); + + if(polygon_param.cfg.point_cnt < 3) { + lv_draw_mask_free_param(&polygon_param); + return; + } + + lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN}; + + uint16_t i; + for(i = 0; i < point_cnt; i++) { + poly_coords.x1 = LV_MIN(poly_coords.x1, polygon_param.cfg.points[i].x); + poly_coords.y1 = LV_MIN(poly_coords.y1, polygon_param.cfg.points[i].y); + poly_coords.x2 = LV_MAX(poly_coords.x2, polygon_param.cfg.points[i].x); + poly_coords.y2 = LV_MAX(poly_coords.y2, polygon_param.cfg.points[i].y); + } + + bool is_common; + lv_area_t draw_area; + is_common = _lv_area_intersect(&draw_area, &poly_coords, draw_ctx->clip_area); + if(!is_common) { + lv_draw_mask_free_param(&polygon_param); + return; + } + + lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; + + int16_t mask_id = lv_draw_mask_add(&polygon_param, NULL); + + lv_coord_t w = lv_area_get_width(&draw_area), h = lv_area_get_height(&draw_area); + SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, w, h); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + dump_masks(texture, &draw_area); + + lv_draw_mask_remove_id(mask_id); + lv_draw_mask_free_param(&polygon_param); + + SDL_Rect srcrect = {0, 0, w, h}, dstrect; + lv_area_to_sdl_rect(&draw_area, &dstrect); + SDL_Color color; + lv_color_to_sdl_color(&draw_dsc->bg_color, &color); + SDL_SetTextureColorMod(texture, color.r, color.g, color.b); + SDL_SetTextureAlphaMod(texture, draw_dsc->bg_opa); + SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void dump_masks(SDL_Texture * texture, const lv_area_t * coords) +{ + lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords); + SDL_assert(w > 0 && h > 0); + SDL_Rect rect = {0, 0, w, h}; + uint8_t * pixels; + int pitch; + if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return; + + lv_opa_t * line_buf = lv_mem_buf_get(rect.w); + for(lv_coord_t y = 0; y < rect.h; y++) { + lv_memset_ff(line_buf, rect.w); + lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w; + lv_draw_mask_res_t res; + res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len); + if(res == LV_DRAW_MASK_RES_TRANSP) { + lv_memset_00(&pixels[y * pitch], 4 * rect.w); + } + else if(res == LV_DRAW_MASK_RES_FULL_COVER) { + lv_memset_ff(&pixels[y * pitch], 4 * rect.w); + } + else { + for(int x = 0; x < rect.w; x++) { + uint8_t * pixel = &pixels[y * pitch + x * 4]; + *pixel = line_buf[x]; + pixel[1] = pixel[2] = pixel[3] = 0xFF; + } + } + } + lv_mem_buf_release(line_buf); + SDL_UnlockTexture(texture); +} + +#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_texture_cache.h b/src/draw/sdl/lv_draw_sdl_texture_cache.h index 538a2e8a8..337c1e3d2 100644 --- a/src/draw/sdl/lv_draw_sdl_texture_cache.h +++ b/src/draw/sdl/lv_draw_sdl_texture_cache.h @@ -37,6 +37,7 @@ extern "C" { typedef struct { char head[8]; SDL_Texture * texture; + SDL_Rect rect; bool texture_managed; bool texture_referenced; } lv_draw_sdl_dec_dsc_userdata_t;