From db53ea925c9502b20f38db0fc30c4ef599bdfc33 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 29 Nov 2021 14:54:37 +0100 Subject: [PATCH] arch(draw): allow replacing the draw engine BREAKING CHANGE: the API of lv_draw_... function have been changed --- demos/widgets/lv_demo_widgets.c | 23 +- examples/anim/lv_example_anim_timeline_1.c | 2 +- examples/libs/ffmpeg/lv_example_ffmpeg_1.c | 5 +- examples/libs/ffmpeg/lv_example_ffmpeg_2.c | 4 +- .../libs/freetype/lv_example_freetype_1.c | 4 +- .../png/{img_wing_png.c => img_wink_png.c} | 0 examples/libs/png/lv_example_png_1.c | 2 +- examples/libs/rlottie/lv_example_rlottie_1.c | 4 +- examples/libs/rlottie/lv_example_rlottie_2.c | 4 +- .../others/snapshot/lv_example_snapshot_1.c | 3 +- examples/scroll/lv_example_scroll_6.c | 2 +- examples/styles/lv_example_style_5.c | 6 +- examples/widgets/bar/lv_example_bar_6.c | 2 +- .../btnmatrix/lv_example_btnmatrix_2.c | 2 +- examples/widgets/canvas/lv_example_canvas_1.c | 4 +- examples/widgets/chart/lv_example_chart_2.c | 2 +- examples/widgets/chart/lv_example_chart_4.c | 4 +- examples/widgets/chart/lv_example_chart_6.c | 4 +- examples/widgets/chart/lv_example_chart_8.c | 2 +- examples/widgets/label/lv_example_label_1.c | 1 - examples/widgets/label/lv_example_label_4.c | 2 +- examples/widgets/meter/lv_example_meter_2.c | 2 +- examples/widgets/slider/lv_example_slider_3.c | 2 +- examples/widgets/span/lv_example_span_1.c | 4 +- examples/widgets/table/lv_example_table_2.c | 4 +- lv_conf_template.h | 6 +- src/core/lv_event.c | 4 +- src/core/lv_event.h | 6 +- src/core/lv_obj.c | 63 +- src/core/lv_obj.h | 2 +- src/core/lv_obj_draw.c | 4 +- src/core/lv_obj_draw.h | 6 +- src/core/lv_refr.c | 403 +++++----- src/core/lv_refr.h | 7 + src/draw/lv_draw.c | 27 +- src/draw/lv_draw.h | 101 ++- src/draw/lv_draw_arc.c | 10 +- src/draw/lv_draw_arc.h | 8 +- src/draw/lv_draw_blend.c | 121 --- src/draw/lv_draw_blend.h | 72 -- src/draw/lv_draw_img.c | 64 +- src/draw/lv_draw_img.h | 9 +- src/draw/lv_draw_label.c | 52 +- src/draw/lv_draw_label.h | 13 +- src/draw/lv_draw_line.c | 7 +- src/draw/lv_draw_line.h | 6 +- .../{sw/lv_draw_sw_mask.c => lv_draw_mask.c} | 10 +- src/draw/lv_draw_rect.c | 6 +- src/draw/lv_draw_rect.h | 4 +- src/draw/lv_draw_triangle.c | 21 +- src/draw/lv_draw_triangle.h | 20 +- src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp.c | 4 +- src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp.h | 6 + .../nxp_pxp}/lv_gpu_nxp_pxp_osa.c | 4 +- .../nxp_pxp}/lv_gpu_nxp_pxp_osa.h | 2 +- .../nxp_vglite}/lv_gpu_nxp_vglite.c | 3 +- .../nxp_vglite}/lv_gpu_nxp_vglite.h | 6 +- src/draw/sdl/lv_draw_sdl.c | 95 +++ src/draw/sdl/lv_draw_sdl.h | 94 +++ src/draw/sdl/lv_draw_sdl.mk | 6 +- src/draw/sdl/lv_draw_sdl_arc.c | 264 +++++++ src/draw/sdl/lv_draw_sdl_blend.c | 107 +-- src/draw/sdl/lv_draw_sdl_composite.c | 258 +++++++ src/draw/sdl/lv_draw_sdl_composite.h | 71 ++ src/draw/sdl/lv_draw_sdl_img.c | 67 +- src/draw/sdl/lv_draw_sdl_label.c | 104 +-- src/draw/sdl/lv_draw_sdl_line.c | 151 ++++ src/draw/sdl/lv_draw_sdl_mask.c | 45 +- src/draw/sdl/lv_draw_sdl_mask.h | 14 +- .../sdl/lv_draw_sdl_priv.h} | 33 +- src/draw/sdl/lv_draw_sdl_rect.c | 729 +++++++++--------- src/draw/sdl/lv_draw_sdl_stack_blur.c | 2 + src/draw/sdl/lv_draw_sdl_stack_blur.h | 4 + src/draw/sdl/lv_draw_sdl_texture_cache.c | 107 ++- src/draw/sdl/lv_draw_sdl_texture_cache.h | 38 +- src/draw/sdl/lv_draw_sdl_utils.c | 88 +-- src/draw/sdl/lv_draw_sdl_utils.h | 17 +- src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c | 255 ++++++ src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h | 66 ++ src/draw/sw/lv_draw_sw.c | 31 +- src/draw/sw/lv_draw_sw.h | 57 +- src/draw/sw/lv_draw_sw_arc.c | 314 +++++--- src/draw/sw/lv_draw_sw_blend.c | 407 +++++----- src/draw/sw/lv_draw_sw_blend.h | 69 ++ src/draw/sw/lv_draw_sw_img.c | 150 ++-- src/draw/sw/lv_draw_sw_letter.c | 166 ++-- src/draw/sw/lv_draw_sw_line.c | 280 +++---- src/draw/sw/lv_draw_sw_polygon.c | 19 +- src/draw/sw/lv_draw_sw_rect.c | 542 +++++++------ src/extra/others/snapshot/lv_snapshot.c | 77 +- src/extra/widgets/chart/lv_chart.c | 171 ++-- src/extra/widgets/colorwheel/lv_colorwheel.c | 8 +- src/extra/widgets/imgbtn/lv_imgbtn.c | 27 +- src/extra/widgets/led/lv_led.c | 6 +- src/extra/widgets/meter/lv_meter.c | 38 +- src/extra/widgets/span/lv_span.c | 83 +- src/gpu/lv_gpu.mk | 1 - src/gpu/lv_gpu_sdl.c | 94 --- src/gpu/lv_gpu_stm32_dma2d.c | 262 ------- src/gpu/lv_gpu_stm32_dma2d.h | 109 --- src/hal/lv_hal_disp.c | 45 +- src/hal/lv_hal_disp.h | 19 +- src/lv_conf_internal.h | 18 +- .../sdl/lv_draw_sdl_lru.c => misc/lv_lru.c} | 76 +- .../sdl/lv_draw_sdl_lru.h => misc/lv_lru.h} | 17 +- src/misc/lv_misc.mk | 1 + src/misc/lv_style.h | 1 + src/widgets/lv_arc.c | 18 +- src/widgets/lv_bar.c | 12 +- src/widgets/lv_btnmatrix.c | 8 +- src/widgets/lv_canvas.c | 282 +++---- src/widgets/lv_checkbox.c | 8 +- src/widgets/lv_dropdown.c | 48 +- src/widgets/lv_img.c | 13 +- src/widgets/lv_label.c | 21 +- src/widgets/lv_line.c | 4 +- src/widgets/lv_roller.c | 29 +- src/widgets/lv_slider.c | 10 +- src/widgets/lv_switch.c | 6 +- src/widgets/lv_table.c | 23 +- src/widgets/lv_textarea.c | 10 +- 121 files changed, 3984 insertions(+), 3382 deletions(-) rename examples/libs/png/{img_wing_png.c => img_wink_png.c} (100%) delete mode 100644 src/draw/lv_draw_blend.c delete mode 100644 src/draw/lv_draw_blend.h rename src/draw/{sw/lv_draw_sw_mask.c => lv_draw_mask.c} (99%) rename src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp.c (99%) rename src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp.h (98%) rename src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp_osa.c (99%) rename src/{gpu => draw/nxp_pxp}/lv_gpu_nxp_pxp_osa.h (97%) rename src/{gpu => draw/nxp_vglite}/lv_gpu_nxp_vglite.c (99%) rename src/{gpu => draw/nxp_vglite}/lv_gpu_nxp_vglite.h (98%) create mode 100644 src/draw/sdl/lv_draw_sdl.c create mode 100644 src/draw/sdl/lv_draw_sdl.h create mode 100644 src/draw/sdl/lv_draw_sdl_arc.c create mode 100644 src/draw/sdl/lv_draw_sdl_composite.c create mode 100644 src/draw/sdl/lv_draw_sdl_composite.h create mode 100644 src/draw/sdl/lv_draw_sdl_line.c rename src/{gpu/lv_gpu_sdl.h => draw/sdl/lv_draw_sdl_priv.h} (63%) create mode 100644 src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c create mode 100644 src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h create mode 100644 src/draw/sw/lv_draw_sw_blend.h delete mode 100644 src/gpu/lv_gpu_sdl.c delete mode 100644 src/gpu/lv_gpu_stm32_dma2d.c delete mode 100644 src/gpu/lv_gpu_stm32_dma2d.h rename src/{draw/sdl/lv_draw_sdl_lru.c => misc/lv_lru.c} (84%) rename src/{draw/sdl/lv_draw_sdl_lru.h => misc/lv_lru.h} (81%) diff --git a/demos/widgets/lv_demo_widgets.c b/demos/widgets/lv_demo_widgets.c index b9e59e3e4..01a033b17 100644 --- a/demos/widgets/lv_demo_widgets.c +++ b/demos/widgets/lv_demo_widgets.c @@ -1280,13 +1280,13 @@ static void slider_event_cb(lv_event_t * e) lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_color = lv_palette_darken(LV_PALETTE_GREY, 3); rect_dsc.radius = LV_DPX(5); - lv_draw_rect(&bg_area, dsc->clip_area, &rect_dsc); + lv_draw_rect(dsc->draw_ctx, &rect_dsc, &bg_area); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); label_dsc.color = lv_color_white(); label_dsc.font = font_normal; - lv_draw_label(&txt_area, dsc->clip_area, &label_dsc, buf, NULL); + lv_draw_label(dsc->draw_ctx, &label_dsc, &txt_area, buf, NULL); } } } @@ -1334,15 +1334,16 @@ static void chart_event_cb(lv_event_t * e) draw_rect_dsc.bg_color = dsc->line_dsc->color; lv_area_t obj_clip_area; - _lv_area_intersect(&obj_clip_area, dsc->clip_area, &obj->coords); - + _lv_area_intersect(&obj_clip_area, dsc->draw_ctx->clip_area, &obj->coords); + const lv_area_t * clip_area_ori = dsc->draw_ctx->clip_area; + dsc->draw_ctx->clip_area = &obj_clip_area; lv_area_t a; a.x1 = dsc->p1->x; a.x2 = dsc->p2->x - 1; a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); a.y2 = obj->coords.y2; - lv_draw_rect(&a, &obj_clip_area, &draw_rect_dsc); - + lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); + dsc->draw_ctx->clip_area = clip_area_ori; /*Remove the masks*/ lv_draw_mask_remove_id(line_mask_id); lv_draw_mask_remove_id(fade_mask_id); @@ -1396,13 +1397,13 @@ static void chart_event_cb(lv_event_t * e) lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_color = ser->color; rect_dsc.radius = LV_DPX(5); - lv_draw_rect(&bg_area, dsc->clip_area, &rect_dsc); + lv_draw_rect(dsc->draw_ctx, &rect_dsc, &bg_area); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); label_dsc.color = lv_color_white(); label_dsc.font = font_normal; - lv_draw_label(&txt_area, dsc->clip_area, &label_dsc, buf, NULL); + lv_draw_label(dsc->draw_ctx, &label_dsc, &txt_area, buf, NULL); } else { dsc->rect_dsc->outline_width = 0; dsc->rect_dsc->shadow_width = 0; @@ -1447,18 +1448,18 @@ static void shop_chart_event_cb(lv_event_t * e) a.y2 = a.y1 + 4 + (devices[dsc->id] * h) / 100; /*+4 to overlap the radius*/ draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_RED); draw_rect_dsc.radius = 4; - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); a.y1 = a.y2 - 4; /*-4 to overlap the radius*/ a.y2 = a.y1 + (clothes[dsc->id] * h) / 100; draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_BLUE); draw_rect_dsc.radius = 0; - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect( dsc->draw_ctx, &draw_rect_dsc, &a); a.y1 = a.y2; a.y2 = a.y1 + (services[dsc->id] * h) / 100; draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_GREEN); - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect( dsc->draw_ctx, &draw_rect_dsc, &a); } } } diff --git a/examples/anim/lv_example_anim_timeline_1.c b/examples/anim/lv_example_anim_timeline_1.c index a65b5fb8b..15c35ed19 100644 --- a/examples/anim/lv_example_anim_timeline_1.c +++ b/examples/anim/lv_example_anim_timeline_1.c @@ -1,5 +1,5 @@ #include "../lv_examples.h" -#if LV_BUILD_EXAMPLES +#if LV_USE_FLEX && LV_BUILD_EXAMPLES static lv_anim_timeline_t * anim_timeline = NULL; diff --git a/examples/libs/ffmpeg/lv_example_ffmpeg_1.c b/examples/libs/ffmpeg/lv_example_ffmpeg_1.c index b1ca35a68..58159857a 100644 --- a/examples/libs/ffmpeg/lv_example_ffmpeg_1.c +++ b/examples/libs/ffmpeg/lv_example_ffmpeg_1.c @@ -1,5 +1,7 @@ #include "../../lv_examples.h" -#if LV_USE_FFMPEG && LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES +#if LV_USE_FFMPEG + /** * Open an image from a file @@ -24,3 +26,4 @@ void lv_example_ffmpeg_1(void) } #endif +#endif diff --git a/examples/libs/ffmpeg/lv_example_ffmpeg_2.c b/examples/libs/ffmpeg/lv_example_ffmpeg_2.c index 5eb5235eb..3a8de1e22 100644 --- a/examples/libs/ffmpeg/lv_example_ffmpeg_2.c +++ b/examples/libs/ffmpeg/lv_example_ffmpeg_2.c @@ -1,5 +1,6 @@ #include "../../lv_examples.h" -#if LV_USE_FFMPEG && LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES +#if LV_USE_FFMPEG /** * Open a video from a file @@ -28,3 +29,4 @@ void lv_example_ffmpeg_2(void) } #endif +#endif diff --git a/examples/libs/freetype/lv_example_freetype_1.c b/examples/libs/freetype/lv_example_freetype_1.c index cacbd19db..6feb24493 100644 --- a/examples/libs/freetype/lv_example_freetype_1.c +++ b/examples/libs/freetype/lv_example_freetype_1.c @@ -1,5 +1,6 @@ #include "../../lv_examples.h" -#if LV_USE_FREETYPE && LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES +#if LV_USE_FREETYPE /** * Load a font with FreeType @@ -42,3 +43,4 @@ void lv_example_freetype_1(void) } #endif +#endif diff --git a/examples/libs/png/img_wing_png.c b/examples/libs/png/img_wink_png.c similarity index 100% rename from examples/libs/png/img_wing_png.c rename to examples/libs/png/img_wink_png.c diff --git a/examples/libs/png/lv_example_png_1.c b/examples/libs/png/lv_example_png_1.c index 91be046a7..63dbff1f7 100644 --- a/examples/libs/png/lv_example_png_1.c +++ b/examples/libs/png/lv_example_png_1.c @@ -1,5 +1,5 @@ #include "../../lv_examples.h" -#if LV_USE_PNG && LV_BUILD_EXAMPLES +#if LV_USE_PNG && LV_USE_IMG && LV_BUILD_EXAMPLES /** * Open a PNG image from a file and a variable diff --git a/examples/libs/rlottie/lv_example_rlottie_1.c b/examples/libs/rlottie/lv_example_rlottie_1.c index 7b889fbbe..ae9c2dbcb 100644 --- a/examples/libs/rlottie/lv_example_rlottie_1.c +++ b/examples/libs/rlottie/lv_example_rlottie_1.c @@ -1,5 +1,6 @@ #include "../../lv_examples.h" -#if LV_USE_RLOTTIE && LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES +#if LV_USE_RLOTTIE /** * Load an lottie animation from flash @@ -23,3 +24,4 @@ void lv_example_rlottie_1(void) } #endif +#endif diff --git a/examples/libs/rlottie/lv_example_rlottie_2.c b/examples/libs/rlottie/lv_example_rlottie_2.c index 1f882b4a5..0f9cf6549 100644 --- a/examples/libs/rlottie/lv_example_rlottie_2.c +++ b/examples/libs/rlottie/lv_example_rlottie_2.c @@ -1,5 +1,6 @@ #include "../../lv_examples.h" -#if LV_USE_RLOTTIE && LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES +#if LV_USE_RLOTTIE /** * Load an lottie animation from file @@ -24,3 +25,4 @@ void lv_example_rlottie_2(void) } #endif +#endif diff --git a/examples/others/snapshot/lv_example_snapshot_1.c b/examples/others/snapshot/lv_example_snapshot_1.c index c13fc1cac..ec396b154 100644 --- a/examples/others/snapshot/lv_example_snapshot_1.c +++ b/examples/others/snapshot/lv_example_snapshot_1.c @@ -31,11 +31,12 @@ void lv_example_snapshot_1(void) lv_obj_set_style_bg_color(snapshot_obj, lv_palette_main(LV_PALETTE_PURPLE), 0); lv_obj_set_style_bg_opa(snapshot_obj, LV_OPA_100, 0); lv_img_set_zoom(snapshot_obj, 128); + lv_img_set_angle(snapshot_obj, 300); /*Create the container and its children*/ lv_obj_t * container = lv_obj_create(root); - lv_obj_align(container, LV_ALIGN_CENTER, 0, 0); + lv_obj_center(container); lv_obj_set_size(container, 180, 180); lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW_WRAP); lv_obj_set_flex_align(container, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); diff --git a/examples/scroll/lv_example_scroll_6.c b/examples/scroll/lv_example_scroll_6.c index 255df09bd..68bdcd3a5 100644 --- a/examples/scroll/lv_example_scroll_6.c +++ b/examples/scroll/lv_example_scroll_6.c @@ -1,5 +1,5 @@ #include "../lv_examples.h" -#if LV_BUILD_EXAMPLES +#if LV_BUILD_EXAMPLES && LV_USE_FLEX static void scroll_event_cb(lv_event_t * e) { diff --git a/examples/styles/lv_example_style_5.c b/examples/styles/lv_example_style_5.c index 663d03d3e..7857fd249 100644 --- a/examples/styles/lv_example_style_5.c +++ b/examples/styles/lv_example_style_5.c @@ -15,10 +15,10 @@ void lv_example_style_5(void) lv_style_set_bg_color(&style, lv_palette_lighten(LV_PALETTE_GREY, 1)); /*Add a shadow*/ - lv_style_set_shadow_width(&style, 25); + lv_style_set_shadow_width(&style, 55); lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_BLUE)); - lv_style_set_shadow_ofs_x(&style, 10); - lv_style_set_shadow_ofs_y(&style, 20); +// lv_style_set_shadow_ofs_x(&style, 10); +// lv_style_set_shadow_ofs_y(&style, 20); /*Create an object with the new style*/ lv_obj_t * obj = lv_obj_create(lv_scr_act()); diff --git a/examples/widgets/bar/lv_example_bar_6.c b/examples/widgets/bar/lv_example_bar_6.c index e67e6792a..8e50b8acd 100644 --- a/examples/widgets/bar/lv_example_bar_6.c +++ b/examples/widgets/bar/lv_example_bar_6.c @@ -40,7 +40,7 @@ static void event_cb(lv_event_t * e) txt_area.y1 = dsc->draw_area->y1 + (lv_area_get_height(dsc->draw_area) - txt_size.y) / 2; txt_area.y2 = txt_area.y1 + txt_size.y - 1; - lv_draw_label(&txt_area, dsc->clip_area, &label_dsc, buf, NULL); + lv_draw_label(dsc->draw_ctx, &label_dsc, &txt_area, buf, NULL); } /** diff --git a/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c b/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c index 3c1102d56..df13bbf42 100644 --- a/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c +++ b/examples/widgets/btnmatrix/lv_example_btnmatrix_2.c @@ -54,7 +54,7 @@ static void event_cb(lv_event_t * e) img_draw_dsc.recolor = lv_color_black(); if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) img_draw_dsc.recolor_opa = LV_OPA_30; - lv_draw_img(&a, dsc->clip_area, &img_star, &img_draw_dsc); + lv_draw_img(dsc->draw_ctx, &img_draw_dsc, &a, &img_star); } } } diff --git a/examples/widgets/canvas/lv_example_canvas_1.c b/examples/widgets/canvas/lv_example_canvas_1.c index 1a421ac10..1b75688a3 100644 --- a/examples/widgets/canvas/lv_example_canvas_1.c +++ b/examples/widgets/canvas/lv_example_canvas_1.c @@ -23,7 +23,7 @@ void lv_example_canvas_1(void) lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); - label_dsc.color = lv_palette_main(LV_PALETTE_YELLOW); + label_dsc.color = lv_palette_main(LV_PALETTE_ORANGE); static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)]; @@ -47,7 +47,7 @@ void lv_example_canvas_1(void) img.header.h = CANVAS_HEIGHT; lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER); - lv_canvas_transform(canvas, &img, 30, LV_IMG_ZOOM_NONE, 0, 0, CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2, true); + lv_canvas_transform(canvas, &img, 120, LV_IMG_ZOOM_NONE, 0, 0, CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2, true); } #endif diff --git a/examples/widgets/chart/lv_example_chart_2.c b/examples/widgets/chart/lv_example_chart_2.c index e1b98aa6b..95963dd52 100644 --- a/examples/widgets/chart/lv_example_chart_2.c +++ b/examples/widgets/chart/lv_example_chart_2.c @@ -36,7 +36,7 @@ static void draw_event_cb(lv_event_t * e) a.x2 = dsc->p2->x - 1; a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); a.y2 = obj->coords.y2; - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); /*Remove the masks*/ lv_draw_mask_free_param(&line_mask_param); diff --git a/examples/widgets/chart/lv_example_chart_4.c b/examples/widgets/chart/lv_example_chart_4.c index 5f5583fd6..1d688d7ec 100644 --- a/examples/widgets/chart/lv_example_chart_4.c +++ b/examples/widgets/chart/lv_example_chart_4.c @@ -45,8 +45,8 @@ static void event_cb(lv_event_t * e) a.y1 = chart->coords.y1 + p.y - 30; a.y2 = chart->coords.y1 + p.y - 10; - const lv_area_t * clip_area = lv_event_get_clip_area(e); - lv_draw_rect(&a, clip_area, &draw_rect_dsc); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); + lv_draw_rect(draw_ctx, &draw_rect_dsc, &a); ser = lv_chart_get_series_next(chart, ser); } diff --git a/examples/widgets/chart/lv_example_chart_6.c b/examples/widgets/chart/lv_example_chart_6.c index 7cc3c3b3b..90e2740e9 100644 --- a/examples/widgets/chart/lv_example_chart_6.c +++ b/examples/widgets/chart/lv_example_chart_6.c @@ -41,7 +41,7 @@ static void event_cb(lv_event_t * e) draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_BLUE); draw_rect_dsc.radius = 3; - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); lv_draw_label_dsc_t draw_label_dsc; lv_draw_label_dsc_init(&draw_label_dsc); @@ -50,7 +50,7 @@ static void event_cb(lv_event_t * e) a.x2 -= 5; a.y1 += 5; a.y2 -= 5; - lv_draw_label(&a, dsc->clip_area, &draw_label_dsc, buf, NULL); + lv_draw_label(dsc->draw_ctx, &draw_label_dsc, &a, buf, NULL); } } diff --git a/examples/widgets/chart/lv_example_chart_8.c b/examples/widgets/chart/lv_example_chart_8.c index f48ffc031..164903bc0 100644 --- a/examples/widgets/chart/lv_example_chart_8.c +++ b/examples/widgets/chart/lv_example_chart_8.c @@ -40,7 +40,7 @@ static void draw_event_cb(lv_event_t *e) a.x2 = dsc->p2->x; a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y); a.y2 = obj->coords.y2 - 13; /* -13 cuts off where the rectangle draws over the chart margin. Without this an area of 0 doesnt look like 0 */ - lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc); + lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a); /*Remove the mask*/ lv_draw_mask_free_param(&line_mask_param); diff --git a/examples/widgets/label/lv_example_label_1.c b/examples/widgets/label/lv_example_label_1.c index a033f92b3..88d910891 100644 --- a/examples/widgets/label/lv_example_label_1.c +++ b/examples/widgets/label/lv_example_label_1.c @@ -15,7 +15,6 @@ void lv_example_label_1(void) lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0); lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40); - lv_obj_t * label2 = lv_label_create(lv_scr_act()); lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR); /*Circular scroll*/ lv_obj_set_width(label2, 150); diff --git a/examples/widgets/label/lv_example_label_4.c b/examples/widgets/label/lv_example_label_4.c index a5e31c368..68b456af2 100644 --- a/examples/widgets/label/lv_example_label_4.c +++ b/examples/widgets/label/lv_example_label_4.c @@ -1,5 +1,5 @@ #include "../../lv_examples.h" -#if LV_USE_LABEL && LV_BUILD_EXAMPLES && LV_DRAW_COMPLEX +#if LV_USE_LABEL && LV_USE_CANVAS && LV_BUILD_EXAMPLES && LV_DRAW_COMPLEX #define MASK_WIDTH 100 #define MASK_HEIGHT 45 diff --git a/examples/widgets/meter/lv_example_meter_2.c b/examples/widgets/meter/lv_example_meter_2.c index 1caf68759..811e056f6 100644 --- a/examples/widgets/meter/lv_example_meter_2.c +++ b/examples/widgets/meter/lv_example_meter_2.c @@ -24,7 +24,7 @@ void lv_example_meter_2(void) /*Add a scale first*/ lv_meter_scale_t * scale = lv_meter_add_scale(meter); lv_meter_set_scale_ticks(meter, scale, 11, 2, 10, lv_palette_main(LV_PALETTE_GREY)); - lv_meter_set_scale_major_ticks(meter, scale, 1, 2, 30, lv_color_hex3(0xeee), 10); + lv_meter_set_scale_major_ticks(meter, scale, 1, 2, 30, lv_color_hex3(0xeee), 15); lv_meter_set_scale_range(meter, scale, 0, 100, 270, 90); /*Add a three arc indicator*/ diff --git a/examples/widgets/slider/lv_example_slider_3.c b/examples/widgets/slider/lv_example_slider_3.c index 8cf88edff..d92b2f3ab 100644 --- a/examples/widgets/slider/lv_example_slider_3.c +++ b/examples/widgets/slider/lv_example_slider_3.c @@ -49,7 +49,7 @@ static void slider_event_cb(lv_event_t * e) lv_draw_label_dsc_t label_draw_dsc; lv_draw_label_dsc_init(&label_draw_dsc); - lv_draw_label(&label_area, dsc->clip_area, &label_draw_dsc, buf, NULL); + lv_draw_label(dsc->draw_ctx, &label_draw_dsc, &label_area, buf, NULL); } } } diff --git a/examples/widgets/span/lv_example_span_1.c b/examples/widgets/span/lv_example_span_1.c index 3481d344d..e465bce68 100644 --- a/examples/widgets/span/lv_example_span_1.c +++ b/examples/widgets/span/lv_example_span_1.c @@ -24,10 +24,10 @@ void lv_example_span_1(void) lv_spangroup_set_mode(spans, LV_SPAN_MODE_BREAK); lv_span_t * span = lv_spangroup_new_span(spans); - lv_span_set_text(span, "china is a beautiful country."); + lv_span_set_text(span, "China is a beautiful country."); lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_RED)); lv_style_set_text_decor(&span->style, LV_TEXT_DECOR_STRIKETHROUGH | LV_TEXT_DECOR_UNDERLINE); - lv_style_set_text_opa(&span->style, LV_OPA_30); + lv_style_set_text_opa(&span->style, LV_OPA_50); span = lv_spangroup_new_span(spans); lv_span_set_text_static(span, "good good study, day day up."); diff --git a/examples/widgets/table/lv_example_table_2.c b/examples/widgets/table/lv_example_table_2.c index b6dd3776c..f2e1b7093 100644 --- a/examples/widgets/table/lv_example_table_2.c +++ b/examples/widgets/table/lv_example_table_2.c @@ -21,7 +21,7 @@ static void draw_event_cb(lv_event_t * e) sw_area.x2 = sw_area.x1 + 40; sw_area.y1 = dsc->draw_area->y1 + lv_area_get_height(dsc->draw_area) / 2 - 10; sw_area.y2 = sw_area.y1 + 20; - lv_draw_rect(&sw_area, dsc->clip_area, &rect_dsc); + lv_draw_rect(dsc->draw_ctx, &rect_dsc, &sw_area); rect_dsc.bg_color = lv_color_white(); if(chk) { @@ -33,7 +33,7 @@ static void draw_event_cb(lv_event_t * e) } sw_area.y1 += 2; sw_area.y2 -= 2; - lv_draw_rect(&sw_area, dsc->clip_area, &rect_dsc); + lv_draw_rect(dsc->draw_ctx, &rect_dsc, &sw_area); } } diff --git a/lv_conf_template.h b/lv_conf_template.h index 62e0df53f..923aeefd8 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -157,13 +157,11 @@ /*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ #define LV_USE_GPU_NXP_VG_LITE 0 -/*Use exnternal renderer*/ -#define LV_USE_EXTERNAL_RENDERER 0 - -/*Use SDL renderer API. Requires LV_USE_EXTERNAL_RENDERER*/ +/*Use SDL renderer API*/ #define LV_USE_GPU_SDL 0 #if LV_USE_GPU_SDL #define LV_GPU_SDL_INCLUDE_PATH + #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) #endif /*------------- diff --git a/src/core/lv_event.c b/src/core/lv_event.c index b82ae96f2..29eccf1e6 100644 --- a/src/core/lv_event.c +++ b/src/core/lv_event.c @@ -85,7 +85,7 @@ lv_res_t lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e) if(class_p == NULL) base = e->current_target->class_p; else base = class_p->base_class; - /*Find a base in which Call the ancestor's event handler_cb is set*/ + /*Find a base in which call the ancestor's event handler_cb if set*/ while(base && base->event_cb == NULL) base = base->base_class; if(base == NULL) return LV_RES_OK; @@ -290,7 +290,7 @@ lv_obj_draw_part_dsc_t * lv_event_get_draw_part_dsc(lv_event_t * e) } } -const lv_area_t * lv_event_get_clip_area(lv_event_t * e) +lv_draw_ctx_t * lv_event_get_draw_ctx(lv_event_t * e) { if(e->code == LV_EVENT_DRAW_MAIN || e->code == LV_EVENT_DRAW_MAIN_BEGIN || diff --git a/src/core/lv_event.h b/src/core/lv_event.h index 623c1884e..a146fc4af 100644 --- a/src/core/lv_event.h +++ b/src/core/lv_event.h @@ -268,12 +268,12 @@ lv_indev_t * lv_event_get_indev(lv_event_t * e); lv_obj_draw_part_dsc_t * lv_event_get_draw_part_dsc(lv_event_t * e); /** - * Get the clip area passed as parameter to draw events events. + * Get the draw context which should be the first parameter of the draw functions. * Namely: `LV_EVENT_DRAW_MAIN/POST`, `LV_EVENT_DRAW_MAIN/POST_BEGIN`, `LV_EVENT_DRAW_MAIN/POST_END` * @param e pointer to an event - * @return the clip area to use during drawing or NULL if called on an unrelated event + * @return pointer to a draw context or NULL if called on an unrelated event */ -const lv_area_t * lv_event_get_clip_area(lv_event_t * e); +lv_draw_ctx_t * lv_event_get_draw_ctx(lv_event_t * e); /** * Get the old area of the object before its size was changed. Can be used in `LV_EVENT_SIZE_CHANGED` diff --git a/src/core/lv_obj.c b/src/core/lv_obj.c index a75f7c107..ab8e2d57f 100644 --- a/src/core/lv_obj.c +++ b/src/core/lv_obj.c @@ -27,7 +27,7 @@ #include #if LV_USE_GPU_STM32_DMA2D - #include "../gpu/lv_gpu_stm32_dma2d.h" + #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" #endif #if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT @@ -35,10 +35,6 @@ #include "../gpu/lv_gpu_nxp_pxp_osa.h" #endif -#if LV_USE_GPU_SDL - #include "../gpu/lv_gpu_sdl.h" -#endif - /********************* * DEFINES *********************/ @@ -59,7 +55,7 @@ static void lv_obj_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_obj_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_obj_draw(lv_event_t * e); static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e); -static void draw_scrollbar(lv_obj_t * obj, const lv_area_t * clip_area); +static void draw_scrollbar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); static lv_res_t scrollbar_init_draw_dsc(lv_obj_t * obj, lv_draw_rect_dsc_t * dsc); static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find); static void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state); @@ -116,20 +112,17 @@ void lv_init(void) lv_draw_init(); - //#if LV_USE_GPU_STM32_DMA2D - // /*Initialize DMA2D GPU*/ - // lv_gpu_stm32_dma2d_init(); - //#endif - // - //#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT - // if(lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) { - // LV_LOG_ERROR("PXP init error. STOP.\n"); - // for(; ;) ; - // } - //#endif - //#if LV_USE_GPU_SDL - // lv_gpu_sdl_init(); - //#endif +#if LV_USE_GPU_STM32_DMA2D + /*Initialize DMA2D GPU*/ + lv_draw_stm32_dma2d_init(); +#endif + +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT + if(lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) { + LV_LOG_ERROR("PXP init error. STOP.\n"); + for(; ;) ; + } +#endif _lv_obj_style_init(); _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); @@ -186,13 +179,10 @@ void lv_init(void) LV_LOG_TRACE("finished"); } -#if LV_ENABLE_GC || !LV_MEM_CUSTOM || LV_USE_GPU_SDL +#if LV_ENABLE_GC || !LV_MEM_CUSTOM void lv_deinit(void) { -#if LV_USE_GPU_SDL - lv_gpu_sdl_deinit(); -#endif _lv_gc_clear_roots(); lv_disp_set_default(NULL); @@ -514,7 +504,7 @@ static void lv_obj_draw(lv_event_t * e) } else if(code == LV_EVENT_DRAW_MAIN) { - const lv_area_t * clip_area = lv_event_get_param(e); + 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); /*If the border is drawn later disable loading its properties*/ @@ -523,7 +513,6 @@ static void lv_obj_draw(lv_event_t * e) } lv_obj_init_draw_rect_dsc(obj, LV_PART_MAIN, &draw_dsc); - lv_coord_t w = lv_obj_get_style_transform_width(obj, LV_PART_MAIN); lv_coord_t h = lv_obj_get_style_transform_height(obj, LV_PART_MAIN); lv_area_t coords; @@ -534,7 +523,7 @@ static void lv_obj_draw(lv_event_t * e) coords.y2 += h; lv_obj_draw_part_dsc_t part_dsc; - lv_obj_draw_dsc_init(&part_dsc, clip_area); + lv_obj_draw_dsc_init(&part_dsc, draw_ctx); part_dsc.class_p = MY_CLASS; part_dsc.type = LV_OBJ_DRAW_PART_RECTANGLE; part_dsc.rect_dsc = &draw_dsc; @@ -542,7 +531,8 @@ static void lv_obj_draw(lv_event_t * e) part_dsc.part = LV_PART_MAIN; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); - lv_draw_rect(&coords, clip_area, &draw_dsc); + + lv_draw_rect(draw_ctx, &draw_dsc, &coords); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); @@ -560,8 +550,8 @@ static void lv_obj_draw(lv_event_t * e) #endif } else if(code == LV_EVENT_DRAW_POST) { - const lv_area_t * clip_area = lv_event_get_param(e); - draw_scrollbar(obj, clip_area); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); + draw_scrollbar(obj, draw_ctx); #if LV_DRAW_COMPLEX if(lv_obj_get_style_clip_corner(obj, LV_PART_MAIN)) { @@ -593,7 +583,7 @@ static void lv_obj_draw(lv_event_t * e) coords.y2 += h; lv_obj_draw_part_dsc_t part_dsc; - lv_obj_draw_dsc_init(&part_dsc, clip_area); + lv_obj_draw_dsc_init(&part_dsc, draw_ctx); part_dsc.class_p = MY_CLASS; part_dsc.type = LV_OBJ_DRAW_PART_BORDER_POST; part_dsc.rect_dsc = &draw_dsc; @@ -601,13 +591,13 @@ static void lv_obj_draw(lv_event_t * e) part_dsc.part = LV_PART_MAIN; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); - lv_draw_rect(&coords, clip_area, &draw_dsc); + lv_draw_rect(draw_ctx, &draw_dsc, &coords); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); } } } -static void draw_scrollbar(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_scrollbar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { lv_area_t hor_area; @@ -621,7 +611,7 @@ static void draw_scrollbar(lv_obj_t * obj, const lv_area_t * clip_area) if(sb_res != LV_RES_OK) return; lv_obj_draw_part_dsc_t part_dsc; - lv_obj_draw_dsc_init(&part_dsc, clip_area); + lv_obj_draw_dsc_init(&part_dsc, draw_ctx); part_dsc.class_p = MY_CLASS; part_dsc.type = LV_OBJ_DRAW_PART_SCROLLBAR; part_dsc.rect_dsc = &draw_dsc; @@ -630,13 +620,14 @@ static void draw_scrollbar(lv_obj_t * obj, const lv_area_t * clip_area) if(lv_area_get_size(&hor_area) > 0) { part_dsc.draw_area = &hor_area; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); - lv_draw_rect(&hor_area, clip_area, &draw_dsc); + lv_draw_rect(draw_ctx, &draw_dsc, &hor_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); } if(lv_area_get_size(&ver_area) > 0) { part_dsc.draw_area = &ver_area; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_dsc); - lv_draw_rect(&ver_area, clip_area, &draw_dsc); + part_dsc.draw_area = &ver_area; + lv_draw_rect(draw_ctx, &draw_dsc, &ver_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_dsc); } } diff --git a/src/core/lv_obj.h b/src/core/lv_obj.h index 4469fcc23..daf392ce5 100644 --- a/src/core/lv_obj.h +++ b/src/core/lv_obj.h @@ -194,7 +194,7 @@ typedef struct _lv_obj_t { */ void lv_init(void); -#if LV_ENABLE_GC || !LV_MEM_CUSTOM || LV_USE_GPU_SDL +#if LV_ENABLE_GC || !LV_MEM_CUSTOM /** * Deinit the 'lv' library diff --git a/src/core/lv_obj_draw.c b/src/core/lv_obj_draw.c index 411135f30..f0aa12ad1 100644 --- a/src/core/lv_obj_draw.c +++ b/src/core/lv_obj_draw.c @@ -322,10 +322,10 @@ lv_coord_t lv_obj_calculate_ext_draw_size(lv_obj_t * obj, uint32_t part) return s; } -void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, const lv_area_t * clip_area) +void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, lv_draw_ctx_t * draw_ctx) { lv_memset_00(dsc, sizeof(lv_obj_draw_part_dsc_t)); - dsc->clip_area = clip_area; + dsc->draw_ctx = draw_ctx; } bool lv_obj_draw_part_check_type(lv_obj_draw_part_dsc_t * dsc, const lv_obj_class_t * class_p, uint32_t type) diff --git a/src/core/lv_obj_draw.h b/src/core/lv_obj_draw.h index 1a9e2e5c5..063216540 100644 --- a/src/core/lv_obj_draw.h +++ b/src/core/lv_obj_draw.h @@ -34,7 +34,7 @@ typedef enum { } lv_cover_res_t; typedef struct { - const lv_area_t * clip_area; /**< The current clip area, required if you need to draw something in the event*/ + lv_draw_ctx_t * draw_ctx; /**< Draw context*/ const struct _lv_obj_class_t * class_p; /**< The class that sent the event */ uint32_t type; /**< The type if part being draw. Element of `lv__draw_part_type_t` */ lv_area_t * draw_area; /**< The area of the part being drawn*/ @@ -125,9 +125,9 @@ lv_coord_t lv_obj_calculate_ext_draw_size(struct _lv_obj_t * obj, uint32_t part) /** * Initialize a draw descriptor used in events. * @param dsc pointer to a descriptor. Later it should be passed as parameter to an `LV_EEVNT_DRAW_PART_BEGIN/END` event. - * @param clip_area the current clip area of the drawing + * @param draw the current draw context. (usually returned by `lv_event_get_draw_ctx(e)`) */ -void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, const lv_area_t * clip_area); +void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, lv_draw_ctx_t * draw_ctx); /** * Check the type obj a part draw descriptor diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index b8accac2c..55fe46962 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -53,11 +53,11 @@ typedef struct { static void lv_refr_join_area(void); static void lv_refr_areas(void); static void lv_refr_area(const lv_area_t * area_p); -static void lv_refr_area_part(const lv_area_t * area_p); +static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx); static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj); -static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p); -static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p); -static void draw_buf_flush(void); +static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj); +static uint32_t get_max_row(lv_disp_t * disp, lv_coord_t area_w, lv_coord_t area_h); +static void draw_buf_flush(lv_disp_t * disp); static void call_flush_cb(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); #if LV_USE_PERF_MONITOR @@ -107,13 +107,6 @@ void _lv_refr_init(void) #endif } -/** - * Redraw the invalidated areas now. - * Normally the redrawing is periodically executed in `lv_timer_handler` but a long blocking process - * can prevent the call of `lv_timer_handler`. In this case if the GUI is updated in the process - * (e.g. progress bar) this function can be called when the screen should be updated. - * @param disp pointer to display to refresh. NULL to refresh all displays. - */ void lv_refr_now(lv_disp_t * disp) { lv_anim_refr_now(); @@ -131,6 +124,68 @@ void lv_refr_now(lv_disp_t * disp) } } +void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj) +{ + /*Do not refresh hidden objects*/ + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + lv_area_t obj_coords_ext; + lv_area_t obj_ext_clip_coords; + lv_obj_get_coords(obj, &obj_coords_ext); + lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj); + lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size); + if(!_lv_area_intersect(&obj_ext_clip_coords, clip_area_ori, &obj_coords_ext)) return; + + draw_ctx->clip_area = &obj_ext_clip_coords; + + /*Redraw the object*/ + lv_event_send(obj, LV_EVENT_DRAW_MAIN_BEGIN, draw_ctx); + lv_event_send(obj, LV_EVENT_DRAW_MAIN, draw_ctx); + lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, draw_ctx); + +#if LV_USE_REFR_DEBUG + lv_color_t debug_color = lv_color_make(lv_rand(0, 0xFF), lv_rand(0, 0xFF), lv_rand(0, 0xFF)); + lv_draw_rect_dsc_t draw_dsc; + lv_draw_rect_dsc_init(&draw_dsc); + draw_dsc.bg_color.full = debug_color.full; + draw_dsc.bg_opa = LV_OPA_20; + draw_dsc.border_width = 1; + draw_dsc.border_opa = LV_OPA_30; + draw_dsc.border_color = debug_color; + lv_draw_rect(&obj_ext_mask, &obj_ext_mask, &draw_dsc); +#endif + + /*Create a new 'obj_clip' without 'ext_size' because the children can't be visible there*/ + lv_area_t obj_clip_coords; + if(_lv_area_intersect(&obj_clip_coords, clip_area_ori, &obj->coords)) { + uint32_t i; + uint32_t child_cnt = lv_obj_get_child_cnt(obj); + for(i = 0; i < child_cnt; i++) { + lv_obj_t * child = obj->spec_attr->children[i]; + lv_area_t child_coords; + lv_obj_get_coords(child, &child_coords); + ext_draw_size = _lv_obj_get_ext_draw_size(child); + lv_area_increase(&child_coords, ext_draw_size, ext_draw_size); + lv_area_t child_clip; + if(_lv_area_intersect(&child_clip, &obj_clip_coords, &child_coords)) { + /*Refresh the next child*/ + draw_ctx->clip_area = &child_clip; + lv_refr_obj(draw_ctx, child); + } + } + } + + draw_ctx->clip_area = &obj_ext_clip_coords; + + /*If all the children are redrawn make 'post draw' draw*/ + lv_event_send(obj, LV_EVENT_DRAW_POST_BEGIN, draw_ctx); + lv_event_send(obj, LV_EVENT_DRAW_POST, draw_ctx); + lv_event_send(obj, LV_EVENT_DRAW_POST_END, draw_ctx); + + draw_ctx->clip_area = clip_area_ori; +} + /** * Invalidate an area on display to redraw it * @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas) @@ -255,7 +310,7 @@ void _lv_disp_refr_timer(lv_timer_t * tmr) /*If refresh happened ...*/ if(disp_refr->inv_p != 0) { if(disp_refr->driver->full_refresh) { - draw_buf_flush(); + draw_buf_flush(disp_refr); } /*Clean up*/ @@ -375,6 +430,7 @@ uint32_t lv_refr_get_fps_avg(void) } #endif + /********************** * STATIC FUNCTIONS **********************/ @@ -457,104 +513,72 @@ static void lv_refr_areas(void) */ static void lv_refr_area(const lv_area_t * area_p) { + lv_draw_ctx_t * draw_ctx = disp_refr->driver->draw_ctx; + draw_ctx->buf = disp_refr->driver->draw_buf->buf_act; + /*With full refresh just redraw directly into the buffer*/ - if(disp_refr->driver->full_refresh) { - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); - draw_buf->area.x1 = 0; - draw_buf->area.x2 = lv_disp_get_hor_res(disp_refr) - 1; - draw_buf->area.y1 = 0; - draw_buf->area.y2 = lv_disp_get_ver_res(disp_refr) - 1; - disp_refr->driver->draw_buf->last_part = 1; - lv_refr_area_part(area_p); + /*In direct mode draw directly on the absolute coordinates of the buffer*/ + if(disp_refr->driver->full_refresh || disp_refr->driver->direct_mode) { + lv_area_t disp_area; + lv_area_set(&disp_area, 0, 0, lv_disp_get_hor_res(disp_refr) - 1, lv_disp_get_ver_res(disp_refr) - 1); + draw_ctx->buf_area = &disp_area; + + if(disp_refr->driver->full_refresh) { + disp_refr->driver->draw_buf->last_part = 1; + draw_ctx->clip_area = &disp_area; + lv_refr_area_part(draw_ctx); + } + else { + disp_refr->driver->draw_buf->last_part = disp_refr->driver->draw_buf->last_area; + draw_ctx->clip_area = area_p; + lv_refr_area_part(draw_ctx); + } return; } /*Normal refresh: draw the area in parts*/ - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); /*Calculate the max row num*/ lv_coord_t w = lv_area_get_width(area_p); lv_coord_t h = lv_area_get_height(area_p); lv_coord_t y2 = area_p->y2 >= lv_disp_get_ver_res(disp_refr) ? lv_disp_get_ver_res(disp_refr) - 1 : area_p->y2; - int32_t max_row = (uint32_t)draw_buf->size / w; + int32_t max_row = get_max_row(disp_refr, w, h); - if(max_row > h) max_row = h; - - /*Round down the lines of draw_buf if rounding is added*/ - if(disp_refr->driver->rounder_cb) { - lv_area_t tmp; - tmp.x1 = 0; - tmp.x2 = 0; - tmp.y1 = 0; - - lv_coord_t h_tmp = max_row; - do { - tmp.y2 = h_tmp - 1; - disp_refr->driver->rounder_cb(disp_refr->driver, &tmp); - - /*If this height fits into `max_row` then fine*/ - if(lv_area_get_height(&tmp) <= max_row) break; - - /*Decrement the height of the area until it fits into `max_row` after rounding*/ - h_tmp--; - } while(h_tmp > 0); - - if(h_tmp <= 0) { - LV_LOG_WARN("Can't set draw_buf height using the round function. (Wrong round_cb or to " - "small draw_buf)"); - return; - } - else { - max_row = tmp.y2 + 1; - } + lv_coord_t row; + lv_coord_t row_last = 0; + lv_area_t sub_area; + for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) { + /*Calc. the next y coordinates of draw_buf*/ + sub_area.x1 = area_p->x1; + sub_area.x2 = area_p->x2; + sub_area.y1 = row; + sub_area.y2 = row + max_row - 1; + draw_ctx->buf_area = &sub_area; + draw_ctx->clip_area = &sub_area; + draw_ctx->buf = disp_refr->driver->draw_buf->buf_act; + if(sub_area.y2 > y2) sub_area.y2 = y2; + row_last = sub_area.y2; + if(y2 == row_last) disp_refr->driver->draw_buf->last_part = 1; + lv_refr_area_part(draw_ctx); } - /*In direct mode draw directly on the absolute coordinates of the buffer*/ - if(disp_refr->driver->direct_mode) { - draw_buf->area.x1 = 0; - draw_buf->area.x2 = lv_disp_get_hor_res(disp_refr) - 1; - draw_buf->area.y1 = 0; - draw_buf->area.y2 = lv_disp_get_ver_res(disp_refr) - 1; - disp_refr->driver->draw_buf->last_part = disp_refr->driver->draw_buf->last_area; - lv_refr_area_part(area_p); - } - /*Else assume the buffer starts at the given area*/ - else { - /*Always use the full row*/ - lv_coord_t row; - lv_coord_t row_last = 0; - for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) { - /*Calc. the next y coordinates of draw_buf*/ - draw_buf->area.x1 = area_p->x1; - draw_buf->area.x2 = area_p->x2; - draw_buf->area.y1 = row; - draw_buf->area.y2 = row + max_row - 1; - if(draw_buf->area.y2 > y2) draw_buf->area.y2 = y2; - row_last = draw_buf->area.y2; - if(y2 == row_last) disp_refr->driver->draw_buf->last_part = 1; - lv_refr_area_part(area_p); - } - - /*If the last y coordinates are not handled yet ...*/ - if(y2 != row_last) { - /*Calc. the next y coordinates of draw_buf*/ - draw_buf->area.x1 = area_p->x1; - draw_buf->area.x2 = area_p->x2; - draw_buf->area.y1 = row; - draw_buf->area.y2 = y2; - - disp_refr->driver->draw_buf->last_part = 1; - lv_refr_area_part(area_p); - } + /*If the last y coordinates are not handled yet ...*/ + if(y2 != row_last) { + /*Calc. the next y coordinates of draw_buf*/ + sub_area.x1 = area_p->x1; + sub_area.x2 = area_p->x2; + sub_area.y1 = row; + sub_area.y2 = y2; + draw_ctx->buf_area = &sub_area; + draw_ctx->clip_area = &sub_area; + draw_ctx->buf = disp_refr->driver->draw_buf->buf_act; + disp_refr->driver->draw_buf->last_part = 1; + lv_refr_area_part(draw_ctx); } } -/** - * Refresh a part of an area which is on the actual Virtual Display Buffer - * @param area_p pointer to an area to refresh - */ -static void lv_refr_area_part(const lv_area_t * area_p) +static void lv_refr_area_part(lv_draw_ctx_t * draw_ctx) { lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); @@ -569,33 +593,28 @@ static void lv_refr_area_part(const lv_area_t * area_p) lv_obj_t * top_act_scr = NULL; lv_obj_t * top_prev_scr = NULL; - /*Get the new mask from the original area and the act. draw_buf - It will be a part of 'area_p'*/ - lv_area_t start_mask; - _lv_area_intersect(&start_mask, area_p, &draw_buf->area); - /*Get the most top object which is not covered by others*/ - top_act_scr = lv_refr_get_top_obj(&start_mask, lv_disp_get_scr_act(disp_refr)); + top_act_scr = lv_refr_get_top_obj(draw_ctx->buf_area, lv_disp_get_scr_act(disp_refr)); if(disp_refr->prev_scr) { - top_prev_scr = lv_refr_get_top_obj(&start_mask, disp_refr->prev_scr); + top_prev_scr = lv_refr_get_top_obj(draw_ctx->buf_area, disp_refr->prev_scr); } /*Draw a display background if there is no top object*/ if(top_act_scr == NULL && top_prev_scr == NULL) { - if(disp_refr->bg_fn) { - disp_refr->bg_fn(&start_mask); - } - else if(disp_refr->bg_img) { - lv_draw_img_dsc_t dsc; - lv_draw_img_dsc_init(&dsc); - dsc.opa = disp_refr->bg_opa; + if(disp_refr->bg_img) { lv_img_header_t header; lv_res_t res; res = lv_img_decoder_get_info(disp_refr->bg_img, &header); if(res == LV_RES_OK) { lv_area_t a; lv_area_set(&a, 0, 0, header.w - 1, header.h - 1); - lv_draw_img(&a, &start_mask, disp_refr->bg_img, &dsc); + lv_draw_img_dsc_t dsc; + lv_draw_img_dsc_init(&dsc); + dsc.opa = disp_refr->bg_opa; + if(dsc.opa < LV_OPA_COVER) { + dsc.blend_mode = LV_BLEND_MODE_REPLACE; + } + lv_draw_img(draw_ctx, &dsc, &a, disp_refr->bg_img); } else { LV_LOG_WARN("Can't draw the background image"); @@ -606,35 +625,29 @@ static void lv_refr_area_part(const lv_area_t * area_p) lv_draw_rect_dsc_init(&dsc); dsc.bg_color = disp_refr->bg_color; dsc.bg_opa = disp_refr->bg_opa; - lv_draw_rect(&start_mask, &start_mask, &dsc); - + if(dsc.bg_opa < LV_OPA_COVER) { + dsc.blend_mode = LV_BLEND_MODE_REPLACE; + } + lv_draw_rect(draw_ctx, &dsc, draw_ctx->buf_area); } } /*Refresh the previous screen if any*/ if(disp_refr->prev_scr) { - /*Get the most top object which is not covered by others*/ - if(top_prev_scr == NULL) { - top_prev_scr = disp_refr->prev_scr; - } - /*Do the refreshing from the top object*/ - lv_refr_obj_and_children(top_prev_scr, &start_mask); - + if(top_prev_scr == NULL) top_prev_scr = disp_refr->prev_scr; + lv_refr_obj_and_children(draw_ctx, top_prev_scr); } - if(top_act_scr == NULL) { - top_act_scr = disp_refr->act_scr; - } - /*Do the refreshing from the top object*/ - lv_refr_obj_and_children(top_act_scr, &start_mask); + if(top_act_scr == NULL) top_act_scr = disp_refr->act_scr; + lv_refr_obj_and_children(draw_ctx, top_act_scr); /*Also refresh top and sys layer unconditionally*/ - lv_refr_obj_and_children(lv_disp_get_layer_top(disp_refr), &start_mask); - lv_refr_obj_and_children(lv_disp_get_layer_sys(disp_refr), &start_mask); + lv_refr_obj_and_children(draw_ctx, lv_disp_get_layer_top(disp_refr)); + lv_refr_obj_and_children(draw_ctx, lv_disp_get_layer_sys(disp_refr)); /*In true double buffered mode flush only once when all areas were rendered. *In normal mode flush after every area*/ if(disp_refr->driver->full_refresh == false) { - draw_buf_flush(); + draw_buf_flush(disp_refr); } } @@ -684,127 +697,88 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj) * @param top_p pointer to an objects. Start the drawing from it. * @param mask_p pointer to an area, the objects will be drawn only here */ -static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p) +static void lv_refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj) { /*Normally always will be a top_obj (at least the screen) *but in special cases (e.g. if the screen has alpha) it won't. *In this case use the screen directly*/ - if(top_p == NULL) top_p = lv_disp_get_scr_act(disp_refr); - if(top_p == NULL) return; /*Shouldn't happen*/ + if(top_obj == NULL) top_obj = lv_disp_get_scr_act(disp_refr); + if(top_obj == NULL) return; /*Shouldn't happen*/ /*Refresh the top object and its children*/ - lv_refr_obj(top_p, mask_p); + lv_refr_obj(draw_ctx, top_obj); /*Draw the 'younger' sibling objects because they can be on top_obj*/ - lv_obj_t * par; - lv_obj_t * border_p = top_p; + lv_obj_t * parent; + lv_obj_t * border_p = top_obj; - par = lv_obj_get_parent(top_p); + parent = lv_obj_get_parent(top_obj); /*Do until not reach the screen*/ - while(par != NULL) { + while(parent != NULL) { bool go = false; uint32_t i; - uint32_t child_cnt = lv_obj_get_child_cnt(par); + uint32_t child_cnt = lv_obj_get_child_cnt(parent); for(i = 0; i < child_cnt; i++) { - lv_obj_t * child = par->spec_attr->children[i]; + lv_obj_t * child = parent->spec_attr->children[i]; if(!go) { if(child == border_p) go = true; } else { /*Refresh the objects*/ - lv_refr_obj(child, mask_p); + lv_refr_obj(draw_ctx, child); } } /*Call the post draw draw function of the parents of the to object*/ - lv_event_send(par, LV_EVENT_DRAW_POST_BEGIN, (void *)mask_p); - lv_event_send(par, LV_EVENT_DRAW_POST, (void *)mask_p); - lv_event_send(par, LV_EVENT_DRAW_POST_END, (void *)mask_p); + lv_event_send(parent, LV_EVENT_DRAW_POST_BEGIN, (void *)draw_ctx); + lv_event_send(parent, LV_EVENT_DRAW_POST, (void *)draw_ctx); + lv_event_send(parent, LV_EVENT_DRAW_POST_END, (void *)draw_ctx); /*The new border will be the last parents, *so the 'younger' brothers of parent will be refreshed*/ - border_p = par; + border_p = parent; /*Go a level deeper*/ - par = lv_obj_get_parent(par); + parent = lv_obj_get_parent(parent); } } -/** - * Refresh an object an all of its children. (Called recursively) - * @param obj pointer to an object to refresh - * @param mask_ori_p pointer to an area, the objects will be drawn only here - */ -static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) +static uint32_t get_max_row(lv_disp_t * disp, lv_coord_t area_w, lv_coord_t area_h) { - /*Do not refresh hidden objects*/ - if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return; + int32_t max_row = (uint32_t)disp->driver->draw_buf->size / area_w; - bool union_ok; /*Store the return value of area_union*/ - /*Truncate the original mask to the coordinates of the parent - *because the parent and its children are visible only here*/ - lv_area_t obj_mask; - lv_area_t obj_ext_mask; - lv_area_t obj_area; - lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); - lv_obj_get_coords(obj, &obj_area); - obj_area.x1 -= ext_size; - obj_area.y1 -= ext_size; - obj_area.x2 += ext_size; - obj_area.y2 += ext_size; - union_ok = _lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area); + if(max_row > area_h) max_row = area_h; - /*Draw the parent and its children only if they ore on 'mask_parent'*/ - if(union_ok != false) { - /*Redraw the object*/ - lv_event_send(obj, LV_EVENT_DRAW_MAIN_BEGIN, &obj_ext_mask); - lv_event_send(obj, LV_EVENT_DRAW_MAIN, &obj_ext_mask); - lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, &obj_ext_mask); + /*Round down the lines of draw_buf if rounding is added*/ + if(disp_refr->driver->rounder_cb) { + lv_area_t tmp; + tmp.x1 = 0; + tmp.x2 = 0; + tmp.y1 = 0; -#if LV_USE_REFR_DEBUG - lv_color_t debug_color = lv_color_make(lv_rand(0, 0xFF), lv_rand(0, 0xFF), lv_rand(0, 0xFF)); - lv_draw_rect_dsc_t draw_dsc; - lv_draw_rect_dsc_init(&draw_dsc); - draw_dsc.bg_color.full = debug_color.full; - draw_dsc.bg_opa = LV_OPA_20; - draw_dsc.border_width = 1; - draw_dsc.border_opa = LV_OPA_30; - draw_dsc.border_color = debug_color; - lv_draw_rect(&obj_ext_mask, &obj_ext_mask, &draw_dsc); -#endif - /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/ - lv_obj_get_coords(obj, &obj_area); - union_ok = _lv_area_intersect(&obj_mask, mask_ori_p, &obj_area); - if(union_ok != false) { - lv_area_t mask_child; /*Mask from obj and its child*/ - lv_area_t child_area; - uint32_t i; - uint32_t child_cnt = lv_obj_get_child_cnt(obj); - for(i = 0; i < child_cnt; i++) { - lv_obj_t * child = obj->spec_attr->children[i]; - lv_obj_get_coords(child, &child_area); - ext_size = _lv_obj_get_ext_draw_size(child); - child_area.x1 -= ext_size; - child_area.y1 -= ext_size; - child_area.x2 += ext_size; - child_area.y2 += ext_size; - /*Get the union (common parts) of original mask (from obj) - *and its child*/ - union_ok = _lv_area_intersect(&mask_child, &obj_mask, &child_area); + lv_coord_t h_tmp = max_row; + do { + tmp.y2 = h_tmp - 1; + disp_refr->driver->rounder_cb(disp_refr->driver, &tmp); - /*If the parent and the child has common area then refresh the child*/ - if(union_ok) { - /*Refresh the next children*/ - lv_refr_obj(child, &mask_child); - } - } + /*If this height fits into `max_row` then fine*/ + if(lv_area_get_height(&tmp) <= max_row) break; + + /*Decrement the height of the area until it fits into `max_row` after rounding*/ + h_tmp--; + } while(h_tmp > 0); + + if(h_tmp <= 0) { + LV_LOG_WARN("Can't set draw_buf height using the round function. (Wrong round_cb or to " + "small draw_buf)"); + return 0; + } + else { + max_row = tmp.y2 + 1; } - - /*If all the children are redrawn make 'post draw' draw*/ - lv_event_send(obj, LV_EVENT_DRAW_POST_BEGIN, &obj_ext_mask); - lv_event_send(obj, LV_EVENT_DRAW_POST, &obj_ext_mask); - lv_event_send(obj, LV_EVENT_DRAW_POST_END, &obj_ext_mask); } + + return max_row; } static void draw_buf_rotate_180(lv_disp_drv_t * drv, lv_area_t * area, lv_color_t * color_p) @@ -987,14 +961,13 @@ static void draw_buf_rotate(lv_area_t * area, lv_color_t * color_p) /** * Flush the content of the draw buffer */ -static void draw_buf_flush(void) +static void draw_buf_flush(lv_disp_t * disp) { lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); - lv_color_t * color_p = draw_buf->buf_act; /*Flush the rendered content to the display*/ - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->gpu_wait_cb) disp->driver->gpu_wait_cb(disp->driver); + lv_draw_ctx_t * draw_ctx = disp->driver->draw_ctx; + if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx); /* In double buffered mode wait until the other buffer is freed * and driver is ready to receive the new buffer */ @@ -1012,10 +985,10 @@ static void draw_buf_flush(void) if(disp->driver->flush_cb) { /*Rotate the buffer to the display's native orientation if necessary*/ if(disp->driver->rotated != LV_DISP_ROT_NONE && disp->driver->sw_rotate) { - draw_buf_rotate(&draw_buf->area, draw_buf->buf_act); + draw_buf_rotate(draw_ctx->buf_area, draw_ctx->buf); } else { - call_flush_cb(disp->driver, &draw_buf->area, color_p); + call_flush_cb(disp->driver, draw_ctx->buf_area, draw_ctx->buf); } } /*If there are 2 buffers swap them. With direct mode swap only on the last area*/ diff --git a/src/core/lv_refr.h b/src/core/lv_refr.h index 873612cc7..984168a96 100644 --- a/src/core/lv_refr.h +++ b/src/core/lv_refr.h @@ -56,6 +56,13 @@ void _lv_refr_init(void); */ void lv_refr_now(lv_disp_t * disp); +/** + * Redrawn on object an all its children using the passed draw context + * @param draw pointer to an initialized draw context + * @param obj the start object from the redraw should start + */ +void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj); + /** * Invalidate an area on display to redraw it * @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas) diff --git a/src/draw/lv_draw.c b/src/draw/lv_draw.c index 65a1142b4..116e3b231 100644 --- a/src/draw/lv_draw.c +++ b/src/draw/lv_draw.c @@ -29,8 +29,6 @@ * STATIC VARIABLES **********************/ -static lv_draw_backend_t * backend_head; - /********************** * MACROS **********************/ @@ -41,26 +39,15 @@ static lv_draw_backend_t * backend_head; void lv_draw_init(void) { - backend_head = NULL; - lv_draw_sw_init(); -} - -void lv_draw_backend_init(lv_draw_backend_t * backend) -{ - lv_memset_00(backend, sizeof(lv_draw_backend_t)); -} - -void lv_draw_backend_add(lv_draw_backend_t * backend) -{ - backend->base = backend_head; - backend_head = backend; -} - -const lv_draw_backend_t * lv_draw_backend_get(void) -{ - return backend_head; + // backend_head = NULL; + // lv_draw_sw_init(); + // + //#if LV_USE_GPU_STM32_DMA2D == 0 + // lv_gpu_stm32_dma2d_init(); + //#endif } /********************** * STATIC FUNCTIONS **********************/ + diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h index ccd4c710c..07310b187 100644 --- a/src/draw/lv_draw.h +++ b/src/draw/lv_draw.h @@ -35,66 +35,61 @@ extern "C" { /********************** * TYPEDEFS **********************/ -typedef struct _lv_draw_backend_t { - struct _lv_draw_backend_t * base; - void * ctx; - - void (*draw_rect)(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); - - void (*draw_arc)(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, - const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc); - - void (*draw_img)(const lv_area_t * map_area, const lv_area_t * clip_area, - const uint8_t * map_p, - const lv_draw_img_dsc_t * draw_dsc, - bool chroma_key, bool alpha_byte); - - lv_res_t (*draw_img_core)(const lv_area_t * coords, const lv_area_t * clip_area, const void * src, - const lv_draw_img_dsc_t * draw_dsc); - - void (*draw_letter)(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, uint32_t letter, - lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); +typedef struct { + void * user_data; +} lv_draw_mask_t; - void (*draw_line)(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); - - - void (*draw_polygon)(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * draw_dsc); - +typedef struct _lv_draw_ctx_t { + /** + * Pointer to a buffer to draw into + */ + void * buf; /** - * Fill an arae of a buffer with a color - * @param dest_buf pointer to a buffer to fill - * @param dest_stride stride of `dest_buf` (number of pixel in a line) - * @param fill_area the area to fill on `dest_buf` - * @param color fill color - * @param mask NULL if ignored, or an alpha mask to apply on `fill_area` - * @param opa overall opacity - * @param blend_mode e.g. LV_BLEND_MODE_ADDITIVE + * The the position and size of `buf` (absolute coordinates) */ - void (*blend_fill)(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode); + lv_area_t * buf_area; /** - * Blend a source buffer to a destination buffer - * @param dest_buf pointer to the destination buffer - * @param dest_stride stride of `dest_buf` (number of pixel in a line) - * @param clip_area clip the blending to this area - * @param src_buf pointer to the destination buffer - * @param src_area coordinates of the `src_buf` relative to the `dest_buf` - * @param mask NULL if ignored, or an alpha mask to apply on `clip_area` (it's size is equal to the `clip_area`) - * @param opa overall opacity - * @param blend_mode e.g. LV_BLEND_MODE_ADDITIVE + * The current clip area with absolute coordinates, always the same or smaller than `buf_area` */ - void (*blend_map)(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode); + const lv_area_t * clip_area; -} lv_draw_backend_t; + + void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + + void (*draw_arc)(struct _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 (*draw_img_decoded)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); + + lv_res_t (*draw_img)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src); + + void (*draw_letter)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); + + + void (*draw_line)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + + + void (*draw_polygon)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, + const lv_point_t * points, uint16_t point_cnt); + + /** + * Wait until all background operation are finished. (E.g. GPU opertions) + */ + void (*wait_for_finish)(struct _lv_draw_ctx_t * draw); + +#if LV_USE_USER_DATA + void * user_data; +#endif + +} lv_draw_ctx_t; /********************** * GLOBAL PROTOTYPES @@ -102,12 +97,6 @@ typedef struct _lv_draw_backend_t { void lv_draw_init(void); -void lv_draw_backend_init(lv_draw_backend_t * backend); - -void lv_draw_backend_add(lv_draw_backend_t * backend); - -const lv_draw_backend_t * lv_draw_backend_get(void); - /********************** * GLOBAL VARIABLES **********************/ diff --git a/src/draw/lv_draw_arc.c b/src/draw/lv_draw_arc.c index bccb7a4fc..b806a002e 100644 --- a/src/draw/lv_draw_arc.c +++ b/src/draw/lv_draw_arc.c @@ -41,15 +41,17 @@ void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc) dsc->color = lv_color_black(); } -void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, - const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc) +void lv_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) { if(dsc->opa <= LV_OPA_MIN) return; if(dsc->width == 0) return; if(start_angle == end_angle) return; - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_arc(center_x, center_y, radius, start_angle, end_angle, clip_area, dsc); + draw_ctx->draw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); + + // const lv_draw_backend_t * backend = lv_draw_backend_get(); + // backend->draw_arc(center_x, center_y, radius, start_angle, end_angle, clip_area, dsc); } void lv_draw_arc_get_area(lv_coord_t x, lv_coord_t y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, diff --git a/src/draw/lv_draw_arc.h b/src/draw/lv_draw_arc.h index a4181fcb6..8783f131b 100644 --- a/src/draw/lv_draw_arc.h +++ b/src/draw/lv_draw_arc.h @@ -28,12 +28,16 @@ extern "C" { typedef struct { lv_color_t color; lv_coord_t width; + uint16_t start_angle; + uint16_t end_angle; const void * img_src; lv_opa_t opa; lv_blend_mode_t blend_mode : 2; uint8_t rounded : 1; } lv_draw_arc_dsc_t; +struct _lv_draw_ctx_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -51,8 +55,8 @@ void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc); * @param clip_area the arc will be drawn only in this area * @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable */ -void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, - const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc); +void lv_draw_arc(struct _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); /** * Get an area the should be invalidated when the arcs angle changed between start_angle and end_ange diff --git a/src/draw/lv_draw_blend.c b/src/draw/lv_draw_blend.c deleted file mode 100644 index 0f846d319..000000000 --- a/src/draw/lv_draw_blend.c +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @file lv_draw_blend.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_draw_blend.h" -#include "lv_img_decoder.h" -#include "../misc/lv_math.h" -#include "../hal/lv_hal_disp.h" -#include "../core/lv_refr.h" - -#if LV_USE_GPU_NXP_PXP - #include "../gpu/lv_gpu_nxp_pxp.h" -#elif LV_USE_GPU_NXP_VG_LITE - #include "../gpu/lv_gpu_nxp_vglite.h" -#elif LV_USE_GPU_STM32_DMA2D - #include "../gpu/lv_gpu_stm32_dma2d.h" -#endif - -/********************* - * DEFINES - *********************/ -#define GPU_SIZE_LIMIT 240 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -LV_ATTRIBUTE_FAST_MEM void lv_draw_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, - lv_blend_mode_t blend_mode) -{ - /*Do not draw transparent things*/ - if(opa < LV_OPA_MIN) return; - if(mask_res == LV_DRAW_MASK_RES_TRANSP) return; - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; - - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `fill_area`*/ - lv_area_t draw_area; - if(!_lv_area_intersect(&draw_area, clip_area, fill_area)) return; - - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - const lv_area_t * disp_area = &draw_buf->area; - lv_color_t * disp_buf = draw_buf->buf_act; - - /*Now `draw_area` has absolute coordinates. - *Make it relative to `disp_area` to simplify the drawing to `disp_buf`*/ - lv_area_move(&draw_area, -disp_area->x1, -disp_area->y1); - - lv_coord_t stride = lv_area_get_width(disp_area); - - if(disp->driver->gpu_wait_cb) disp->driver->gpu_wait_cb(disp->driver); - - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->blend_fill(disp_buf, stride, &draw_area, color, mask, opa, blend_mode); - -} - -void lv_draw_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area, - const lv_color_t * map_buf, - lv_opa_t * mask, lv_draw_mask_res_t mask_res, - lv_opa_t opa, lv_blend_mode_t blend_mode) -{ - /*Do not draw transparent things*/ - if(opa < LV_OPA_MIN) return; - if(mask_res == LV_DRAW_MASK_RES_TRANSP) return; - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; - - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `map_area`*/ - lv_area_t draw_area; - if(!_lv_area_intersect(&draw_area, clip_area, map_area)) return; - - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - const lv_area_t * disp_area = &draw_buf->area; - lv_color_t * buf = draw_buf->buf_act; - - - /*Now `draw_area` has absolute coordinates. - *Make it relative to `disp_area` to simplify draw to `disp_buf`*/ - lv_area_move(&draw_area, -disp_area->x1, -disp_area->y1); - - lv_area_t map_area_relative; - lv_area_copy(&map_area_relative, map_area); - lv_area_move(&map_area_relative, -disp_area->x1, -disp_area->y1); - - if(disp->driver->gpu_wait_cb) disp->driver->gpu_wait_cb(disp->driver); - - lv_coord_t stride = lv_area_get_width(disp_area); - - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->blend_map(buf, stride, &draw_area, - map_buf, &map_area_relative, - mask, opa, blend_mode); -} - -/********************** - * STATIC FUNCTIONS - **********************/ diff --git a/src/draw/lv_draw_blend.h b/src/draw/lv_draw_blend.h deleted file mode 100644 index cf7e3aff7..000000000 --- a/src/draw/lv_draw_blend.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file lv_draw_blend.h - * - */ - -#ifndef LV_DRAW_BLEND_H -#define LV_DRAW_BLEND_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include "../misc/lv_color.h" -#include "../misc/lv_area.h" -#include "../misc/lv_style.h" -#include "lv_draw_mask.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Fill an area with a color in the display's draw buffer. - * @param clip_area the current clip area (absolute coordinate) - * @param fill_area the area to fill (absolute coordinate) - * @param color the fill color - * @param mask an alpha mask to apply on `fill_area` or `NULL` to simply fill. (Interpreted on the fill area) - * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), - * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), - * LV_MASK_RES_CHANGED: the mask has mixed values - * @param opa overall opacity - * @param mode blend mode from `lv_blend_mode_t` - */ -void lv_draw_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, lv_color_t color, - lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode); - -/** - * Copy a source buffer to the display's draw buffer. - * @param clip_area clip the result to this area (absolute coordinates) - * @param src_area coordinates of the source buffer (absolute coordinates) - * @param src_buf the source buffer - * @param mask an alpha mask to apply on `clip_area` or `NULL` to simply fill. (Interpreted on the clip area) - * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), - * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), - * LV_MASK_RES_CHANGED: the mask has mixed values - * @param opa overall opacity in 0x00..0xff range - * @param mode blend mode from `lv_blend_mode_t` - */ -void lv_draw_blend_map(const lv_area_t * clip_area, const lv_area_t * src_area, - const lv_color_t * src_buf, - lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode); - -/********************** - * MACROS - **********************/ - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*LV_DRAW_BLEND_H*/ diff --git a/src/draw/lv_draw_img.c b/src/draw/lv_draw_img.c index 2c30e736b..f7496d329 100644 --- a/src/draw/lv_draw_img.c +++ b/src/draw/lv_draw_img.c @@ -25,11 +25,10 @@ /********************** * STATIC PROTOTYPES **********************/ -LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area, - const void * src, - const lv_draw_img_dsc_t * draw_dsc); +LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src); -static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg); +static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg); static void draw_cleanup(_lv_img_cache_entry_t * cache); /********************** @@ -60,29 +59,27 @@ void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc) * @param src pointer to a lv_color_t array which contains the pixels of the image * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable */ -void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_draw_img_dsc_t * dsc) +void lv_draw_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const lv_area_t * coords, const void * src) { if(src == NULL) { LV_LOG_WARN("Image draw: src is NULL"); - show_error(coords, mask, "No\ndata"); + show_error(draw_ctx, coords, "No\ndata"); return; } if(dsc->opa <= LV_OPA_MIN) return; - const lv_draw_backend_t * backend = lv_draw_backend_get(); - lv_res_t res; - if(backend->draw_img_core) { - res = backend->draw_img_core(coords, mask, src, dsc); + if(draw_ctx->draw_img) { + res = draw_ctx->draw_img(draw_ctx, dsc, coords, src); } else { - res = lv_img_draw_core(coords, mask, src, dsc); + res = decode_and_draw(draw_ctx, dsc, coords, src); } if(res == LV_RES_INV) { LV_LOG_WARN("Image draw error"); - show_error(coords, mask, "No\ndata"); + show_error(draw_ctx, coords, "No\ndata"); return; } } @@ -222,13 +219,20 @@ lv_img_src_t lv_img_src_get_type(const void * src) return img_src_type; } +void lv_draw_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format) +{ + if(draw_ctx->draw_img_decoded == NULL) return; + + draw_ctx->draw_img_decoded(draw_ctx, dsc, coords, map_p, color_format); +} + /********************** * STATIC FUNCTIONS **********************/ -LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area, - const void * src, - const lv_draw_img_dsc_t * draw_dsc) +LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src) { if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK; @@ -237,14 +241,15 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, if(cdsc == NULL) return LV_RES_INV; - const lv_draw_backend_t * backend = lv_draw_backend_get(); - bool chroma_keyed = lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf); - bool alpha_byte = lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf); + lv_img_cf_t cf; + if(lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; + else if(lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; + else cf = LV_IMG_CF_TRUE_COLOR; if(cdsc->dec_dsc.error_msg != NULL) { LV_LOG_WARN("Image draw error"); - show_error(coords, clip_area, cdsc->dec_dsc.error_msg); + show_error(draw_ctx, coords, cdsc->dec_dsc.error_msg); } /*The decoder could open the image and gave the entire uncompressed image. *Just draw it!*/ @@ -263,22 +268,25 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, map_area_rot.y2 += coords->y1; } - lv_area_t mask_com; /*Common area of mask and coords*/ + lv_area_t clip_com; /*Common area of mask and coords*/ bool union_ok; - union_ok = _lv_area_intersect(&mask_com, clip_area, &map_area_rot); + union_ok = _lv_area_intersect(&clip_com, draw_ctx->clip_area, &map_area_rot); /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { draw_cleanup(cdsc); return LV_RES_OK; } - backend->draw_img(coords, &mask_com, cdsc->dec_dsc.img_data, draw_dsc, chroma_keyed, alpha_byte); + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_com; + lv_draw_img_decoded(draw_ctx, draw_dsc, coords, cdsc->dec_dsc.img_data, cf); + draw_ctx->clip_area = clip_area_ori; } /*The whole uncompressed image is not available. Try to read it line-by-line*/ else { lv_area_t mask_com; /*Common area of mask and coords*/ bool union_ok; - union_ok = _lv_area_intersect(&mask_com, clip_area, coords); + union_ok = _lv_area_intersect(&mask_com, draw_ctx->clip_area, coords); /*Out of mask. There is nothing to draw so the image is drawn successfully.*/ if(union_ok == false) { draw_cleanup(cdsc); @@ -299,7 +307,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, lv_res_t read_res; for(row = mask_com.y1; row <= mask_com.y2; row++) { lv_area_t mask_line; - union_ok = _lv_area_intersect(&mask_line, clip_area, &line); + union_ok = _lv_area_intersect(&mask_line, draw_ctx->clip_area, &line); if(union_ok == false) continue; read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf); @@ -311,7 +319,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, return LV_RES_INV; } - backend->draw_img(&line, &mask_line, buf, draw_dsc, chroma_keyed, alpha_byte); + lv_draw_img_decoded(draw_ctx, draw_dsc, &line, buf, cf); line.y1++; line.y2++; y++; @@ -324,16 +332,16 @@ LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, } -static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg) +static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg) { lv_draw_rect_dsc_t rect_dsc; lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_color = lv_color_white(); - lv_draw_rect(coords, clip_area, &rect_dsc); + lv_draw_rect(draw_ctx, &rect_dsc, coords); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); - lv_draw_label(coords, clip_area, &label_dsc, msg, NULL); + lv_draw_label(draw_ctx, &label_dsc, coords, msg, NULL); } static void draw_cleanup(_lv_img_cache_entry_t * cache) diff --git a/src/draw/lv_draw_img.h b/src/draw/lv_draw_img.h index 883e2be7b..504bedae4 100644 --- a/src/draw/lv_draw_img.h +++ b/src/draw/lv_draw_img.h @@ -45,6 +45,8 @@ typedef struct { uint8_t antialias : 1; } lv_draw_img_dsc_t; +struct _lv_draw_ctx_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -57,7 +59,12 @@ void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc); * @param src pointer to a lv_color_t array which contains the pixels of the image * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable */ -void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_draw_img_dsc_t * dsc); +void lv_draw_img(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const lv_area_t * coords, + const void * src); + + +void lv_draw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); /** * Get the type of an image source diff --git a/src/draw/lv_draw_label.c b/src/draw/lv_draw_label.c index a7cb4ef8e..942c609f5 100644 --- a/src/draw/lv_draw_label.c +++ b/src/draw/lv_draw_label.c @@ -74,12 +74,22 @@ void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc) * @param hint pointer to a `lv_draw_label_hint_t` variable. * It is managed by the draw to speed up the drawing of very long texts (thousands of lines). */ -LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, - const lv_draw_label_dsc_t * dsc, - const char * txt, - lv_draw_label_hint_t * hint) +LV_ATTRIBUTE_FAST_MEM void lv_draw_label(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, + const lv_area_t * coords, const char * txt, lv_draw_label_hint_t * hint) { if(dsc->opa <= LV_OPA_MIN) return; + if(dsc->font == NULL) { + LV_LOG_WARN("dsc->font == NULL"); + return; + } + + if(draw_ctx->draw_letter == NULL) { + LV_LOG_WARN("draw->draw_letter == NULL (there is no function to draw letters)"); + return; + } + + lv_draw_label_dsc_t dsc_mod = *dsc; + const lv_font_t * font = dsc->font; int32_t w; @@ -88,7 +98,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area return; lv_area_t clipped_area; - bool clip_ok = _lv_area_intersect(&clipped_area, coords, mask); + bool clip_ok = _lv_area_intersect(&clipped_area, coords, draw_ctx->clip_area); if(!clip_ok) return; lv_text_align_t align = dsc->align; @@ -144,7 +154,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area uint32_t line_end = line_start + _lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, NULL, dsc->flag); /*Go the first visible line*/ - while(pos.y + line_height_font < mask->y1) { + while(pos.y + line_height_font < draw_ctx->clip_area->y1) { /*Go to next line*/ line_start = line_end; line_end += _lv_txt_get_next_line(&txt[line_start], font, dsc->letter_space, w, NULL, dsc->flag); @@ -172,9 +182,6 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area line_width = lv_txt_get_width(&txt[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += lv_area_get_width(coords) - line_width; } - - lv_opa_t opa = dsc->opa; - uint32_t sel_start = dsc->sel_start; uint32_t sel_end = dsc->sel_end; if(sel_start > sel_end) { @@ -196,6 +203,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area uint32_t i; uint32_t par_start = 0; lv_color_t recolor; + lv_color_t color = lv_color_black(); int32_t letter_w; lv_draw_rect_dsc_t draw_dsc_sel; @@ -272,7 +280,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area } } - lv_color_t color = dsc->color; + color = dsc->color; if(cmd_state == CMD_STATE_IN) color = recolor; @@ -285,12 +293,13 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area sel_coords.y1 = pos.y; sel_coords.x2 = pos.x + letter_w + dsc->letter_space - 1; sel_coords.y2 = pos.y + line_height - 1; - lv_draw_rect(&sel_coords, mask, &draw_dsc_sel); + lv_draw_rect(draw_ctx, &draw_dsc_sel, &sel_coords); color = dsc->sel_color; } } - lv_draw_letter(&pos, mask, font, letter, color, opa, dsc->blend_mode); + dsc_mod.color = color; + lv_draw_letter(draw_ctx, &dsc_mod, &pos, letter); if(letter_w > 0) { pos.x += letter_w + dsc->letter_space; @@ -304,7 +313,8 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area p1.y = pos.y + (dsc->font->line_height / 2) + line_dsc.width / 2; p2.x = pos.x; p2.y = p1.y; - lv_draw_line(&p1, &p2, mask, &line_dsc); + line_dsc.color = color; + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) { @@ -314,7 +324,8 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area p1.y = pos.y + dsc->font->line_height - dsc->font->base_line - font->underline_position; p2.x = pos.x; p2.y = p1.y; - lv_draw_line(&p1, &p2, mask, &line_dsc); + line_dsc.color = color; + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } #if LV_USE_BIDI @@ -344,22 +355,19 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area /*Go the next line position*/ pos.y += line_height; - if(pos.y > mask->y2) return; + if(pos.y > draw_ctx->clip_area->y2) return; } LV_ASSERT_MEM_INTEGRITY(); } -void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, - uint32_t letter, - lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) +void lv_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter) { - - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_letter(pos_p, clip_area, font_p, letter, color, opa, blend_mode); + draw_ctx->draw_letter(draw_ctx, dsc, pos_p, letter); } + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/draw/lv_draw_label.h b/src/draw/lv_draw_label.h index 6556d22ed..de72eddf3 100644 --- a/src/draw/lv_draw_label.h +++ b/src/draw/lv_draw_label.h @@ -63,6 +63,7 @@ typedef struct _lv_draw_label_hint_t { int32_t coord_y; } lv_draw_label_hint_t; +struct _lv_draw_ctx_t; /********************** * GLOBAL PROTOTYPES **********************/ @@ -78,14 +79,12 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc); * @param hint pointer to a `lv_draw_label_hint_t` variable. * It is managed by the draw to speed up the drawing of very long texts (thousands of lines). */ -LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, - const lv_draw_label_dsc_t * dsc, - const char * txt, lv_draw_label_hint_t * hint); +LV_ATTRIBUTE_FAST_MEM void lv_draw_label(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, + const lv_area_t * coords, const char * txt, lv_draw_label_hint_t * hint); + +void lv_draw_letter(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); -void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, - uint32_t letter, - lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); /*********************** * GLOBAL VARIABLES ***********************/ diff --git a/src/draw/lv_draw_line.c b/src/draw/lv_draw_line.c index f0ace451b..b4844dbd1 100644 --- a/src/draw/lv_draw_line.c +++ b/src/draw/lv_draw_line.c @@ -42,14 +42,13 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc) dsc->color = lv_color_black(); } -LV_ATTRIBUTE_FAST_MEM void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM void lv_draw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2) { if(dsc->width == 0) return; if(dsc->opa <= LV_OPA_MIN) return; - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_line(point1, point2, clip, dsc); + draw_ctx->draw_line(draw_ctx, dsc, point1, point2); } /********************** diff --git a/src/draw/lv_draw_line.h b/src/draw/lv_draw_line.h index 18b4769e1..d82ea51bd 100644 --- a/src/draw/lv_draw_line.h +++ b/src/draw/lv_draw_line.h @@ -37,6 +37,8 @@ typedef struct { uint8_t raw_end : 1; /*Do not bother with perpendicular line ending if it's not visible for any reason*/ } lv_draw_line_dsc_t; +struct _lv_draw_ctx_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -50,8 +52,8 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc); * @param clip the line will be drawn only in this area * @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable */ -LV_ATTRIBUTE_FAST_MEM void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); +void lv_draw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); /********************** diff --git a/src/draw/sw/lv_draw_sw_mask.c b/src/draw/lv_draw_mask.c similarity index 99% rename from src/draw/sw/lv_draw_sw_mask.c rename to src/draw/lv_draw_mask.c index 3e2c6cd6f..587913628 100644 --- a/src/draw/sw/lv_draw_sw_mask.c +++ b/src/draw/lv_draw_mask.c @@ -6,12 +6,12 @@ /********************* * INCLUDES *********************/ -#include "lv_draw_sw.h" +#include "lv_draw.h" #if LV_DRAW_COMPLEX -#include "../../misc/lv_math.h" -#include "../../misc/lv_log.h" -#include "../../misc/lv_assert.h" -#include "../../misc/lv_gc.h" +#include "../misc/lv_math.h" +#include "../misc/lv_log.h" +#include "../misc/lv_assert.h" +#include "../misc/lv_gc.h" /********************* * DEFINES diff --git a/src/draw/lv_draw_rect.c b/src/draw/lv_draw_rect.c index b6153c50b..8d5d06a9d 100644 --- a/src/draw/lv_draw_rect.c +++ b/src/draw/lv_draw_rect.c @@ -57,13 +57,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc) * @param mask the rectangle will be drawn only in this mask * @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable */ -void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +void lv_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return; - - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_rect(coords, clip, dsc); + draw_ctx->draw_rect(draw_ctx, dsc, coords); LV_ASSERT_MEM_INTEGRITY(); } diff --git a/src/draw/lv_draw_rect.h b/src/draw/lv_draw_rect.h index c6b1412e5..87522876d 100644 --- a/src/draw/lv_draw_rect.h +++ b/src/draw/lv_draw_rect.h @@ -70,6 +70,8 @@ typedef struct { lv_opa_t shadow_opa; } lv_draw_rect_dsc_t; +struct _lv_draw_ctx_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -83,7 +85,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc); * @param clip the rectangle will be drawn only in this area * @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable */ -void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); +void lv_draw_rect(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); /********************** * MACROS diff --git a/src/draw/lv_draw_triangle.c b/src/draw/lv_draw_triangle.c index 7a2d816a4..42b4d7799 100644 --- a/src/draw/lv_draw_triangle.c +++ b/src/draw/lv_draw_triangle.c @@ -35,27 +35,16 @@ * GLOBAL FUNCTIONS **********************/ -/** - * Draw a polygon. Only convex polygons are supported - * @param points an array of points - * @param point_cnt number of points - * @param clip_area polygon will be drawn only in this area - * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable - */ -void lv_draw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * draw_dsc) +void lv_draw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t points[], + uint16_t point_cnt) { - - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_polygon(points, point_cnt, clip_area, draw_dsc); + draw_ctx->draw_polygon(draw_ctx, draw_dsc, points, point_cnt); } -void lv_draw_triangle(const lv_point_t points[], const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * draw_dsc) +void lv_draw_triangle(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t points[]) { - const lv_draw_backend_t * backend = lv_draw_backend_get(); - backend->draw_polygon(points, 3, clip_area, draw_dsc); + draw_ctx->draw_polygon(draw_ctx, draw_dsc, points, 3); } /********************** diff --git a/src/draw/lv_draw_triangle.h b/src/draw/lv_draw_triangle.h index 5a16585a1..e8d857502 100644 --- a/src/draw/lv_draw_triangle.h +++ b/src/draw/lv_draw_triangle.h @@ -27,24 +27,10 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -/** - * Draw a triangle - * @param points pointer to an array with 3 points - * @param clip_area the triangle will be drawn only in this area - * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable - */ -void lv_draw_triangle(const lv_point_t points[], const lv_area_t * clip, const lv_draw_rect_dsc_t * draw_dsc); - -/** - * Draw a polygon. Only convex polygons are supported. - * @param points an array of points - * @param point_cnt number of points - * @param clip_area polygon will be drawn only in this area - * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable - */ -void lv_draw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * mask, - const lv_draw_rect_dsc_t * draw_dsc); +void lv_draw_polygon(struct _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_triangle(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t points[]); /********************** * MACROS **********************/ diff --git a/src/gpu/lv_gpu_nxp_pxp.c b/src/draw/nxp_pxp/lv_gpu_nxp_pxp.c similarity index 99% rename from src/gpu/lv_gpu_nxp_pxp.c rename to src/draw/nxp_pxp/lv_gpu_nxp_pxp.c index 1b669d861..a6fb49b7b 100644 --- a/src/gpu/lv_gpu_nxp_pxp.c +++ b/src/draw/nxp_pxp/lv_gpu_nxp_pxp.c @@ -31,12 +31,10 @@ * INCLUDES *********************/ -#include "../lv_conf_internal.h" +#include "lv_gpu_nxp_pxp.h" #if LV_USE_GPU_NXP_PXP -#include "lvgl.h" -#include "lv_gpu_nxp_pxp.h" #include "../misc/lv_mem.h" #include "../misc/lv_log.h" diff --git a/src/gpu/lv_gpu_nxp_pxp.h b/src/draw/nxp_pxp/lv_gpu_nxp_pxp.h similarity index 98% rename from src/gpu/lv_gpu_nxp_pxp.h rename to src/draw/nxp_pxp/lv_gpu_nxp_pxp.h index 9aba7c27d..8d812882c 100644 --- a/src/gpu/lv_gpu_nxp_pxp.h +++ b/src/draw/nxp_pxp/lv_gpu_nxp_pxp.h @@ -38,6 +38,10 @@ extern "C" { * INCLUDES *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP + #include "../misc/lv_area.h" #include "../misc/lv_color.h" @@ -180,6 +184,8 @@ void lv_gpu_nxp_pxp_disable_recolor(void); * STATIC FUNCTIONS **********************/ +#endif /*LV_USE_GPU_NXP_PXP*/ + #ifdef __cplusplus } /*extern "C"*/ #endif diff --git a/src/gpu/lv_gpu_nxp_pxp_osa.c b/src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.c similarity index 99% rename from src/gpu/lv_gpu_nxp_pxp_osa.c rename to src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.c index d247f2b74..1203434c7 100644 --- a/src/gpu/lv_gpu_nxp_pxp_osa.c +++ b/src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.c @@ -31,10 +31,10 @@ * INCLUDES *********************/ -#include "../lv_conf_internal.h" +#include "lv_gpu_nxp_pxp_osa.h" +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT #include "../misc/lv_log.h" -#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT #include "lv_gpu_nxp_pxp.h" #include "fsl_pxp.h" diff --git a/src/gpu/lv_gpu_nxp_pxp_osa.h b/src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.h similarity index 97% rename from src/gpu/lv_gpu_nxp_pxp_osa.h rename to src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.h index ab30b8d06..89524dae5 100644 --- a/src/gpu/lv_gpu_nxp_pxp_osa.h +++ b/src/draw/nxp_pxp/lv_gpu_nxp_pxp_osa.h @@ -34,7 +34,7 @@ extern "C" { #endif -#include "../lv_conf_internal.h" +#include "../../lv_conf_internal.h" #if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT extern lv_nxp_pxp_cfg_t pxp_default_cfg; diff --git a/src/gpu/lv_gpu_nxp_vglite.c b/src/draw/nxp_vglite/lv_gpu_nxp_vglite.c similarity index 99% rename from src/gpu/lv_gpu_nxp_vglite.c rename to src/draw/nxp_vglite/lv_gpu_nxp_vglite.c index 8e6ee193d..43dd88179 100644 --- a/src/gpu/lv_gpu_nxp_vglite.c +++ b/src/draw/nxp_vglite/lv_gpu_nxp_vglite.c @@ -31,12 +31,11 @@ * INCLUDES *********************/ -#include "../lv_conf_internal.h" +#include "lv_gpu_nxp_vglite.h" #if LV_USE_GPU_NXP_VG_LITE #include "lvgl.h" -#include "lv_gpu_nxp_vglite.h" #include "../misc/lv_log.h" #include "fsl_cache.h" #include "vg_lite.h" diff --git a/src/gpu/lv_gpu_nxp_vglite.h b/src/draw/nxp_vglite/lv_gpu_nxp_vglite.h similarity index 98% rename from src/gpu/lv_gpu_nxp_vglite.h rename to src/draw/nxp_vglite/lv_gpu_nxp_vglite.h index 31416598e..26f4c3fe4 100644 --- a/src/gpu/lv_gpu_nxp_vglite.h +++ b/src/draw/nxp_vglite/lv_gpu_nxp_vglite.h @@ -37,7 +37,9 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "misc/lv_area.h" +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE /********************* * DEFINES @@ -134,6 +136,8 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv */ lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit); +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + #ifdef __cplusplus } /*extern "C"*/ #endif diff --git a/src/draw/sdl/lv_draw_sdl.c b/src/draw/sdl/lv_draw_sdl.c new file mode 100644 index 000000000..9edd398c1 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl.c @@ -0,0 +1,95 @@ +/** + * @file lv_draw_sdl.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" + +/********************* + * DEFINES + *********************/ +void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src); + +void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); + +void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + +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_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +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; + 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); +} + +void lv_draw_sdl_deinit_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sdl_ctx_t * draw_ctx_sdl = (lv_draw_sdl_ctx_t *) draw_ctx; + lv_draw_sdl_texture_cache_deinit(draw_ctx_sdl); + lv_mem_free(draw_ctx_sdl->internals); + _lv_draw_sdl_utils_deinit(); +} + +SDL_Texture * lv_draw_sdl_create_screen_texture(SDL_Renderer * renderer, lv_coord_t hor, lv_coord_t ver) +{ + SDL_Texture * texture = SDL_CreateTexture(renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, hor, ver); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + return texture; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl.h b/src/draw/sdl/lv_draw_sdl.h new file mode 100644 index 000000000..0de6ebc1e --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl.h @@ -0,0 +1,94 @@ +/** + * @file lv_draw_sdl.h + * + */ + +#ifndef LV_DRAW_SDL_H +#define LV_DRAW_SDL_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_ARGB8888 +#else +#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_RGBA8888 +#endif + +/********************** + * TYPEDEFS + **********************/ + +struct lv_draw_sdl_context_internals_t; + +typedef struct { + /** + * Render for display driver + */ + SDL_Renderer * renderer; +} lv_draw_sdl_drv_param_t; + +typedef struct { + lv_draw_sw_ctx_t base_draw; + SDL_Renderer * renderer; + struct lv_draw_sdl_context_internals_t * internals; +} lv_draw_sdl_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + +/** + * @brief Free caches + * + */ +void lv_draw_sdl_deinit_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + +SDL_Texture * lv_draw_sdl_create_screen_texture(SDL_Renderer * renderer, lv_coord_t hor, lv_coord_t ver); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_H*/ diff --git a/src/draw/sdl/lv_draw_sdl.mk b/src/draw/sdl/lv_draw_sdl.mk index b5bbeb0eb..2fb69f00f 100644 --- a/src/draw/sdl/lv_draw_sdl.mk +++ b/src/draw/sdl/lv_draw_sdl.mk @@ -1,9 +1,11 @@ +CSRCS += lv_draw_sdl.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_rect.c -CSRCS += lv_draw_sdl_lru.c +CSRCS += lv_draw_sdl_line.c CSRCS += lv_draw_sdl_mask.c +CSRCS += lv_draw_sdl_rect.c CSRCS += lv_draw_sdl_stack_blur.c CSRCS += lv_draw_sdl_texture_cache.c CSRCS += lv_draw_sdl_utils.c diff --git a/src/draw/sdl/lv_draw_sdl_arc.c b/src/draw/sdl/lv_draw_sdl_arc.c new file mode 100644 index 000000000..4853b5cd1 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_arc.c @@ -0,0 +1,264 @@ +/** + * @file lv_templ.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" +#include "lv_draw_sdl_mask.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * 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 + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * 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); + +static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center, + lv_area_t * out); + +/********************** + * GLOBAL FUNCTIONS + **********************/ +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) +{ + 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; + area_out.y1 = center->y - radius; + area_out.x2 = center->x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/ + area_out.y2 = center->y + radius - 1; + + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, &area_out, draw_ctx->clip_area)) { + return; + } + + lv_area_t area_in; + lv_area_copy(&area_in, &area_out); + area_in.x1 += dsc->width; + area_in.y1 += dsc->width; + area_in.x2 -= dsc->width; + area_in.y2 -= dsc->width; + + + while(start_angle >= 360) start_angle -= 360; + while(end_angle >= 360) end_angle -= 360; + + int16_t mask_ids[3] = {LV_MASK_ID_INV, LV_MASK_ID_INV, LV_MASK_ID_INV}, mask_ids_count = 1; + int16_t cap_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV}; + + lv_draw_mask_radius_param_t mask_out_param; + lv_draw_mask_radius_init(&mask_out_param, &area_out, LV_RADIUS_CIRCLE, false); + mask_ids[0] = lv_draw_mask_add(&mask_out_param, NULL); + + lv_draw_mask_radius_param_t mask_in_param; + if(lv_area_get_width(&area_in) > 0 && lv_area_get_height(&area_in) > 0) { + lv_draw_mask_radius_init(&mask_in_param, &area_in, LV_RADIUS_CIRCLE, true); + mask_ids[1] = lv_draw_mask_add(&mask_in_param, NULL); + mask_ids_count++; + } + + lv_draw_mask_angle_param_t mask_angle_param; + if((start_angle - end_angle) % 360) { + lv_draw_mask_angle_init(&mask_angle_param, center->x, center->y, start_angle, end_angle); + mask_ids[2] = lv_draw_mask_add(&mask_angle_param, NULL); + mask_ids_count++; + } + + lv_draw_mask_radius_param_t cap_start_param, cap_end_param; + if(mask_ids_count == 3 && dsc->rounded) { + lv_area_t start_area, end_area; + get_cap_area((int16_t) start_angle, dsc->width, radius, center, &start_area); + get_cap_area((int16_t) end_angle, dsc->width, radius, center, &end_area); + lv_draw_mask_radius_init(&cap_start_param, &start_area, dsc->width / 2, false); + cap_ids[0] = lv_draw_mask_add(&cap_start_param, NULL); + lv_draw_mask_radius_init(&cap_end_param, &end_area, dsc->width / 2, false); + cap_ids[1] = lv_draw_mask_add(&cap_end_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, mask_ids, mask_ids_count, cap_ids[0] != LV_MASK_ID_INV ? cap_ids : NULL); + + lv_draw_mask_remove_id(mask_ids[0]); + lv_draw_mask_free_param(&mask_out_param); + + if(mask_ids_count > 1) { + lv_draw_mask_remove_id(mask_ids[1]); + lv_draw_mask_free_param(&mask_in_param); + } + + if(mask_ids_count > 2) { + lv_draw_mask_remove_id(mask_ids[2]); + lv_draw_mask_free_param(&mask_angle_param); + } + + if(cap_ids[0] != LV_MASK_ID_INV) { + lv_draw_mask_remove_id(cap_ids[0]); + lv_draw_mask_remove_id(cap_ids[1]); + lv_draw_mask_free_param(&cap_start_param); + lv_draw_mask_free_param(&cap_end_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(&dsc->color, &color); + SDL_SetTextureColorMod(texture, color.r, color.g, color.b); + SDL_SetTextureAlphaMod(texture, dsc->opa); + SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect); +} + +/********************** + * 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) +{ + 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_ids(line_buf, abs_x, abs_y, len, ids, ids_count); + 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; + } + } + if(caps) { + for(int i = 0; i < 2; i++) { + lv_memset_ff(line_buf, rect.w); + res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, &caps[i], 1); + if(res == LV_DRAW_MASK_RES_TRANSP) { + /* Ignore */ + } + 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]; + uint16_t old_opa = line_buf[x] + *pixel; + *pixel = LV_MIN(old_opa, 0xFF); + pixel[1] = pixel[2] = pixel[3] = 0xFF; + } + } + } + } + } + lv_mem_buf_release(line_buf); + SDL_UnlockTexture(texture); +} + +static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center, + lv_area_t * out) +{ + const uint8_t ps = 8; + const uint8_t pa = 127; + + int32_t thick_half = thickness / 2; + uint8_t thick_corr = (thickness & 0x01) ? 0 : 1; + + int32_t cir_x; + int32_t cir_y; + + cir_x = ((radius - thick_half) * lv_trigo_sin(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*/ + if(cir_x > 0) { + cir_x = (cir_x - pa) >> ps; + out->x1 = cir_x - thick_half + thick_corr; + out->x2 = cir_x + thick_half; + } + else { + cir_x = (cir_x + pa) >> ps; + out->x1 = cir_x - thick_half; + out->x2 = cir_x + thick_half - thick_corr; + } + + if(cir_y > 0) { + cir_y = (cir_y - pa) >> ps; + out->y1 = cir_y - thick_half + thick_corr; + out->y2 = cir_y + thick_half; + } + else { + cir_y = (cir_y + pa) >> ps; + out->y1 = cir_y - thick_half; + out->y2 = cir_y + thick_half - thick_corr; + } + lv_area_move(out, center->x, center->y); +} + +#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_blend.c b/src/draw/sdl/lv_draw_sdl_blend.c index 6599cc5ab..1f9683d18 100644 --- a/src/draw/sdl/lv_draw_sdl_blend.c +++ b/src/draw/sdl/lv_draw_sdl_blend.c @@ -11,10 +11,9 @@ #if LV_USE_GPU_SDL -#include "../../draw/lv_draw_blend.h" #include "lv_draw_sdl_texture_cache.h" #include "lv_draw_sdl_utils.h" -#include "lv_draw_sdl_mask.h" +#include "lv_draw_sdl_composite.h" #include LV_GPU_SDL_INCLUDE_PATH @@ -30,6 +29,9 @@ * 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 **********************/ @@ -42,85 +44,95 @@ * GLOBAL FUNCTIONS **********************/ -void lv_draw_sdl_draw_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode) +void lv_draw_sdl_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - LV_UNUSED(dest_buf); + 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; - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; + SDL_Renderer * renderer = draw_ctx->renderer; - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `fill_area`*/ - lv_area_t draw_area = *fill_area; - // if(!_lv_area_intersect(&draw_area, clip_area, fill_area)) return; + 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); - SDL_Rect draw_area_rect; - lv_area_to_sdl_rect(&draw_area, &draw_area_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); - if(mask) { - SDL_Surface * mask_surface = lv_sdl_create_mask_surface(mask, lv_area_get_width(&draw_area), - lv_area_get_height(&draw_area), - lv_area_get_width(&draw_area)); - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, mask_surface); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(texture, opa); SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue); - SDL_RenderSetClipRect(renderer, &draw_area_rect); - SDL_RenderCopy(renderer, texture, NULL, &draw_area_rect); - SDL_DestroyTexture(texture); - SDL_FreeSurface(mask_surface); + 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_RenderSetClipRect(renderer, &draw_area_rect); - SDL_RenderFillRect(renderer, &draw_area_rect); + SDL_RenderFillRect(renderer, &fill_rect); } } -void lv_draw_sdl_draw_blend_map(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode) +void blend_map(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - LV_UNUSED(dest_buf); + 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); - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; + SDL_Renderer * renderer = draw_ctx->renderer; SDL_Rect draw_area_rect; - lv_area_to_sdl_rect(clip_area, &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 *) src_buf, lv_area_get_width(src_area), - lv_area_get_height(src_area), LV_COLOR_DEPTH, - lv_area_get_width(src_area) * LV_COLOR_DEPTH / 8, - rmask, gmask, bmask, amask); - if(mask) { - SDL_Texture * masked = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - lv_area_get_width(src_area), lv_area_get_height(src_area)); - SDL_Texture * mask_texture = lv_sdl_create_mask_texture(renderer, mask, lv_area_get_width(src_area), - lv_area_get_height(src_area), - lv_area_get_width(src_area)); + 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_RenderSetClipRect(renderer, NULL); 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, ctx->texture); - SDL_RenderSetClipRect(renderer, &draw_area_rect); + 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); @@ -132,16 +144,11 @@ void lv_draw_sdl_draw_blend_map(lv_color_t * dest_buf, lv_coord_t dest_stride, c else { SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_SetTextureAlphaMod(texture, opa); - SDL_SetRenderTarget(renderer, ctx->texture); - SDL_RenderSetClipRect(renderer, &draw_area_rect); + SDL_SetRenderTarget(renderer, draw_ctx->base_draw.base_draw.buf); SDL_RenderCopy(renderer, texture, NULL, &draw_area_rect); SDL_DestroyTexture(texture); } SDL_FreeSurface(surface); } -/********************** - * STATIC FUNCTIONS - **********************/ - #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 new file mode 100644 index 000000000..022969e07 --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_composite.c @@ -0,0 +1,258 @@ +/** + * @file lv_draw_sdl_composite.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include "../../misc/lv_gc.h" +#include "../../core/lv_refr.h" +#include "lv_draw_sdl_composite.h" +#include "lv_draw_sdl_mask.h" +#include "lv_draw_sdl_utils.h" +#include "lv_draw_sdl_priv.h" +#include "lv_draw_sdl_texture_cache.h" + +/********************* + * DEFINES + *********************/ +#define HAS_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_draw_sdl_composite_texture_id_t type; +} composite_key_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type); + +static lv_coord_t next_pow_of_2(lv_coord_t num); + +static void dump_masks(SDL_Texture * texture, const lv_area_t * coords); +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in, + const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out, + lv_area_t * clip_out, lv_area_t * apply_area) +{ + lv_area_t full_coords = *coords_in; + + /* Normalize full_coords */ + if(full_coords.x1 > full_coords.x2) { + lv_coord_t x2 = full_coords.x2; + full_coords.x2 = full_coords.x1; + full_coords.x1 = x2; + } + if(full_coords.y1 > full_coords.y2) { + lv_coord_t y2 = full_coords.y2; + full_coords.y2 = full_coords.y1; + full_coords.y1 = y2; + } + + if(extension) { + full_coords.x1 -= extension->x1; + full_coords.x2 += extension->x2; + full_coords.y1 -= extension->y1; + full_coords.y2 += extension->y2; + } + + if(!_lv_area_intersect(apply_area, &full_coords, clip_in)) return false; + bool has_mask = lv_draw_mask_is_any(apply_area); + + const bool draw_mask = has_mask && HAS_CUSTOM_BLEND_MODE; + const bool draw_blend = blend_mode != LV_BLEND_MODE_NORMAL && blend_mode != LV_BLEND_MODE_REPLACE; + if(draw_mask || draw_blend) { + lv_draw_sdl_context_internals_t * internals = ctx->internals; + LV_ASSERT(internals->mask == NULL && internals->composition == NULL); + + lv_coord_t w = lv_area_get_width(apply_area), h = lv_area_get_height(apply_area); + internals->composition = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, w, h); + /* Don't need to worry about overflow */ + lv_coord_t ofs_x = (lv_coord_t) - apply_area->x1, ofs_y = (lv_coord_t) - apply_area->y1; + /* Offset draw area to start with (0,0) of coords */ + lv_area_move(coords_out, ofs_x, ofs_y); + lv_area_move(clip_out, ofs_x, ofs_y); + SDL_SetRenderTarget(ctx->renderer, internals->composition); + SDL_SetRenderDrawColor(ctx->renderer, 255, 255, 255, 0); + SDL_RenderClear(ctx->renderer); +#if HAS_CUSTOM_BLEND_MODE + internals->mask = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, w, h); + dump_masks(internals->mask, apply_area); +#endif + } + else if(has_mask) { + /* Fallback mask handling. This will at least make bars looks less bad */ + for(uint8_t i = 0; i < _LV_MASK_MAX_NUM; i++) { + _lv_draw_mask_common_dsc_t * comm_param = LV_GC_ROOT(_lv_draw_mask_list[i]).param; + if(comm_param == NULL) continue; + switch(comm_param->type) { + case LV_DRAW_MASK_TYPE_RADIUS: { + const lv_draw_mask_radius_param_t * param = (const lv_draw_mask_radius_param_t *) comm_param; + if(param->cfg.outer) break; + _lv_area_intersect(clip_out, apply_area, ¶m->cfg.rect); + break; + } + default: + break; + } + } + } + return has_mask; +} + +void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode) +{ + lv_draw_sdl_context_internals_t * internals = ctx->internals; + SDL_Rect src_rect = {0, 0, lv_area_get_width(apply_area), lv_area_get_height(apply_area)}; +#if HAS_CUSTOM_BLEND_MODE + if(internals->mask) { + SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, + SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, + SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD); + SDL_SetTextureBlendMode(internals->mask, mode); + SDL_RenderCopy(ctx->renderer, internals->mask, &src_rect, &src_rect); + } +#endif + + /* Shapes are drawn on composite layer when mask or blend mode is present */ + if(internals->composition) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(apply_area, &dst_rect); + + SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.base_draw.buf); + switch(blend_mode) { + case LV_BLEND_MODE_NORMAL: + case LV_BLEND_MODE_REPLACE: + SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); + break; + case LV_BLEND_MODE_ADDITIVE: + SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_ADD); + break; +#if HAS_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); + 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); + break; + } +#endif + default: + LV_LOG_WARN("Doesn't support blend mode %d", blend_mode); + SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); + /* Unsupported yet */ + break; + } + SDL_RenderCopy(ctx->renderer, internals->composition, &src_rect, &dst_rect); + } + + internals->mask = internals->composition = NULL; +} + +SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id, + lv_coord_t w, lv_coord_t h) +{ + lv_point_t * tex_size = NULL; + composite_key_t mask_key = mask_key_create(id); + SDL_Texture * result = lv_draw_sdl_texture_cache_get_with_userdata(ctx, &mask_key, sizeof(composite_key_t), NULL, + (void **) &tex_size); + if(!result || tex_size->x < w || tex_size->y < h) { + lv_coord_t size = next_pow_of_2(LV_MAX(w, h)); + int access = SDL_TEXTUREACCESS_STREAMING; + if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0) { + access = SDL_TEXTUREACCESS_TARGET; + } + result = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, access, size, size); + tex_size = lv_mem_alloc(sizeof(lv_point_t)); + tex_size->x = tex_size->y = size; + lv_draw_sdl_texture_cache_put_advanced(ctx, &mask_key, sizeof(composite_key_t), result, tex_size, lv_mem_free, 0); + } + return result; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type) +{ + composite_key_t key; + /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */ + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_MASK; + key.type = type; + return key; +} + +static lv_coord_t next_pow_of_2(lv_coord_t num) +{ + lv_coord_t n = 128; + while(n < num && n < 16384) { + n = n << 1; + } + return n; +} + +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++) { + const size_t idx = y * pitch + x * 4; + pixels[idx] = line_buf[x]; + pixels[idx + 1] = pixels[idx + 2] = pixels[idx + 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_composite.h b/src/draw/sdl/lv_draw_sdl_composite.h new file mode 100644 index 000000000..89c5a5c5a --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_composite.h @@ -0,0 +1,71 @@ +/** + * @file lv_draw_sdl_composite.h + * + */ + +#ifndef LV_DRAW_SDL_COMPOSITE_H +#define LV_DRAW_SDL_COMPOSITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../../lv_conf_internal.h" + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "lv_draw_sdl.h" +#include "../../misc/lv_area.h" +#include "../../misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +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_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Begin drawing with mask. Render target will be switched to a temporary texture, + * and drawing coordinates may get clipped or translated + * @param coords_in Original coordinates + * @param clip_in Original clip area + * @param extension Useful for shadows or outlines, can be NULL + * @param coords_out Translated coords + * @param clip_out Translated clip area + * @param apply_area Area of actual composited texture will be drawn + * @return true if there are any mask needs to be drawn, false otherwise + */ +bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in, + const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out, + lv_area_t * clip_out, lv_area_t * apply_area); + +void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode); + +SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id, + lv_coord_t w, lv_coord_t h); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_COMPOSITE_H*/ diff --git a/src/draw/sdl/lv_draw_sdl_img.c b/src/draw/sdl/lv_draw_sdl_img.c index 36fca5528..5a1519cdc 100644 --- a/src/draw/sdl/lv_draw_sdl_img.c +++ b/src/draw/sdl/lv_draw_sdl_img.c @@ -11,12 +11,12 @@ #if LV_USE_GPU_SDL -#include "../../draw/lv_draw_img.h" -#include "../../draw/lv_img_cache.h" -#include "../../draw/lv_draw_mask.h" +#include "../lv_draw_img.h" +#include "../lv_img_cache.h" +#include "../lv_draw_mask.h" +#include "../../misc/lv_lru.h" #include "lv_draw_sdl_utils.h" -#include "lv_draw_sdl_lru.h" #include "lv_draw_sdl_texture_cache.h" /********************* @@ -48,24 +48,29 @@ static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_draw_sdl_img_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_draw_img_dsc_t * draw_dsc) +lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src) { - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); + 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_img_cache_key_create(src, draw_dsc->frame_id, &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_gpu_draw_cache_get(key, key_size, &texture_found); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, key, key_size, &texture_found); 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; 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) { - texture = ((lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data)->texture; - tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED; + lv_draw_sdl_dec_dsc_userdata_t * ptr = (lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data; + texture = ptr->texture; + if(ptr->texture_managed) { + tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED; + } + ptr->texture_referenced = true; } else { texture = upload_img_texture(renderer, dsc); @@ -77,10 +82,10 @@ lv_res_t lv_draw_sdl_img_core(const lv_area_t * coords, const lv_area_t * mask, 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)); - lv_draw_sdl_draw_cache_put_advanced(key, key_size, texture, header, SDL_free, tex_flags); + lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_size, texture, header, SDL_free, tex_flags); } else { - lv_draw_sdl_draw_cache_put(key, key_size, NULL); + lv_draw_sdl_texture_cache_put(ctx, key, key_size, NULL); } } SDL_free(key); @@ -88,35 +93,39 @@ lv_res_t lv_draw_sdl_img_core(const lv_area_t * coords, const lv_area_t * mask, return LV_RES_INV; } - SDL_Rect mask_rect, coords_rect; - lv_area_to_sdl_rect(mask, &mask_rect); + 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); SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y}; - SDL_SetTextureAlphaMod(texture, draw_dsc->opa); - SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_RenderSetClipRect(renderer, &mask_rect); + SDL_RenderSetClipRect(renderer, &clip_rect); SDL_Color recolor; lv_color_to_sdl_color(&draw_dsc->recolor, &recolor); - /*Draw original image if not fully recolored*/ - /*TODO: what if the image is translucent as well?*/ - if(draw_dsc->recolor_opa < LV_OPA_MAX) { - SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); - } - - SDL_SetTextureColorMod(texture, recolor.r, recolor.g, recolor.b); - if(draw_dsc->recolor_opa >= LV_OPA_MAX) { - /*Draw fully colored image*/ + 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, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE); } - else if(draw_dsc->recolor_opa >= LV_OPA_MIN) { - SDL_SetTextureAlphaMod(texture, draw_dsc->recolor_opa); + 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_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); } + 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_RenderSetClipRect(renderer, NULL); return LV_RES_OK; } diff --git a/src/draw/sdl/lv_draw_sdl_label.c b/src/draw/sdl/lv_draw_sdl_label.c index 216dfd837..f6129f96b 100644 --- a/src/draw/sdl/lv_draw_sdl_label.c +++ b/src/draw/sdl/lv_draw_sdl_label.c @@ -11,15 +11,14 @@ #if LV_USE_GPU_SDL -#include "../../draw/lv_draw_label.h" -#include "../../draw/lv_draw_mask.h" -#include "../../misc/lv_utils.h" - #include LV_GPU_SDL_INCLUDE_PATH +#include "../lv_draw_label.h" +#include "../../misc/lv_utils.h" + #include "lv_draw_sdl_utils.h" #include "lv_draw_sdl_texture_cache.h" -#include "lv_draw_sdl_mask.h" +#include "lv_draw_sdl_composite.h" /********************* * DEFINES @@ -30,7 +29,7 @@ **********************/ typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; const lv_font_t * font_p; uint32_t letter; } lv_font_glyph_key_t; @@ -39,9 +38,6 @@ typedef struct { * STATIC PROTOTYPES **********************/ -static void draw_letter_masked(SDL_Renderer * renderer, SDL_Texture * atlas, SDL_Rect * src, SDL_Rect * dst, - SDL_Rect * clip, lv_color_t color, lv_opa_t opa); - static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter); @@ -57,10 +53,13 @@ static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint3 * GLOBAL FUNCTIONS **********************/ -void lv_draw_sdl_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa, - lv_blend_mode_t blend_mode) +void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter) { + const lv_area_t * clip_area = draw_ctx->clip_area; + const lv_font_t * font_p = dsc->font; + lv_opa_t opa = dsc->opa; + lv_color_t color = dsc->color; if(opa < LV_OPA_MIN) return; if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; @@ -88,20 +87,20 @@ void lv_draw_sdl_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_ar int32_t pos_x = pos_p->x + g.ofs_x; int32_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y; + const lv_area_t letter_area = {pos_x, pos_y, pos_x + g.box_w - 1, pos_y + g.box_h - 1}; + lv_area_t draw_area; + /*If the letter is completely out of mask don't draw it*/ - if(pos_x + g.box_w < clip_area->x1 || - pos_x > clip_area->x2 || - pos_y + g.box_h < clip_area->y1 || - pos_y > clip_area->y2) { + if(!_lv_area_intersect(&draw_area, &letter_area, clip_area)) { return; } - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); + lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; SDL_Renderer * renderer = ctx->renderer; lv_font_glyph_key_t glyph_key = font_key_glyph_create(font_p, letter); bool glyph_found = false; - SDL_Texture * texture = lv_gpu_draw_cache_get(&glyph_key, sizeof(glyph_key), &glyph_found); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &glyph_key, sizeof(glyph_key), &glyph_found); if(!glyph_found) { if(g.resolved_font) { font_p = g.resolved_font; @@ -109,79 +108,42 @@ void lv_draw_sdl_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_ar const uint8_t * bmp = lv_font_get_glyph_bitmap(font_p, letter); uint8_t * buf = lv_mem_alloc(g.box_w * g.box_h); lv_sdl_to_8bpp(buf, bmp, g.box_w, g.box_h, g.box_w, g.bpp); - SDL_Surface * mask = lv_sdl_create_mask_surface(buf, g.box_w, g.box_h, g.box_w); + SDL_Surface * mask = lv_sdl_create_opa_surface(buf, g.box_w, g.box_h, g.box_w); texture = SDL_CreateTextureFromSurface(renderer, mask); SDL_FreeSurface(mask); lv_mem_free(buf); - lv_draw_sdl_draw_cache_put(&glyph_key, sizeof(glyph_key), texture); + lv_draw_sdl_texture_cache_put(ctx, &glyph_key, sizeof(glyph_key), texture); } if(!texture) { return; } - lv_area_t dst = {pos_x, pos_y, pos_x + g.box_w - 1, pos_y + g.box_h - 1}; - SDL_Rect dstrect; - lv_area_to_sdl_rect(&dst, &dstrect); - SDL_Rect clip_area_rect; - lv_area_to_sdl_rect(clip_area, &clip_area_rect); + lv_area_t t_letter = letter_area, t_clip = *clip_area, apply_area; + bool has_mask = lv_draw_sdl_composite_begin(ctx, &letter_area, clip_area, NULL, dsc->blend_mode, &t_letter, &t_clip, + &apply_area); - if(lv_draw_mask_is_any(&dst)) { - draw_letter_masked(renderer, texture, NULL, &dstrect, &clip_area_rect, color, opa); + /*If the letter is completely out of mask don't draw it*/ + if(!_lv_area_intersect(&draw_area, &t_letter, &t_clip)) { return; } - + SDL_Rect srcrect, dstrect; + lv_area_to_sdl_rect(&draw_area, &dstrect); + srcrect.x = draw_area.x1 - t_letter.x1; + srcrect.y = draw_area.y1 - t_letter.y1; + srcrect.w = dstrect.w; + srcrect.h = dstrect.h; SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(texture, opa); SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue); - SDL_RenderSetClipRect(renderer, &clip_area_rect); - SDL_RenderCopy(renderer, texture, NULL, &dstrect); + SDL_RenderCopy(renderer, texture, &srcrect, &dstrect); + + lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode); } /********************** * STATIC FUNCTIONS **********************/ -static void draw_letter_masked(SDL_Renderer * renderer, SDL_Texture * atlas, SDL_Rect * src, SDL_Rect * dst, - SDL_Rect * clip, lv_color_t color, lv_opa_t opa) -{ - SDL_Texture * screen = SDL_GetRenderTarget(renderer); - - lv_area_t mask_area = {.x1 = dst->x, .x2 = dst->x + dst->w - 1, .y1 = dst->y, .y2 = dst->y + dst->h - 1}; - SDL_Texture * content = lv_gpu_temp_texture_obtain(renderer, dst->w, dst->h); - SDL_SetTextureBlendMode(content, SDL_BLENDMODE_NONE); - SDL_SetRenderTarget(renderer, content); - SDL_RenderSetClipRect(renderer, NULL); - - /* Replace texture with clip mask */ - SDL_Rect mask_rect = {.w = dst->w, .h = dst->h, .x = 0, .y = 0}; - SDL_Texture * mask = lv_sdl_gen_mask_texture(renderer, &mask_area, NULL, 0); - SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE); - SDL_RenderCopy(renderer, mask, NULL, &mask_rect); - - /* Multiply with font atlas */ - SDL_SetTextureAlphaMod(atlas, 0xFF); - SDL_SetTextureColorMod(atlas, 0xFF, 0xFF, 0xFF); -#if SDL_VERSION_ATLEAST(2, 0, 6) - SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, - SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, - SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD); - SDL_SetTextureBlendMode(atlas, mode); -#else - SDL_SetTextureBlendMode(atlas, SDL_BLENDMODE_BLEND); -#endif - SDL_RenderCopy(renderer, atlas, src, &mask_rect); - - /* Draw composited part on screen */ - SDL_SetTextureBlendMode(content, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(content, opa); - SDL_SetTextureColorMod(content, color.ch.red, color.ch.green, color.ch.blue); - - SDL_SetRenderTarget(renderer, screen); - SDL_RenderSetClipRect(renderer, clip); - SDL_RenderCopy(renderer, content, &mask_rect, dst); - SDL_DestroyTexture(mask); -} - static lv_font_glyph_key_t font_key_glyph_create(const lv_font_t * font_p, uint32_t letter) { lv_font_glyph_key_t key; diff --git a/src/draw/sdl/lv_draw_sdl_line.c b/src/draw/sdl/lv_draw_sdl_line.c new file mode 100644 index 000000000..bd24ff6fb --- /dev/null +++ b/src/draw/sdl/lv_draw_sdl_line.c @@ -0,0 +1,151 @@ +/** + * @file lv_templ.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" +#include "lv_draw_sdl_mask.h" + +/********************* + * DEFINES + *********************/ +#define ROUND_START 0x01 +#define ROUND_END 0x02 +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_coord_t length; + lv_coord_t width; + uint8_t round; +} lv_draw_line_key_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +static lv_draw_line_key_t line_key_create(const lv_draw_line_dsc_t * dsc, lv_coord_t length); + +static SDL_Texture * line_texture_create(lv_draw_sdl_ctx_t * sdl_ctx, const lv_draw_line_dsc_t * dsc, + lv_coord_t length); + +/********************** + * GLOBAL FUNCTIONS + **********************/ +void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2) +{ + lv_draw_sdl_ctx_t * sdl_ctx = (lv_draw_sdl_ctx_t *) draw_ctx; + SDL_Renderer * renderer = sdl_ctx->renderer; + lv_coord_t x1 = point1->x, x2 = point2->x, y1 = point1->y, y2 = point2->y; + double length = SDL_sqrt(SDL_pow(x2 - x1, 2) + SDL_pow(y2 - y1, 2)); + if(length - (long) length > 0.5) { + length = (long) length + 1; + } + + double angle = SDL_atan2(y2 - y1, x2 - x1) * 180 / M_PI; + lv_draw_line_key_t key = line_key_create(dsc, 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); + lv_draw_sdl_texture_cache_put(sdl_ctx, &key, sizeof(key), texture); + } + + lv_area_t coords = {x1, y1, x2, y2}; + const lv_area_t * clip = draw_ctx->clip_area; + + SDL_Rect coords_r, clip_r; + lv_area_to_sdl_rect(&coords, &coords_r); + lv_area_to_sdl_rect(clip, &clip_r); + + 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); + + 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}, + 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_RenderCopyEx(renderer, texture, &srcrect, &dstrect, angle, ¢er, 0); + SDL_RenderSetClipRect(renderer, NULL); + + lv_draw_sdl_composite_end(sdl_ctx, &apply_area, dsc->blend_mode); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_draw_line_key_t line_key_create(const lv_draw_line_dsc_t * dsc, lv_coord_t length) +{ + lv_draw_line_key_t key; + lv_memset_00(&key, sizeof(lv_draw_line_key_t)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_LINE; + key.length = length; + key.width = dsc->width; + key.round = (dsc->round_start ? ROUND_START : 0) | (dsc->round_end ? ROUND_END : 0); + return key; +} + +static SDL_Texture * line_texture_create(lv_draw_sdl_ctx_t * sdl_ctx, const lv_draw_line_dsc_t * dsc, lv_coord_t length) +{ + SDL_Texture * texture = SDL_CreateTexture(sdl_ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, + length + dsc->width + 2, dsc->width + 2); + SDL_Texture * target = SDL_GetRenderTarget(sdl_ctx->renderer); + SDL_SetRenderTarget(sdl_ctx->renderer, texture); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(sdl_ctx->renderer, 0xFF, 0xFF, 0xFF, 0x0); + SDL_RenderClear(sdl_ctx->renderer); + SDL_SetRenderDrawColor(sdl_ctx->renderer, 0xFF, 0xFF, 0xFF, 0xFF); + SDL_Rect line_rect = {1 + dsc->width / 2, 1, length, dsc->width}; + SDL_RenderFillRect(sdl_ctx->renderer, &line_rect); + if(dsc->round_start || dsc->round_end) { + lv_draw_mask_radius_param_t param; + lv_area_t round_area = {0, 0, dsc->width - 1, dsc->width - 1}; + lv_draw_mask_radius_init(¶m, &round_area, LV_RADIUS_CIRCLE, false); + + int16_t mask_id = lv_draw_mask_add(¶m, NULL); + SDL_Texture * round_texture = lv_draw_sdl_mask_dump_texture(sdl_ctx->renderer, &round_area, &mask_id, 1); + lv_draw_mask_remove_id(mask_id); + + SDL_Rect round_src = {0, 0, dsc->width, dsc->width}; + SDL_Rect round_dst = {line_rect.x - dsc->width / 2, 1, dsc->width, dsc->width}; + SDL_RenderCopy(sdl_ctx->renderer, round_texture, &round_src, &round_dst); + round_dst.x = line_rect.w + dsc->width / 2; + SDL_RenderCopy(sdl_ctx->renderer, round_texture, &round_src, &round_dst); + SDL_DestroyTexture(round_texture); + } + + SDL_SetRenderTarget(sdl_ctx->renderer, target); + return texture; +} + +#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_mask.c b/src/draw/sdl/lv_draw_sdl_mask.c index 8ef28d49e..f76266ad0 100644 --- a/src/draw/sdl/lv_draw_sdl_mask.c +++ b/src/draw/sdl/lv_draw_sdl_mask.c @@ -6,18 +6,18 @@ /********************* * INCLUDES *********************/ - #include "../../lv_conf_internal.h" #if LV_USE_GPU_SDL -#include "../../draw/lv_draw_mask.h" +#include "../../misc/lv_gc.h" #include "lv_draw_sdl_mask.h" #include "lv_draw_sdl_utils.h" /********************* * DEFINES *********************/ +#define HAS_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) /********************** * TYPEDEFS @@ -39,26 +39,7 @@ * GLOBAL FUNCTIONS **********************/ - -SDL_Surface * lv_sdl_create_mask_surface(lv_opa_t * pixels, lv_coord_t width, lv_coord_t height, lv_coord_t stride) -{ - SDL_Surface * indexed = SDL_CreateRGBSurfaceFrom(pixels, width, height, 8, stride, 0, 0, 0, 0); - SDL_SetSurfacePalette(indexed, lv_sdl_get_grayscale_palette(8)); - SDL_Surface * converted = SDL_ConvertSurfaceFormat(indexed, SDL_PIXELFORMAT_ARGB8888, 0); - SDL_FreeSurface(indexed); - return converted; -} - -SDL_Texture * lv_sdl_create_mask_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width, - lv_coord_t height, lv_coord_t stride) -{ - SDL_Surface * indexed = lv_sdl_create_mask_surface(pixels, width, height, stride); - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed); - SDL_FreeSurface(indexed); - return texture; -} - -lv_opa_t * lv_draw_mask_dump(const lv_area_t * coords, const int16_t * ids, int16_t ids_count) +lv_opa_t * lv_draw_sdl_mask_dump_opa(const lv_area_t * coords, const int16_t * ids, int16_t ids_count) { SDL_assert(coords->x2 >= coords->x1); SDL_assert(coords->y2 >= coords->y1); @@ -82,28 +63,20 @@ lv_opa_t * lv_draw_mask_dump(const lv_area_t * coords, const int16_t * ids, int1 return mask_buf; } -SDL_Surface * lv_sdl_apply_mask_surface(const lv_area_t * coords, const int16_t * ids, int16_t ids_count) +SDL_Texture * lv_draw_sdl_mask_dump_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, + int16_t ids_count) { lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords); - - lv_opa_t * mask_buf = lv_draw_mask_dump(coords, ids, ids_count); + lv_opa_t * mask_buf = lv_draw_sdl_mask_dump_opa(coords, ids, ids_count); + SDL_Surface * surface = lv_sdl_create_opa_surface(mask_buf, w, h, w); lv_mem_buf_release(mask_buf); - return lv_sdl_create_mask_surface(mask_buf, w, h, w); -} - -SDL_Texture * lv_sdl_gen_mask_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, - int16_t ids_count) -{ - SDL_Surface * indexed = lv_sdl_apply_mask_surface(coords, ids, ids_count); - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed); - SDL_FreeSurface(indexed); + SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_FreeSurface(surface); return texture; } - /********************** * STATIC FUNCTIONS **********************/ - #endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_mask.h b/src/draw/sdl/lv_draw_sdl_mask.h index bc9f42900..a562d73d7 100644 --- a/src/draw/sdl/lv_draw_sdl_mask.h +++ b/src/draw/sdl/lv_draw_sdl_mask.h @@ -18,6 +18,7 @@ extern "C" { #include LV_GPU_SDL_INCLUDE_PATH +#include "lv_draw_sdl.h" #include "../../misc/lv_area.h" #include "../../misc/lv_color.h" @@ -33,18 +34,11 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +lv_opa_t * lv_draw_sdl_mask_dump_opa(const lv_area_t * coords, const int16_t * ids, int16_t ids_count); -lv_opa_t * lv_draw_mask_dump(const lv_area_t * coords, const int16_t * ids, int16_t ids_count); +SDL_Texture * lv_draw_sdl_mask_dump_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, + int16_t ids_count); -SDL_Surface * lv_sdl_create_mask_surface(lv_opa_t * pixels, lv_coord_t width, lv_coord_t height, lv_coord_t stride); - -SDL_Texture * lv_sdl_create_mask_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width, - lv_coord_t height, lv_coord_t stride); - -SDL_Surface * lv_sdl_apply_mask_surface(const lv_area_t * coords, const int16_t * ids, int16_t ids_count); - -SDL_Texture * -lv_sdl_gen_mask_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, int16_t ids_count); /********************** * MACROS diff --git a/src/gpu/lv_gpu_sdl.h b/src/draw/sdl/lv_draw_sdl_priv.h similarity index 63% rename from src/gpu/lv_gpu_sdl.h rename to src/draw/sdl/lv_draw_sdl_priv.h index f83e4489a..1f44c22ac 100644 --- a/src/gpu/lv_gpu_sdl.h +++ b/src/draw/sdl/lv_draw_sdl_priv.h @@ -1,10 +1,10 @@ /** - * @file lv_gpu_sdl.h + * @file lv_draw_sdl_priv.h * */ -#ifndef LV_GPU_SDL_H -#define LV_GPU_SDL_H +#ifndef LV_DRAW_SDL_PRIV_H +#define LV_DRAW_SDL_PRIV_H #ifdef __cplusplus @@ -14,17 +14,14 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "../lv_conf_internal.h" +#include "../../lv_conf_internal.h" #if LV_USE_GPU_SDL -#if LV_USE_EXTERNAL_RENDERER == 0 -#error "SDL GPU requires LV_USE_EXTERNAL_RENDERER 1. Enable it in lv_conf.h" -#endif - #include LV_GPU_SDL_INCLUDE_PATH -#include "../draw/lv_draw.h" +#include "../lv_draw.h" +#include "../../misc/lv_lru.h" /********************* * DEFINES @@ -34,20 +31,16 @@ extern "C" { * TYPEDEFS **********************/ +typedef struct lv_draw_sdl_context_internals_t { + lv_lru_t * texture_cache; + SDL_Texture * mask; + SDL_Texture * composition; +} lv_draw_sdl_context_internals_t; + /********************** * GLOBAL PROTOTYPES **********************/ -void lv_gpu_sdl_init(); - -/** - * @brief Free caches - * - */ -void lv_gpu_sdl_deinit(); - -void lv_gpu_sdl_backend_init(lv_draw_backend_t * backend, SDL_Renderer * renderer, SDL_Texture * texture); - /*====================== * Add/remove functions *=====================*/ @@ -74,4 +67,4 @@ void lv_gpu_sdl_backend_init(lv_draw_backend_t * backend, SDL_Renderer * rendere } /*extern "C"*/ #endif -#endif /*LV_GPU_SDL_H*/ +#endif /*LV_DRAW_SDL_PRIV_H*/ diff --git a/src/draw/sdl/lv_draw_sdl_rect.c b/src/draw/sdl/lv_draw_sdl_rect.c index 0881e5a20..4ce217135 100644 --- a/src/draw/sdl/lv_draw_sdl_rect.c +++ b/src/draw/sdl/lv_draw_sdl_rect.c @@ -11,12 +11,14 @@ #if LV_USE_GPU_SDL -#include "../../draw/lv_draw_rect.h" -#include "../../draw/lv_draw_img.h" -#include "../../draw/lv_draw_label.h" -#include "../../draw/lv_draw_mask.h" +#include "../lv_draw_rect.h" +#include "../lv_draw_img.h" +#include "../lv_draw_label.h" +#include "../lv_draw_mask.h" +#include "../../core/lv_refr.h" #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" #include "lv_draw_sdl_stack_blur.h" @@ -29,67 +31,62 @@ **********************/ typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; lv_coord_t radius; lv_coord_t size; } lv_draw_rect_bg_key_t; typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; lv_coord_t radius; lv_coord_t size; lv_coord_t blur; } lv_draw_rect_shadow_key_t; typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; lv_coord_t rout, rin; - lv_coord_t thickness; - lv_coord_t size; - lv_border_side_t side; + lv_area_t offsets; } lv_draw_rect_border_key_t; /********************** * STATIC PROTOTYPES **********************/ -static void draw_bg_color(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc); +static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc); -static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, +static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); -static void draw_border(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc); - -static void draw_shadow(SDL_Renderer * renderer, const lv_area_t * coords, const lv_area_t * clip, +static void draw_border(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); -static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); +static void draw_shadow(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip, + const lv_draw_rect_dsc_t * dsc); -static void draw_border_generic(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout, - lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); +static void draw_outline(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip, + const lv_draw_rect_dsc_t * dsc); -static void draw_border_simple(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, - lv_opa_t opa); - -static void draw_rect_masked(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); - -static void draw_rect_masked_simple(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc); +static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, + 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 * 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 * coords, const lv_area_t * clipped, bool full); static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, - const lv_area_t * coords); + const lv_area_t * coords, const lv_area_t * clipped, bool full); static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size); static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur); -static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, lv_coord_t thickness, - lv_coord_t size, lv_border_side_t side); +static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area, + const lv_area_t * inner_area); /********************** * STATIC VARIABLES @@ -107,81 +104,113 @@ static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coor * GLOBAL FUNCTIONS **********************/ -void lv_draw_sdl_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { - lv_area_t draw_area; - bool has_draw_content = _lv_area_intersect(&draw_area, coords, clip); + const lv_area_t * clip = draw_ctx->clip_area; + lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; - if(lv_draw_mask_is_any(&draw_area)) { - draw_rect_masked(coords, clip, dsc); - return; + lv_area_t extension = {0, 0, 0, 0}; + if(!SKIP_SHADOW(dsc)) { + lv_coord_t ext = (lv_coord_t)(dsc->shadow_spread - dsc->shadow_width / 2 + 1); + extension.x1 = LV_MAX(extension.x1, -dsc->shadow_ofs_x + ext); + extension.x2 = LV_MAX(extension.x2, dsc->shadow_ofs_x + ext); + extension.y1 = LV_MAX(extension.y1, -dsc->shadow_ofs_y + ext); + extension.y2 = LV_MAX(extension.y2, dsc->shadow_ofs_y + ext); } - - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; - + if(!SKIP_OUTLINE(dsc)) { + lv_coord_t ext = (lv_coord_t)(dsc->outline_pad - 1 + dsc->outline_width); + extension.x1 = LV_MAX(extension.x1, ext); + extension.x2 = LV_MAX(extension.x2, ext); + extension.y1 = LV_MAX(extension.y1, ext); + extension.y2 = LV_MAX(extension.y2, ext); + } + if(dsc->blend_mode == LV_BLEND_MODE_REPLACE) { + /* Remove all pixels for draw area first */ + SDL_Rect re_coords, re_clip, re_area; + lv_area_to_sdl_rect(coords, &re_coords); + lv_area_to_sdl_rect(clip, &re_clip); + re_coords.x -= extension.x1; + re_coords.w += extension.x1 + extension.x2; + re_coords.y -= extension.y1; + re_coords.h += extension.y1 + extension.y2; + SDL_IntersectRect(&re_coords, &re_clip, &re_area); + SDL_Color bg_color; + lv_color_to_sdl_color(&dsc->bg_color, &bg_color); + SDL_SetRenderDrawColor(ctx->renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa); + SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_NONE); + SDL_RenderFillRect(ctx->renderer, &re_area); + } + /* Coords will be translated so coords will start at (0,0) */ + lv_area_t t_coords = *coords, t_clip = *clip, apply_area, t_area; + bool has_mask = lv_draw_sdl_composite_begin(ctx, coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip, + &apply_area); + bool has_content = _lv_area_intersect(&t_area, &t_coords, &t_clip); SDL_Rect clip_rect; - lv_area_to_sdl_rect(clip, &clip_rect); - SDL_RenderSetClipRect(renderer, &clip_rect); - draw_shadow(renderer, coords, clip, dsc); + lv_area_to_sdl_rect(&t_clip, &clip_rect); + draw_shadow(ctx, &t_coords, &t_clip, dsc); /* Shadows and outlines will also draw in extended area */ - if(has_draw_content) { - draw_bg_color(renderer, coords, dsc); - draw_bg_img(coords, clip, dsc); - draw_border(renderer, coords, dsc); + if(has_content) { + draw_bg_color(ctx, &t_coords, &t_area, dsc); + draw_bg_img(ctx, &t_coords, &t_area, dsc); + draw_border(ctx, &t_coords, &t_area, dsc); } - draw_outline(coords, clip, dsc); + draw_outline(ctx, &t_coords, &t_clip, dsc); + + lv_draw_sdl_composite_end(ctx, &apply_area, dsc->blend_mode); } /********************** * STATIC FUNCTIONS **********************/ -static void draw_bg_color(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc) +static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc) { + if(dsc->bg_opa == 0) { + return; + } SDL_Color bg_color; lv_color_to_sdl_color(&dsc->bg_color, &bg_color); lv_coord_t radius = dsc->radius; - if(radius > 0) { - /*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), bg_min = LV_MIN(bg_w, bg_h); - /* If size isn't times of 2, increase 1 px */ - lv_coord_t min_half = bg_min % 2 == 0 ? bg_min / 2 : bg_min / 2 + 1; - lv_coord_t frag_size = radius == LV_RADIUS_CIRCLE ? min_half : LV_MIN(radius + 1, min_half); - 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_gpu_draw_cache_get(&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_sdl_gen_mask_texture(renderer, &coords_frag, &mask_id, 1); - lv_draw_mask_remove_id(mask_id); - SDL_assert(texture); - lv_draw_sdl_draw_cache_put(&key, sizeof(key), texture); - } + if(radius <= 0) { + SDL_Rect rect; + lv_area_to_sdl_rect(draw_area, &rect); + SDL_SetRenderDrawColor(ctx->renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa); + SDL_SetRenderDrawBlendMode(ctx->renderer, SDL_BLENDMODE_BLEND); + SDL_RenderFillRect(ctx->renderer, &rect); + return; + } - 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(renderer, texture, frag_size, coords); - frag_render_borders(renderer, texture, frag_size, coords); - frag_render_center(renderer, texture, frag_size, coords); - } - else { - SDL_Rect coords_rect; - lv_area_to_sdl_rect(coords, &coords_rect); - SDL_SetRenderDrawColor(renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - SDL_RenderFillRect(renderer, &coords_rect); + /*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); } + + 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); } -static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc) { if(SKIP_IMAGE(dsc)) return; @@ -200,15 +229,16 @@ static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, const label_draw_dsc.font = dsc->bg_img_symbol_font; label_draw_dsc.color = dsc->bg_img_recolor; label_draw_dsc.opa = dsc->bg_img_opa; - lv_draw_label(&a, clip, &label_draw_dsc, dsc->bg_img_src, NULL); + lv_draw_label((lv_draw_ctx_t *) ctx, &label_draw_dsc, &a, dsc->bg_img_src, NULL); } else { lv_img_header_t header; size_t key_size; - lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_img_cache_key_create(dsc->bg_img_src, 0, &key_size); + lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(dsc->bg_img_src, 0, &key_size); bool key_found; lv_img_header_t * cache_header = NULL; - SDL_Texture * texture = lv_gpu_draw_cache_get_with_userdata(key, key_size, &key_found, (void **) &cache_header); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &key_found, + (void **) &cache_header); SDL_free(key); if(texture) { header = *cache_header; @@ -234,7 +264,7 @@ static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, const area.x2 = area.x1 + header.w - 1; area.y2 = area.y1 + header.h - 1; - lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc); + lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src); } else { lv_area_t area; @@ -246,14 +276,14 @@ static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, const area.x1 = coords->x1; area.x2 = area.x1 + header.w - 1; for(; area.x1 <= coords->x2; area.x1 += header.w, area.x2 += header.w) { - lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc); + lv_draw_img((lv_draw_ctx_t *) ctx, &img_dsc, &area, dsc->bg_img_src); } } } } } -static void draw_shadow(SDL_Renderer * renderer, const lv_area_t * coords, const lv_area_t * clip, +static void draw_shadow(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) { /*Check whether the shadow is visible*/ @@ -286,35 +316,37 @@ static void draw_shadow(SDL_Renderer * renderer, const lv_area_t * coords, const lv_area_to_sdl_rect(&shadow_area, &core_area_rect); lv_coord_t radius = dsc->radius; - lv_coord_t sh_width = lv_area_get_width(&core_area); - lv_coord_t sh_height = lv_area_get_height(&core_area); - lv_coord_t sh_min = LV_MIN(sh_width, sh_height); - /* If size isn't times of 2, increase 1 px */ - lv_coord_t min_half = sh_min % 2 == 0 ? sh_min / 2 : sh_min / 2 + 1; /* No matter how big the shadow is, what we need is just a corner */ - lv_coord_t frag_size = radius == LV_RADIUS_CIRCLE ? min_half : LV_MIN(radius + 1, min_half); + lv_coord_t frag_size = LV_MIN3(lv_area_get_width(&core_area) / 2, lv_area_get_height(&core_area) / 2, + LV_MAX(sw / 2, radius)); + /* This is how big the corner is after blurring */ - lv_coord_t blur_frag_size = frag_size + sw + 2; + lv_coord_t blur_growth = (lv_coord_t)(sw / 2 + 1); + + lv_coord_t blur_frag_size = (lv_coord_t)(frag_size + blur_growth); lv_draw_rect_shadow_key_t key = rect_shadow_key_create(radius, frag_size, sw); - lv_area_t blur_frag; - lv_area_copy(&blur_frag, &shadow_area); - lv_area_set_width(&blur_frag, blur_frag_size * 2); - lv_area_set_height(&blur_frag, blur_frag_size * 2); - SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { + lv_area_t mask_area = {blur_growth, blur_growth}, mask_area_blurred = {0, 0}; + lv_area_set_width(&mask_area, frag_size * 2); + lv_area_set_height(&mask_area, frag_size * 2); + lv_area_set_width(&mask_area_blurred, blur_frag_size * 2); + lv_area_set_height(&mask_area_blurred, blur_frag_size * 2); + lv_draw_mask_radius_param_t mask_rout_param; - lv_draw_mask_radius_init(&mask_rout_param, &core_area, radius, false); + lv_draw_mask_radius_init(&mask_rout_param, &mask_area, radius, false); int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); - lv_opa_t * mask_buf = lv_draw_mask_dump(&blur_frag, &mask_id, 1); - lv_stack_blur_grayscale(mask_buf, lv_area_get_width(&blur_frag), lv_area_get_height(&blur_frag), sw / 2 + 1); - texture = lv_sdl_create_mask_texture(renderer, mask_buf, blur_frag_size, blur_frag_size, - lv_area_get_width(&blur_frag)); + lv_opa_t * mask_buf = lv_draw_sdl_mask_dump_opa(&mask_area_blurred, &mask_id, 1); + lv_stack_blur_grayscale(mask_buf, lv_area_get_width(&mask_area_blurred), lv_area_get_height(&mask_area_blurred), + sw / 2 + sw % 2); + texture = lv_sdl_create_opa_texture(ctx->renderer, mask_buf, blur_frag_size, blur_frag_size, + lv_area_get_width(&mask_area_blurred)); lv_mem_buf_release(mask_buf); lv_draw_mask_remove_id(mask_id); SDL_assert(texture); - lv_draw_sdl_draw_cache_put(&key, sizeof(key), texture); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); } SDL_Color shadow_color; @@ -323,61 +355,36 @@ static void draw_shadow(SDL_Renderer * renderer, 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(renderer, texture, blur_frag_size, &shadow_area); - frag_render_borders(renderer, texture, blur_frag_size, &shadow_area); - frag_render_center(renderer, texture, blur_frag_size, &shadow_area); + frag_render_corners(ctx->renderer, 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); } -static void draw_border(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc) +static void draw_border(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc) { if(SKIP_BORDER(dsc)) return; SDL_Color border_color; lv_color_to_sdl_color(&dsc->border_color, &border_color); - - if(dsc->border_side != LV_BORDER_SIDE_FULL) { - SDL_SetRenderDrawColor(renderer, border_color.r, border_color.g, border_color.b, dsc->border_opa); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - for(int w = 0; w <= dsc->border_width; w++) { - if(dsc->border_side & LV_BORDER_SIDE_TOP) { - SDL_RenderDrawLine(renderer, coords->x1, coords->y1 + w, coords->x2, coords->y1 + w); - } - if(dsc->border_side & LV_BORDER_SIDE_BOTTOM) { - SDL_RenderDrawLine(renderer, coords->x1, coords->y2 - w, coords->x2, coords->y2 - w); - } - if(dsc->border_side & LV_BORDER_SIDE_LEFT) { - SDL_RenderDrawLine(renderer, coords->x1 + w, coords->y1, coords->x1 + w, coords->y2); - } - if(dsc->border_side & LV_BORDER_SIDE_RIGHT) { - SDL_RenderDrawLine(renderer, coords->x2 - w, coords->y1, coords->x2 - w, coords->y2); - } - } - } - else { - int32_t coords_w = lv_area_get_width(coords); - int32_t coords_h = lv_area_get_height(coords); - int32_t rout = dsc->radius; - int32_t short_side = LV_MIN(coords_w, coords_h); - if(rout > short_side >> 1) rout = short_side >> 1; - - /*Get the inner area*/ - lv_area_t area_inner; - lv_area_copy(&area_inner, coords); - area_inner.x1 += ((dsc->border_side & LV_BORDER_SIDE_LEFT) ? dsc->border_width : -(dsc->border_width + rout)); - area_inner.x2 -= ((dsc->border_side & LV_BORDER_SIDE_RIGHT) ? dsc->border_width : -(dsc->border_width + rout)); - area_inner.y1 += ((dsc->border_side & LV_BORDER_SIDE_TOP) ? dsc->border_width : -(dsc->border_width + rout)); - area_inner.y2 -= ((dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? dsc->border_width : -(dsc->border_width + rout)); - - lv_coord_t rin = rout - dsc->border_width; - if(rin < 0) rin = 0; - draw_border_generic(coords, &area_inner, rout, rin, dsc->border_color, dsc->border_opa, - dsc->blend_mode); - } + lv_coord_t coords_w = lv_area_get_width(coords), coords_h = lv_area_get_height(coords); + lv_coord_t short_side = LV_MIN(coords_w, coords_h); + lv_coord_t rout = LV_MIN(dsc->radius, short_side / 2);/*Get the inner area*/ + lv_area_t area_inner; + lv_area_copy(&area_inner, coords);// lv_area_increase(&area_inner, 1, 1); + area_inner.x1 += ((dsc->border_side & LV_BORDER_SIDE_LEFT) ? dsc->border_width : -(dsc->border_width + rout)); + area_inner.x2 -= ((dsc->border_side & LV_BORDER_SIDE_RIGHT) ? dsc->border_width : -(dsc->border_width + rout)); + area_inner.y1 += ((dsc->border_side & LV_BORDER_SIDE_TOP) ? dsc->border_width : -(dsc->border_width + rout)); + area_inner.y2 -= ((dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? dsc->border_width : -(dsc->border_width + rout)); + lv_coord_t rin = LV_MAX(rout - dsc->border_width, 0); + draw_border_generic(ctx, coords, &area_inner, draw_area, rout, rin, dsc->border_color, dsc->border_opa, + dsc->blend_mode); } -static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +static void draw_outline(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * clip, + const lv_draw_rect_dsc_t * dsc) { if(SKIP_OUTLINE(dsc)) return; @@ -389,8 +396,8 @@ static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_area_t area_inner; lv_area_copy(&area_inner, coords); - /*Extend the outline into the background area if it's overlapping the edge*/ - lv_coord_t pad = (dsc->outline_pad == 0 ? (dsc->outline_pad - 1) : dsc->outline_pad); + /*Bring the outline closer to make sure there is no color bleeding with pad=0*/ + lv_coord_t pad = dsc->outline_pad - 1; area_inner.x1 -= pad; area_inner.y1 -= pad; area_inner.x2 += pad; @@ -409,63 +416,56 @@ static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const int32_t inner_w = lv_area_get_width(&area_inner); int32_t inner_h = lv_area_get_height(&area_inner); - int32_t rin = dsc->radius; + lv_coord_t rin = dsc->radius; int32_t short_side = LV_MIN(inner_w, inner_h); if(rin > short_side >> 1) rin = short_side >> 1; lv_coord_t rout = rin + dsc->outline_width; - draw_border_generic(&area_outer, &area_inner, rout, rin, dsc->outline_color, dsc->outline_opa, + draw_border_generic(ctx, &area_outer, &area_inner, clip, rout, rin, dsc->outline_color, dsc->outline_opa, dsc->blend_mode); } -static void draw_border_generic(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout, - lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) +static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, + 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) { opa = opa >= LV_OPA_COVER ? LV_OPA_COVER : opa; - if(rout == 0 || rin == 0) { - draw_border_simple(outer_area, inner_area, color, opa); - return; - } - - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); SDL_Renderer * renderer = ctx->renderer; - lv_coord_t border_width = lv_area_get_width(outer_area); - lv_coord_t border_height = lv_area_get_height(outer_area); - lv_coord_t border_min = LV_MIN(border_width, border_height); - lv_coord_t min_half = border_min % 2 == 0 ? border_min / 2 : border_min / 2 + 1; - lv_coord_t frag_size = rout == LV_RADIUS_CIRCLE ? min_half : LV_MIN(rout + 1, min_half); - lv_draw_rect_border_key_t key = rect_border_key_create(rout, rin, inner_area->x1 - outer_area->x1 + 1, - frag_size, LV_BORDER_SIDE_FULL); - SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL); + lv_draw_rect_border_key_t key = rect_border_key_create(rout, rin, outer_area, inner_area); + lv_coord_t radius = LV_MIN3(rout, lv_area_get_width(outer_area) / 2, lv_area_get_height(outer_area) / 2); + lv_coord_t max_side = LV_MAX4(key.offsets.x1, key.offsets.y1, -key.offsets.x2, -key.offsets.y2); + lv_coord_t frag_size = LV_MAX(radius, max_side); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { + /* Create a mask texture with size of (frag_size * 2 + 1) */ + const lv_area_t frag_area = {0, 0, frag_size * 2, frag_size * 2}; + /*Create mask for the outer area*/ int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV}; lv_draw_mask_radius_param_t mask_rout_param; if(rout > 0) { - lv_draw_mask_radius_init(&mask_rout_param, outer_area, rout, false); + lv_draw_mask_radius_init(&mask_rout_param, &frag_area, rout, false); mask_ids[0] = lv_draw_mask_add(&mask_rout_param, NULL); } /*Create mask for the inner mask*/ if(rin < 0) rin = 0; + const lv_area_t frag_inner_area = {frag_area.x1 + key.offsets.x1, frag_area.y1 + key.offsets.y1, + frag_area.x2 + key.offsets.x2, frag_area.y2 + key.offsets.y2 + }; lv_draw_mask_radius_param_t mask_rin_param; - lv_draw_mask_radius_init(&mask_rin_param, inner_area, rin, true); + lv_draw_mask_radius_init(&mask_rin_param, &frag_inner_area, rin, true); mask_ids[1] = lv_draw_mask_add(&mask_rin_param, NULL); - lv_area_t frag_area; - lv_area_copy(&frag_area, outer_area); - lv_area_set_width(&frag_area, frag_size); - lv_area_set_height(&frag_area, frag_size); - - texture = lv_sdl_gen_mask_texture(renderer, &frag_area, mask_ids, 2); + texture = lv_draw_sdl_mask_dump_texture(renderer, &frag_area, mask_ids, 2); lv_draw_mask_remove_id(mask_ids[1]); lv_draw_mask_remove_id(mask_ids[0]); SDL_assert(texture); - lv_draw_sdl_draw_cache_put(&key, sizeof(key), texture); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); } SDL_Rect outer_rect; @@ -477,221 +477,195 @@ static void draw_border_generic(const lv_area_t * outer_area, const lv_area_t * 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); - frag_render_borders(renderer, texture, frag_size, outer_area); -} - -static void draw_border_simple(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, - lv_opa_t opa) -{ - - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; - - SDL_Color color_sdl; - lv_color_to_sdl_color(&color, &color_sdl); - - SDL_SetRenderDrawColor(renderer, color_sdl.r, color_sdl.g, color_sdl.b, opa); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - SDL_Rect simple_rect; - simple_rect.w = inner_area->x2 - outer_area->x1 + 1; - simple_rect.h = inner_area->y1 - outer_area->y1 + 1; - /*Top border*/ - simple_rect.x = outer_area->x1; - simple_rect.y = outer_area->y1; - SDL_RenderFillRect(renderer, &simple_rect); - /*Bottom border*/ - simple_rect.x = inner_area->x1; - simple_rect.y = inner_area->y2; - SDL_RenderFillRect(renderer, &simple_rect); - - simple_rect.w = inner_area->x1 - outer_area->x1 + 1; - simple_rect.h = inner_area->y2 - outer_area->y1 + 1; - /*Left border*/ - simple_rect.x = outer_area->x1; - simple_rect.y = inner_area->y1; - SDL_RenderFillRect(renderer, &simple_rect); - /*Right border*/ - simple_rect.x = inner_area->x2; - simple_rect.y = outer_area->y1; - SDL_RenderFillRect(renderer, &simple_rect); - + frag_render_corners(renderer, 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 * coords, const lv_area_t * clipped, bool full) { - lv_coord_t bg_w = lv_area_get_width(coords); - lv_coord_t bg_h = lv_area_get_height(coords); - SDL_Rect srcrect = {0, 0, frag_size, frag_size}; - SDL_Rect dstrect = {.x = coords->x1, .y = coords->y1, .w = frag_size, .h = frag_size}; + lv_area_t corner_area, dst_area; /* Upper left */ - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_NONE); + 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 */ - srcrect.w = dstrect.w = LV_MIN(frag_size, bg_w - frag_size); - dstrect.x = coords->x2 - srcrect.w + 1; - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL); + 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 + 1 + 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 */ - srcrect.h = dstrect.h = LV_MIN(frag_size, bg_h - frag_size); - dstrect.y = coords->y2 - srcrect.h + 1; - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL); + 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 + 1 + sx, frag_size + 1 + 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 */ - srcrect.w = dstrect.w = frag_size; - dstrect.x = coords->x1; - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_VERTICAL); + 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 + 1 + 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 * coords, const lv_area_t * clipped, bool full) { - lv_coord_t bg_w = lv_area_get_width(coords); - lv_coord_t bg_h = lv_area_get_height(coords); - SDL_Rect srcrect; - SDL_Rect dstrect; - /* For top/bottom edges, stretch pixels on the right */ - srcrect.h = dstrect.h = frag_size; - dstrect.w = bg_w - frag_size * 2; - /* Has space to fill */ - if(dstrect.w > 0 && dstrect.h > 0) { - srcrect.w = 1; - srcrect.y = 0; - srcrect.x = frag_size - 1; - dstrect.x = coords->x1 + frag_size; - /* Top edge */ - dstrect.y = coords->y1; - SDL_RenderCopy(renderer, frag, &srcrect, &dstrect); - /* Bottom edge */ - dstrect.y = coords->y2 - frag_size + 1; - if(bg_h < frag_size * 2) { - /* Bottom edge will overlap with top, so decrease it by 1 px */ - srcrect.h = dstrect.h = frag_size - 1; - dstrect.y += 1; + lv_area_t border_area, dst_area; + /* Top border */ + border_area.x1 = coords->x1 + frag_size; + border_area.y1 = coords->y1; + border_area.x2 = coords->x2 - frag_size; + border_area.y2 = coords->y1 + frag_size - 1; + if(_lv_area_intersect(&dst_area, &border_area, clipped)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1); + if(full) { + SDL_Rect src_rect = {frag_size, sy, 1, lv_area_get_height(&dst_area)}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } - if(srcrect.h > 0) { - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_VERTICAL); + else { + SDL_Rect src_rect = {frag_size - 1, sy, 1, lv_area_get_height(&dst_area)}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } } - /* For left/right edges, stretch pixels on the bottom */ - srcrect.w = dstrect.w = frag_size; - dstrect.h = bg_h - frag_size * 2; - if(dstrect.w > 0 && dstrect.h > 0) { - srcrect.h = 1; - srcrect.x = 0; - srcrect.y = frag_size - 1; - dstrect.y = coords->y1 + frag_size; - /* Left edge */ - dstrect.x = coords->x1; - SDL_RenderCopy(renderer, frag, &srcrect, &dstrect); - /* Right edge */ - dstrect.x = coords->x2 - frag_size + 1; - if(bg_w < frag_size * 2) { - /* Right edge will overlap with left, so decrease it by 1 px */ - srcrect.w = dstrect.w = frag_size - 1; - dstrect.x += 1; + /* Bottom border */ + border_area.y1 = LV_MAX(coords->y2 - frag_size + 1, coords->y1 + frag_size); + border_area.y2 = coords->y2; + if(_lv_area_intersect(&dst_area, &border_area, clipped)) { + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&dst_area, &dst_rect); + + lv_coord_t dh = lv_area_get_height(&dst_area); + if(full) { + lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1); + SDL_Rect src_rect = {frag_size, frag_size + 1 + sy, 1, dh}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } - if(srcrect.w > 0) { - SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL); + else { + lv_coord_t sy = (lv_coord_t)(border_area.y2 - dst_area.y2); + SDL_Rect src_rect = {frag_size - 1, sy, 1, dh}; + SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL); + } + } + /* Left border */ + border_area.x1 = coords->x1; + border_area.y1 = coords->y1 + frag_size; + border_area.x2 = coords->x1 + frag_size - 1; + border_area.y2 = coords->y2 - frag_size; + if(_lv_area_intersect(&dst_area, &border_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); + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1); + if(full) { + SDL_Rect src_rect = {sx, frag_size, dw, 1}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); + } + else { + SDL_Rect src_rect = {sx, frag_size - 1, dw, 1}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); + } + } + /* Right border */ + border_area.x1 = LV_MAX(coords->x2 - frag_size + 1, coords->x1 + frag_size); + border_area.x2 = coords->x2; + if(_lv_area_intersect(&dst_area, &border_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); + if(full) { + lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1); + SDL_Rect src_rect = {frag_size + 1 + sx, frag_size, dw, 1}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); + } + else { + lv_coord_t sx = (lv_coord_t)(border_area.x2 - dst_area.x2); + SDL_Rect src_rect = {sx, frag_size - 1, dw, 1}; + SDL_RenderCopyEx(renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); } } } -static void -frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords) +static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, + const lv_area_t * coords, + const lv_area_t * clipped, bool full) { - lv_coord_t bg_w = lv_area_get_width(coords); - lv_coord_t bg_h = lv_area_get_height(coords); - SDL_Rect dstrect = {coords->x1 + frag_size, coords->y1 + frag_size, bg_w - frag_size * 2, bg_h - frag_size * 2}; - if(dstrect.w > 0 && dstrect.h > 0) { - SDL_Rect srcrect = {frag_size - 1, frag_size - 1, 1, 1}; - SDL_RenderCopy(renderer, frag, &srcrect, &dstrect); - } -} - -static void draw_rect_masked(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) -{ - if(dsc->radius <= 0 && SKIP_BORDER(dsc) && SKIP_SHADOW(dsc) && SKIP_IMAGE(dsc) && SKIP_OUTLINE(dsc)) { - draw_rect_masked_simple(coords, clip, dsc); + lv_area_t center_area = { + coords->x1 + frag_size, + coords->y1 + frag_size, + coords->x2 - frag_size, + coords->y2 - frag_size, + }; + if(center_area.x2 < center_area.x1 || center_area.y2 < center_area.y1) return; + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, ¢er_area, clipped)) { return; } - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; - - SDL_Texture * screen = SDL_GetRenderTarget(renderer); - - lv_coord_t sw = dsc->shadow_width; - - lv_area_t sh_area = *coords; - lv_area_increase(&sh_area, dsc->shadow_spread + sw / 2 + 1, dsc->shadow_spread + sw / 2 + 1); - lv_area_move(&sh_area, dsc->shadow_ofs_x, dsc->shadow_ofs_y); - - lv_coord_t draw_w = lv_area_get_width(&sh_area); - lv_coord_t draw_h = lv_area_get_height(&sh_area); - /* Render drawing area to an offscreen texture */ - SDL_Texture * content = lv_gpu_temp_texture_obtain(renderer, draw_w, draw_h); - SDL_assert(content); - SDL_SetTextureColorMod(content, 0xFF, 0xFF, 0xFF); - SDL_SetTextureAlphaMod(content, 0xFF); - SDL_SetTextureBlendMode(content, SDL_BLENDMODE_BLEND); - - SDL_SetRenderTarget(renderer, content); - SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0x00); - SDL_RenderClear(renderer); - SDL_RenderSetClipRect(renderer, NULL); - lv_area_t content_coords; - lv_area_copy(&content_coords, coords); - lv_area_move(&content_coords, -sh_area.x1, -sh_area.y1); - - draw_shadow(renderer, &content_coords, clip, dsc); - draw_bg_color(renderer, &content_coords, dsc); - draw_bg_img(&content_coords, clip, dsc); - draw_border(renderer, &content_coords, dsc); - draw_outline(&content_coords, clip, dsc); - - SDL_Texture * clip_mask = lv_sdl_gen_mask_texture(renderer, &sh_area, NULL, 0); - SDL_Rect src_rect = {.w = draw_w, .h = draw_h, .x = 0, .y = 0}; -#if SDL_VERSION_ATLEAST(2, 0, 6) - SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, - SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, - SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD); - SDL_SetTextureBlendMode(clip_mask, mode); - SDL_RenderCopy(renderer, clip_mask, NULL, &src_rect); -#endif - - SDL_Rect mask_rect; - SDL_Rect draw_rect; - lv_area_to_sdl_rect(&sh_area, &draw_rect); - lv_area_to_sdl_rect(clip, &mask_rect); - - SDL_SetRenderTarget(renderer, screen); - SDL_RenderSetClipRect(renderer, &mask_rect); - SDL_RenderCopy(renderer, content, &src_rect, &draw_rect); - SDL_DestroyTexture(clip_mask); -} - -static void draw_rect_masked_simple(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc) -{ - SDL_Color bg_color; - lv_color_to_sdl_color(&dsc->bg_color, &bg_color); - - lv_draw_sdl_backend_context_t * ctx = lv_draw_sdl_get_context(); - SDL_Renderer * renderer = ctx->renderer; - - SDL_Surface * indexed = lv_sdl_apply_mask_surface(coords, NULL, 0); - SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed); - - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - SDL_SetTextureAlphaMod(texture, dsc->bg_opa); - SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b); - - SDL_Rect coords_rect, mask_rect; - lv_area_to_sdl_rect(coords, &coords_rect); - lv_area_to_sdl_rect(mask, &mask_rect); - - SDL_RenderSetClipRect(renderer, &mask_rect); - SDL_RenderCopy(renderer, texture, NULL, &coords_rect); - - SDL_DestroyTexture(texture); - SDL_FreeSurface(indexed); + SDL_Rect dst_rect; + lv_area_to_sdl_rect(&draw_area, &dst_rect); + if(full) { + SDL_Rect src_rect = {frag_size, frag_size, 1, 1}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); + } + else { + SDL_Rect src_rect = {frag_size - 1, frag_size - 1, 1, 1}; + SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); + } } static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size) @@ -715,8 +689,8 @@ static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_co return key; } -static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, lv_coord_t thickness, - lv_coord_t size, lv_border_side_t side) +static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area, + const lv_area_t * inner_area) { lv_draw_rect_border_key_t key; /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */ @@ -724,9 +698,10 @@ static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coor key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER; key.rout = rout; key.rin = rin; - key.thickness = thickness; - key.size = size; - key.side = side; + key.offsets.x1 = inner_area->x1 - outer_area->x1; + key.offsets.x2 = inner_area->x2 - outer_area->x2; + key.offsets.y1 = inner_area->y1 - outer_area->y1; + key.offsets.y2 = inner_area->y2 - outer_area->y2; return key; } diff --git a/src/draw/sdl/lv_draw_sdl_stack_blur.c b/src/draw/sdl/lv_draw_sdl_stack_blur.c index 9e82d833a..1c411b0ee 100644 --- a/src/draw/sdl/lv_draw_sdl_stack_blur.c +++ b/src/draw/sdl/lv_draw_sdl_stack_blur.c @@ -8,6 +8,7 @@ *********************/ #include "lv_draw_sdl_stack_blur.h" +#if LV_USE_GPU_SDL /********************* * DEFINES *********************/ @@ -245,3 +246,4 @@ static void stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsig } } +#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_stack_blur.h b/src/draw/sdl/lv_draw_sdl_stack_blur.h index 7fbe6048d..413b1c949 100644 --- a/src/draw/sdl/lv_draw_sdl_stack_blur.h +++ b/src/draw/sdl/lv_draw_sdl_stack_blur.h @@ -15,6 +15,8 @@ extern "C" { #include "../../lv_conf_internal.h" +#if LV_USE_GPU_SDL + #include "../../misc/lv_color.h" /********************* @@ -35,6 +37,8 @@ void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r) * MACROS **********************/ +#endif /*LV_USE_GPU_SDL*/ + #ifdef __cplusplus } /*extern "C"*/ #endif diff --git a/src/draw/sdl/lv_draw_sdl_texture_cache.c b/src/draw/sdl/lv_draw_sdl_texture_cache.c index 916a40aa7..8ceaf893c 100644 --- a/src/draw/sdl/lv_draw_sdl_texture_cache.c +++ b/src/draw/sdl/lv_draw_sdl_texture_cache.c @@ -13,9 +13,7 @@ #include "lv_draw_sdl_texture_cache.h" -#include "../../misc/lv_log.h" -#include "../../draw/lv_draw_label.h" -#include "../../draw/lv_draw_img.h" +#include "lv_draw_sdl_utils.h" /********************* * DEFINES @@ -33,25 +31,21 @@ typedef struct { } draw_cache_value_t; typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; } temp_texture_key_t; typedef struct { lv_coord_t width, height; } temp_texture_userdata_t; -/********************** - * STATIC PROTOTYPES - **********************/ - static void draw_cache_free_value(draw_cache_value_t *); +static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + bool * found); /********************** * STATIC VARIABLES **********************/ -static lv_lru_t * lv_sdl_texture_cache; - /********************** * MACROS **********************/ @@ -60,64 +54,56 @@ static lv_lru_t * lv_sdl_texture_cache; * GLOBAL FUNCTIONS **********************/ -void _lv_draw_sdl_texture_cache_init() +void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx) { - lv_sdl_texture_cache = lv_lru_new(1024 * 1024 * 8, 65536, (lv_lru_free_t *) draw_cache_free_value, - NULL); + ctx->internals->texture_cache = lv_lru_new(LV_GPU_SDL_LRU_SIZE, 65536, + (lv_lru_free_t *) draw_cache_free_value, NULL); } -void _lv_draw_sdl_texture_cache_deinit() +void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx) { - lv_lru_free(lv_sdl_texture_cache); + lv_lru_free(ctx->internals->texture_cache); } -SDL_Texture * lv_gpu_draw_cache_get(const void * key, size_t key_length, bool * found) +SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found) { - return lv_gpu_draw_cache_get_with_userdata(key, key_length, found, NULL); + return lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_length, found, NULL); } -SDL_Texture * lv_gpu_draw_cache_get_with_userdata(const void * key, size_t key_length, bool * found, void ** userdata) +SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + bool * found, void ** userdata) { - draw_cache_value_t * value = NULL; - lv_lru_get(lv_sdl_texture_cache, key, key_length, (void **) &value); - if(!value) { - if(found) { - *found = false; - } - return NULL; - } - else { - if(userdata) { - *userdata = value->userdata; - } - } - if(found) { - *found = true; + draw_cache_value_t * value = draw_cache_get_entry(ctx, key, key_length, found); + if(!value) return NULL; + if(userdata) { + *userdata = value->userdata; } return value->texture; } -void lv_draw_sdl_draw_cache_put(const void * key, size_t key_length, SDL_Texture * texture) +void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture) { - lv_draw_sdl_draw_cache_put_advanced(key, key_length, texture, NULL, NULL, 0); + lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_length, texture, NULL, NULL, 0); } -void lv_draw_sdl_draw_cache_put_advanced(const void * key, size_t key_length, SDL_Texture * texture, void * userdata, - lv_lru_free_t userdata_free, lv_draw_sdl_cache_flag_t flags) +void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + SDL_Texture * texture, void * userdata, void userdata_free(void *), + lv_draw_sdl_cache_flag_t flags) { + lv_lru_t * lru = ctx->internals->texture_cache; draw_cache_value_t * value = SDL_malloc(sizeof(draw_cache_value_t)); value->texture = texture; value->userdata = userdata; value->userdata_free = userdata_free; value->flags = flags; if(!texture) { - lv_lru_set(lv_sdl_texture_cache, key, key_length, value, 1); + lv_lru_set(lru, key, key_length, value, 1); return; } if(flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED) { /* Managed texture doesn't count into cache size */ LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format)); - lv_lru_set(lv_sdl_texture_cache, key, key_length, value, 1); + lv_lru_set(lru, key, key_length, value, 1); return; } Uint32 format; @@ -126,28 +112,10 @@ void lv_draw_sdl_draw_cache_put_advanced(const void * key, size_t key_length, SD return; } LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format)); - lv_lru_set(lv_sdl_texture_cache, key, key_length, value, width * height * SDL_BITSPERPIXEL(format) / 8); + lv_lru_set(lru, key, key_length, value, width * height * SDL_BITSPERPIXEL(format) / 8); } -SDL_Texture * lv_gpu_temp_texture_obtain(SDL_Renderer * renderer, lv_coord_t width, lv_coord_t height) -{ - temp_texture_key_t key; - SDL_memset(&key, 0, sizeof(key)); - key.magic = LV_GPU_CACHE_KEY_TEMP; - temp_texture_userdata_t * userdata = NULL; - SDL_Texture * texture = lv_gpu_draw_cache_get_with_userdata(&key, sizeof(key), NULL, (void **) &userdata); - if(texture && userdata->width >= width && userdata->height >= height) { - return texture; - } - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width, height); - userdata = SDL_malloc(sizeof(temp_texture_userdata_t)); - userdata->width = width; - userdata->height = height; - lv_draw_sdl_draw_cache_put_advanced(&key, sizeof(key), texture, userdata, SDL_free, 0); - return texture; -} - -lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_img_cache_key_create(const void * src, int32_t frame_id, size_t * size) +lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id, size_t * size) { lv_draw_sdl_cache_key_head_img_t header; /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */ @@ -176,10 +144,6 @@ lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_img_cache_key_create(const void * return (lv_draw_sdl_cache_key_head_img_t *) key; } -/********************** - * STATIC FUNCTIONS - **********************/ - static void draw_cache_free_value(draw_cache_value_t * value) { if(value->texture && !(value->flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED)) { @@ -192,6 +156,23 @@ static void draw_cache_free_value(draw_cache_value_t * value) SDL_free(value); } +static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + bool * found) +{ + lv_lru_t * lru = ctx->internals->texture_cache; + draw_cache_value_t * value = NULL; + lv_lru_get(lru, key, key_length, (void **) &value); + if(!value) { + if(found) { + *found = false; + } + return NULL; + } + if(found) { + *found = true; + } + return value; +} #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 341201cc2..538a2e8a8 100644 --- a/src/draw/sdl/lv_draw_sdl_texture_cache.h +++ b/src/draw/sdl/lv_draw_sdl_texture_cache.h @@ -16,10 +16,13 @@ extern "C" { #include "../../lv_conf_internal.h" +#if LV_USE_GPU_SDL + #include LV_GPU_SDL_INCLUDE_PATH +#include "lv_draw_sdl.h" +#include "lv_draw_sdl_priv.h" #include "../../draw/lv_img_decoder.h" #include "../../misc/lv_area.h" -#include "lv_draw_sdl_lru.h" /********************* * DEFINES @@ -34,6 +37,8 @@ extern "C" { typedef struct { char head[8]; SDL_Texture * texture; + bool texture_managed; + bool texture_referenced; } lv_draw_sdl_dec_dsc_userdata_t; typedef enum { @@ -44,8 +49,8 @@ typedef enum { LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32, LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33, LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH = 0x41, - LV_GPU_CACHE_KEY_TEMP = 0xFF, -} lv_gpu_cache_key_magic_t; + LV_GPU_CACHE_KEY_MAGIC_MASK = 0x51, +} lv_sdl_cache_key_magic_t; typedef enum { LV_DRAW_SDL_CACHE_FLAG_NONE = 0, @@ -53,7 +58,7 @@ typedef enum { } lv_draw_sdl_cache_flag_t; typedef struct { - lv_gpu_cache_key_magic_t magic; + lv_sdl_cache_key_magic_t magic; lv_img_src_t type; int32_t frame_id; } lv_draw_sdl_cache_key_head_img_t; @@ -62,26 +67,31 @@ typedef struct { * GLOBAL PROTOTYPES **********************/ -void _lv_draw_sdl_texture_cache_init(); +void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx); -void _lv_draw_sdl_texture_cache_deinit(); +void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx); -SDL_Texture * lv_gpu_draw_cache_get(const void * key, size_t key_length, bool * found); +/** + * Find cached texture by key. The texture can be destroyed during usage. + */ +SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found); -SDL_Texture * lv_gpu_draw_cache_get_with_userdata(const void * key, size_t key_length, bool * found, void ** userdata); +SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + bool * found, void ** userdata); -void lv_draw_sdl_draw_cache_put(const void * key, size_t key_length, SDL_Texture * texture); +void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture); -void lv_draw_sdl_draw_cache_put_advanced(const void * key, size_t key_length, SDL_Texture * texture, void * userdata, - lv_lru_free_t userdata_free, lv_draw_sdl_cache_flag_t flags); +void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + SDL_Texture * texture, void * userdata, void userdata_free(void *), + lv_draw_sdl_cache_flag_t flags); -SDL_Texture * lv_gpu_temp_texture_obtain(SDL_Renderer * renderer, lv_coord_t width, lv_coord_t height); - -lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_img_cache_key_create(const void * src, int32_t frame_id, size_t * size); +lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id, + size_t * size); /********************** * MACROS **********************/ +#endif /*LV_USE_GPU_SDL*/ #ifdef __cplusplus } /*extern "C"*/ diff --git a/src/draw/sdl/lv_draw_sdl_utils.c b/src/draw/sdl/lv_draw_sdl_utils.c index d49cdba38..3bbbfdbdd 100644 --- a/src/draw/sdl/lv_draw_sdl_utils.c +++ b/src/draw/sdl/lv_draw_sdl_utils.c @@ -12,8 +12,9 @@ #include "lv_draw_sdl_utils.h" -#include "../../draw/lv_draw.h" -#include "../../draw/lv_draw_label.h" +#include "../lv_draw.h" +#include "../lv_draw_label.h" +#include "../../core/lv_refr.h" /********************* * DEFINES @@ -26,20 +27,15 @@ /********************** * STATIC PROTOTYPES **********************/ - /********************** * STATIC VARIABLES **********************/ extern const uint8_t _lv_bpp1_opa_table[2]; extern const uint8_t _lv_bpp2_opa_table[4]; -extern const uint8_t _lv_bpp3_opa_table[8]; extern const uint8_t _lv_bpp4_opa_table[16]; extern const uint8_t _lv_bpp8_opa_table[256]; -static SDL_Palette * lv_sdl_palette_grayscale1 = NULL; -static SDL_Palette * lv_sdl_palette_grayscale2 = NULL; -static SDL_Palette * lv_sdl_palette_grayscale3 = NULL; -static SDL_Palette * lv_sdl_palette_grayscale4 = NULL; +static int utils_init_count = 0; static SDL_Palette * lv_sdl_palette_grayscale8 = NULL; /********************** @@ -52,20 +48,23 @@ static SDL_Palette * lv_sdl_palette_grayscale8 = NULL; void _lv_draw_sdl_utils_init() { - lv_sdl_palette_grayscale1 = lv_sdl_alloc_palette_for_bpp(_lv_bpp1_opa_table, 1); - lv_sdl_palette_grayscale2 = lv_sdl_alloc_palette_for_bpp(_lv_bpp2_opa_table, 2); - lv_sdl_palette_grayscale3 = lv_sdl_alloc_palette_for_bpp(_lv_bpp3_opa_table, 3); - lv_sdl_palette_grayscale4 = lv_sdl_alloc_palette_for_bpp(_lv_bpp4_opa_table, 4); + utils_init_count++; + if(utils_init_count > 1) { + return; + } lv_sdl_palette_grayscale8 = lv_sdl_alloc_palette_for_bpp(_lv_bpp8_opa_table, 8); } void _lv_draw_sdl_utils_deinit() { - SDL_FreePalette(lv_sdl_palette_grayscale1); - SDL_FreePalette(lv_sdl_palette_grayscale2); - SDL_FreePalette(lv_sdl_palette_grayscale3); - SDL_FreePalette(lv_sdl_palette_grayscale4); - SDL_FreePalette(lv_sdl_palette_grayscale8); + if(utils_init_count == 0) { + return; + } + utils_init_count--; + if(utils_init_count == 0) { + SDL_FreePalette(lv_sdl_palette_grayscale8); + lv_sdl_palette_grayscale8 = NULL; + } } void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out) @@ -78,12 +77,19 @@ void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out) void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out) { +#if LV_COLOR_DEPTH == 32 + out->a = in->ch.alpha; + out->r = in->ch.red; + out->g = in->ch.green; + out->b = in->ch.blue; +#else uint32_t color32 = lv_color_to32(*in); lv_color32_t * color32_t = (lv_color32_t *) &color32; out->a = color32_t->ch.alpha; out->r = color32_t->ch.red; out->g = color32_t->ch.green; out->b = color32_t->ch.blue; +#endif } void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot) @@ -102,11 +108,6 @@ void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoo out->h = sh; } -double lv_sdl_round(double d) -{ - return (d - (long) d) < 0.5 ? SDL_floor(d) : SDL_ceil(d); -} - SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp) { SDL_assert(bpp >= 1 && bpp <= 8); @@ -121,30 +122,22 @@ SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp) return result; } -SDL_Palette * lv_sdl_get_grayscale_palette(uint8_t bpp) +SDL_Surface * lv_sdl_create_opa_surface(lv_opa_t * opa, lv_coord_t width, lv_coord_t height, lv_coord_t stride) { - SDL_Palette * palette; - switch(bpp) { - case 1: - palette = lv_sdl_palette_grayscale1; - break; - case 2: - palette = lv_sdl_palette_grayscale2; - break; - case 3: - palette = lv_sdl_palette_grayscale3; - break; - case 4: - palette = lv_sdl_palette_grayscale4; - break; - case 8: - palette = lv_sdl_palette_grayscale8; - break; - default: - return NULL; - } - LV_ASSERT_MSG(lv_sdl_palette_grayscale8, "lv_draw_sdl was not initialized properly"); - return palette; + SDL_Surface * indexed = SDL_CreateRGBSurfaceFrom(opa, width, height, 8, stride, 0, 0, 0, 0); + SDL_SetSurfacePalette(indexed, lv_sdl_palette_grayscale8); + SDL_Surface * converted = SDL_ConvertSurfaceFormat(indexed, LV_DRAW_SDL_TEXTURE_FORMAT, 0); + SDL_FreeSurface(indexed); + return converted; +} + +SDL_Texture * lv_sdl_create_opa_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width, + lv_coord_t height, lv_coord_t stride) +{ + SDL_Surface * indexed = lv_sdl_create_opa_surface(pixels, width, height, stride); + SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed); + SDL_FreeSurface(indexed); + return texture; } void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp) @@ -187,11 +180,6 @@ void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, } } -lv_draw_sdl_backend_context_t * lv_draw_sdl_get_context() -{ - return lv_draw_backend_get()->ctx; -} - /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/draw/sdl/lv_draw_sdl_utils.h b/src/draw/sdl/lv_draw_sdl_utils.h index d8e86cd9f..9afae6879 100644 --- a/src/draw/sdl/lv_draw_sdl_utils.h +++ b/src/draw/sdl/lv_draw_sdl_utils.h @@ -14,7 +14,9 @@ extern "C" { *********************/ #include "../../lv_conf_internal.h" +#if LV_USE_GPU_SDL +#include "lv_draw_sdl.h" #include "../../misc/lv_color.h" #include "../../misc/lv_area.h" @@ -27,10 +29,7 @@ extern "C" { /********************** * TYPEDEFS **********************/ -typedef struct lv_draw_sdl_backend_context_t { - SDL_Renderer * renderer; - SDL_Texture * texture; -} lv_draw_sdl_backend_context_t; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -45,20 +44,20 @@ void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out); void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot); -double lv_sdl_round(double d); - SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp); -SDL_Palette * lv_sdl_get_grayscale_palette(uint8_t bpp); +SDL_Surface * lv_sdl_create_opa_surface(lv_opa_t * opa, lv_coord_t width, lv_coord_t height, lv_coord_t stride); + +SDL_Texture * lv_sdl_create_opa_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width, + lv_coord_t height, lv_coord_t stride); void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp); -lv_draw_sdl_backend_context_t * lv_draw_sdl_get_context(); - /********************** * MACROS **********************/ +#endif /*LV_USE_GPU_SDL*/ #ifdef __cplusplus } /*extern "C"*/ #endif diff --git a/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c b/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c new file mode 100644 index 000000000..d0db1be98 --- /dev/null +++ b/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c @@ -0,0 +1,255 @@ +/** + * @file lv_gpu_stm32_dma2d.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_gpu_stm32_dma2d.h" +#include "../../core/lv_refr.h" + +#if LV_USE_GPU_STM32_DMA2D + +#include LV_GPU_DMA2D_CMSIS_INCLUDE + +/********************* + * DEFINES + *********************/ + +#if LV_COLOR_16_SWAP + // TODO: F7 has red blue swap bit in control register for all layers and output + #error "Can't use DMA2D with LV_COLOR_16_SWAP 1" +#endif + +#if LV_COLOR_DEPTH == 8 + #error "Can't use DMA2D with LV_COLOR_DEPTH == 8" +#endif + +#if LV_COLOR_DEPTH == 16 + #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565 +#elif LV_COLOR_DEPTH == 32 + #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888 +#else + /*Can't use GPU with other formats*/ +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, + lv_color_t color); + + +static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa); + +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); + + +static void invalidate_cache(void); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_draw_stm32_dma2d_init(void) +{ + /*Enable DMA2D clock*/ +#if defined(STM32F4) || defined(STM32F7) + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; +#elif defined(STM32H7) + RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN; +#else +# warning "LVGL can't enable the clock of DMA2D" +#endif + + /*Wait for hardware access to complete*/ + __asm volatile("DSB\n"); + + /*Delay after setting peripheral clock*/ + volatile uint32_t temp = RCC->AHB1ENR; + LV_UNUSED(temp); + + /*set output colour mode*/ + DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT; +} + + +void lv_draw_stm32_dma2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + + lv_draw_sw_init_ctx(drv, draw_ctx); + + lv_draw_stm32_dma2d_ctx_t * dma2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; + + dma2d_draw_ctx->blend = lv_draw_stm32_dma2d_blend; + // dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded; + dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb; + +} + +void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + LV_UNUSED(drv); + LV_UNUSED(draw_ctx); +} + + +void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +{ + lv_area_t blend_area; + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; + + bool done = false; + + if(dsc->mask == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) { + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_color_t * dest_buf = draw_ctx->buf; + dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); + + const lv_color_t * src_buf = dsc->src_buf; + if(src_buf) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + lv_coord_t src_stride; + src_stride = lv_area_get_width(dsc->blend_area); + src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1); + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + lv_draw_stm32_dma2d_blend_map(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa); + done = true; + } + else if(dsc->opa >= LV_OPA_MAX) { + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + lv_draw_stm32_dma2d_blend_fill(dest_buf, dest_stride, &blend_area, dsc->color); + done = true; + } + } + + if(!done) lv_draw_sw_blend_basic(draw_ctx, dsc); +} + + +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format) +{ + /*TODO basic ARGB8888 image can be handles here*/ + + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, color_format); +} + +static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, + lv_color_t color) +{ + /*Simply fill an area*/ + int32_t area_w = lv_area_get_width(fill_area); + int32_t area_h = lv_area_get_height(fill_area); + invalidate_cache(); + + DMA2D->CR = 0x30000; + DMA2D->OMAR = (uint32_t)dest_buf; + /*as input color mode is same as output we don't need to convert here do we?*/ + DMA2D->OCOLR = color.full; + DMA2D->OOR = dest_stride - area_w; + DMA2D->NLR = (area_w << DMA2D_NLR_PL_Pos) | (area_h << DMA2D_NLR_NL_Pos); + + /*start transfer*/ + DMA2D->CR |= DMA2D_CR_START_Msk; + +} + + +static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa) +{ + + /*Simple copy*/ + int32_t dest_w = lv_area_get_width(dest_area); + int32_t dest_h = lv_area_get_height(dest_area); + + invalidate_cache(); + if(opa >= LV_OPA_MAX) { + DMA2D->CR = 0; + /*copy output colour mode, this register controls both input and output colour format*/ + DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT; + DMA2D->FGMAR = (uint32_t)src_buf; + DMA2D->FGOR = src_stride - dest_w; + DMA2D->OMAR = (uint32_t)dest_buf; + DMA2D->OOR = dest_stride - dest_w; + DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); + + /*start transfer*/ + DMA2D->CR |= DMA2D_CR_START_Msk; + } + else { + DMA2D->CR = 0x20000; + + DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT; + DMA2D->BGMAR = (uint32_t)dest_buf; + DMA2D->BGOR = dest_stride - dest_w; + + DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT + /*alpha mode 2, replace with foreground * alpha value*/ + | (2 << DMA2D_FGPFCCR_AM_Pos) + /*alpha value*/ + | (opa << DMA2D_FGPFCCR_ALPHA_Pos); + DMA2D->FGMAR = (uint32_t)src_buf; + DMA2D->FGOR = src_stride - dest_w; + + DMA2D->OMAR = (uint32_t)src_buf; + DMA2D->OOR = src_stride - dest_w; + DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); + + /*start transfer*/ + DMA2D->CR |= DMA2D_CR_START_Msk; + } +} + +void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx) +{ + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver && disp->driver->wait_cb) { + while(DMA2D->CR & DMA2D_CR_START_Msk) { + disp->driver->wait_cb(disp->driver); + } + } + else { + while(DMA2D->CR & DMA2D_CR_START_Msk); + } + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void invalidate_cache(void) +{ + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver); + else { +#if __CORTEX_M >= 0x07 + if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk) + SCB_CleanInvalidateDCache(); +#endif + } +} + +#endif diff --git a/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h b/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h new file mode 100644 index 000000000..73054ca2d --- /dev/null +++ b/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h @@ -0,0 +1,66 @@ +/** + * @file lv_gpu_stm32_dma2d.h + * + */ + +#ifndef LV_GPU_STM32_DMA2D_H +#define LV_GPU_STM32_DMA2D_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../misc/lv_color.h" +#include "../../hal/lv_hal_disp.h" +#include "../sw/lv_draw_sw.h" + +#if LV_USE_GPU_STM32_DMA2D + +/********************* + * DEFINES + *********************/ + +#define LV_DMA2D_ARGB8888 0 +#define LV_DMA2D_RGB888 1 +#define LV_DMA2D_RGB565 2 +#define LV_DMA2D_ARGB1555 3 +#define LV_DMA2D_ARGB4444 4 + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_stm32_dma2d_ctx_t; + +struct _lv_disp_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_draw_stm32_dma2d_init(void); + +void lv_draw_stm32_dma2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_stm32_dma2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_STM32_DMA2D*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_STM32_DMA2D_H*/ diff --git a/src/draw/sw/lv_draw_sw.c b/src/draw/sw/lv_draw_sw.c index 70fd8ea4c..fa7ffe984 100644 --- a/src/draw/sw/lv_draw_sw.c +++ b/src/draw/sw/lv_draw_sw.c @@ -37,21 +37,28 @@ * GLOBAL FUNCTIONS **********************/ -void lv_draw_sw_init(void) +void lv_draw_sw_init_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) { - static lv_draw_backend_t backend; - lv_draw_backend_init(&backend); + LV_UNUSED(drv); - backend.draw_arc = lv_draw_sw_arc; - backend.draw_rect = lv_draw_sw_rect; - backend.draw_letter = lv_draw_sw_letter; - backend.draw_img = lv_draw_sw_img; - backend.draw_line = lv_draw_sw_line; - backend.draw_polygon = lv_draw_sw_polygon; - backend.blend_fill = lv_blend_sw_fill; - backend.blend_map = lv_blend_sw_map; + lv_draw_sw_ctx_t * draw_sw_ctx = (lv_draw_sw_ctx_t *) draw_ctx; + lv_memset_00(draw_sw_ctx, sizeof(lv_draw_sw_ctx_t)); - lv_draw_backend_add(&backend); + draw_sw_ctx->base_draw.draw_arc = lv_draw_sw_arc; + draw_sw_ctx->base_draw.draw_rect = lv_draw_sw_rect; + draw_sw_ctx->base_draw.draw_letter = lv_draw_sw_letter; + draw_sw_ctx->base_draw.draw_img_decoded = lv_draw_sw_img_decoded; + draw_sw_ctx->base_draw.draw_line = lv_draw_sw_line; + draw_sw_ctx->base_draw.draw_polygon = lv_draw_sw_polygon; + draw_sw_ctx->blend = lv_draw_sw_blend_basic; +} + +void lv_draw_sw_deinit_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + LV_UNUSED(drv); + + lv_draw_sw_ctx_t * draw_sw_ctx = (lv_draw_sw_ctx_t *) draw_ctx; + lv_memset_00(draw_sw_ctx, sizeof(lv_draw_sw_ctx_t)); } /********************** diff --git a/src/draw/sw/lv_draw_sw.h b/src/draw/sw/lv_draw_sw.h index 1ec2f46df..342f4bce1 100644 --- a/src/draw/sw/lv_draw_sw.h +++ b/src/draw/sw/lv_draw_sw.h @@ -13,15 +13,11 @@ extern "C" { /********************* * INCLUDES *********************/ +#include "lv_draw_sw_blend.h" +#include "../lv_draw.h" #include "../../misc/lv_area.h" #include "../../misc/lv_color.h" -#include "../lv_draw_arc.h" -#include "../lv_draw_rect.h" -#include "../lv_draw_mask.h" -#include "../lv_draw_line.h" -#include "../lv_draw_img.h" -#include "../lv_draw_mask.h" -#include "../lv_draw_blend.h" +#include "../../hal/lv_hal_disp.h" /********************* * DEFINES @@ -31,41 +27,38 @@ extern "C" { * TYPEDEFS **********************/ +struct _lv_disp_drv_t; + +typedef struct { + lv_draw_ctx_t base_draw; + + /** Fill an area of the destination buffer with a color*/ + void (*blend)(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); +} lv_draw_sw_ctx_t; + /********************** * GLOBAL PROTOTYPES **********************/ -void lv_draw_sw_init(void); +void lv_draw_sw_init_ctx(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_sw_deinit_ctx(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); -void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, - uint16_t end_angle, - const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc); +void lv_draw_sw_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_sw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); +void lv_draw_sw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); -void lv_draw_sw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, - uint32_t letter, - lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); +void lv_draw_sw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); -void lv_draw_sw_img(const lv_area_t * map_area, const lv_area_t * clip_area, - const uint8_t * map_p, - const lv_draw_img_dsc_t * draw_dsc, - bool chroma_key, bool alpha_byte); +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf); -void lv_draw_sw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2); -void lv_draw_sw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * draw_dsc); - - -void lv_blend_sw_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode); - -void lv_blend_sw_map(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t mode); +void lv_draw_sw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, + const lv_point_t * points, uint16_t point_cnt); /*********************** * GLOBAL VARIABLES diff --git a/src/draw/sw/lv_draw_sw_arc.c b/src/draw/sw/lv_draw_sw_arc.c index 0f5104a5f..775944d7c 100644 --- a/src/draw/sw/lv_draw_sw_arc.c +++ b/src/draw/sw/lv_draw_sw_arc.c @@ -10,6 +10,7 @@ #include "../../misc/lv_math.h" #include "../../misc/lv_log.h" #include "../../misc/lv_mem.h" +#include "../lv_draw.h" /********************* * DEFINES @@ -21,8 +22,7 @@ * TYPEDEFS **********************/ typedef struct { - lv_coord_t center_x; - lv_coord_t center_y; + const lv_point_t * center; lv_coord_t radius; uint16_t start_angle; uint16_t end_angle; @@ -31,7 +31,7 @@ typedef struct { lv_coord_t width; lv_draw_rect_dsc_t * draw_dsc; const lv_area_t * draw_area; - const lv_area_t * clip_area; + lv_draw_ctx_t * draw_ctx; } quarter_draw_dsc_t; /********************** @@ -57,9 +57,8 @@ typedef struct { * GLOBAL FUNCTIONS **********************/ -void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, - uint16_t end_angle, - const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc) +void lv_draw_sw_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) { #if LV_DRAW_COMPLEX if(dsc->opa <= LV_OPA_MIN) return; @@ -83,10 +82,10 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, } lv_area_t area_out; - area_out.x1 = center_x - radius; - area_out.y1 = center_y - radius; - area_out.x2 = center_x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/ - area_out.y2 = center_y + radius - 1; + area_out.x1 = center->x - radius; + area_out.y1 = center->y - radius; + area_out.x2 = center->x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/ + area_out.y2 = center->y + radius - 1; lv_area_t area_in; lv_area_copy(&area_in, &area_out); @@ -110,7 +109,7 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, /*Draw a full ring*/ if(start_angle + 360 == end_angle || start_angle == end_angle + 360) { cir_dsc.radius = LV_RADIUS_CIRCLE; - lv_draw_rect(&area_out, clip_area, &cir_dsc); + lv_draw_rect(draw_ctx, &cir_dsc, &area_out); lv_draw_mask_remove_id(mask_out_id); if(mask_in_id != LV_MASK_ID_INV) lv_draw_mask_remove_id(mask_in_id); @@ -125,7 +124,7 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, while(end_angle >= 360) end_angle -= 360; lv_draw_mask_angle_param_t mask_angle_param; - lv_draw_mask_angle_init(&mask_angle_param, center_x, center_y, start_angle, end_angle); + lv_draw_mask_angle_init(&mask_angle_param, center->x, center->y, start_angle, end_angle); int16_t mask_angle_id = lv_draw_mask_add(&mask_angle_param, NULL); int32_t angle_gap; @@ -135,11 +134,13 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, else { angle_gap = start_angle - end_angle; } + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + if(angle_gap > SPLIT_ANGLE_GAP_LIMIT && radius > SPLIT_RADIUS_LIMIT) { /*Handle each quarter individually and skip which is empty*/ quarter_draw_dsc_t q_dsc; - q_dsc.center_x = center_x; - q_dsc.center_y = center_y; + q_dsc.center = center; q_dsc.radius = radius; q_dsc.start_angle = start_angle; q_dsc.end_angle = end_angle; @@ -148,7 +149,7 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, q_dsc.width = width; q_dsc.draw_dsc = &cir_dsc; q_dsc.draw_area = &area_out; - q_dsc.clip_area = clip_area; + q_dsc.draw_ctx = draw_ctx; draw_quarter_0(&q_dsc); draw_quarter_1(&q_dsc); @@ -156,7 +157,7 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, draw_quarter_3(&q_dsc); } else { - lv_draw_rect(&area_out, clip_area, &cir_dsc); + lv_draw_rect(draw_ctx, &cir_dsc, &area_out); } lv_draw_mask_free_param(&mask_angle_param); @@ -173,42 +174,44 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, lv_area_t round_area; get_rounded_area(start_angle, radius, width, &round_area); - round_area.x1 += center_x; - round_area.x2 += center_x; - round_area.y1 += center_y; - round_area.y2 += center_y; + round_area.x1 += center->x; + round_area.x2 += center->x; + round_area.y1 += center->y; + round_area.y2 += center->y; lv_area_t clip_area2; - if(_lv_area_intersect(&clip_area2, clip_area, &round_area)) { + if(_lv_area_intersect(&clip_area2, clip_area_ori, &round_area)) { lv_draw_mask_radius_init(&mask_end_param, &round_area, LV_RADIUS_CIRCLE, false); int16_t mask_end_id = lv_draw_mask_add(&mask_end_param, NULL); - lv_draw_rect(&area_out, &clip_area2, &cir_dsc); + draw_ctx->clip_area = &clip_area2; + lv_draw_rect(draw_ctx, &cir_dsc, &area_out); lv_draw_mask_remove_id(mask_end_id); lv_draw_mask_free_param(&mask_end_param); } get_rounded_area(end_angle, radius, width, &round_area); - round_area.x1 += center_x; - round_area.x2 += center_x; - round_area.y1 += center_y; - round_area.y2 += center_y; - if(_lv_area_intersect(&clip_area2, clip_area, &round_area)) { + round_area.x1 += center->x; + round_area.x2 += center->x; + round_area.y1 += center->y; + round_area.y2 += center->y; + if(_lv_area_intersect(&clip_area2, clip_area_ori, &round_area)) { lv_draw_mask_radius_init(&mask_end_param, &round_area, LV_RADIUS_CIRCLE, false); int16_t mask_end_id = lv_draw_mask_add(&mask_end_param, NULL); - lv_draw_rect(&area_out, &clip_area2, &cir_dsc); + draw_ctx->clip_area = &clip_area2; + lv_draw_rect(draw_ctx, &cir_dsc, &area_out); lv_draw_mask_remove_id(mask_end_id); lv_draw_mask_free_param(&mask_end_param); } + draw_ctx->clip_area = clip_area_ori; } #else LV_LOG_WARN("Can't draw arc with LV_DRAW_COMPLEX == 0"); - LV_UNUSED(center_x); - LV_UNUSED(center_y); + LV_UNUSED(center); LV_UNUSED(radius); LV_UNUSED(start_angle); LV_UNUSED(end_angle); - LV_UNUSED(clip_area); + LV_UNUSED(draw_ctx); LV_UNUSED(dsc); #endif /*LV_DRAW_COMPLEX*/ } @@ -220,40 +223,50 @@ void lv_draw_sw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, #if LV_DRAW_COMPLEX static void draw_quarter_0(quarter_draw_dsc_t * q) { + const lv_area_t * clip_area_ori = q->draw_ctx->clip_area; lv_area_t quarter_area; if(q->start_quarter == 0 && q->end_quarter == 0 && q->start_angle < q->end_angle) { /*Small arc here*/ - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } else if(q->start_quarter == 0 || q->end_quarter == 0) { /*Start and/or end arcs here*/ if(q->start_quarter == 0) { - quarter_area.x1 = q->center_x; - quarter_area.y2 = q->center_y + q->radius; + quarter_area.x1 = q->center->x; + quarter_area.y2 = q->center->y + q->radius; - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } if(q->end_quarter == 0) { - quarter_area.x2 = q->center_x + q->radius; - quarter_area.y1 = q->center_y; + quarter_area.x2 = q->center->x + q->radius; + quarter_area.y1 = q->center->y; - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } } else if((q->start_quarter == q->end_quarter && q->start_quarter != 0 && q->end_angle < q->start_angle) || @@ -261,52 +274,66 @@ static void draw_quarter_0(quarter_draw_dsc_t * q) (q->start_quarter == 3 && q->end_quarter == 2) || (q->start_quarter == 3 && q->end_quarter == 1)) { /*Arc crosses here*/ - quarter_area.x1 = q->center_x; - quarter_area.y1 = q->center_y; - quarter_area.x2 = q->center_x + q->radius; - quarter_area.y2 = q->center_y + q->radius; + quarter_area.x1 = q->center->x; + quarter_area.y1 = q->center->y; + quarter_area.x2 = q->center->x + q->radius; + quarter_area.y2 = q->center->y + q->radius; - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } + q->draw_ctx->clip_area = clip_area_ori; } static void draw_quarter_1(quarter_draw_dsc_t * q) { + const lv_area_t * clip_area_ori = q->draw_ctx->clip_area; lv_area_t quarter_area; if(q->start_quarter == 1 && q->end_quarter == 1 && q->start_angle < q->end_angle) { /*Small arc here*/ - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } else if(q->start_quarter == 1 || q->end_quarter == 1) { /*Start and/or end arcs here*/ if(q->start_quarter == 1) { - quarter_area.x1 = q->center_x - q->radius; - quarter_area.y1 = q->center_y; + quarter_area.x1 = q->center->x - q->radius; + quarter_area.y1 = q->center->y; - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } if(q->end_quarter == 1) { - quarter_area.x2 = q->center_x - 1; - quarter_area.y2 = q->center_y + q->radius; + quarter_area.x2 = q->center->x - 1; + quarter_area.y2 = q->center->y + q->radius; - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } } else if((q->start_quarter == q->end_quarter && q->start_quarter != 1 && q->end_angle < q->start_angle) || @@ -314,52 +341,66 @@ static void draw_quarter_1(quarter_draw_dsc_t * q) (q->start_quarter == 0 && q->end_quarter == 3) || (q->start_quarter == 3 && q->end_quarter == 2)) { /*Arc crosses here*/ - quarter_area.x1 = q->center_x - q->radius; - quarter_area.y1 = q->center_y; - quarter_area.x2 = q->center_x - 1; - quarter_area.y2 = q->center_y + q->radius; + quarter_area.x1 = q->center->x - q->radius; + quarter_area.y1 = q->center->y; + quarter_area.x2 = q->center->x - 1; + quarter_area.y2 = q->center->y + q->radius; - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } + q->draw_ctx->clip_area = clip_area_ori; } static void draw_quarter_2(quarter_draw_dsc_t * q) { + const lv_area_t * clip_area_ori = q->draw_ctx->clip_area; lv_area_t quarter_area; if(q->start_quarter == 2 && q->end_quarter == 2 && q->start_angle < q->end_angle) { /*Small arc here*/ - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->end_angle) * q->radius) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } else if(q->start_quarter == 2 || q->end_quarter == 2) { /*Start and/or end arcs here*/ if(q->start_quarter == 2) { - quarter_area.x2 = q->center_x - 1; - quarter_area.y1 = q->center_y - q->radius; + quarter_area.x2 = q->center->x - 1; + quarter_area.y1 = q->center->y - q->radius; - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } if(q->end_quarter == 2) { - quarter_area.x1 = q->center_x - q->radius; - quarter_area.y2 = q->center_y - 1; + quarter_area.x1 = q->center->x - q->radius; + quarter_area.y2 = q->center->y - 1; - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->end_angle) * (q->radius)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } } else if((q->start_quarter == q->end_quarter && q->start_quarter != 2 && q->end_angle < q->start_angle) || @@ -367,52 +408,66 @@ static void draw_quarter_2(quarter_draw_dsc_t * q) (q->start_quarter == 1 && q->end_quarter == 3) || (q->start_quarter == 1 && q->end_quarter == 0)) { /*Arc crosses here*/ - quarter_area.x1 = q->center_x - q->radius; - quarter_area.y1 = q->center_y - q->radius; - quarter_area.x2 = q->center_x - 1; - quarter_area.y2 = q->center_y - 1; + quarter_area.x1 = q->center->x - q->radius; + quarter_area.y1 = q->center->y - q->radius; + quarter_area.x2 = q->center->x - 1; + quarter_area.y2 = q->center->y - 1; - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } + q->draw_ctx->clip_area = clip_area_ori; } static void draw_quarter_3(quarter_draw_dsc_t * q) { + const lv_area_t * clip_area_ori = q->draw_ctx->clip_area; lv_area_t quarter_area; if(q->start_quarter == 3 && q->end_quarter == 3 && q->start_angle < q->end_angle) { /*Small arc here*/ - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } else if(q->start_quarter == 3 || q->end_quarter == 3) { /*Start and/or end arcs here*/ if(q->start_quarter == 3) { - quarter_area.x2 = q->center_x + q->radius; - quarter_area.y2 = q->center_y - 1; + quarter_area.x2 = q->center->x + q->radius; + quarter_area.y2 = q->center->y - 1; - quarter_area.x1 = q->center_x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - quarter_area.y1 = q->center_y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.x1 = q->center->x + ((lv_trigo_sin(q->start_angle + 90) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.y1 = q->center->y + ((lv_trigo_sin(q->start_angle) * (q->radius)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } if(q->end_quarter == 3) { - quarter_area.x1 = q->center_x; - quarter_area.y1 = q->center_y - q->radius; + quarter_area.x1 = q->center->x; + quarter_area.y1 = q->center->y - q->radius; - quarter_area.x2 = q->center_x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); - quarter_area.y2 = q->center_y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); + quarter_area.x2 = q->center->x + ((lv_trigo_sin(q->end_angle + 90) * (q->radius)) >> LV_TRIGO_SHIFT); + quarter_area.y2 = q->center->y + ((lv_trigo_sin(q->end_angle) * (q->radius - q->width)) >> LV_TRIGO_SHIFT); - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } } else if((q->start_quarter == q->end_quarter && q->start_quarter != 3 && q->end_angle < q->start_angle) || @@ -420,14 +475,19 @@ static void draw_quarter_3(quarter_draw_dsc_t * q) (q->start_quarter == 1 && q->end_quarter == 0) || (q->start_quarter == 2 && q->end_quarter == 1)) { /*Arc crosses here*/ - quarter_area.x1 = q->center_x; - quarter_area.y1 = q->center_y - q->radius; - quarter_area.x2 = q->center_x + q->radius; - quarter_area.y2 = q->center_y - 1; + quarter_area.x1 = q->center->x; + quarter_area.y1 = q->center->y - q->radius; + quarter_area.x2 = q->center->x + q->radius; + quarter_area.y2 = q->center->y - 1; - bool ok = _lv_area_intersect(&quarter_area, &quarter_area, q->clip_area); - if(ok) lv_draw_rect(q->draw_area, &quarter_area, q->draw_dsc); + bool ok = _lv_area_intersect(&quarter_area, &quarter_area, clip_area_ori); + if(ok) { + q->draw_ctx->clip_area = &quarter_area; + lv_draw_rect(q->draw_ctx, q->draw_dsc, &quarter_area); + } } + + q->draw_ctx->clip_area = clip_area_ori; } static void get_rounded_area(int16_t angle, lv_coord_t radius, uint8_t thickness, lv_area_t * res_area) diff --git a/src/draw/sw/lv_draw_sw_blend.c b/src/draw/sw/lv_draw_sw_blend.c index b1a8c7cb1..c3cbd48ba 100644 --- a/src/draw/sw/lv_draw_sw_blend.c +++ b/src/draw/sw/lv_draw_sw_blend.c @@ -1,5 +1,5 @@ /** - * @file lv_draw_blend.c + * @file lv_draw_sw_blend.c * */ @@ -14,7 +14,6 @@ /********************* * DEFINES *********************/ -#define GPU_SIZE_LIMIT 240 /********************** * TYPEDEFS @@ -24,34 +23,30 @@ * STATIC PROTOTYPES **********************/ -static void fill_set_px(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask); - -LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask); - +static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide); +LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, + lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride); #if LV_DRAW_COMPLEX -static void fill_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_blend_mode_t mode); +static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, lv_color_t color, + lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode); #endif /*LV_DRAW_COMPLEX*/ +static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride); -static void map_set_px(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa); - -LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa); +LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride); #if LV_DRAW_COMPLEX -static void map_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t mode); +static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, + const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode); static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa); static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa); static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color_t bg, lv_opa_t opa); +static inline lv_color_t color_blend_true_color_replace(lv_color_t fg, lv_color_t bg, lv_opa_t opa); #endif /*LV_DRAW_COMPLEX*/ /********************** @@ -70,11 +65,11 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color #else #define FILL_NORMAL_MASK_PX(color) \ - if(*mask == LV_OPA_COVER) *disp_buf = color; \ - else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*disp_buf, disp_buf->ch.alpha, color, *mask, disp_buf, &disp_buf->ch.alpha); \ - else *disp_buf = lv_color_mix(color, *disp_buf, *mask); \ + if(*mask == LV_OPA_COVER) *dest_buf = color; \ + else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*dest_buf, dest_buf->ch.alpha, color, *mask, dest_buf, &dest_buf->ch.alpha); \ + else *dest_buf = lv_color_mix(color, *dest_buf, *mask); \ mask++; \ - disp_buf++; + dest_buf++; #endif #define MAP_NORMAL_MASK_PX(x) \ @@ -86,76 +81,109 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color #define MAP_NORMAL_MASK_PX_SCR_TRANSP(x) \ if(*mask_tmp_x) { \ - if(*mask_tmp_x == LV_OPA_COVER) disp_buf[x] = map_buf[x]; \ - else if(disp->driver->screen_transp) lv_color_mix_with_alpha(disp_buf[x], disp_buf[x].ch.alpha, \ - map_buf[x], *mask_tmp_x, &disp_buf[x], &disp_buf[x].ch.alpha); \ - else disp_buf[x] = lv_color_mix(map_buf[x], disp_buf[x], *mask_tmp_x); \ + if(*mask_tmp_x == LV_OPA_COVER) dest_buf[x] = src_buf[x]; \ + else if(disp->driver->screen_transp) lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, \ + src_buf[x], *mask_tmp_x, &dest_buf[x], &dest_buf[x].ch.alpha); \ + else dest_buf[x] = lv_color_mix(src_buf[x], dest_buf[x], *mask_tmp_x); \ } \ mask_tmp_x++; + /********************** * GLOBAL FUNCTIONS **********************/ - -LV_ATTRIBUTE_FAST_MEM void lv_blend_sw_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode) +void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + /*Do not draw transparent things*/ + if(dsc->opa <= LV_OPA_MIN) return; - /*Round the values in the mask if anti-aliasing is disabled*/ - lv_coord_t area_size = lv_area_get_size(fill_area); - if(mask && disp->driver->antialiasing == 0 && mask) { - lv_coord_t i; - for(i = 0; i < area_size; i++) mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP; - } + lv_area_t blend_area; + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; - if(disp->driver->set_px_cb) { - fill_set_px(dest_buf, dest_stride, fill_area, color, opa, mask); - } - else if(blend_mode == LV_BLEND_MODE_NORMAL) { - fill_normal(dest_buf, dest_stride, fill_area, color, opa, mask); - } -#if LV_DRAW_COMPLEX - else { - fill_blended(dest_buf, dest_stride, fill_area, color, opa, mask, blend_mode); - } -#endif + if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx); + + ((lv_draw_sw_ctx_t *)draw_ctx)->blend(draw_ctx, dsc); } -void lv_blend_sw_map(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t mode) +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + const lv_opa_t * mask; + if(dsc->mask == NULL) mask = NULL; + if(dsc->mask && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return; + else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; + else mask = dsc->mask; - /*Round the values in the mask if anti-aliasing is disabled*/ - int32_t area_size = lv_area_get_size(clip_area); - if(mask && disp->driver->antialiasing == 0) { - lv_coord_t i; - for(i = 0; i < area_size; i++) mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t blend_area; + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; + + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + lv_color_t * dest_buf = draw_ctx->buf; + if(disp->driver->set_px_cb == NULL) { + dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); } + const lv_color_t * src_buf = dsc->src_buf; + lv_coord_t src_stride; + if(src_buf) { + src_stride = lv_area_get_width(dsc->blend_area); + src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1); + } + else { + src_stride = 0; + } + + lv_coord_t mask_stride; + if(mask) { + mask_stride = lv_area_get_width(dsc->mask_area); + mask += mask_stride * (dsc->mask_area->y1 - blend_area.y1) + (dsc->mask_area->x1 - blend_area.x1); + } + else { + mask_stride = 0; + } + + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + if(disp->driver->set_px_cb) { - map_set_px(dest_buf, dest_stride, clip_area, src_buf, src_area, mask, opa); - } - else if(mode == LV_BLEND_MODE_NORMAL) { - map_normal(dest_buf, dest_stride, clip_area, src_buf, src_area, mask, opa); + if(dsc->src_buf == NULL) { + fill_set_px(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride); + } + else { + map_set_px(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride); + } } + else if(dsc->src_buf == NULL) { + if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { + fill_normal(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride); + } #if LV_DRAW_COMPLEX - else { - map_blended(dest_buf, dest_stride, clip_area, src_buf, src_area, mask, opa, mode); - } + else { + fill_blended(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa, mask, mask_stride, dsc->blend_mode); + } #endif + } + else { + if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { + map_normal(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride); + } +#if LV_DRAW_COMPLEX + else { + map_blended(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa, mask, mask_stride, dsc->blend_mode); + } +#endif + } } + /********************** * STATIC FUNCTIONS **********************/ -static void fill_set_px(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask) +static void fill_set_px(lv_color_t * dest_buf, const lv_area_t * blend_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stide) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); @@ -163,50 +191,47 @@ static void fill_set_px(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_ int32_t y; if(mask == NULL) { - for(y = fill_area->y1; y <= fill_area->y2; y++) { - for(x = fill_area->x1; x <= fill_area->x2; x++) { + for(y = blend_area->y1; y <= blend_area->y2; y++) { + for(x = blend_area->x1; x <= blend_area->x2; x++) { disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, x, y, color, opa); } } } else { - int32_t area_w = lv_area_get_width(fill_area); - int32_t area_h = lv_area_get_height(fill_area); + int32_t w = lv_area_get_width(blend_area); + int32_t h = lv_area_get_height(blend_area); - for(y = 0; y < area_h; y++) { - for(x = 0; x < area_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(mask[x]) { - disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, fill_area->x1 + x, fill_area->y1 + y, color, + disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, blend_area->x1 + x, blend_area->y1 + y, color, (uint32_t)((uint32_t)opa * mask[x]) >> 8); } } - mask += area_w; + mask += mask_stide; } } } -LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t dest_stride, - const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask) +LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, + lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride) { - - int32_t area_w = lv_area_get_width(fill_area); - int32_t area_h = lv_area_get_height(fill_area); - - dest_buf += dest_stride * fill_area->y1 + fill_area->x1; + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + int32_t w = lv_area_get_width(dest_area); + int32_t h = lv_area_get_height(dest_area); int32_t x; int32_t y; - /*Simple fill (maybe with opacity), no masking*/ + /*No mask*/ if(mask == NULL) { - if(opa > LV_OPA_MAX) { - for(y = 0; y < area_h; y++) { - lv_color_fill(dest_buf, color, area_w); + if(opa >= LV_OPA_MAX) { + for(y = 0; y < h; y++) { + lv_color_fill(dest_buf, color, w); dest_buf += dest_stride; } } - /*No mask with opacity*/ + /*Has opacity*/ else { lv_color_t last_dest_color = lv_color_black(); lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa); @@ -215,8 +240,8 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t lv_color_premult(color, opa, color_premult); lv_opa_t opa_inv = 255 - opa; - for(y = 0; y < area_h; y++) { - for(x = 0; x < area_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(last_dest_color.full != dest_buf[x].full) { last_dest_color = dest_buf[x]; @@ -226,6 +251,8 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t &last_res_color.ch.alpha); } else +#else + LV_UNUSED(disp); #endif { last_res_color = lv_color_mix_premult(color_premult, dest_buf[x], opa_inv); @@ -239,16 +266,14 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t } /*Masked*/ else { - int32_t x_end4 = area_w - 4; - #if LV_COLOR_DEPTH == 16 uint32_t c32 = color.full + ((uint32_t)color.full << 16); #endif - /*Only the mask matters*/ - if(opa > LV_OPA_MAX) { - for(y = 0; y < area_h; y++) { - for(x = 0; x < area_w && ((lv_uintptr_t)(mask) & 0x3); x++) { + if(opa >= LV_OPA_MAX) { + int32_t x_end4 = w - 4; + for(y = 0; y < h; y++) { + for(x = 0; x < w && ((lv_uintptr_t)(mask) & 0x3); x++) { FILL_NORMAL_MASK_PX(color) } @@ -288,13 +313,14 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t } } - for(; x < area_w ; x++) { + for(; x < w ; x++) { FILL_NORMAL_MASK_PX(color) } - dest_buf += (dest_stride - area_w); + dest_buf += (dest_stride - w); + mask += (mask_stride - w); } } - /*Handle opa and mask values too*/ + /*With opacity*/ else { /*Buffer the result color to avoid recalculating the same color*/ lv_color_t last_dest_color; @@ -304,13 +330,12 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t last_res_color.full = dest_buf[0].full; lv_opa_t opa_tmp = LV_OPA_TRANSP; - for(y = 0; y < area_h; y++) { - const lv_opa_t * mask_line = mask; - for(x = 0; x < area_w; x++) { - if(*mask_line) { - if(*mask_line != last_mask) opa_tmp = *mask_line == LV_OPA_COVER ? opa : - (uint32_t)((uint32_t)(*mask_line) * opa) >> 8; - if(*mask_line != last_mask || last_dest_color.full != dest_buf[x].full) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + if(*mask) { + if(*mask != last_mask) opa_tmp = *mask == LV_OPA_COVER ? opa : + (uint32_t)((uint32_t)(*mask) * opa) >> 8; + if(*mask != last_mask || last_dest_color.full != dest_buf[x].full) { #if LV_COLOR_SCREEN_TRANSP if(disp->driver->screen_transp) { lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, color, opa_tmp, &last_res_color, @@ -322,28 +347,34 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(lv_color_t * dest_buf, lv_coord_t if(opa_tmp == LV_OPA_COVER) last_res_color = color; else last_res_color = lv_color_mix(color, dest_buf[x], opa_tmp); } - last_mask = *mask_line; + last_mask = *mask; last_dest_color.full = dest_buf[x].full; } dest_buf[x] = last_res_color; } - mask_line++; + mask++; } dest_buf += dest_stride; - mask += area_w; + mask += (mask_stride - w); } } } } #if LV_DRAW_COMPLEX -static void fill_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_blend_mode_t mode) +static void fill_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, + lv_coord_t dest_stride, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride, + lv_blend_mode_t blend_mode) { - dest_buf += dest_stride * fill_area->y1 + fill_area->x1; + + int32_t w = lv_area_get_width(dest_area); + int32_t h = lv_area_get_height(dest_area); + + int32_t x; + int32_t y; lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t); - switch(mode) { + switch(blend_mode) { case LV_BLEND_MODE_ADDITIVE: blend_fp = color_blend_true_color_additive; break; @@ -353,23 +384,20 @@ static void fill_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv case LV_BLEND_MODE_MULTIPLY: blend_fp = color_blend_true_color_multiply; break; + case LV_BLEND_MODE_REPLACE: + blend_fp = color_blend_true_color_replace; + break; default: LV_LOG_WARN("fill_blended: unsupported blend mode"); return; } - int32_t area_w = lv_area_get_width(fill_area); - int32_t area_h = lv_area_get_height(fill_area); - - int32_t x; - int32_t y; - /*Simple fill (maybe with opacity), no masking*/ if(mask == NULL) { - lv_color_t last_dest_color = lv_color_black(); - lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa); - for(y = 0; y < area_h; y++) { - for(x = 0; x < area_w; x++) { + lv_color_t last_dest_color = dest_buf[0]; + lv_color_t last_res_color = blend_fp(color, dest_buf[0], opa); + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(last_dest_color.full != dest_buf[x].full) { last_dest_color = dest_buf[x]; last_res_color = blend_fp(color, dest_buf[x], opa); @@ -381,19 +409,19 @@ static void fill_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv } /*Masked*/ else { - /*Buffer the result color to avoid recalculating the same color*/ lv_color_t last_dest_color; lv_color_t last_res_color; lv_opa_t last_mask = LV_OPA_TRANSP; - last_dest_color.full = dest_buf[0].full; - last_res_color.full = dest_buf[0].full; + last_dest_color = dest_buf[0]; + lv_opa_t opa_tmp = mask[0] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[0] * opa) >> 8; + last_res_color = blend_fp(color, last_dest_color, opa_tmp); - for(y = 0; y < area_h; y++) { - for(x = 0; x < area_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(mask[x] == 0) continue; if(mask[x] != last_mask || last_dest_color.full != dest_buf[x].full) { - lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[x] * opa) >> 8; + opa_tmp = mask[x] >= LV_OPA_MAX ? opa : (uint32_t)((uint32_t)mask[x] * opa) >> 8; last_res_color = blend_fp(color, dest_buf[x], opa_tmp); last_mask = mask[x]; @@ -402,86 +430,73 @@ static void fill_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv dest_buf[x] = last_res_color; } dest_buf += dest_stride; - mask += area_w; + mask += mask_stride; } } } #endif -static void map_set_px(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa) +static void map_set_px(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - int32_t clip_w = lv_area_get_width(clip_area); - int32_t clip_h = lv_area_get_height(clip_area); - - int32_t src_stride = lv_area_get_width(src_area); - - src_buf += src_stride * (clip_area->y1 - src_area->y1); - src_buf += (clip_area->x1 - src_area->x1); + int32_t w = lv_area_get_width(dest_area); + int32_t h = lv_area_get_height(dest_area); int32_t x; int32_t y; if(mask == NULL) { - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { - disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, clip_area->x1 + x, clip_area->y1 + y, src_buf[x], + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x], opa); } src_buf += src_stride; } } else { - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(mask[x]) { - disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, clip_area->x1 + x, clip_area->y1 + y, src_buf[x], + disp->driver->set_px_cb(disp->driver, (void *)dest_buf, dest_stride, dest_area->x1 + x, dest_area->y1 + y, src_buf[x], (uint32_t)((uint32_t)opa * mask[x]) >> 8); } } - mask += clip_w; + mask += mask_stride; src_buf += src_stride; } } } -LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa) +LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, const lv_opa_t * mask, lv_coord_t mask_stride) + { - int32_t clip_w = lv_area_get_width(clip_area); - int32_t clip_h = lv_area_get_height(clip_area); + int32_t w = lv_area_get_width(dest_area); + int32_t h = lv_area_get_height(dest_area); - int32_t src_stride = lv_area_get_width(src_area); - - dest_buf += dest_stride * clip_area->y1 + clip_area->x1; - - src_buf += src_stride * (clip_area->y1 - src_area->y1); - src_buf += (clip_area->x1 - src_area->x1); + int32_t x; + int32_t y; #if LV_COLOR_SCREEN_TRANSP lv_disp_t * disp = _lv_refr_get_disp_refreshing(); #endif - int32_t x; - int32_t y; - /*Simple fill (maybe with opacity), no masking*/ if(mask == NULL) { if(opa >= LV_OPA_MAX) { - for(y = 0; y < clip_h; y++) { - lv_memcpy(dest_buf, src_buf, clip_w * sizeof(lv_color_t)); + for(y = 0; y < h; y++) { + lv_memcpy(dest_buf, src_buf, w * sizeof(lv_color_t)); dest_buf += dest_stride; src_buf += src_stride; } } else { - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { #if LV_COLOR_SCREEN_TRANSP if(disp->driver->screen_transp) { lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa, &dest_buf[x], @@ -502,16 +517,16 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t d else { /*Only the mask matters*/ if(opa > LV_OPA_MAX) { - int32_t x_end4 = clip_w - 4; + int32_t x_end4 = w - 4; - for(y = 0; y < clip_h; y++) { + for(y = 0; y < h; y++) { const lv_opa_t * mask_tmp_x = mask; #if 0 - for(x = 0; x < clip_w; x++) { + for(x = 0; x < w; x++) { MAP_NORMAL_MASK_PX(x); } #else - for(x = 0; x < clip_w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { + for(x = 0; x < w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { #if LV_COLOR_SCREEN_TRANSP MAP_NORMAL_MASK_PX_SCR_TRANSP(x) #else @@ -547,7 +562,7 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t d } mask_tmp_x = (const lv_opa_t *)mask32; - for(; x < clip_w ; x++) { + for(; x < w ; x++) { #if LV_COLOR_SCREEN_TRANSP MAP_NORMAL_MASK_PX_SCR_TRANSP(x) #else @@ -557,19 +572,19 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t d #endif dest_buf += dest_stride; src_buf += src_stride; - mask += clip_w; + mask += mask_stride; } } /*Handle opa and mask values too*/ else { - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(mask[x]) { lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8); #if LV_COLOR_SCREEN_TRANSP if(disp->driver->screen_transp) { - lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp, &dest_buf[x], - &dest_buf[x].ch.alpha); + lv_color_mix_with_alpha(dest_buf[x], dest_buf[x].ch.alpha, src_buf[x], opa_tmp, + &dest_buf[x], &dest_buf[x].ch.alpha); } else #endif @@ -580,28 +595,25 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(lv_color_t * dest_buf, lv_coord_t d } dest_buf += dest_stride; src_buf += src_stride; - mask += clip_w; + mask += mask_stride; } } } } #if LV_DRAW_COMPLEX -static void map_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t mode) +static void map_blended(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa, + const lv_opa_t * mask, lv_coord_t mask_stride, lv_blend_mode_t blend_mode) { - int32_t clip_w = lv_area_get_width(clip_area); - int32_t clip_h = lv_area_get_height(clip_area); - int32_t src_stride = lv_area_get_width(src_area); + int32_t w = lv_area_get_width(dest_area); + int32_t h = lv_area_get_height(dest_area); - dest_buf += dest_stride * clip_area->y1 + clip_area->x1; - - src_buf += src_stride * (clip_area->y1 - src_area->y1); - src_buf += (clip_area->x1 - src_area->x1); + int32_t x; + int32_t y; lv_color_t (*blend_fp)(lv_color_t, lv_color_t, lv_opa_t); - switch(mode) { + switch(blend_mode) { case LV_BLEND_MODE_ADDITIVE: blend_fp = color_blend_true_color_additive; break; @@ -611,20 +623,20 @@ static void map_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_ case LV_BLEND_MODE_MULTIPLY: blend_fp = color_blend_true_color_multiply; break; + case LV_BLEND_MODE_REPLACE: + blend_fp = color_blend_true_color_replace; + break; default: LV_LOG_WARN("fill_blended: unsupported blend mode"); return; } - int32_t x; - int32_t y; - /*Simple fill (maybe with opacity), no masking*/ if(mask == NULL) { /*The map will be indexed from `draw_area->x1` so compensate it.*/ - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa); } dest_buf += dest_stride; @@ -633,15 +645,15 @@ static void map_blended(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_ } /*Masked*/ else { - for(y = 0; y < clip_h; y++) { - for(x = 0; x < clip_w; x++) { + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { if(mask[x] == 0) continue; lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8); dest_buf[x] = blend_fp(src_buf[x], dest_buf[x], opa_tmp); } dest_buf += dest_stride; src_buf += src_stride; - mask += clip_w; + mask += mask_stride; } } } @@ -748,5 +760,10 @@ static inline lv_color_t color_blend_true_color_multiply(lv_color_t fg, lv_color return lv_color_mix(fg, bg, opa); } +static inline lv_color_t color_blend_true_color_replace(lv_color_t fg, lv_color_t bg, lv_opa_t opa) +{ + return fg; +} + #endif diff --git a/src/draw/sw/lv_draw_sw_blend.h b/src/draw/sw/lv_draw_sw_blend.h new file mode 100644 index 000000000..293b50bcd --- /dev/null +++ b/src/draw/sw/lv_draw_sw_blend.h @@ -0,0 +1,69 @@ +/** + * @file lv_draw_sw_blend.h + * + */ + +#ifndef LV_DRAW_SW_BLEND_H +#define LV_DRAW_SW_BLEND_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../misc/lv_color.h" +#include "../../misc/lv_area.h" +#include "../../misc/lv_style.h" +#include "../lv_draw_mask.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + const lv_area_t * blend_area; /**< The area with absolute coordinates to draw on `draw_ctx->buf` + * will be clipped to draw_`ctx->clip_area` */ + const lv_color_t * src_buf; /**< Pointer to an image to blend. If set `fill_color is ignored`*/ + lv_color_t color; /**< Fill color*/ + lv_opa_t * mask; /**< NULL if ignored, or an alpha mask to apply on `blend_area`*/ + lv_draw_mask_res_t mask_res; /**< The result of the previous mask operation */ + const lv_area_t * mask_area; /**< The area of `mask_buf` with absolute coordinates*/ + lv_opa_t opa; /**< The overall opacity*/ + lv_blend_mode_t blend_mode; /**< E.g. LV_BLEND_MODE_ADDITIVE*/ +} lv_draw_sw_blend_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Call the blend function of the `draw_ctx`. + * @param draw_ctx pointer to a draw context + * @param dsc pointer to an initialized blend descriptor + */ +void lv_draw_sw_blend(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/** + * The basic blend function used with software rendering. + * @param draw_ctx pointer to a draw context + * @param dsc pointer to an initialized blend descriptor + */ +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SW_BLEND_H*/ diff --git a/src/draw/sw/lv_draw_sw_img.c b/src/draw/sw/lv_draw_sw_img.c index a00e8d70e..e01e8eae6 100644 --- a/src/draw/sw/lv_draw_sw_img.c +++ b/src/draw/sw/lv_draw_sw_img.c @@ -8,7 +8,6 @@ *********************/ #include "lv_draw_sw.h" #include "../lv_img_cache.h" -#include "../lv_draw_blend.h" #include "../../hal/lv_hal_disp.h" #include "../../misc/lv_log.h" #include "../../core/lv_refr.h" @@ -39,45 +38,35 @@ * GLOBAL FUNCTIONS **********************/ -LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_area_t * clip_area, - const uint8_t * map_p, - const lv_draw_img_dsc_t * draw_dsc, - bool chroma_key, bool alpha_byte) +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf) { /*Use the clip area as draw area*/ lv_area_t draw_area; - lv_area_copy(&draw_area, clip_area); + lv_area_copy(&draw_area, draw_ctx->clip_area); - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - const lv_area_t * disp_area = &draw_buf->area; + bool mask_any = lv_draw_mask_is_any(&draw_area); - /*Now `draw_area` has absolute coordinates. - *Make it relative to `disp_area` to simplify draw to `disp_buf`*/ - draw_area.x1 -= disp_area->x1; - draw_area.y1 -= disp_area->y1; - draw_area.x2 -= disp_area->x1; - draw_area.y2 -= disp_area->y1; - - bool mask_any = lv_draw_mask_is_any(clip_area); + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.opa = draw_dsc->opa; + blend_dsc.blend_mode = draw_dsc->blend_mode; /*The simplest case just copy the pixels into the draw_buf*/ if(!mask_any && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE && - chroma_key == false && alpha_byte == false && draw_dsc->recolor_opa == LV_OPA_TRANSP) { - lv_draw_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa, - draw_dsc->blend_mode); + cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) { + blend_dsc.blend_area = coords; + blend_dsc.src_buf = (const lv_color_t *)src_buf; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*In the other cases every pixel need to be checked one-by-one*/ else { //#if LV_DRAW_COMPLEX /*The pixel size in byte is different if an alpha byte is added too*/ - uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t); + uint8_t px_size_byte = cf == LV_IMG_CF_TRUE_COLOR_ALPHA ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t); /*Go to the first displayed pixel of the map*/ - int32_t map_w = lv_area_get_width(map_area); - const uint8_t * map_buf_tmp = map_p; - map_buf_tmp += map_w * (draw_area.y1 - (map_area->y1 - disp_area->y1)) * px_size_byte; - map_buf_tmp += (draw_area.x1 - (map_area->x1 - disp_area->x1)) * px_size_byte; + int32_t src_stride = lv_area_get_width(coords); lv_color_t c; lv_color_t chroma_keyed_color = LV_COLOR_CHROMA_KEY; @@ -89,47 +78,55 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a lv_coord_t draw_area_w = lv_area_get_width(&draw_area); lv_area_t blend_area; - blend_area.x1 = draw_area.x1 + disp_area->x1; - blend_area.x2 = blend_area.x1 + draw_area_w - 1; - blend_area.y1 = disp_area->y1 + draw_area.y1; + blend_area.x1 = draw_area.x1; + blend_area.x2 = draw_area.x2; + blend_area.y1 = draw_area.y1; blend_area.y2 = blend_area.y1; + blend_dsc.blend_area = &blend_area; bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false; /*Simple ARGB image. Handle it as special case because it's very common*/ - if(!mask_any && !transform && !chroma_key && draw_dsc->recolor_opa == LV_OPA_TRANSP && alpha_byte) { - uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(disp); + if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR_ALPHA && draw_dsc->recolor_opa == LV_OPA_TRANSP) { + uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing()); uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area); - lv_color_t * map2 = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); + lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); + blend_dsc.mask = mask_buf; + blend_dsc.mask_area = &blend_area; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.src_buf = src_buf_rgb; + + const uint8_t * src_buf_tmp = src_buf; + src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte; + src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte; int32_t x; int32_t y; for(y = 0; y < draw_area_h; y++) { - map_px = map_buf_tmp; + map_px = src_buf_tmp; for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) { lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; mask_buf[px_i] = px_opa; if(px_opa) { #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1 - map2[px_i].full = map_px[0]; + src_buf_rgb[px_i].full = map_px[0]; #elif LV_COLOR_DEPTH == 16 - map2[px_i].full = map_px[0] + (map_px[1] << 8); + src_buf_rgb[px_i].full = map_px[0] + (map_px[1] << 8); #elif LV_COLOR_DEPTH == 32 - map2[px_i].full = *((uint32_t *)map_px); + src_buf_rgb[px_i].full = *((uint32_t *)map_px); #endif } #if LV_COLOR_DEPTH == 32 - map2[px_i].ch.alpha = 0xFF; + src_buf_rgb[px_i].ch.alpha = 0xFF; #endif } - map_buf_tmp += map_w * px_size_byte; - if(px_i + draw_area_w < mask_buf_size) { + src_buf_tmp += src_stride * px_size_byte; + if(px_i + draw_area_w <= mask_buf_size) { blend_area.y2 ++; } else { - lv_draw_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, - draw_dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); blend_area.y1 = blend_area.y2 + 1; blend_area.y2 = blend_area.y1; @@ -140,34 +137,34 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a /*Flush the last part*/ if(blend_area.y1 != blend_area.y2) { blend_area.y2--; - lv_draw_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, - draw_dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } lv_mem_buf_release(mask_buf); - lv_mem_buf_release(map2); + lv_mem_buf_release(src_buf_rgb); } /*Most complicated case: transform or other mask or chroma keyed*/ else { /*Build the image and a mask line-by-line*/ - uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(disp); + uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing()); uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area); - lv_color_t * map2 = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); + lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); + blend_dsc.mask = mask_buf; + blend_dsc.mask_area = &blend_area; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.src_buf = src_buf_rgb; + const uint8_t * src_buf_tmp = NULL; #if LV_DRAW_COMPLEX lv_img_transform_dsc_t trans_dsc; lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t)); if(transform) { - lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR; - if(alpha_byte) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; - else if(chroma_key) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; - trans_dsc.cfg.angle = draw_dsc->angle; trans_dsc.cfg.zoom = draw_dsc->zoom; - trans_dsc.cfg.src = map_p; - trans_dsc.cfg.src_w = map_w; - trans_dsc.cfg.src_h = lv_area_get_height(map_area);; + trans_dsc.cfg.src = src_buf; + trans_dsc.cfg.src_w = src_stride; + trans_dsc.cfg.src_h = lv_area_get_height(coords); trans_dsc.cfg.cf = cf; trans_dsc.cfg.pivot_x = draw_dsc->pivot.x; trans_dsc.cfg.pivot_y = draw_dsc->pivot.y; @@ -176,6 +173,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a _lv_img_buf_transform_init(&trans_dsc); } + else { + src_buf_tmp = src_buf; + src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte; + src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte; + } #endif uint16_t recolor_premult[3] = {0}; lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa; @@ -183,9 +185,8 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult); } - lv_draw_mask_res_t mask_res; - mask_res = (alpha_byte || chroma_key || draw_dsc->angle || - draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; + blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle || + draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; /*Prepare the `mask_buf`if there are other masks*/ if(mask_any) { @@ -195,16 +196,16 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a int32_t x; int32_t y; #if LV_DRAW_COMPLEX - int32_t rot_y = disp_area->y1 + draw_area.y1 - map_area->y1; + int32_t rot_y = blend_area.y1 - coords->y1; #endif for(y = 0; y < draw_area_h; y++) { - map_px = map_buf_tmp; + map_px = src_buf_tmp; #if LV_DRAW_COMPLEX uint32_t px_i_start = px_i; - int32_t rot_x = disp_area->x1 + draw_area.x1 - map_area->x1; + int32_t rot_x = blend_area.x1 - coords->x1; #endif - for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) { + for(x = 0; x < draw_area_w; x++, px_i++, map_px += px_size_byte) { #if LV_DRAW_COMPLEX if(transform) { @@ -225,12 +226,12 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a else #endif { - if(alpha_byte) { + if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) { lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1]; mask_buf[px_i] = px_opa; if(px_opa == 0) { #if LV_COLOR_DEPTH == 32 - map2[px_i].full = 0; + src_buf_rgb[px_i].full = 0; #endif continue; } @@ -249,11 +250,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a c.full = *((uint32_t *)map_px); c.ch.alpha = 0xFF; #endif - if(chroma_key) { + if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { if(c.full == chroma_keyed_color.full) { mask_buf[px_i] = LV_OPA_TRANSP; #if LV_COLOR_DEPTH == 32 - map2[px_i].full = 0; + src_buf_rgb[px_i].full = 0; #endif continue; } @@ -264,39 +265,38 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv); } - map2[px_i].full = c.full; + src_buf_rgb[px_i].full = c.full; } #if LV_DRAW_COMPLEX /*Apply the masks if any*/ if(mask_any) { lv_draw_mask_res_t mask_res_sub; - mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, draw_area.x1 + draw_buf->area.x1, - y + draw_area.y1 + draw_buf->area.y1, - draw_area_w); + mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, blend_area.x1, + y + blend_area.y1, draw_area_w); if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(mask_buf + px_i_start, draw_area_w); - mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) { - mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } } #endif - map_buf_tmp += map_w * px_size_byte; + src_buf_tmp += src_stride * px_size_byte; if(px_i + draw_area_w < mask_buf_size) { blend_area.y2 ++; } else { - lv_draw_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); blend_area.y1 = blend_area.y2 + 1; blend_area.y2 = blend_area.y1; px_i = 0; - mask_res = (alpha_byte || chroma_key || draw_dsc->angle || - draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; + blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle || + draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; /*Prepare the `mask_buf`if there are other masks*/ if(mask_any) { @@ -308,11 +308,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img(const lv_area_t * map_area, const lv_a /*Flush the last part*/ if(blend_area.y1 != blend_area.y2) { blend_area.y2--; - lv_draw_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } lv_mem_buf_release(mask_buf); - lv_mem_buf_release(map2); + lv_mem_buf_release(src_buf_rgb); } } } diff --git a/src/draw/sw/lv_draw_sw_letter.c b/src/draw/sw/lv_draw_sw_letter.c index 2658c3eca..ac9279c77 100644 --- a/src/draw/sw/lv_draw_sw_letter.c +++ b/src/draw/sw/lv_draw_sw_letter.c @@ -7,7 +7,6 @@ * INCLUDES *********************/ #include "lv_draw_sw.h" -#include "../lv_draw_mask.h" #include "../../hal/lv_hal_disp.h" #include "../../misc/lv_math.h" #include "../../misc/lv_assert.h" @@ -15,12 +14,10 @@ #include "../../misc/lv_style.h" #include "../../font/lv_font.h" #include "../../core/lv_refr.h" -#include "../../draw/lv_draw_blend.h" /********************* * DEFINES *********************/ -#define MASK_BUF_MAX_SIZE 2048 /********************** * TYPEDEFS @@ -30,13 +27,13 @@ * STATIC PROTOTYPES **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, - const lv_area_t * clip_area, - const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); +LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, + const lv_point_t * pos, lv_font_glyph_dsc_t * g, const uint8_t * map_p); + #if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX -static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, - const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); +static void draw_letter_subpx(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos, + lv_font_glyph_dsc_t * g, const uint8_t * map_p); #endif /*LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX*/ /********************** @@ -95,21 +92,11 @@ const uint8_t _lv_bpp8_opa_table[256] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1 * @param color color of letter * @param opa opacity of letter (0..255) */ -LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, - uint32_t letter, - lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) +void lv_draw_sw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter) { - if(opa < LV_OPA_MIN) return; - if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; - - if(font_p == NULL) { - LV_LOG_WARN("lv_draw_letter: font is NULL"); - return; - } - lv_font_glyph_dsc_t g; - bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0'); + bool g_ret = lv_font_get_glyph_dsc(dsc->font, &g, letter, '\0'); if(g_ret == false) { /*Add warning if the dsc is not found *but do not print warning for non printable ASCII chars (e.g. '\n')*/ @@ -124,32 +111,33 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_letter(const lv_point_t * pos_p, const lv_ /*Don't draw anything if the character is empty. E.g. space*/ if((g.box_h == 0) || (g.box_w == 0)) return; - int32_t pos_x = pos_p->x + g.ofs_x; - int32_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y; + lv_point_t gpos; + gpos.x = pos_p->x + g.ofs_x; + gpos.y = pos_p->y + (dsc->font->line_height - dsc->font->base_line) - g.box_h - g.ofs_y; /*If the letter is completely out of mask don't draw it*/ - if(pos_x + g.box_w < clip_area->x1 || - pos_x > clip_area->x2 || - pos_y + g.box_h < clip_area->y1 || - pos_y > clip_area->y2) { + if(gpos.x + g.box_w < draw_ctx->clip_area->x1 || + gpos.x > draw_ctx->clip_area->x2 || + gpos.y + g.box_h < draw_ctx->clip_area->y1 || + gpos.y > draw_ctx->clip_area->y2) { return; } - const uint8_t * map_p = lv_font_get_glyph_bitmap(font_p, letter); + const uint8_t * map_p = lv_font_get_glyph_bitmap(g.resolved_font, letter); if(map_p == NULL) { LV_LOG_WARN("lv_draw_letter: character's bitmap not found"); return; } - if(font_p->subpx) { + if(g.resolved_font->subpx) { #if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX - draw_letter_subpx(pos_x, pos_y, &g, clip_area, map_p, color, opa, blend_mode); + draw_letter_subpx(draw_ctx, dsc, &gpos, &g, map_p); #else LV_LOG_WARN("Can't draw sub-pixel rendered letter because LV_USE_FONT_SUBPX == 0 in lv_conf.h"); #endif } else { - draw_letter_normal(pos_x, pos_y, &g, clip_area, map_p, color, opa, blend_mode); + draw_letter_normal(draw_ctx, dsc, &gpos, &g, map_p); } } @@ -157,14 +145,15 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_letter(const lv_point_t * pos_p, const lv_ * STATIC FUNCTIONS **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, - const lv_area_t * clip_area, - const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) +LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, + const lv_point_t * pos, lv_font_glyph_dsc_t * g, const uint8_t * map_p) { + const uint8_t * bpp_opa_table_p; uint32_t bitmask_init; uint32_t bitmask; uint32_t bpp = g->bpp; + lv_opa_t opa = dsc->opa; uint32_t shades; if(bpp == 3) bpp = 4; @@ -215,10 +204,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ int32_t width_bit = box_w * bpp; /*Letter width in bits*/ /*Calculate the col/row start/end on the map*/ - int32_t col_start = pos_x >= clip_area->x1 ? 0 : clip_area->x1 - pos_x; - int32_t col_end = pos_x + box_w <= clip_area->x2 ? box_w : clip_area->x2 - pos_x + 1; - int32_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; - int32_t row_end = pos_y + box_h <= clip_area->y2 ? box_h : clip_area->y2 - pos_y + 1; + int32_t col_start = pos->x >= draw_ctx->clip_area->x1 ? 0 : draw_ctx->clip_area->x1 - pos->x; + int32_t col_end = pos->x + box_w <= draw_ctx->clip_area->x2 ? box_w : draw_ctx->clip_area->x2 - pos->x + 1; + int32_t row_start = pos->y >= draw_ctx->clip_area->y1 ? 0 : draw_ctx->clip_area->y1 - pos->y; + int32_t row_end = pos->y + box_h <= draw_ctx->clip_area->y2 ? box_h : draw_ctx->clip_area->y2 - pos->y + 1; /*Move on the map too*/ uint32_t bit_ofs = (row_start * width_bit) + (col_start * bpp); @@ -228,22 +217,32 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ uint32_t col_bit; col_bit = bit_ofs & 0x7; /*"& 0x7" equals to "% 8" just faster*/ + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.color = dsc->color; + blend_dsc.opa = dsc->opa; + blend_dsc.blend_mode = dsc->blend_mode; + lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing()); uint32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : box_w * box_h; lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); + blend_dsc.mask = mask_buf; int32_t mask_p = 0; lv_area_t fill_area; - fill_area.x1 = col_start + pos_x; - fill_area.x2 = col_end + pos_x - 1; - fill_area.y1 = row_start + pos_y; + fill_area.x1 = col_start + pos->x; + fill_area.x2 = col_end + pos->x - 1; + fill_area.y1 = row_start + pos->y; fill_area.y2 = fill_area.y1; #if LV_DRAW_COMPLEX + lv_coord_t fill_w = lv_area_get_width(&fill_area); lv_area_t mask_area; lv_area_copy(&mask_area, &fill_area); mask_area.y2 = mask_area.y1 + row_end; bool mask_any = lv_draw_mask_is_any(&mask_area); #endif + blend_dsc.blend_area = &fill_area; + blend_dsc.mask_area = &fill_area; uint32_t col_bit_max = 8 - bpp; uint32_t col_bit_row_ofs = (box_w + col_start - col_end) * bpp; @@ -281,10 +280,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ #if LV_DRAW_COMPLEX /*Apply masks if any*/ if(mask_any) { - lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2, - lv_area_get_width(&fill_area)); - if(mask_res == LV_DRAW_MASK_RES_TRANSP) { - lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&fill_area)); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2, + fill_w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_TRANSP) { + lv_memset_00(mask_buf + mask_p_start, fill_w); } } #endif @@ -293,9 +292,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ fill_area.y2 ++; } else { - lv_draw_blend_fill(clip_area, &fill_area, - color, mask_buf, LV_DRAW_MASK_RES_CHANGED, LV_OPA_COVER, - blend_mode); + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); fill_area.y1 = fill_area.y2 + 1; fill_area.y2 = fill_area.y1; @@ -310,9 +308,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ /*Flush the last part*/ if(fill_area.y1 != fill_area.y2) { fill_area.y2--; - lv_draw_blend_fill(clip_area, &fill_area, - color, mask_buf, LV_DRAW_MASK_RES_CHANGED, LV_OPA_COVER, - blend_mode); + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); mask_p = 0; } @@ -320,13 +317,14 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_ } #if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX -static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area, - const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) +static void draw_letter_subpx(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos, + lv_font_glyph_dsc_t * g, const uint8_t * map_p) { const uint8_t * bpp_opa_table; uint32_t bitmask_init; uint32_t bitmask; uint32_t bpp = g->bpp; + lv_opa_t opa = dsc->opa; if(bpp == 3) bpp = 4; switch(bpp) { @@ -358,10 +356,10 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ int32_t width_bit = box_w * bpp; /*Letter width in bits*/ /*Calculate the col/row start/end on the map*/ - int32_t col_start = pos_x >= clip_area->x1 ? 0 : (clip_area->x1 - pos_x) * 3; - int32_t col_end = pos_x + box_w / 3 <= clip_area->x2 ? box_w : (clip_area->x2 - pos_x + 1) * 3; - int32_t row_start = pos_y >= clip_area->y1 ? 0 : clip_area->y1 - pos_y; - int32_t row_end = pos_y + box_h <= clip_area->y2 ? box_h : clip_area->y2 - pos_y + 1; + int32_t col_start = pos->x >= draw_ctx->clip_area->x1 ? 0 : (draw_ctx->clip_area->x1 - pos->x) * 3; + int32_t col_end = pos->x + box_w / 3 <= draw_ctx->clip_area->x2 ? box_w : (draw_ctx->clip_area->x2 - pos->x + 1) * 3; + int32_t row_start = pos->y >= draw_ctx->clip_area->y1 ? 0 : draw_ctx->clip_area->y1 - pos->y; + int32_t row_end = pos->y + box_h <= draw_ctx->clip_area->y2 ? box_h : draw_ctx->clip_area->y2 - pos->y + 1; /*Move on the map too*/ int32_t bit_ofs = (row_start * width_bit) + (col_start * bpp); @@ -373,30 +371,28 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ col_bit = bit_ofs & 0x7; /*"& 0x7" equals to "% 8" just faster*/ lv_area_t map_area; - map_area.x1 = col_start / 3 + pos_x; - map_area.x2 = col_end / 3 + pos_x - 1; - map_area.y1 = row_start + pos_y; + map_area.x1 = col_start / 3 + pos->x; + map_area.x2 = col_end / 3 + pos->x - 1; + map_area.y1 = row_start + pos->y; map_area.y2 = map_area.y1; if(map_area.x2 <= map_area.x1) return; - int32_t mask_buf_size = box_w * box_h > MASK_BUF_MAX_SIZE ? MASK_BUF_MAX_SIZE : g->box_w * g->box_h; + lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing()); + int32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : g->box_w * g->box_h; lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); int32_t mask_p = 0; lv_color_t * color_buf = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t)); - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - - int32_t disp_buf_width = lv_area_get_width(&draw_buf->area); - lv_color_t * disp_buf_buf_tmp = draw_buf->buf_act; + int32_t dest_buf_stride = lv_area_get_width(draw_ctx->buf_area); + lv_color_t * dest_buf_tmp = draw_ctx->buf; /*Set a pointer on draw_buf to the first pixel of the letter*/ - disp_buf_buf_tmp += ((pos_y - draw_buf->area.y1) * disp_buf_width) + pos_x - draw_buf->area.x1; + dest_buf_tmp += ((pos->y - draw_ctx->buf_area->y1) * dest_buf_stride) + pos->x - draw_ctx->buf_area->x1; /*If the letter is partially out of mask the move there on draw_buf*/ - disp_buf_buf_tmp += (row_start * disp_buf_width) + col_start / 3; + dest_buf_tmp += (row_start * dest_buf_stride) + col_start / 3; lv_area_t mask_area; lv_area_copy(&mask_area, &map_area); @@ -404,12 +400,22 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ bool mask_any = lv_draw_mask_is_any(&map_area); uint8_t font_rgb[3]; + lv_color_t color = dsc->color; #if LV_COLOR_16_SWAP == 0 uint8_t txt_rgb[3] = {color.ch.red, color.ch.green, color.ch.blue}; #else uint8_t txt_rgb[3] = {color.ch.red, (color.ch.green_h << 3) + color.ch.green_l, color.ch.blue}; #endif + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(&blend_dsc)); + blend_dsc.blend_area = &map_area; + blend_dsc.mask_area = &map_area; + blend_dsc.src_buf = color_buf; + blend_dsc.mask = mask_buf; + blend_dsc.opa = opa; + blend_dsc.blend_mode = dsc->blend_mode; + for(row = row_start ; row < row_end; row++) { uint32_t subpx_cnt = 0; bitmask = bitmask_init >> col_bit; @@ -419,7 +425,7 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ /*Load the pixel's opacity into the mask*/ letter_px = (*map_p & bitmask) >> (8 - col_bit - bpp); if(letter_px != 0) { - if(opa == LV_OPA_COVER) { + if(opa >= LV_OPA_MAX) { px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px]; } else { @@ -439,11 +445,11 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ lv_color_t res_color; #if LV_COLOR_16_SWAP == 0 - uint8_t bg_rgb[3] = {disp_buf_buf_tmp->ch.red, disp_buf_buf_tmp->ch.green, disp_buf_buf_tmp->ch.blue}; + uint8_t bg_rgb[3] = {dest_buf_tmp->ch.red, dest_buf_tmp->ch.green, dest_buf_tmp->ch.blue}; #else - uint8_t bg_rgb[3] = {disp_buf_buf_tmp->ch.red, - (disp_buf_buf_tmp->ch.green_h << 3) + disp_buf_buf_tmp->ch.green_l, - disp_buf_buf_tmp->ch.blue + uint8_t bg_rgb[3] = {dest_buf_tmp->ch.red, + (dest_buf_tmp->ch.green_h << 3) + dest_buf_tmp->ch.green_l, + dest_buf_tmp->ch.blue }; #endif @@ -473,7 +479,7 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ /*Next mask byte*/ mask_p++; - disp_buf_buf_tmp++; + dest_buf_tmp++; } /*Go to the next column*/ @@ -490,9 +496,9 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ /*Apply masks if any*/ if(mask_any) { - lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2, - lv_area_get_width(&map_area)); - if(mask_res == LV_DRAW_MASK_RES_TRANSP) { + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2, + lv_area_get_width(&map_area)); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&map_area)); } } @@ -501,7 +507,7 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ map_area.y2 ++; } else { - lv_draw_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); map_area.y1 = map_area.y2 + 1; map_area.y2 = map_area.y1; @@ -514,13 +520,13 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ col_bit = col_bit & 0x7; /*Next row in draw_buf*/ - disp_buf_buf_tmp += disp_buf_width - (col_end - col_start) / 3; + dest_buf_tmp += dest_buf_stride - (col_end - col_start) / 3; } /*Flush the last part*/ if(map_area.y1 != map_area.y2) { map_area.y2--; - lv_draw_blend_map(clip_area, &map_area, color_buf, mask_buf, LV_DRAW_MASK_RES_CHANGED, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } lv_mem_buf_release(mask_buf); diff --git a/src/draw/sw/lv_draw_sw_line.c b/src/draw/sw/lv_draw_sw_line.c index 7173501c0..c4fe5fe4d 100644 --- a/src/draw/sw/lv_draw_sw_line.c +++ b/src/draw/sw/lv_draw_sw_line.c @@ -23,16 +23,13 @@ * STATIC PROTOTYPES **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); +LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2); +LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2); +LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2); -LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); -LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc); /********************** * STATIC VARIABLES **********************/ @@ -52,8 +49,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const * @param clip the line will be drawn only in this area * @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable */ -LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2) { if(dsc->width == 0) return; if(dsc->opa <= LV_OPA_MIN) return; @@ -67,12 +64,14 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(const lv_point_t * point1, const lv_p clip_line.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2; bool is_common; - is_common = _lv_area_intersect(&clip_line, &clip_line, clip); + is_common = _lv_area_intersect(&clip_line, &clip_line, draw_ctx->clip_area); if(!is_common) return; + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_line; - if(point1->y == point2->y) draw_line_hor(point1, point2, &clip_line, dsc); - else if(point1->x == point2->x) draw_line_ver(point1, point2, &clip_line, dsc); - else draw_line_skew(point1, point2, &clip_line, dsc); + if(point1->y == point2->y) draw_line_hor(draw_ctx, dsc, point1, point2); + else if(point1->x == point2->x) draw_line_ver(draw_ctx, dsc, point1, point2); + else draw_line_skew(draw_ctx, dsc, point1, point2); if(dsc->round_end || dsc->round_start) { lv_draw_rect_dsc_t cir_dsc; @@ -90,7 +89,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(const lv_point_t * point1, const lv_p cir_area.y1 = point1->y - r; cir_area.x2 = point1->x + r - r_corr; cir_area.y2 = point1->y + r - r_corr ; - lv_draw_rect(&cir_area, clip, &cir_dsc); + lv_draw_rect(draw_ctx, &cir_dsc, &cir_area); } if(dsc->round_end) { @@ -98,9 +97,11 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(const lv_point_t * point1, const lv_p cir_area.y1 = point2->y - r; cir_area.x2 = point2->x + r - r_corr; cir_area.y2 = point2->y + r - r_corr ; - lv_draw_rect(&cir_area, clip, &cir_dsc); + lv_draw_rect(draw_ctx, &cir_dsc, &cir_area); } } + + draw_ctx->clip_area = clip_area_ori; } /********************** @@ -108,78 +109,65 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(const lv_point_t * point1, const lv_p **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2) { - lv_opa_t opa = dsc->opa; - int32_t w = dsc->width - 1; int32_t w_half0 = w >> 1; int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ - lv_area_t draw_area; - draw_area.x1 = LV_MIN(point1->x, point2->x); - draw_area.x2 = LV_MAX(point1->x, point2->x) - 1; - draw_area.y1 = point1->y - w_half1; - draw_area.y2 = point1->y + w_half0; + lv_area_t blend_area; + blend_area.x1 = LV_MIN(point1->x, point2->x); + blend_area.x2 = LV_MAX(point1->x, point2->x) - 1; + blend_area.y1 = point1->y - w_half1; + blend_area.y2 = point1->y + w_half0; + + bool is_common; + is_common = _lv_area_intersect(&blend_area, &blend_area, draw_ctx->clip_area); + if(!is_common) return; bool dashed = dsc->dash_gap && dsc->dash_width ? true : false; bool simple_mode = true; - if(lv_draw_mask_is_any(&draw_area)) simple_mode = false; + if(lv_draw_mask_is_any(&blend_area)) simple_mode = false; else if(dashed) simple_mode = false; + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.blend_area = &blend_area; + blend_dsc.color = dsc->color; + blend_dsc.opa = dsc->opa; /*If there is no mask then simply draw a rectangle*/ if(simple_mode) { - lv_draw_blend_fill(clip, &draw_area, - dsc->color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, - dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } #if LV_DRAW_COMPLEX /*If there other mask apply it*/ else { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - const lv_area_t * disp_area = &draw_buf->area; - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `fill_area`*/ - bool is_common; - is_common = _lv_area_intersect(&draw_area, clip, &draw_area); - if(!is_common) return; - /*Now `draw_area` has absolute coordinates. - *Make it relative to `disp_area` to simplify draw to `disp_buf`*/ - draw_area.x1 -= disp_area->x1; - draw_area.y1 -= disp_area->y1; - draw_area.x2 -= disp_area->x1; - draw_area.y2 -= disp_area->y1; + int32_t blend_area_w = lv_area_get_width(&blend_area); - int32_t draw_area_w = lv_area_get_width(&draw_area); - - lv_area_t fill_area; - fill_area.x1 = draw_area.x1 + disp_area->x1; - fill_area.x2 = draw_area.x2 + disp_area->x1; - fill_area.y1 = draw_area.y1 + disp_area->y1; - fill_area.y2 = fill_area.y1; + lv_coord_t y2 = blend_area.y2; + blend_area.y2 = blend_area.y1; lv_coord_t dash_start = 0; if(dashed) { - dash_start = (draw_buf->area.x1 + draw_area.x1) % (dsc->dash_gap + dsc->dash_width); + dash_start = (blend_area.x1) % (dsc->dash_gap + dsc->dash_width); } - lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w); + lv_opa_t * mask_buf = lv_mem_buf_get(blend_area_w); + blend_dsc.mask = mask_buf; + blend_dsc.mask_area = &blend_area; int32_t h; - for(h = draw_area.y1; h <= draw_area.y2; h++) { - lv_memset_ff(mask_buf, draw_area_w); - lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, - draw_area_w); + for(h = blend_area.y1; h <= y2; h++) { + lv_memset_ff(mask_buf, blend_area_w); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, blend_area_w); if(dashed) { - if(mask_res != LV_DRAW_MASK_RES_TRANSP) { + if(blend_dsc.mask_res != LV_DRAW_MASK_RES_TRANSP) { lv_coord_t dash_cnt = dash_start; lv_coord_t i; - for(i = 0; i < draw_area_w; i++, dash_cnt++) { + for(i = 0; i < blend_area_w; i++, dash_cnt++) { if(dash_cnt <= dsc->dash_width) { int16_t diff = dsc->dash_width - dash_cnt; i += diff; @@ -193,96 +181,81 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const } } - mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } } - lv_draw_blend_fill(clip, &fill_area, - dsc->color, mask_buf, mask_res, dsc->opa, - dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); - fill_area.y1++; - fill_area.y2++; + blend_area.y1++; + blend_area.y2++; } lv_mem_buf_release(mask_buf); } #endif /*LV_DRAW_COMPLEX*/ } -LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2) { - lv_opa_t opa = dsc->opa; - int32_t w = dsc->width - 1; int32_t w_half0 = w >> 1; int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ - lv_area_t draw_area; - draw_area.x1 = point1->x - w_half1; - draw_area.x2 = point1->x + w_half0; - draw_area.y1 = LV_MIN(point1->y, point2->y); - draw_area.y2 = LV_MAX(point1->y, point2->y) - 1; + lv_area_t blend_area; + blend_area.x1 = point1->x - w_half1; + blend_area.x2 = point1->x + w_half0; + blend_area.y1 = LV_MIN(point1->y, point2->y); + blend_area.y2 = LV_MAX(point1->y, point2->y) - 1; + + bool is_common; + is_common = _lv_area_intersect(&blend_area, &blend_area, draw_ctx->clip_area); + if(!is_common) return; bool dashed = dsc->dash_gap && dsc->dash_width ? true : false; bool simple_mode = true; - if(lv_draw_mask_is_any(&draw_area)) simple_mode = false; + if(lv_draw_mask_is_any(&blend_area)) simple_mode = false; else if(dashed) simple_mode = false; + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.blend_area = &blend_area; + blend_dsc.color = dsc->color; + blend_dsc.opa = dsc->opa; + /*If there is no mask then simply draw a rectangle*/ if(simple_mode) { - lv_draw_blend_fill(clip, &draw_area, - dsc->color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, - dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } #if LV_DRAW_COMPLEX /*If there other mask apply it*/ else { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - const lv_area_t * disp_area = &draw_buf->area; - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `fill_area`*/ - bool is_common; - is_common = _lv_area_intersect(&draw_area, clip, &draw_area); - if(!is_common) return; + int32_t draw_area_w = lv_area_get_width(&blend_area); - /*Now `draw_area` has absolute coordinates. - *Make it relative to `disp_area` to simplify draw to `disp_buf`*/ - draw_area.x1 -= draw_buf->area.x1; - draw_area.y1 -= draw_buf->area.y1; - draw_area.x2 -= draw_buf->area.x1; - draw_area.y2 -= draw_buf->area.y1; - - int32_t draw_area_w = lv_area_get_width(&draw_area); - - lv_area_t fill_area; - fill_area.x1 = draw_area.x1 + disp_area->x1; - fill_area.x2 = draw_area.x2 + disp_area->x1; - fill_area.y1 = draw_area.y1 + disp_area->y1; - fill_area.y2 = fill_area.y1; + lv_coord_t y2 = blend_area.y2; + blend_area.y2 = blend_area.y1; lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w); + blend_dsc.mask = mask_buf; + blend_dsc.mask_area = &blend_area; lv_coord_t dash_start = 0; if(dashed) { - dash_start = (draw_buf->area.y1 + draw_area.y1) % (dsc->dash_gap + dsc->dash_width); + dash_start = (blend_area.y1) % (dsc->dash_gap + dsc->dash_width); } lv_coord_t dash_cnt = dash_start; int32_t h; - for(h = draw_area.y1; h <= draw_area.y2; h++) { + for(h = blend_area.y1; h <= y2; h++) { lv_memset_ff(mask_buf, draw_area_w); - lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, - draw_area_w); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, draw_area_w); if(dashed) { - if(mask_res != LV_DRAW_MASK_RES_TRANSP) { + if(blend_dsc.mask_res != LV_DRAW_MASK_RES_TRANSP) { if(dash_cnt > dsc->dash_width) { - mask_res = LV_DRAW_MASK_RES_TRANSP; + blend_dsc.mask_res = LV_DRAW_MASK_RES_TRANSP; } if(dash_cnt >= dsc->dash_gap + dsc->dash_width) { @@ -292,21 +265,18 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const dash_cnt ++; } - lv_draw_blend_fill(clip, &fill_area, - dsc->color, mask_buf, mask_res, dsc->opa, - LV_BLEND_MODE_NORMAL); + lv_draw_sw_blend(draw_ctx, &blend_dsc); - fill_area.y1++; - fill_area.y2++; + blend_area.y1++; + blend_area.y2++; } lv_mem_buf_release(mask_buf); } #endif /*LV_DRAW_COMPLEX*/ } -LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, - const lv_area_t * clip, - const lv_draw_line_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2) { #if LV_DRAW_COMPLEX /*Keep the great y in p1*/ @@ -346,16 +316,16 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, cons int32_t w_half0 = w >> 1; int32_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/ - lv_area_t draw_area; - draw_area.x1 = LV_MIN(p1.x, p2.x) - w; - draw_area.x2 = LV_MAX(p1.x, p2.x) + w; - draw_area.y1 = LV_MIN(p1.y, p2.y) - w; - draw_area.y2 = LV_MAX(p1.y, p2.y) + w; + lv_area_t blend_area; + blend_area.x1 = LV_MIN(p1.x, p2.x) - w; + blend_area.x2 = LV_MAX(p1.x, p2.x) + w; + blend_area.y1 = LV_MIN(p1.y, p2.y) - w; + blend_area.y2 = LV_MAX(p1.y, p2.y) + w; /*Get the union of `coords` and `clip`*/ /*`clip` is already truncated to the `draw_buf` size *in 'lv_refr_area' function*/ - bool is_common = _lv_area_intersect(&draw_area, &draw_area, clip); + bool is_common = _lv_area_intersect(&blend_area, &blend_area, draw_ctx->clip_area); if(is_common == false) return; lv_draw_mask_line_param_t mask_left_param; @@ -398,70 +368,58 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, cons mask_bottom_id = lv_draw_mask_add(&mask_bottom_param, NULL); } - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp); - - const lv_area_t * disp_area = &draw_buf->area; - - /*Store the coordinates of the `draw_a` relative to the draw_buf*/ - draw_area.x1 -= disp_area->x1; - draw_area.y1 -= disp_area->y1; - draw_area.x2 -= disp_area->x1; - draw_area.y2 -= disp_area->y1; - /*The real draw area is around the line. *It's easy to calculate with steep lines, but the area can be very wide with very flat lines. *So deal with it only with steep lines.*/ - int32_t draw_area_w = lv_area_get_width(&draw_area); + int32_t draw_area_w = lv_area_get_width(&blend_area); /*Draw the background line by line*/ int32_t h; - uint32_t hor_res = (uint32_t)lv_disp_get_hor_res(disp); - size_t mask_buf_size = LV_MIN(lv_area_get_size(&draw_area), hor_res); + uint32_t hor_res = (uint32_t)lv_disp_get_hor_res(_lv_refr_get_disp_refreshing()); + size_t mask_buf_size = LV_MIN(lv_area_get_size(&blend_area), hor_res); lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size); - lv_area_t fill_area; - fill_area.x1 = draw_area.x1 + disp_area->x1; - fill_area.x2 = draw_area.x2 + disp_area->x1; - fill_area.y1 = draw_area.y1 + disp_area->y1; - fill_area.y2 = fill_area.y1; - - int32_t x = draw_buf->area.x1 + draw_area.x1; + lv_coord_t y2 = blend_area.y2; + blend_area.y2 = blend_area.y1; uint32_t mask_p = 0; - lv_memset_ff(mask_buf, mask_buf_size); - /*Fill the first row with 'color'*/ - for(h = draw_area.y1 + disp_area->y1; h <= draw_area.y2 + disp_area->y1; h++) { - lv_draw_mask_res_t mask_res = lv_draw_mask_apply(&mask_buf[mask_p], x, h, draw_area_w); - if(mask_res == LV_DRAW_MASK_RES_TRANSP) { + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.blend_area = &blend_area; + blend_dsc.color = dsc->color; + blend_dsc.opa = dsc->opa; + blend_dsc.mask = mask_buf; + blend_dsc.mask_area = &blend_area; + + /*Fill the first row with 'color'*/ + for(h = blend_area.y1; h <= y2; h++) { + blend_dsc.mask_res = lv_draw_mask_apply(&mask_buf[mask_p], blend_area.x1, h, draw_area_w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[mask_p], draw_area_w); } mask_p += draw_area_w; if((uint32_t) mask_p + draw_area_w < mask_buf_size) { - fill_area.y2 ++; + blend_area.y2 ++; } else { - lv_draw_blend_fill(&fill_area, clip, - dsc->color, mask_buf, LV_DRAW_MASK_RES_CHANGED, dsc->opa, - dsc->blend_mode); + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); - fill_area.y1 = fill_area.y2 + 1; - fill_area.y2 = fill_area.y1; + blend_area.y1 = blend_area.y2 + 1; + blend_area.y2 = blend_area.y1; mask_p = 0; lv_memset_ff(mask_buf, mask_buf_size); } } /*Flush the last part*/ - if(fill_area.y1 != fill_area.y2) { - fill_area.y2--; - lv_draw_blend_fill(&fill_area, clip, - dsc->color, mask_buf, LV_DRAW_MASK_RES_CHANGED, dsc->opa, - dsc->blend_mode); - + if(blend_area.y1 != blend_area.y2) { + blend_area.y2--; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } lv_mem_buf_release(mask_buf); @@ -477,7 +435,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, cons #else LV_UNUSED(point1); LV_UNUSED(point2); - LV_UNUSED(clip); + LV_UNUSED(draw_ctx); LV_UNUSED(dsc); LV_LOG_WARN("Can't draw skewed line with LV_DRAW_COMPLEX == 0"); #endif /*LV_DRAW_COMPLEX*/ diff --git a/src/draw/sw/lv_draw_sw_polygon.c b/src/draw/sw/lv_draw_sw_polygon.c index 696ed45d1..717728130 100644 --- a/src/draw/sw/lv_draw_sw_polygon.c +++ b/src/draw/sw/lv_draw_sw_polygon.c @@ -12,7 +12,6 @@ #include "../../misc/lv_area.h" #include "../../misc/lv_color.h" #include "../lv_draw_rect.h" -#include "../lv_draw_mask.h" /********************* * DEFINES @@ -45,8 +44,8 @@ * @param clip_area polygon will be drawn only in this area * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable */ -void lv_draw_sw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * draw_dsc) +void lv_draw_sw_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 LV_DRAW_COMPLEX if(point_cnt < 3) return; @@ -86,12 +85,16 @@ void lv_draw_sw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_ } bool is_common; - lv_area_t poly_mask; - is_common = _lv_area_intersect(&poly_mask, &poly_coords, clip_area); + lv_area_t clip_area; + is_common = _lv_area_intersect(&clip_area, &poly_coords, draw_ctx->clip_area); if(!is_common) { lv_mem_buf_release(p); return; } + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; + /*Find the lowest point*/ lv_coord_t y_min = p[0].y; int16_t y_min_i = 0; @@ -182,16 +185,18 @@ void lv_draw_sw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_ } while(mask_cnt < point_cnt); - lv_draw_rect(&poly_coords, clip_area, draw_dsc); + lv_draw_rect(draw_ctx, draw_dsc, &poly_coords); lv_draw_mask_remove_custom(mp); lv_mem_buf_release(mp); lv_mem_buf_release(p); + + draw_ctx->clip_area = clip_area_ori; #else LV_UNUSED(points); LV_UNUSED(point_cnt); - LV_UNUSED(clip_area); + LV_UNUSED(draw_ctx); LV_UNUSED(draw_dsc); LV_LOG_WARN("Can't draw polygon with LV_DRAW_COMPLEX == 0"); #endif /*LV_DRAW_COMPLEX*/ diff --git a/src/draw/sw/lv_draw_sw_rect.c b/src/draw/sw/lv_draw_sw_rect.c index 2b8b2aa96..64d871d7f 100644 --- a/src/draw/sw/lv_draw_sw_rect.c +++ b/src/draw/sw/lv_draw_sw_rect.c @@ -26,27 +26,24 @@ /********************** * STATIC PROTOTYPES **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * dsc); -LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc); -LV_ATTRIBUTE_FAST_MEM static void draw_border(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc); +static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +static void draw_bg_img(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +static void draw_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); -static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); +static void draw_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); #if LV_DRAW_COMPLEX -LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc); +LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords); LV_ATTRIBUTE_FAST_MEM static void shadow_draw_corner_buf(const lv_area_t * coords, uint16_t * sh_buf, lv_coord_t s, lv_coord_t r); LV_ATTRIBUTE_FAST_MEM static void shadow_blur_corner(lv_coord_t size, lv_coord_t sw, uint16_t * sh_ups_buf); #endif -void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_area, const lv_area_t * inner_area, +void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout, lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode); -static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_area, const lv_area_t * inner_area, +static void draw_border_simple(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, lv_opa_t opa); #if LV_DRAW_COMPLEX @@ -70,25 +67,18 @@ static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_a * GLOBAL FUNCTIONS **********************/ -/** - * Draw a rectangle - * @param coords the coordinates of the rectangle - * @param mask the rectangle will be drawn only in this mask - * @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable - */ -void lv_draw_sw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +void lv_draw_sw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { - if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return; #if LV_DRAW_COMPLEX - draw_shadow(coords, clip, dsc); + draw_shadow(draw_ctx, dsc, coords); #endif - draw_bg(coords, clip, dsc); - draw_bg_img(coords, clip, dsc); + draw_bg(draw_ctx, dsc, coords); + draw_bg_img(draw_ctx, dsc, coords); - draw_border(coords, clip, dsc); + draw_border(draw_ctx, dsc, coords); - draw_outline(coords, clip, dsc); + draw_outline(draw_ctx, dsc, coords); LV_ASSERT_MEM_INTEGRITY(); } @@ -97,32 +87,39 @@ void lv_draw_sw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_ * STATIC FUNCTIONS **********************/ -LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, - const lv_draw_rect_dsc_t * dsc) +static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { if(dsc->bg_opa <= LV_OPA_MIN) return; - lv_area_t coords_bg; - lv_area_copy(&coords_bg, coords); + lv_area_t bg_coords; + lv_area_copy(&bg_coords, coords); /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/ if(dsc->border_width > 1 && dsc->border_opa >= LV_OPA_MAX && dsc->radius != 0) { - coords_bg.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; - coords_bg.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; - coords_bg.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; - coords_bg.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; + bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; + bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; + bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; + bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; } - lv_opa_t opa = dsc->bg_opa >= LV_OPA_MAX ? LV_OPA_COVER : dsc->bg_opa; + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, &bg_coords, draw_ctx->clip_area)) return; + lv_grad_dir_t grad_dir = dsc->bg_grad_dir; if(dsc->bg_color.full == dsc->bg_grad_color.full) grad_dir = LV_GRAD_DIR_NONE; - bool mask_any = lv_draw_mask_is_any(&coords_bg); + bool mask_any = lv_draw_mask_is_any(&bg_coords); /*Most simple case: just a plain rectangle*/ if(!mask_any && dsc->radius == 0 && (grad_dir == LV_GRAD_DIR_NONE)) { - lv_draw_blend_fill(clip_area, &coords_bg, dsc->bg_color, NULL, - LV_DRAW_MASK_RES_FULL_COVER, opa, dsc->blend_mode); + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t)); + blend_dsc.blend_mode = dsc->blend_mode; + blend_dsc.color = dsc->bg_color; + blend_dsc.blend_area = &bg_coords; + blend_dsc.opa = dsc->bg_opa; + + lv_draw_sw_blend(draw_ctx, &blend_dsc); return; } @@ -130,152 +127,138 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are #if LV_DRAW_COMPLEX == 0 LV_LOG_WARN("Can't draw complex rectangle because LV_DRAW_COMPLEX = 0"); #else - /*Get clipped fill area which is the real draw area. - *It is always the same or inside `fill_area`*/ - lv_area_t draw_area; - if(!_lv_area_intersect(&draw_area, &coords_bg, clip_area)) return; + lv_opa_t opa = dsc->bg_opa >= LV_OPA_MAX ? LV_OPA_COVER : dsc->bg_opa; /*Get the real radius. Can't be larger than the half of the shortest side */ - lv_coord_t coords_w = lv_area_get_width(&coords_bg); - lv_coord_t coords_h = lv_area_get_height(&coords_bg); - int32_t short_side = LV_MIN(coords_w, coords_h); + lv_coord_t coords_bg_w = lv_area_get_width(&bg_coords); + lv_coord_t coords_bg_h = lv_area_get_height(&bg_coords); + int32_t short_side = LV_MIN(coords_bg_w, coords_bg_h); int32_t rout = LV_MIN(dsc->radius, short_side >> 1); /*Add a radius mask if there is radius*/ - int32_t draw_area_w = lv_area_get_width(&draw_area); + int32_t clipped_w = lv_area_get_width(&clipped_coords); int16_t mask_rout_id = LV_MASK_ID_INV; lv_opa_t * mask_buf = NULL; lv_draw_mask_radius_param_t mask_rout_param; if(rout > 0 || mask_any) { - mask_buf = lv_mem_buf_get(draw_area_w); - lv_draw_mask_radius_init(&mask_rout_param, &coords_bg, rout, false); + mask_buf = lv_mem_buf_get(clipped_w); + lv_draw_mask_radius_init(&mask_rout_param, &bg_coords, rout, false); mask_rout_id = lv_draw_mask_add(&mask_rout_param, NULL); } + int32_t h; + + lv_area_t blend_area; + blend_area.x1 = clipped_coords.x1; + blend_area.x2 = clipped_coords.x2; + + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t)); + blend_dsc.blend_mode = dsc->blend_mode; + blend_dsc.color = dsc->bg_color; + blend_dsc.mask = mask_buf; + blend_dsc.opa = LV_OPA_COVER; + blend_dsc.blend_area = &blend_area; + blend_dsc.mask_area = &blend_area; + /*In case of horizontal gradient pre-compute a line with a gradient*/ lv_color_t * grad_map = NULL; lv_color_t * grad_map_ofs = NULL; if(grad_dir == LV_GRAD_DIR_HOR) { - grad_map = lv_mem_buf_get(coords_w * sizeof(lv_color_t)); + grad_map = lv_mem_buf_get(coords_bg_w * sizeof(lv_color_t)); int32_t i; - for(i = 0; i < coords_w; i++) { - grad_map[i] = grad_get(dsc, coords_w, i); - } - grad_map_ofs = grad_map; - if(dsc->bg_grad_dir == LV_GRAD_DIR_HOR) grad_map_ofs += draw_area.x1 - coords_bg.x1; - } + for(i = 0; i < coords_bg_w; i++) grad_map[i] = grad_get(dsc, coords_bg_w, i); - int32_t h; - lv_draw_mask_res_t mask_res; - lv_area_t blend_area; - blend_area.x1 = draw_area.x1; - blend_area.x2 = draw_area.x2; + grad_map_ofs = grad_map; + if(dsc->bg_grad_dir == LV_GRAD_DIR_HOR) grad_map_ofs += clipped_coords.x1 - bg_coords.x1; + blend_dsc.src_buf = grad_map_ofs; + } /*There is another mask too. Draw line by line. */ if(mask_any) { - for(h = draw_area.y1; h <= draw_area.y2; h++) { + for(h = clipped_coords.y1; h <= clipped_coords.y2; h++) { blend_area.y1 = h; blend_area.y2 = h; /* Initialize the mask to opa instead of 0xFF and blend with LV_OPA_COVER. - * It saves calculating the final opa in lv_draw_blend_fill*/ - lv_memset(mask_buf, opa, draw_area_w); - mask_res = lv_draw_mask_apply(mask_buf, draw_area.x1, h, draw_area_w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + * It saves calculating the final opa in lv_draw_sw_blend*/ + lv_memset(mask_buf, opa, clipped_w); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clipped_coords.x1, h, clipped_w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; - if(grad_dir == LV_GRAD_DIR_NONE) { - lv_draw_blend_fill(clip_area, &blend_area, dsc->bg_color, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_HOR) { - lv_draw_blend_map(clip_area, &blend_area, grad_map_ofs, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_VER) { - lv_color_t c = grad_get(dsc, coords_h, h - coords_bg.y1); - lv_draw_blend_fill(clip_area, &blend_area, c, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } + if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad_get(dsc, coords_bg_h, h - bg_coords.y1); + + lv_draw_sw_blend(draw_ctx, &blend_dsc); } goto bg_clean_up; } - /* Draw the top of the rectangle line by line and mirror it to the bottom. - * If there is no radius this cycle won't run because `h` is always `>= h_end`*/ - blend_area.x1 = draw_area.x1; - blend_area.x2 = draw_area.x2; + /* Draw the top of the rectangle line by line and mirror it to the bottom. */ for(h = 0; h < rout; h++) { - lv_coord_t top_y = coords_bg.y1 + h; - lv_coord_t bottom_y = coords_bg.y2 - h; - if(top_y < draw_area.y1 && bottom_y > draw_area.y2) continue; /*This line is clipped now*/ + lv_coord_t top_y = bg_coords.y1 + h; + lv_coord_t bottom_y = bg_coords.y2 - h; + if(top_y < clipped_coords.y1 && bottom_y > clipped_coords.y2) continue; /*This line is clipped now*/ /* Initialize the mask to opa instead of 0xFF and blend with LV_OPA_COVER. - * It saves calculating the final opa in lv_draw_blend_fill*/ - lv_memset(mask_buf, opa, draw_area_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, top_y, draw_area_w); + * It saves calculating the final opa in lv_draw_sw_blend*/ + lv_memset(mask_buf, opa, clipped_w); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, top_y, clipped_w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; - if(top_y >= draw_area.y1) { + if(top_y >= clipped_coords.y1) { blend_area.y1 = top_y; blend_area.y2 = top_y; - if(grad_dir == LV_GRAD_DIR_NONE) { - lv_draw_blend_fill(clip_area, &blend_area, dsc->bg_color, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_HOR) { - lv_draw_blend_map(clip_area, &blend_area, grad_map_ofs, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_VER) { - lv_color_t c = grad_get(dsc, coords_h, top_y - coords_bg.y1); - lv_draw_blend_fill(clip_area, &blend_area, c, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } + if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad_get(dsc, coords_bg_h, top_y - bg_coords.y1); + + lv_draw_sw_blend(draw_ctx, &blend_dsc); } - if(bottom_y <= draw_area.y2) { + if(bottom_y <= clipped_coords.y2) { blend_area.y1 = bottom_y; blend_area.y2 = bottom_y; - if(grad_dir == LV_GRAD_DIR_NONE) { - lv_draw_blend_fill(clip_area, &blend_area, dsc->bg_color, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_HOR) { - lv_draw_blend_map(clip_area, &blend_area, grad_map_ofs, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_VER) { - lv_color_t c = grad_get(dsc, coords_h, bottom_y - coords_bg.y1); - lv_draw_blend_fill(clip_area, &blend_area, c, mask_buf, mask_res, LV_OPA_COVER, dsc->blend_mode); - } + if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad_get(dsc, coords_bg_h, bottom_y - bg_coords.y1); + + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } /* Draw the center of the rectangle.*/ /*If no other masks and no gradient, the center is a simple rectangle*/ - if(!mask_any && grad_dir == LV_GRAD_DIR_NONE) { - blend_area.y1 = coords_bg.y1 + rout; - blend_area.y2 = coords_bg.y2 - rout; - lv_draw_blend_fill(clip_area, &blend_area, dsc->bg_color, mask_buf, LV_DRAW_MASK_RES_FULL_COVER, opa, dsc->blend_mode); + lv_area_t center_coords; + center_coords.x1 = bg_coords.x1; + center_coords.x2 = bg_coords.x2; + center_coords.y1 = bg_coords.y1 + rout; + center_coords.y2 = bg_coords.y2 - rout; + bool mask_any_center = lv_draw_mask_is_any(¢er_coords); + if(!mask_any_center && grad_dir == LV_GRAD_DIR_NONE) { + blend_area.y1 = bg_coords.y1 + rout; + blend_area.y2 = bg_coords.y2 - rout; + blend_dsc.opa = opa; + blend_dsc.mask = NULL; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*With gradient and/or mask draw line by line*/ else { - mask_res = LV_DRAW_MASK_RES_FULL_COVER; - int32_t h_end = coords_bg.y2 - rout; - for(h = coords_bg.y1 + rout; h <= h_end; h++) { + blend_dsc.opa = opa; + blend_dsc.mask_res = LV_DRAW_MASK_RES_FULL_COVER; + int32_t h_end = bg_coords.y2 - rout; + for(h = bg_coords.y1 + rout; h <= h_end; h++) { /*If there is no other mask do not apply mask as in the center there is no radius to mask*/ - if(mask_any) { - lv_memset_ff(mask_buf, draw_area_w); - mask_res = lv_draw_mask_apply(mask_buf, draw_area.x1, h, draw_area_w); + if(mask_any_center) { + lv_memset(mask_buf, opa, clipped_w); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clipped_coords.x1, h, clipped_w); } blend_area.y1 = h; blend_area.y2 = h; - if(grad_dir == LV_GRAD_DIR_NONE) { - lv_draw_blend_fill(clip_area, &blend_area, dsc->bg_color, mask_buf, mask_res, opa, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_HOR) { - lv_draw_blend_map(clip_area, &blend_area, grad_map_ofs, mask_buf, mask_res, opa, dsc->blend_mode); - } - else if(grad_dir == LV_GRAD_DIR_VER) { - lv_color_t c = grad_get(dsc, coords_h, h - coords_bg.y1); - lv_draw_blend_fill(clip_area, &blend_area, c, mask_buf, mask_res, opa, dsc->blend_mode); - } + + if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad_get(dsc, coords_bg_h, h - bg_coords.y1); + + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } @@ -291,8 +274,7 @@ bg_clean_up: #endif } -LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc) +static void draw_bg_img(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { if(dsc->bg_img_src == NULL) return; if(dsc->bg_img_opa <= LV_OPA_MIN) return; @@ -312,7 +294,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv label_draw_dsc.font = dsc->bg_img_symbol_font; label_draw_dsc.color = dsc->bg_img_recolor; label_draw_dsc.opa = dsc->bg_img_opa; - lv_draw_label(&a, clip, &label_draw_dsc, dsc->bg_img_src, NULL); + lv_draw_label(draw_ctx, &label_draw_dsc, &a, dsc->bg_img_src, NULL); } else { lv_img_header_t header; @@ -337,7 +319,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv area.x2 = area.x1 + header.w - 1; area.y2 = area.y1 + header.h - 1; - lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &area, dsc->bg_img_src); } else { lv_area_t area; @@ -349,15 +331,14 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv area.x1 = coords->x1; area.x2 = area.x1 + header.w - 1; for(; area.x1 <= coords->x2; area.x1 += header.w, area.x2 += header.w) { - lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &area, dsc->bg_img_src); } } } } } -LV_ATTRIBUTE_FAST_MEM static void draw_border(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc) +static void draw_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { if(dsc->border_opa <= LV_OPA_MIN) return; if(dsc->border_width == 0) return; @@ -381,7 +362,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_border(const lv_area_t * coords, const lv lv_coord_t rin = rout - dsc->border_width; if(rin < 0) rin = 0; - draw_border_generic(clip, coords, &area_inner, rout, rin, dsc->border_color, dsc->border_opa, dsc->blend_mode); + draw_border_generic(draw_ctx, coords, &area_inner, rout, rin, dsc->border_color, dsc->border_opa, dsc->blend_mode); } @@ -402,8 +383,8 @@ LV_ATTRIBUTE_FAST_MEM static inline lv_color_t grad_get(const lv_draw_rect_dsc_t return lv_color_mix(dsc->bg_grad_color, dsc->bg_color, mix); } -LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, - const lv_draw_rect_dsc_t * dsc) +LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords) { /*Check whether the shadow is visible*/ if(dsc->shadow_width == 0) return; @@ -434,7 +415,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Get clipped draw area which is the real draw area. *It is always the same or inside `shadow_area`*/ lv_area_t draw_area; - if(!_lv_area_intersect(&draw_area, &shadow_area, clip)) return; + if(!_lv_area_intersect(&draw_area, &shadow_area, draw_ctx->clip_area)) return; /*Consider 1 px smaller bg to be sure the edge will be covered by the shadow*/ lv_area_t bg_area; @@ -482,10 +463,9 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Skip a lot of masking if the background will cover the shadow that would be masked out*/ bool mask_any = lv_draw_mask_is_any(&shadow_area); bool simple = true; - if(mask_any || dsc->bg_opa < LV_OPA_COVER) simple = false; + if(mask_any || dsc->bg_opa < LV_OPA_COVER || dsc->blend_mode != LV_BLEND_MODE_NORMAL) simple = false; /*Create a radius mask to clip remove shadow on the bg area*/ - lv_draw_mask_res_t mask_res; lv_draw_mask_radius_param_t mask_rout_param; int16_t mask_rout_id = LV_MASK_ID_INV; @@ -496,11 +476,19 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv lv_opa_t * mask_buf = lv_mem_buf_get(lv_area_get_width(&shadow_area)); lv_area_t blend_area; lv_area_t clip_area_sub; - lv_opa_t ** mask_act; lv_opa_t * sh_buf_tmp; lv_coord_t y; bool simple_sub; + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.blend_area = &blend_area; + blend_dsc.mask_area = &blend_area; + blend_dsc.mask = mask_buf; + blend_dsc.color = dsc->shadow_color; + blend_dsc.opa = dsc->shadow_opa; + blend_dsc.blend_mode = dsc->blend_mode; + lv_coord_t w_half = shadow_area.x1 + lv_area_get_width(&shadow_area) / 2; lv_coord_t h_half = shadow_area.y1 + lv_area_get_height(&shadow_area) / 2; @@ -511,11 +499,12 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.x1 = shadow_area.x2 - corner_size + 1; blend_area.y1 = shadow_area.y1; blend_area.y2 = shadow_area.y1 + corner_size - 1; - /*Do not overdraw the top other corners*/ + /*Do not overdraw the other top corners*/ blend_area.x1 = LV_MAX(blend_area.x1, w_half); blend_area.y2 = LV_MIN(blend_area.y2, h_half); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (clip_area_sub.y1 - shadow_area.y1) * corner_size; @@ -524,20 +513,24 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_dsc.mask = mask_buf; + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, corner_size); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + else { + blend_dsc.mask = sh_buf_tmp; + } + lv_draw_sw_blend(draw_ctx, &blend_dsc); sh_buf_tmp += corner_size; } } @@ -553,7 +546,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.x1 = LV_MAX(blend_area.x1, w_half); blend_area.y1 = LV_MAX(blend_area.y1, h_half + 1); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (blend_area.y2 - clip_area_sub.y2) * corner_size; @@ -561,21 +555,25 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_dsc.mask = mask_buf; + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y2; y >= clip_area_sub.y1; y--) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, corner_size); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + else { + blend_dsc.mask = sh_buf_tmp; + } + lv_draw_sw_blend(draw_ctx, &blend_dsc); sh_buf_tmp += corner_size; } } @@ -588,7 +586,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.y2 = shadow_area.y1 + corner_size - 1; blend_area.y2 = LV_MIN(blend_area.y2, h_half); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (clip_area_sub.y1 - blend_area.y1) * corner_size; @@ -598,27 +597,34 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv else simple_sub = simple; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + if(!simple_sub) { + blend_dsc.mask = mask_buf; + } + else { + blend_dsc.mask = NULL; + } + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memset(mask_buf, sh_buf_tmp[0], w); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, mask_buf, mask_res, dsc->shadow_opa, - dsc->blend_mode); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } else { - lv_opa_t line_opa = opa == LV_OPA_COVER ? sh_buf_tmp[0] : (sh_buf_tmp[0] * dsc->shadow_opa) >> 8; - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, line_opa, - dsc->blend_mode); + blend_dsc.opa = opa == LV_OPA_COVER ? sh_buf_tmp[0] : (sh_buf_tmp[0] * dsc->shadow_opa) >> 8; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } sh_buf_tmp += corner_size; } } } + blend_dsc.opa = dsc->shadow_opa; /*Restore*/ /*Bottom side*/ blend_area.x1 = shadow_area.x1 + corner_size; @@ -627,12 +633,26 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.y2 = shadow_area.y2; blend_area.y1 = LV_MAX(blend_area.y1, h_half + 1); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (blend_area.y2 - clip_area_sub.y2) * corner_size; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + /*Do not mask if out of the bg*/ + if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; + else simple_sub = simple; + + if(!simple_sub) { + blend_dsc.mask = mask_buf; + } + else { + blend_dsc.mask = NULL; + } + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + for(y = clip_area_sub.y2; y >= clip_area_sub.y1; y--) { blend_area.y1 = y; blend_area.y2 = y; @@ -643,15 +663,13 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv if(!simple_sub) { lv_memset(mask_buf, sh_buf_tmp[0], w); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, mask_buf, mask_res, dsc->shadow_opa, - dsc->blend_mode); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } else { - lv_opa_t line_opa = opa == LV_OPA_COVER ? sh_buf_tmp[0] : (sh_buf_tmp[0] * dsc->shadow_opa) >> 8; - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, NULL, LV_DRAW_MASK_RES_FULL_COVER, line_opa, - dsc->blend_mode); + blend_dsc.opa = opa == LV_OPA_COVER ? sh_buf_tmp[0] : (sh_buf_tmp[0] * dsc->shadow_opa) >> 8; + lv_draw_sw_blend(draw_ctx, &blend_dsc); } sh_buf_tmp += corner_size; @@ -659,6 +677,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv } } + blend_dsc.opa = dsc->shadow_opa; /*Restore*/ + /*Right side*/ blend_area.x1 = shadow_area.x2 - corner_size + 1; blend_area.x2 = shadow_area.x2; @@ -669,7 +689,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.y2 = LV_MAX(blend_area.y2, h_half); blend_area.x1 = LV_MAX(blend_area.x1, w_half); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (corner_size - 1) * corner_size; @@ -678,21 +699,22 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; + blend_dsc.mask = simple_sub ? sh_buf_tmp : mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, w); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -724,7 +746,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.y2 = LV_MAX(blend_area.y2, h_half); blend_area.x2 = LV_MIN(blend_area.x2, w_half - 1); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (corner_size - 1) * corner_size; @@ -733,20 +756,22 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; + blend_dsc.mask = simple_sub ? sh_buf_tmp : mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, w); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -760,7 +785,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.x2 = LV_MIN(blend_area.x2, w_half - 1); blend_area.y2 = LV_MIN(blend_area.y2, h_half); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (clip_area_sub.y1 - blend_area.y1) * corner_size; @@ -769,21 +795,26 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; + blend_dsc.mask = mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, corner_size); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + else { + blend_dsc.mask = sh_buf_tmp; + } + + lv_draw_sw_blend(draw_ctx, &blend_dsc); sh_buf_tmp += corner_size; } } @@ -799,7 +830,8 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.y1 = LV_MAX(blend_area.y1, h_half + 1); blend_area.x2 = LV_MIN(blend_area.x2, w_half - 1); - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); sh_buf_tmp = sh_buf; sh_buf_tmp += (blend_area.y2 - clip_area_sub.y2) * corner_size; @@ -808,20 +840,24 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv /*Do not mask if out of the bg*/ if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true; else simple_sub = simple; - mask_act = simple_sub ? &sh_buf_tmp : &mask_buf; + blend_dsc.mask = mask_buf; if(w > 0) { - mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; + blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/ for(y = clip_area_sub.y2; y >= clip_area_sub.y1; y--) { blend_area.y1 = y; blend_area.y2 = y; if(!simple_sub) { lv_memcpy(mask_buf, sh_buf_tmp, corner_size); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; } - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, *mask_act, mask_res, dsc->shadow_opa, - dsc->blend_mode); + else { + blend_dsc.mask = sh_buf_tmp; + } + lv_draw_sw_blend(draw_ctx, &blend_dsc); sh_buf_tmp += corner_size; } } @@ -832,18 +868,21 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv blend_area.x2 = shadow_area.x2 - corner_size; blend_area.y1 = shadow_area.y1 + corner_size; blend_area.y2 = shadow_area.y2 - corner_size; + blend_dsc.mask = mask_buf; - if(_lv_area_intersect(&clip_area_sub, &blend_area, clip) && !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { + if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) && + !_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) { lv_coord_t w = lv_area_get_width(&clip_area_sub); if(w > 0) { + blend_area.x1 = clip_area_sub.x1; + blend_area.x2 = clip_area_sub.x2; for(y = clip_area_sub.y1; y <= clip_area_sub.y2; y++) { blend_area.y1 = y; blend_area.y2 = y; lv_memset_ff(mask_buf, w); - mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); - lv_draw_blend_fill(&clip_area_sub, &blend_area, dsc->shadow_color, mask_buf, mask_res, dsc->shadow_opa, - dsc->blend_mode); + blend_dsc.mask_res = lv_draw_mask_apply(mask_buf, clip_area_sub.x1, y, w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -1025,7 +1064,7 @@ LV_ATTRIBUTE_FAST_MEM static void shadow_blur_corner(lv_coord_t size, lv_coord_t #endif -static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc) +static void draw_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) { if(dsc->outline_opa <= LV_OPA_MIN) return; if(dsc->outline_width == 0) return; @@ -1062,10 +1101,11 @@ static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_coord_t rout = rin + dsc->outline_width; - draw_border_generic(clip, &area_outer, &area_inner, rout, rin, dsc->outline_color, dsc->outline_opa, dsc->blend_mode); + draw_border_generic(draw_ctx, &area_outer, &area_inner, rout, rin, dsc->outline_color, dsc->outline_opa, + dsc->blend_mode); } -void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_area, const lv_area_t * inner_area, +void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout, lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) { opa = opa >= LV_OPA_COVER ? LV_OPA_COVER : opa; @@ -1073,7 +1113,7 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar bool mask_any = lv_draw_mask_is_any(outer_area); if(!mask_any && rout == 0 && rin == 0) { - draw_border_simple(clip_area, outer_area, inner_area, color, opa); + draw_border_simple(draw_ctx, outer_area, inner_area, color, opa); return; } @@ -1081,11 +1121,13 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar /*Get clipped draw area which is the real draw area. *It is always the same or inside `coords`*/ lv_area_t draw_area; - if(!_lv_area_intersect(&draw_area, outer_area, clip_area)) return; + if(!_lv_area_intersect(&draw_area, outer_area, draw_ctx->clip_area)) return; int32_t draw_area_w = lv_area_get_width(&draw_area); - /*Create a mask if there is a radius*/ - lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w); + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(blend_dsc)); + blend_dsc.mask = lv_mem_buf_get(draw_area_w);; + /*Create mask for the outer area*/ int16_t mask_rout_id = LV_MASK_ID_INV; @@ -1101,8 +1143,12 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar int16_t mask_rin_id = lv_draw_mask_add(&mask_rin_param, NULL); int32_t h; - lv_draw_mask_res_t mask_res; lv_area_t blend_area; + blend_dsc.blend_area = &blend_area; + blend_dsc.mask_area = &blend_area; + blend_dsc.color = color; + blend_dsc.opa = opa; + blend_dsc.blend_mode = blend_mode; /*Calculate the x and y coordinates where the straight parts area*/ lv_area_t core_area; @@ -1126,9 +1172,9 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.y1 = h; blend_area.y2 = h; - lv_memset_ff(mask_buf, draw_area_w); - mask_res = lv_draw_mask_apply(mask_buf, draw_area.x1, h, draw_area_w); - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_memset_ff(blend_dsc.mask, draw_area_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, draw_area.x1, h, draw_area_w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } lv_draw_mask_free_param(&mask_rin_param); @@ -1137,7 +1183,7 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar lv_draw_mask_free_param(&mask_rout_param); lv_draw_mask_remove_id(mask_rout_id); } - lv_mem_buf_release(mask_buf); + lv_mem_buf_release(blend_dsc.mask); return; } @@ -1151,13 +1197,14 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar split_hor = false; } + blend_dsc.mask_res = LV_DRAW_MASK_RES_FULL_COVER; /*Draw the straight lines first if they are long enough*/ if(top_side && split_hor) { blend_area.x1 = core_area.x1; blend_area.x2 = core_area.x2; blend_area.y1 = outer_area->y1; blend_area.y2 = inner_area->y1 - 1; - lv_draw_blend_fill(clip_area, &blend_area, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } if(bottom_side && split_hor) { @@ -1165,7 +1212,7 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.x2 = core_area.x2; blend_area.y1 = inner_area->y2 + 1; blend_area.y2 = outer_area->y2; - lv_draw_blend_fill(clip_area, &blend_area, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } if(left_side) { @@ -1173,7 +1220,7 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.x2 = inner_area->x1 - 1; blend_area.y1 = core_area.y1; blend_area.y2 = core_area.y2; - lv_draw_blend_fill(clip_area, &blend_area, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } if(right_side) { @@ -1181,7 +1228,7 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.x2 = outer_area->x2; blend_area.y1 = core_area.y1; blend_area.y2 = core_area.y2; - lv_draw_blend_fill(clip_area, &blend_area, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*Draw the corners*/ @@ -1198,19 +1245,19 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar lv_coord_t bottom_y = outer_area->y2 - h; if(top_y < draw_area.y1 && bottom_y > draw_area.y2) continue; /*This line is clipped now*/ - lv_memset_ff(mask_buf, draw_area_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, top_y, draw_area_w); + lv_memset_ff(blend_dsc.mask, draw_area_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, top_y, draw_area_w); if(top_y >= draw_area.y1) { blend_area.y1 = top_y; blend_area.y2 = top_y; - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } if(bottom_y <= draw_area.y2) { blend_area.y1 = bottom_y; blend_area.y2 = bottom_y; - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -1225,9 +1272,9 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.y1 = h; blend_area.y2 = h; - lv_memset_ff(mask_buf, blend_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, blend_w); - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_memset_ff(blend_dsc.mask, blend_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } @@ -1236,9 +1283,9 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.y1 = h; blend_area.y2 = h; - lv_memset_ff(mask_buf, blend_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, blend_w); - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_memset_ff(blend_dsc.mask, blend_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -1254,9 +1301,9 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.y1 = h; blend_area.y2 = h; - lv_memset_ff(mask_buf, blend_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, blend_w); - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_memset_ff(blend_dsc.mask, blend_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } @@ -1265,9 +1312,9 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar blend_area.y1 = h; blend_area.y2 = h; - lv_memset_ff(mask_buf, blend_w); - mask_res = lv_draw_mask_apply(mask_buf, blend_area.x1, h, blend_w); - lv_draw_blend_fill(clip_area, &blend_area, color, mask_buf, mask_res, opa, blend_mode); + lv_memset_ff(blend_dsc.mask, blend_w); + blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } } } @@ -1277,36 +1324,42 @@ void draw_border_generic(const lv_area_t * clip_area, const lv_area_t * outer_ar lv_draw_mask_remove_id(mask_rin_id); lv_draw_mask_free_param(&mask_rout_param); lv_draw_mask_remove_id(mask_rout_id); - lv_mem_buf_release(mask_buf); + lv_mem_buf_release(blend_dsc.mask); #else /*LV_DRAW_COMPLEX*/ LV_UNUSED(blend_mode); #endif /*LV_DRAW_COMPLEX*/ } - -static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_area, const lv_area_t * inner_area, +static void draw_border_simple(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, lv_opa_t opa) { + lv_area_t a; + lv_draw_sw_blend_dsc_t blend_dsc; + lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t)); + blend_dsc.blend_area = &a; + blend_dsc.color = color; + blend_dsc.opa = opa; + bool top_side = outer_area->y1 <= inner_area->y1 ? true : false; bool bottom_side = outer_area->y2 >= inner_area->y2 ? true : false; bool left_side = outer_area->x1 <= inner_area->x1 ? true : false; bool right_side = outer_area->x2 >= inner_area->x2 ? true : false; - lv_area_t a; + /*Top*/ a.x1 = outer_area->x1; a.x2 = outer_area->x2; a.y1 = outer_area->y1; a.y2 = inner_area->y1 - 1; if(top_side) { - lv_draw_blend_fill(clip, &a, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, LV_BLEND_MODE_NORMAL); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*Bottom*/ a.y1 = inner_area->y2 + 1; a.y2 = outer_area->y2; if(bottom_side) { - lv_draw_blend_fill(clip, &a, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, LV_BLEND_MODE_NORMAL); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*Left*/ @@ -1315,15 +1368,14 @@ static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_a a.y1 = (top_side) ? inner_area->y1 : outer_area->y1; a.y2 = (bottom_side) ? inner_area->y2 : outer_area->y2; if(left_side) { - lv_draw_blend_fill(clip, &a, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, LV_BLEND_MODE_NORMAL); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } /*Right*/ a.x1 = inner_area->x2 + 1; a.x2 = outer_area->x2; if(right_side) { - lv_draw_blend_fill(clip, &a, color, NULL, LV_DRAW_MASK_RES_FULL_COVER, opa, LV_BLEND_MODE_NORMAL); + lv_draw_sw_blend(draw_ctx, &blend_dsc); } - } diff --git a/src/extra/others/snapshot/lv_snapshot.c b/src/extra/others/snapshot/lv_snapshot.c index 7195177f3..913f0adb1 100644 --- a/src/extra/others/snapshot/lv_snapshot.c +++ b/src/extra/others/snapshot/lv_snapshot.c @@ -105,72 +105,47 @@ lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * w += ext_size * 2; h += ext_size * 2; - /*Backup obj original info.*/ - lv_obj_t * parent_old = lv_obj_get_parent(obj); - lv_area_t coords_bkp; - lv_area_copy(&coords_bkp, &obj->coords); + lv_area_t snapshot_area; + lv_obj_get_coords(obj, &snapshot_area); + lv_area_increase(&snapshot_area, ext_size, ext_size); lv_memset(buf, 0x00, buff_size); lv_memset_00(dsc, sizeof(lv_img_dsc_t)); - /*We are safe to use stack for below variables since disp will be - * unregistered when function returns. */ - lv_disp_t * disp; + lv_disp_t * obj_disp = lv_obj_get_disp(obj); lv_disp_drv_t driver; - lv_disp_draw_buf_t draw_buf; - - lv_disp_draw_buf_init(&draw_buf, buf, NULL, w * h); - lv_disp_drv_init(&driver); - driver.draw_buf = &draw_buf; - - /*Make the display big enough to involve the objects on its original places. */ - driver.hor_res = obj->coords.x1 + w; - driver.ver_res = obj->coords.y1 + h; + /*In lack of a better idea use the resolution of the object's display*/ + driver.hor_res = lv_disp_get_hor_res(obj_disp); + driver.ver_res = lv_disp_get_hor_res(obj_disp); lv_disp_drv_use_generic_set_px_cb(&driver, cf); - disp = lv_disp_drv_register(&driver); - if(disp == NULL) { - return LV_RES_INV; - } + lv_disp_t fake_disp; + lv_memset_00(&fake_disp, sizeof(lv_disp_t)); + fake_disp.driver = &driver; - /*Make background transparent */ - lv_disp_set_bg_opa(disp, LV_OPA_TRANSP); - /*Move obj to newly created disp and refresh it. */ - lv_obj_t * screen = lv_disp_get_scr_act(disp); - lv_obj_remove_style_all(screen); - lv_obj_allocate_spec_attr(screen); - screen->spec_attr->child_cnt = 1; - screen->spec_attr->children = &obj; + lv_draw_ctx_t * draw_ctx = lv_mem_alloc(obj_disp->driver->draw_ctx_size); + LV_ASSERT_MALLOC(draw_ctx); + if(draw_ctx == NULL) return LV_RES_INV; + obj_disp->driver->draw_ctx_init(fake_disp.driver, draw_ctx); + fake_disp.driver->draw_ctx = draw_ctx; + draw_ctx->clip_area = &snapshot_area; + draw_ctx->buf_area = &snapshot_area; + draw_ctx->buf = (void *)buf; + driver.draw_ctx = draw_ctx; - obj->parent = screen; + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); - disp->inv_p = 0; + lv_refr_obj(draw_ctx, obj); - /*Shift obj by ext_size, so there is room for shadow etc.*/ - obj->coords.x2 += ext_size; - obj->coords.x1 += ext_size; - obj->coords.y2 += ext_size; - obj->coords.y1 += ext_size; - - lv_obj_invalidate(obj); - - /*Don't call lv_refr_now to avoid animation disruption */ - _lv_disp_refr_timer(disp->refr_timer); - - /*Restore obj original parameters and clean up*/ - obj->parent = parent_old; - screen->spec_attr->child_cnt = 0; - screen->spec_attr->children = NULL; - - lv_disp_remove(disp); - - lv_area_copy(&obj->coords, &coords_bkp); + _lv_refr_set_disp_refreshing(refr_ori); + obj_disp->driver->draw_ctx_deinit(fake_disp.driver, draw_ctx); dsc->data = buf; - dsc->header.w = lv_area_get_width(&draw_buf.area); - dsc->header.h = lv_area_get_height(&draw_buf.area); + dsc->header.w = w; + dsc->header.h = h; dsc->header.cf = cf; return LV_RES_OK; } diff --git a/src/extra/widgets/chart/lv_chart.c b/src/extra/widgets/chart/lv_chart.c index 18d0f5fe1..2eb37f425 100644 --- a/src/extra/widgets/chart/lv_chart.c +++ b/src/extra/widgets/chart/lv_chart.c @@ -32,12 +32,12 @@ static void lv_chart_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) static void lv_chart_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_chart_event(const lv_obj_class_t * class_p, lv_event_t * e); -static void draw_div_lines(lv_obj_t * obj, const lv_area_t * mask); -static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area); -static void draw_series_bar(lv_obj_t * obj, const lv_area_t * clip_area); -static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area); -static void draw_cursors(lv_obj_t * obj, const lv_area_t * clip_area); -static void draw_axes(lv_obj_t * obj, const lv_area_t * mask); +static void draw_div_lines(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); +static void draw_series_line(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); +static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); +static void draw_series_scatter(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); +static void draw_cursors(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); +static void draw_axes(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); static uint32_t get_index_from_x(lv_obj_t * obj, lv_coord_t x); static void invalidate_point(lv_obj_t * obj, uint16_t i); static void new_points_alloc(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t cnt, lv_coord_t ** a); @@ -736,28 +736,31 @@ static void lv_chart_event(const lv_obj_class_t * class_p, lv_event_t * e) p->y = ((int32_t)lv_obj_get_content_height(obj) * chart->zoom_y) >> 8; } else if(code == LV_EVENT_DRAW_MAIN) { - const lv_area_t * clip_area = lv_event_get_param(e); - draw_div_lines(obj, clip_area); - draw_axes(obj, clip_area); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); + draw_div_lines(obj, draw_ctx); + draw_axes(obj, draw_ctx); if(_lv_ll_is_empty(&chart->series_ll) == false) { - if(chart->type == LV_CHART_TYPE_LINE) draw_series_line(obj, clip_area); - else if(chart->type == LV_CHART_TYPE_BAR) draw_series_bar(obj, clip_area); - else if(chart->type == LV_CHART_TYPE_SCATTER) draw_series_scatter(obj, clip_area); + if(chart->type == LV_CHART_TYPE_LINE) draw_series_line(obj, draw_ctx); + else if(chart->type == LV_CHART_TYPE_BAR) draw_series_bar(obj, draw_ctx); + else if(chart->type == LV_CHART_TYPE_SCATTER) draw_series_scatter(obj, draw_ctx); } - draw_cursors(obj, clip_area); + draw_cursors(obj, draw_ctx); } } -static void draw_div_lines(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_div_lines(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { lv_chart_t * chart = (lv_chart_t *)obj; - lv_area_t series_mask; - bool mask_ret = _lv_area_intersect(&series_mask, &obj->coords, clip_area); + lv_area_t series_clip_area; + bool mask_ret = _lv_area_intersect(&series_clip_area, &obj->coords, draw_ctx->clip_area); if(mask_ret == false) return; + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &series_clip_area; + int16_t i; int16_t i_start; int16_t i_end; @@ -774,7 +777,7 @@ static void draw_div_lines(lv_obj_t * obj, const lv_area_t * clip_area) lv_obj_init_draw_line_dsc(obj, LV_PART_MAIN, &line_dsc); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_MAIN; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_DIV_LINE_INIT; @@ -814,7 +817,7 @@ static void draw_div_lines(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.id = i; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_line(&p1, &p2, &series_mask, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } @@ -842,7 +845,7 @@ static void draw_div_lines(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.id = i; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_line(&p1, &p2, &series_mask, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } @@ -852,12 +855,16 @@ static void draw_div_lines(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.p2 = NULL; lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); + draw_ctx->clip_area = clip_area_ori; } -static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_series_line(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { - lv_area_t com_area; - if(_lv_area_intersect(&com_area, &obj->coords, clip_area) == false) return; + lv_area_t clip_area; + if(_lv_area_intersect(&clip_area, &obj->coords, draw_ctx->clip_area) == false) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; lv_chart_t * chart = (lv_chart_t *)obj; if(chart->point_cnt < 2) return; @@ -874,8 +881,8 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) lv_coord_t y_ofs = obj->coords.y1 + pad_top - lv_obj_get_scroll_top(obj); lv_chart_series_t * ser; - lv_area_t series_mask; - bool mask_ret = _lv_area_intersect(&series_mask, &obj->coords, clip_area); + lv_area_t series_clip_area; + bool mask_ret = _lv_area_intersect(&series_clip_area, &obj->coords, draw_ctx->clip_area); if(mask_ret == false) return; lv_draw_line_dsc_t line_dsc_default; @@ -914,7 +921,7 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) p2.y = h - y_tmp + y_ofs; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_LINE_AND_POINT; part_draw_dsc.part = LV_PART_ITEMS; @@ -929,7 +936,7 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) p1.x = p2.x; p1.y = p2.y; - if(p1.x > clip_area->x2 + point_w + 1) break; + if(p1.x > clip_area_ori->x2 + point_w + 1) break; p2.x = ((w * i) / (chart->point_cnt - 1)) + x_ofs; p_act = (start_point + i) % chart->point_cnt; @@ -938,7 +945,7 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) y_tmp = y_tmp / (chart->ymax[ser->y_axis_sec] - chart->ymin[ser->y_axis_sec]); p2.y = h - y_tmp + y_ofs; - if(p2.x < clip_area->x1 - point_w - 1) { + if(p2.x < clip_area_ori->x1 - point_w - 1) { p_prev = p_act; continue; } @@ -957,7 +964,7 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) p1.y = y_min; p2.y = y_max; if(p1.y == p2.y) p2.y++; /*If they are the same no line will be drawn*/ - lv_draw_line(&p1, &p2, &series_mask, &line_dsc_default); + lv_draw_line(draw_ctx, &line_dsc_default, &p1, &p2); p2.x++; /*Compensate the previous x--*/ y_min = y_cur; /*Start the line of the next x from the current last y*/ y_max = y_cur; @@ -980,11 +987,11 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); if(ser->y_points[p_prev] != LV_CHART_POINT_NONE && ser->y_points[p_act] != LV_CHART_POINT_NONE) { - lv_draw_line(&p1, &p2, &series_mask, &line_dsc_default); + lv_draw_line(draw_ctx, &line_dsc_default, &p1, &p2); } if(point_w && point_h && ser->y_points[p_prev] != LV_CHART_POINT_NONE) { - lv_draw_rect(&point_area, &series_mask, &point_dsc_default); + lv_draw_rect(draw_ctx, &point_dsc_default, &point_area); } lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); @@ -1009,19 +1016,25 @@ static void draw_series_line(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.p2 = NULL; part_draw_dsc.draw_area = &point_area; part_draw_dsc.value = ser->y_points[p_act]; + lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&point_area, &series_mask, &point_dsc_default); + lv_draw_rect(draw_ctx, &point_dsc_default, &point_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } } + + draw_ctx->clip_area = clip_area_ori; } -static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_series_scatter(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { - lv_area_t com_area; - if(_lv_area_intersect(&com_area, &obj->coords, clip_area) == false) return; + lv_area_t clip_area; + if(_lv_area_intersect(&clip_area, &obj->coords, draw_ctx->clip_area) == false) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; lv_chart_t * chart = (lv_chart_t *)obj; @@ -1037,10 +1050,6 @@ static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area) lv_coord_t y_ofs = obj->coords.y1 + pad_top + border_width - lv_obj_get_scroll_top(obj); lv_chart_series_t * ser; - lv_area_t series_mask; - bool mask_ret = _lv_area_intersect(&series_mask, &obj->coords, clip_area); - if(mask_ret == false) return; - lv_draw_line_dsc_t line_dsc_default; lv_draw_line_dsc_init(&line_dsc_default); lv_obj_init_draw_line_dsc(obj, LV_PART_ITEMS, &line_dsc_default); @@ -1083,7 +1092,7 @@ static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area) } lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_ITEMS; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_LINE_AND_POINT; @@ -1126,9 +1135,9 @@ static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area) lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); if(ser->y_points[p_prev] != LV_CHART_POINT_NONE && ser->y_points[p_act] != LV_CHART_POINT_NONE) { - lv_draw_line(&p1, &p2, &series_mask, &line_dsc_default); + lv_draw_line(draw_ctx, &line_dsc_default, &p1, &p2); if(point_w && point_h) { - lv_draw_rect(&point_area, &series_mask, &point_dsc_default); + lv_draw_rect(draw_ctx, &point_dsc_default, &point_area); } } @@ -1153,17 +1162,22 @@ static void draw_series_scatter(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.draw_area = &point_area; part_draw_dsc.value = ser->y_points[p_act]; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&point_area, &series_mask, &point_dsc_default); + lv_draw_rect(draw_ctx, &point_dsc_default, &point_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } } + draw_ctx->clip_area = clip_area_ori; } -static void draw_series_bar(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { - lv_area_t com_area; - if(_lv_area_intersect(&com_area, &obj->coords, clip_area) == false) return; + lv_area_t clip_area; + if(_lv_area_intersect(&clip_area, &obj->coords, draw_ctx->clip_area) == false) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; + lv_chart_t * chart = (lv_chart_t *)obj; @@ -1194,12 +1208,8 @@ static void draw_series_bar(lv_obj_t * obj, const lv_area_t * clip_area) /*Make the cols longer with `radius` to clip the rounding from the bottom*/ col_a.y2 = obj->coords.y2 + col_dsc.radius; - lv_area_t series_mask; - bool mask_ret = _lv_area_intersect(&series_mask, &obj->coords, clip_area); - if(mask_ret == false) return; - lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, &series_mask); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_ITEMS; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_BAR; @@ -1219,8 +1229,8 @@ static void draw_series_bar(lv_obj_t * obj, const lv_area_t * clip_area) col_a.x2 = col_a.x1 + col_w - ser_gap - 1; x_act += col_w; - if(col_a.x2 < series_mask.x1) continue; - if(col_a.x1 > series_mask.x2) break; + if(col_a.x2 < clip_area.x1) continue; + if(col_a.x1 > clip_area.x2) break; col_dsc.bg_color = ser->color; @@ -1235,20 +1245,27 @@ static void draw_series_bar(lv_obj_t * obj, const lv_area_t * clip_area) part_draw_dsc.sub_part_ptr = ser; part_draw_dsc.value = ser->y_points[p_act]; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&col_a, &series_mask, &col_dsc); + lv_draw_rect(draw_ctx, &col_dsc, &col_a); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } } + draw_ctx->clip_area = clip_area_ori; } -static void draw_cursors(lv_obj_t * obj, const lv_area_t * clip_area) +static void draw_cursors(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_chart_t * chart = (lv_chart_t *)obj; if(_lv_ll_is_empty(&chart->cursor_ll)) return; + lv_area_t clip_area; + if(!_lv_area_intersect(&clip_area, draw_ctx->clip_area, &obj->coords)) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; + lv_point_t p1; lv_point_t p2; lv_chart_cursor_t * cursor; @@ -1269,16 +1286,13 @@ static void draw_cursors(lv_obj_t * obj, const lv_area_t * clip_area) lv_coord_t point_h = lv_obj_get_style_width(obj, LV_PART_CURSOR) / 2; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.line_dsc = &line_dsc_tmp; part_draw_dsc.rect_dsc = &point_dsc_tmp; part_draw_dsc.part = LV_PART_CURSOR; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_CURSOR; - lv_area_t clip_area2; - _lv_area_intersect(&clip_area2, clip_area, &obj->coords); - /*Go through all cursor lines*/ _LV_LL_READ_BACK(&chart->cursor_ll, cursor) { lv_memcpy(&line_dsc_tmp, &line_dsc_ori, sizeof(lv_draw_line_dsc_t)); @@ -1326,8 +1340,8 @@ static void draw_cursors(lv_obj_t * obj, const lv_area_t * clip_area) p2.y = p1.y; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_line(&p1, &p2, &clip_area2, &line_dsc_tmp); - lv_draw_rect(&point_area, &clip_area2, &point_dsc_tmp); + lv_draw_line(draw_ctx, &line_dsc_tmp, &p1, &p2); + lv_draw_rect(draw_ctx, &point_dsc_tmp, &point_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } @@ -1338,15 +1352,16 @@ static void draw_cursors(lv_obj_t * obj, const lv_area_t * clip_area) p2.y = cursor->dir & LV_DIR_BOTTOM ? obj->coords.y2 : cy; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_line(&p1, &p2, &clip_area2, &line_dsc_tmp); - lv_draw_rect(&point_area, &clip_area2, &point_dsc_tmp); + lv_draw_line(draw_ctx, &line_dsc_tmp, &p1, &p2); + lv_draw_rect(draw_ctx, &point_dsc_tmp, &point_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } - } + + draw_ctx->clip_area = clip_area_ori; } -static void draw_y_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_axis_t axis) +static void draw_y_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis_t axis) { lv_chart_t * chart = (lv_chart_t *)obj; @@ -1395,7 +1410,7 @@ static void draw_y_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a lv_obj_init_draw_label_dsc(obj, LV_PART_TICKS, &label_dsc); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_TICK_LABEL; part_draw_dsc.id = axis; @@ -1458,7 +1473,7 @@ static void draw_y_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a if(a.y2 >= obj->coords.y1 && a.y1 <= obj->coords.y2) { - lv_draw_label(&a, clip_area, &label_dsc, part_draw_dsc.text, NULL); + lv_draw_label(draw_ctx, &label_dsc, &a, part_draw_dsc.text, NULL); } } else { @@ -1470,14 +1485,14 @@ static void draw_y_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a if(p1.y + line_dsc.width / 2 >= obj->coords.y1 && p2.y - line_dsc.width / 2 <= obj->coords.y2) { - lv_draw_line(&p1, &p2, clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } -static void draw_x_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_axis_t axis) +static void draw_x_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis_t axis) { lv_chart_t * chart = (lv_chart_t *)obj; @@ -1510,8 +1525,8 @@ static void draw_x_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a } if(axis == LV_CHART_AXIS_PRIMARY_X) { - if(y_ofs > clip_area->y2) return; - if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < clip_area->y1) return; + if(y_ofs > draw_ctx->clip_area->y2) return; + if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < draw_ctx->clip_area->y1) return; } lv_draw_line_dsc_t line_dsc; @@ -1521,7 +1536,7 @@ static void draw_x_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a line_dsc.dash_width = 0; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHART_DRAW_PART_TICK_LABEL; part_draw_dsc.id = LV_CHART_AXIS_PRIMARY_X; @@ -1594,7 +1609,7 @@ static void draw_x_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a if(a.x2 >= obj->coords.x1 && a.x1 <= obj->coords.x2) { - lv_draw_label(&a, clip_area, &label_dsc, part_draw_dsc.text, NULL); + lv_draw_label(draw_ctx, &label_dsc, &a, part_draw_dsc.text, NULL); } } else { @@ -1607,19 +1622,19 @@ static void draw_x_ticks(lv_obj_t * obj, const lv_area_t * clip_area, lv_chart_a if(p1.x + line_dsc.width / 2 >= obj->coords.x1 && p2.x - line_dsc.width / 2 <= obj->coords.x2) { - lv_draw_line(&p1, &p2, clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } -static void draw_axes(lv_obj_t * obj, const lv_area_t * mask) +static void draw_axes(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { - draw_y_ticks(obj, mask, LV_CHART_AXIS_PRIMARY_Y); - draw_y_ticks(obj, mask, LV_CHART_AXIS_SECONDARY_Y); - draw_x_ticks(obj, mask, LV_CHART_AXIS_PRIMARY_X); - draw_x_ticks(obj, mask, LV_CHART_AXIS_SECONDARY_X); + draw_y_ticks(obj, draw_ctx, LV_CHART_AXIS_PRIMARY_Y); + draw_y_ticks(obj, draw_ctx, LV_CHART_AXIS_SECONDARY_Y); + draw_x_ticks(obj, draw_ctx, LV_CHART_AXIS_PRIMARY_X); + draw_x_ticks(obj, draw_ctx, LV_CHART_AXIS_SECONDARY_X); } /** diff --git a/src/extra/widgets/colorwheel/lv_colorwheel.c b/src/extra/widgets/colorwheel/lv_colorwheel.c index ed4505e8b..3fb7128cf 100644 --- a/src/extra/widgets/colorwheel/lv_colorwheel.c +++ b/src/extra/widgets/colorwheel/lv_colorwheel.c @@ -242,7 +242,7 @@ static void lv_colorwheel_constructor(const lv_obj_class_t * class_p, lv_obj_t * static void draw_disc_grad(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_coord_t w = lv_obj_get_width(obj); lv_coord_t h = lv_obj_get_height(obj); lv_coord_t cx = obj->coords.x1 + w / 2; @@ -292,7 +292,7 @@ static void draw_disc_grad(lv_event_t * e) p[1].x = cx + ((r - cir_w - cir_w_extra) * lv_trigo_sin(angle_trigo) >> LV_TRIGO_SHIFT); p[1].y = cy + ((r - cir_w - cir_w_extra) * lv_trigo_cos(angle_trigo) >> LV_TRIGO_SHIFT); - lv_draw_line(&p[0], &p[1], clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p[0], &p[1]); } #if LV_DRAW_COMPLEX @@ -306,7 +306,7 @@ static void draw_disc_grad(lv_event_t * e) static void draw_knob(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_colorwheel_t * colorwheel = (lv_colorwheel_t *)obj; lv_draw_rect_dsc_t cir_dsc; @@ -321,7 +321,7 @@ static void draw_knob(lv_event_t * e) lv_area_t knob_area = get_knob_area(obj); - lv_draw_rect(&knob_area, clip_area, &cir_dsc); + lv_draw_rect(draw_ctx, &cir_dsc, &knob_area); } static void invalidate_knob(lv_obj_t * obj) diff --git a/src/extra/widgets/imgbtn/lv_imgbtn.c b/src/extra/widgets/imgbtn/lv_imgbtn.c index 95111027c..00c3011ca 100644 --- a/src/extra/widgets/imgbtn/lv_imgbtn.c +++ b/src/extra/widgets/imgbtn/lv_imgbtn.c @@ -211,7 +211,7 @@ static void draw_main(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_imgbtn_t * imgbtn = (lv_imgbtn_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); /*Just draw_main an image*/ lv_imgbtn_state_t state = suggest_state(obj, get_state(obj)); @@ -244,7 +244,7 @@ static void draw_main(lv_event_t * e) coords_part.y1 = coords.y1; coords_part.x2 = coords.x1 + header.w - 1; coords_part.y2 = coords.y1 + header.h - 1; - lv_draw_img(&coords_part, clip_area, src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &coords_part, src); } src = imgbtn->img_src_right[state]; @@ -255,33 +255,38 @@ static void draw_main(lv_event_t * e) coords_part.y1 = coords.y1; coords_part.x2 = coords.x2; coords_part.y2 = coords.y1 + header.h - 1; - lv_draw_img(&coords_part, clip_area, src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &coords_part, src); } src = imgbtn->img_src_mid[state]; if(src) { - lv_area_t clip_center_area; - clip_center_area.x1 = coords.x1 + left_w; - clip_center_area.x2 = coords.x2 - right_w; - clip_center_area.y1 = coords.y1; - clip_center_area.y2 = coords.y2; + lv_area_t clip_area_center; + clip_area_center.x1 = coords.x1 + left_w; + clip_area_center.x2 = coords.x2 - right_w; + clip_area_center.y1 = coords.y1; + clip_area_center.y2 = coords.y2; + bool comm_res; - comm_res = _lv_area_intersect(&clip_center_area, &clip_center_area, clip_area); + comm_res = _lv_area_intersect(&clip_area_center, &clip_area_center, draw_ctx->clip_area); if(comm_res) { lv_coord_t i; lv_img_decoder_get_info(src, &header); + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area_center; + coords_part.x1 = coords.x1 + left_w; coords_part.y1 = coords.y1; coords_part.x2 = coords_part.x1 + header.w - 1; coords_part.y2 = coords_part.y1 + header.h - 1; - for(i = coords_part.x1; i < (lv_coord_t)(clip_center_area.x2 + header.w - 1); i += header.w) { - lv_draw_img(&coords_part, &clip_center_area, src, &img_dsc); + for(i = coords_part.x1; i < (lv_coord_t)(clip_area_center.x2 + header.w - 1); i += header.w) { + lv_draw_img(draw_ctx, &img_dsc, &coords_part, src); coords_part.x1 = coords_part.x2 + 1; coords_part.x2 += header.w; } + draw_ctx->clip_area = clip_area_ori; } } } diff --git a/src/extra/widgets/led/lv_led.c b/src/extra/widgets/led/lv_led.c index e021d429d..5899ddac9 100644 --- a/src/extra/widgets/led/lv_led.c +++ b/src/extra/widgets/led/lv_led.c @@ -198,10 +198,10 @@ static void lv_led_event(const lv_obj_class_t * class_p, lv_event_t * e) rect_dsc.shadow_spread = ((led->bright - LV_LED_BRIGHT_MIN) * rect_dsc.shadow_spread) / (LV_LED_BRIGHT_MAX - LV_LED_BRIGHT_MIN); - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.draw_area = &obj->coords; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_LED_DRAW_PART_RECTANGLE; @@ -209,7 +209,7 @@ static void lv_led_event(const lv_obj_class_t * class_p, lv_event_t * e) part_draw_dsc.part = LV_PART_MAIN; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&obj->coords, clip_area, &rect_dsc); + lv_draw_rect(draw_ctx, &rect_dsc, &obj->coords); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } diff --git a/src/extra/widgets/meter/lv_meter.c b/src/extra/widgets/meter/lv_meter.c index 0932ecec7..c12dc33c9 100644 --- a/src/extra/widgets/meter/lv_meter.c +++ b/src/extra/widgets/meter/lv_meter.c @@ -26,9 +26,9 @@ static void lv_meter_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_meter_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e); -static void draw_arcs(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area); -static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area); -static void draw_needles(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area); +static void draw_arcs(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area); +static void draw_ticks_and_labels(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area); +static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area); static void inv_arc(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t old_value, int32_t new_value); static void inv_line(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value); @@ -296,13 +296,13 @@ static void lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e) lv_event_code_t code = lv_event_get_code(e); lv_obj_t * obj = lv_event_get_target(e); if(code == LV_EVENT_DRAW_MAIN) { - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t scale_area; lv_obj_get_content_coords(obj, &scale_area); - draw_arcs(obj, clip_area, &scale_area); - draw_ticks_and_labels(obj, clip_area, &scale_area); - draw_needles(obj, clip_area, &scale_area); + draw_arcs(obj, draw_ctx, &scale_area); + draw_ticks_and_labels(obj, draw_ctx, &scale_area); + draw_needles(obj, draw_ctx, &scale_area); lv_coord_t r_edge = lv_area_get_width(&scale_area) / 2; lv_point_t scale_center; @@ -319,11 +319,11 @@ static void lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e) nm_cord.y1 = scale_center.y - h; nm_cord.x2 = scale_center.x + w; nm_cord.y2 = scale_center.y + h; - lv_draw_rect(&nm_cord, clip_area, &mid_dsc); + lv_draw_rect(draw_ctx, &mid_dsc, &nm_cord); } } -static void draw_arcs(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area) +static void draw_arcs(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area) { lv_meter_t * meter = (lv_meter_t *)obj; @@ -340,7 +340,7 @@ static void draw_arcs(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area lv_meter_indicator_t * indic; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.arc_dsc = &arc_dsc; part_draw_dsc.part = LV_PART_INDICATOR; part_draw_dsc.class_p = MY_CLASS; @@ -365,12 +365,12 @@ static void draw_arcs(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area part_draw_dsc.p1 = &scale_center; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_arc(scale_center.x, scale_center.y, part_draw_dsc.radius, start_angle, end_angle, clip_area, &arc_dsc); + lv_draw_arc(draw_ctx, &arc_dsc, &scale_center, part_draw_dsc.radius, start_angle, end_angle); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } -static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area) +static void draw_ticks_and_labels(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area) { lv_meter_t * meter = (lv_meter_t *)obj; @@ -397,7 +397,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c lv_draw_mask_radius_param_t outer_mask; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.part = LV_PART_TICKS; part_draw_dsc.type = LV_METER_DRAW_PART_TICK; @@ -532,7 +532,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c label_cord.x2 = label_cord.x1 + label_size.x; label_cord.y2 = label_cord.y1 + label_size.y; - lv_draw_label(&label_cord, clip_area, &label_dsc, part_draw_dsc.text, NULL); + lv_draw_label(draw_ctx, part_draw_dsc.label_dsc, &label_cord, part_draw_dsc.text, NULL); outer_mask_id = lv_draw_mask_add(&outer_mask, NULL); } @@ -543,7 +543,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c } inner_act_mask_id = lv_draw_mask_add(major ? &inner_major_mask : &inner_minor_mask, NULL); - lv_draw_line(&p_outer, &p_center, clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p_outer, &p_center); lv_draw_mask_remove_id(inner_act_mask_id); lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, &part_draw_dsc); @@ -559,7 +559,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c } -static void draw_needles(lv_obj_t * obj, const lv_area_t * clip_area, const lv_area_t * scale_area) +static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area) { lv_meter_t * meter = (lv_meter_t *)obj; @@ -578,7 +578,7 @@ static void draw_needles(lv_obj_t * obj, const lv_area_t * clip_area, const lv_a lv_opa_t opa_main = lv_obj_get_style_opa(obj, LV_PART_MAIN); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.p1 = &scale_center; @@ -602,7 +602,7 @@ static void draw_needles(lv_obj_t * obj, const lv_area_t * clip_area, const lv_a part_draw_dsc.p2 = &p_end; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_line(&scale_center, &p_end, clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &scale_center, &p_end); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG) { @@ -627,7 +627,7 @@ static void draw_needles(lv_obj_t * obj, const lv_area_t * clip_area, const lv_a part_draw_dsc.img_dsc = &img_dsc; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_img(&a, clip_area, indic->type_data.needle_img.src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &a, indic->type_data.needle_img.src); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } diff --git a/src/extra/widgets/span/lv_span.c b/src/extra/widgets/span/lv_span.c index 9282ae989..10ba4c571 100644 --- a/src/extra/widgets/span/lv_span.c +++ b/src/extra/widgets/span/lv_span.c @@ -52,7 +52,7 @@ static lv_opa_t lv_span_get_style_text_blend_mode(lv_obj_t * par, lv_span_t * sp static int32_t lv_span_get_style_text_decor(lv_obj_t * par, lv_span_t * span); static inline void span_text_check(const char ** text); -static void lv_draw_span(lv_obj_t * spans, const lv_area_t * coords, const lv_area_t * mask); +static void lv_draw_span(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx); static bool lv_txt_get_snippet(const char * txt, const lv_font_t * font, lv_coord_t letter_space, lv_coord_t max_width, lv_text_flag_t flag, lv_coord_t * use_width, uint32_t * end_ofs); @@ -663,12 +663,9 @@ static void lv_spangroup_event(const lv_obj_class_t * class_p, lv_event_t * e) static void draw_main(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); - lv_area_t txt_coords; - lv_obj_get_content_coords(obj, &txt_coords); - - lv_draw_span(obj, &txt_coords, clip_area); + lv_draw_span(obj, draw_ctx); } /** @@ -832,12 +829,11 @@ static lv_coord_t convert_indent_pct(lv_obj_t * obj, lv_coord_t width) * @param coords coordinates of the label * @param mask the label will be drawn only in this area */ -static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area_t * mask) +static void lv_draw_span(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) { - /* return if no draw area */ - lv_area_t clipped_area; - bool clip_ok = _lv_area_intersect(&clipped_area, coords, mask); - if(!clip_ok) return; + + lv_area_t coords; + lv_obj_get_content_coords(obj, &coords); lv_spangroup_t * spans = (lv_spangroup_t *)obj; @@ -846,25 +842,34 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area return; } + /* return if no draw area */ + lv_area_t clip_area; + if(!_lv_area_intersect(&clip_area, &coords, draw_ctx->clip_area)) return; + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; + /* init draw variable */ lv_text_flag_t txt_flag = LV_TEXT_FLAG_NONE; lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);; - lv_coord_t max_width = lv_area_get_width(coords); + lv_coord_t max_width = lv_area_get_width(&coords); lv_coord_t indent = convert_indent_pct(obj, max_width); lv_coord_t max_w = max_width - indent; /* first line need minus indent */ lv_opa_t obj_opa = lv_obj_get_style_opa(obj, LV_PART_MAIN); /* coords of draw span-txt */ lv_point_t txt_pos; - txt_pos.y = coords->y1; - txt_pos.x = coords->x1 + indent; /* first line need add indent */ + txt_pos.y = coords.y1; + txt_pos.x = coords.x1 + indent; /* first line need add indent */ lv_span_t * cur_span = _lv_ll_get_head(&spans->child_ll); const char * cur_txt = cur_span->txt; span_text_check(&cur_txt); uint32_t cur_txt_ofs = 0; lv_snippet_t snippet; /* use to save cur_span info and push it to stack */ - memset(&snippet, 0, sizeof(snippet)); + lv_memset_00(&snippet, sizeof(snippet)); + + lv_draw_label_dsc_t label_draw_dsc; + lv_draw_label_dsc_init(&label_draw_dsc); bool is_first_line = true; /* the loop control how many lines need to draw */ @@ -897,7 +902,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area if(spans->overflow == LV_SPAN_OVERFLOW_ELLIPSIS) { /* curretn line span txt overflow, don't push */ - if(txt_pos.y + snippet.line_h - line_space > coords->y2 + 1) { + if(txt_pos.y + snippet.line_h - line_space > coords.y2 + 1) { ellipsis_valid = true; is_end_line = true; break; @@ -920,7 +925,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area } } lv_coord_t cur_line_h = max_line_h < snippet.line_h ? snippet.line_h : max_line_h; - if(txt_pos.y + cur_line_h + next_line_h - line_space > coords->y2 + 1) { /* for overflow if is end line. */ + if(txt_pos.y + cur_line_h + next_line_h - line_space > coords.y2 + 1) { /* for overflow if is end line. */ if(cur_txt[cur_txt_ofs + next_ofs] != '\0') { next_ofs = strlen(&cur_txt[cur_txt_ofs]); use_width = lv_txt_get_width(&cur_txt[cur_txt_ofs], next_ofs, snippet.font, snippet.letter_space, txt_flag); @@ -969,7 +974,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area } /*Go the first visible line*/ - if(txt_pos.y + max_line_h < mask->y1) { + if(txt_pos.y + max_line_h < clip_area.y1) { goto Next_line_init; } @@ -991,7 +996,8 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area } /* draw line letters */ - for(int i = 0; i < item_cnt; i++) { + int i; + for(i = 0; i < item_cnt; i++) { lv_snippet_t * pinfo = lv_get_snippet(i); /* bidi deal with:todo */ @@ -1000,12 +1006,13 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area lv_point_t pos; pos.x = txt_pos.x; pos.y = txt_pos.y + max_line_h - pinfo->line_h; - lv_color_t letter_color = lv_span_get_style_text_color(obj, pinfo->span); - lv_opa_t letter_opa = lv_span_get_style_text_opa(obj, pinfo->span); + label_draw_dsc.color = lv_span_get_style_text_color(obj, pinfo->span); + label_draw_dsc.opa = lv_span_get_style_text_opa(obj, pinfo->span); + label_draw_dsc.font = lv_span_get_style_text_font(obj, pinfo->span); + label_draw_dsc.blend_mode = lv_span_get_style_text_blend_mode(obj, pinfo->span); if(obj_opa < LV_OPA_MAX) { - letter_opa = (uint16_t)((uint16_t)letter_opa * obj_opa) >> 8; + label_draw_dsc.opa = (uint16_t)((uint16_t)label_draw_dsc.opa * obj_opa) >> 8; } - lv_blend_mode_t blend_mode = lv_span_get_style_text_blend_mode(obj, pinfo->span); uint32_t txt_bytes = pinfo->bytes; /* overflow */ @@ -1015,12 +1022,12 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area dot_letter_w = lv_font_get_glyph_width(pinfo->font, '.', '.'); dot_width = dot_letter_w * 3; } - lv_coord_t ellipsis_width = coords->x1 + max_width - dot_width; + lv_coord_t ellipsis_width = coords.x1 + max_width - dot_width; uint32_t j = 0; while(j < txt_bytes) { /* skip invalid fields */ - if(pos.x > clipped_area.x2) { + if(pos.x > clip_area.x2) { break; } uint32_t letter = _lv_txt_encoded_next(bidi_txt, &j); @@ -1028,7 +1035,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area int32_t letter_w = lv_font_get_glyph_width(pinfo->font, letter, letter_next); /* skip invalid fields */ - if(pos.x + letter_w + pinfo->letter_space < clipped_area.x1) { + if(pos.x + letter_w + pinfo->letter_space < clip_area.x1) { if(letter_w > 0) { pos.x = pos.x + letter_w + pinfo->letter_space; } @@ -1037,7 +1044,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area if(ellipsis_valid && pos.x + letter_w + pinfo->letter_space > ellipsis_width) { for(int ell = 0; ell < 3; ell++) { - lv_draw_letter(&pos, &clipped_area, pinfo->font, '.', letter_color, letter_opa, blend_mode); + lv_draw_letter(draw_ctx, &label_draw_dsc, &pos, '.'); pos.x = pos.x + dot_letter_w + pinfo->letter_space; } if(pos.x <= ellipsis_width) { @@ -1046,7 +1053,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area break; } else { - lv_draw_letter(&pos, &clipped_area, pinfo->font, letter, letter_color, letter_opa, blend_mode); + lv_draw_letter(draw_ctx, &label_draw_dsc, &pos, letter); if(letter_w > 0) { pos.x = pos.x + letter_w + pinfo->letter_space; } @@ -1055,7 +1062,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area if(ellipsis_valid && i == item_cnt - 1 && pos.x <= ellipsis_width) { for(int ell = 0; ell < 3; ell++) { - lv_draw_letter(&pos, &clipped_area, pinfo->font, '.', letter_color, letter_opa, blend_mode); + lv_draw_letter(draw_ctx, &label_draw_dsc, &pos, '.'); pos.x = pos.x + dot_letter_w + pinfo->letter_space; } } @@ -1065,10 +1072,10 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area if(decor != LV_TEXT_DECOR_NONE) { lv_draw_line_dsc_t line_dsc; lv_draw_line_dsc_init(&line_dsc); - line_dsc.color = letter_color; - line_dsc.width = pinfo->font->underline_thickness ? pinfo->font->underline_thickness : 1; - line_dsc.opa = letter_opa; - line_dsc.blend_mode = blend_mode; + line_dsc.color = label_draw_dsc.color; + line_dsc.width = label_draw_dsc.font->underline_thickness ? pinfo->font->underline_thickness : 1; + line_dsc.opa = label_draw_dsc.opa; + line_dsc.blend_mode = label_draw_dsc.blend_mode; if(decor & LV_TEXT_DECOR_STRIKETHROUGH) { lv_point_t p1; @@ -1077,7 +1084,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area p1.y = pos.y + ((pinfo->line_h - line_space) >> 1) + (line_dsc.width >> 1); p2.x = pos.x; p2.y = p1.y; - lv_draw_line(&p1, &p2, mask, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } if(decor & LV_TEXT_DECOR_UNDERLINE) { @@ -1087,7 +1094,7 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area p1.y = pos.y + pinfo->line_h - line_space - pinfo->font->base_line - pinfo->font->underline_position; p2.x = pos.x; p2.y = p1.y; - lv_draw_line(&p1, &p2, &clipped_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); } } txt_pos.x = pos.x; @@ -1096,13 +1103,15 @@ static void lv_draw_span(lv_obj_t * obj, const lv_area_t * coords, const lv_area Next_line_init: /* next line init */ is_first_line = false; - txt_pos.x = coords->x1; + txt_pos.x = coords.x1; txt_pos.y += max_line_h; - if(is_end_line || txt_pos.y > clipped_area.y2 + 1) { + if(is_end_line || txt_pos.y > clip_area.y2 + 1) { + draw_ctx->clip_area = clip_area_ori; return; } max_w = max_width; } + draw_ctx->clip_area = clip_area_ori; } static void refresh_self_size(lv_obj_t * obj) diff --git a/src/gpu/lv_gpu.mk b/src/gpu/lv_gpu.mk index c34350f8b..f810e0c70 100644 --- a/src/gpu/lv_gpu.mk +++ b/src/gpu/lv_gpu.mk @@ -2,7 +2,6 @@ CSRCS += lv_gpu_nxp_pxp.c CSRCS += lv_gpu_nxp_pxp_osa.c CSRCS += lv_gpu_nxp_vglite.c CSRCS += lv_gpu_stm32_dma2d.c -CSRCS += lv_gpu_sdl.c DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu diff --git a/src/gpu/lv_gpu_sdl.c b/src/gpu/lv_gpu_sdl.c deleted file mode 100644 index 447f8120e..000000000 --- a/src/gpu/lv_gpu_sdl.c +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @file lv_gpu_sdl.c - * - */ - -/********************* - * INCLUDES - *********************/ - - -#include "../lv_conf_internal.h" - -#if LV_USE_GPU_SDL - -#include "lv_gpu_sdl.h" -#include "../draw/sdl/lv_draw_sdl_utils.h" -#include "../draw/sdl/lv_draw_sdl_texture_cache.h" - -#include "../draw/sw/lv_draw_sw.h" - -/********************* - * DEFINES - *********************/ -void lv_draw_sdl_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc); - -lv_res_t lv_draw_sdl_img_core(const lv_area_t * coords, const lv_area_t * mask, const void * src, - const lv_draw_img_dsc_t * draw_dsc); - -void lv_draw_sdl_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area, - const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa, - lv_blend_mode_t blend_mode); - -void lv_draw_sdl_draw_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode); - -void lv_draw_sdl_draw_blend_map(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * clip_area, - const lv_color_t * src_buf, const lv_area_t * src_area, - lv_opa_t * mask, lv_opa_t opa, lv_blend_mode_t blend_mode); -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_gpu_sdl_init() -{ - _lv_draw_sdl_utils_init(); - _lv_draw_sdl_texture_cache_init(); -} - -void lv_gpu_sdl_deinit() -{ - _lv_draw_sdl_texture_cache_deinit(); - _lv_draw_sdl_utils_deinit(); -} - -void lv_gpu_sdl_backend_init(lv_draw_backend_t * backend, SDL_Renderer * renderer, SDL_Texture * texture) -{ - lv_draw_backend_init(backend); - lv_draw_sdl_backend_context_t * ctx = lv_mem_alloc(sizeof(lv_draw_sdl_backend_context_t)); - lv_memset_00(ctx, sizeof(lv_draw_sdl_backend_context_t)); - ctx->renderer = renderer; - ctx->texture = texture; - backend->ctx = ctx; - backend->draw_rect = lv_draw_sdl_draw_rect; - backend->draw_arc = lv_draw_sw_arc; - backend->draw_img_core = lv_draw_sdl_img_core; - backend->draw_letter = lv_draw_sdl_draw_letter; - backend->draw_line = lv_draw_sw_line; - backend->draw_polygon = lv_draw_sw_polygon; - backend->blend_fill = lv_draw_sdl_draw_blend_fill; - backend->blend_map = lv_draw_sdl_draw_blend_map; -} - -/********************** - * STATIC FUNCTIONS - **********************/ - - -#endif /*LV_USE_GPU_SDL*/ diff --git a/src/gpu/lv_gpu_stm32_dma2d.c b/src/gpu/lv_gpu_stm32_dma2d.c deleted file mode 100644 index 9653e4121..000000000 --- a/src/gpu/lv_gpu_stm32_dma2d.c +++ /dev/null @@ -1,262 +0,0 @@ -/** - * @file lv_gpu_stm32_dma2d.c - * - */ - -/********************* - * INCLUDES - *********************/ -#include "lv_gpu_stm32_dma2d.h" -#include "../core/lv_disp.h" -#include "../core/lv_refr.h" - -#if LV_USE_GPU_STM32_DMA2D - -#include LV_GPU_DMA2D_CMSIS_INCLUDE - -/********************* - * DEFINES - *********************/ - -#if LV_COLOR_16_SWAP - // TODO: F7 has red blue swap bit in control register for all layers and output - #error "Can't use DMA2D with LV_COLOR_16_SWAP 1" -#endif - -#if LV_COLOR_DEPTH == 8 - #error "Can't use DMA2D with LV_COLOR_DEPTH == 8" -#endif - -#if LV_COLOR_DEPTH == 16 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565 -#elif LV_COLOR_DEPTH == 32 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888 -#else - /*Can't use GPU with other formats*/ -#endif - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ -static void invalidate_cache(void); -static void wait_finish(void); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * Turn on the peripheral and set output color mode, this only needs to be done once - */ -void lv_gpu_stm32_dma2d_init(void) -{ - /*Enable DMA2D clock*/ -#if defined(STM32F4) || defined(STM32F7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; -#elif defined(STM32H7) - RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN; -#else -# warning "LVGL can't enable the clock of DMA2D" -#endif - - /*Wait for hardware access to complete*/ - __asm volatile("DSB\n"); - - /*Delay after setting peripheral clock*/ - volatile uint32_t temp = RCC->AHB1ENR; - LV_UNUSED(temp); - - /*set output colour mode*/ - DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT; -} - -/** - * Fill an area in the buffer with a color - * @param buf a buffer which should be filled - * @param buf_w width of the buffer in pixels - * @param color fill color - * @param fill_w width to fill in pixels (<= buf_w) - * @param fill_h height to fill in pixels - * @note `buf_w - fill_w` is offset to the next line after fill - */ -void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h) -{ - invalidate_cache(); - - DMA2D->CR = 0x30000; - DMA2D->OMAR = (uint32_t)buf; - /*as input color mode is same as output we don't need to convert here do we?*/ - DMA2D->OCOLR = color.full; - DMA2D->OOR = buf_w - fill_w; - DMA2D->NLR = (fill_w << DMA2D_NLR_PL_Pos) | (fill_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; - - wait_finish(); -} - -/** - * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel - * @param buf a buffer which should be filled using a mask - * @param buf_w width of the buffer in pixels - * @param color fill color - * @param mask 0..255 values describing the opacity of the corresponding pixel. Its width is `fill_w` - * @param opa overall opacity. 255 in `mask` should mean this opacity. - * @param fill_w width to fill in pixels (<= buf_w) - * @param fill_h height to fill in pixels - * @note `buf_w - fill_w` is offset to the next line after fill - */ -void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, - lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h) -{ -#if 0 - invalidate_cache(); - - /*Configure the DMA2D Mode, Color Mode and line output offset*/ - hdma2d.Init.Mode = DMA2D_M2M_BLEND; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = buf_w - fill_w; - - /*Configure the foreground -> The character*/ - lv_color32_t c32; - c32.full = lv_color_to32(color); - c32.ch.alpha = opa; - hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = c32.full; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8; - hdma2d.LayerCfg[1].InputOffset = 0; - - /*Configure the background -> Display buffer*/ - hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[0].InputAlpha = 0x00; - hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[0].InputOffset = buf_w - fill_w; - - /*DMA2D Initialization*/ - HAL_DMA2D_Init(&hdma2d); - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - HAL_DMA2D_ConfigLayer(&hdma2d, 1); - HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h); - wait_finish(); -#endif -} - -/** - * Copy a map (typically RGB image) to a buffer - * @param buf a buffer where map should be copied - * @param buf_w width of the buffer in pixels - * @param map an "image" to copy - * @param map_w width of the map in pixels - * @param copy_w width of the area to copy in pixels (<= buf_w) - * @param copy_h height of the area to copy in pixels - * @note `map_w - fill_w` is offset to the next line after copy - */ -void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, - lv_coord_t copy_w, lv_coord_t copy_h) -{ - invalidate_cache(); - - DMA2D->CR = 0; - /*copy output colour mode, this register controls both input and output colour format*/ - DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->FGMAR = (uint32_t)map; - DMA2D->FGOR = map_w - copy_w; - DMA2D->OMAR = (uint32_t)buf; - DMA2D->OOR = buf_w - copy_w; - DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; - wait_finish(); -} - -/** - * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer - * @param buf a buffer where `map` should be copied - * @param buf_w width of the buffer in pixels - * @param map an "image" to copy - * @param opa opacity of `map` - * @param map_w width of the map in pixels - * @param copy_w width of the area to copy in pixels (<= buf_w) - * @param copy_h height of the area to copy in pixels - * @note `map_w - fill_w` is offset to the next line after copy - */ -void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, - lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) -{ - invalidate_cache(); - DMA2D->CR = 0x20000; - - DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->BGMAR = (uint32_t)buf; - DMA2D->BGOR = buf_w - copy_w; - - DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT - /*alpha mode 2, replace with foreground * alpha value*/ - | (2 << DMA2D_FGPFCCR_AM_Pos) - /*alpha value*/ - | (opa << DMA2D_FGPFCCR_ALPHA_Pos); - DMA2D->FGMAR = (uint32_t)map; - DMA2D->FGOR = map_w - copy_w; - - DMA2D->OMAR = (uint32_t)buf; - DMA2D->OOR = buf_w - copy_w; - DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; - wait_finish(); -} - -void lv_gpu_stm32_dma2d_wait_cb(lv_disp_drv_t * drv) -{ - if(drv && drv->wait_cb) { - while(DMA2D->CR & DMA2D_CR_START_Msk) { - drv->wait_cb(drv); - } - } - else { - while(DMA2D->CR & DMA2D_CR_START_Msk); - } -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static void invalidate_cache(void) -{ - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver); - else { -#if __CORTEX_M >= 0x07 - if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk) - SCB_CleanInvalidateDCache(); -#endif - } -} - -static void wait_finish(void) -{ - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->gpu_wait_cb) return; - - while(DMA2D->CR & DMA2D_CR_START_Msk) { - if(disp->driver->wait_cb) disp->driver->wait_cb(disp->driver); - } -} - -#endif diff --git a/src/gpu/lv_gpu_stm32_dma2d.h b/src/gpu/lv_gpu_stm32_dma2d.h deleted file mode 100644 index 014093cec..000000000 --- a/src/gpu/lv_gpu_stm32_dma2d.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file lv_gpu_stm32_dma2d.h - * - */ - -#ifndef LV_GPU_STM32_DMA2D_H -#define LV_GPU_STM32_DMA2D_H - -#ifdef __cplusplus -extern "C" { -#endif - -/********************* - * INCLUDES - *********************/ -#include "../misc/lv_area.h" -#include "../misc/lv_color.h" -#include "../hal/lv_hal_disp.h" - -/********************* - * DEFINES - *********************/ - -#define LV_DMA2D_ARGB8888 0 -#define LV_DMA2D_RGB888 1 -#define LV_DMA2D_RGB565 2 -#define LV_DMA2D_ARGB1555 3 -#define LV_DMA2D_ARGB4444 4 - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * GLOBAL PROTOTYPES - **********************/ - -/** - * Turn on the peripheral and set output color mode, this only needs to be done once - */ -void lv_gpu_stm32_dma2d_init(void); - -/** - * Fill an area in the buffer with a color - * @param buf a buffer which should be filled - * @param buf_w width of the buffer in pixels - * @param color fill color - * @param fill_w width to fill in pixels (<= buf_w) - * @param fill_h height to fill in pixels - * @note `buf_w - fill_w` is offset to the next line after fill - */ -void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, - lv_coord_t fill_h); - -/** - * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel - * @param buf a buffer which should be filled using a mask - * @param buf_w width of the buffer in pixels - * @param color fill color - * @param mask 0..255 values describing the opacity of the corresponding pixel. Its width is `fill_w` - * @param opa overall opacity. 255 in `mask` should mean this opacity. - * @param fill_w width to fill in pixels (<= buf_w) - * @param fill_h height to fill in pixels - * @note `buf_w - fill_w` is offset to the next line after fill - */ -void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, - lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h); - -/** - * Copy a map (typically RGB image) to a buffer - * @param buf a buffer where map should be copied - * @param buf_w width of the buffer in pixels - * @param map an "image" to copy - * @param map_w width of the map in pixels - * @param copy_w width of the area to copy in pixels (<= buf_w) - * @param copy_h height of the area to copy in pixels - * @note `map_w - fill_w` is offset to the next line after copy - */ -void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, - lv_coord_t copy_w, lv_coord_t copy_h); -/** - * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer - * @param buf a buffer where `map` should be copied - * @param buf_w width of the buffer in pixels - * @param map an "image" to copy - * @param opa opacity of `map` - * @param map_w width of the map in pixels - * @param copy_w width of the area to copy in pixels (<= buf_w) - * @param copy_h height of the area to copy in pixels - * @note `map_w - fill_w` is offset to the next line after copy - */ -void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, - lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); - -/** - * Can be used as `gpu_wait_cb` in display driver to - * let the MCU run while the GPU is working - */ -void lv_gpu_stm32_dma2d_wait_cb(lv_disp_drv_t * drv); - -/********************** - * MACROS - **********************/ - -#ifdef __cplusplus -} /*extern "C"*/ -#endif - -#endif /*LV_GPU_STM32_DMA2D_H*/ diff --git a/src/hal/lv_hal_disp.c b/src/hal/lv_hal_disp.c index 4bbf20adf..9a8e42d28 100644 --- a/src/hal/lv_hal_disp.c +++ b/src/hal/lv_hal_disp.c @@ -17,6 +17,11 @@ #include "../core/lv_obj.h" #include "../core/lv_refr.h" #include "../core/lv_theme.h" +#include "../draw/sdl/lv_draw_sdl.h" +#include "../draw/sw/lv_draw_sw.h" +#include "../draw/sdl/lv_draw_sdl.h" +#include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" + #if LV_USE_THEME_DEFAULT #include "../extra/themes/default/lv_theme_default.h" #endif @@ -85,6 +90,30 @@ void lv_disp_drv_init(lv_disp_drv_t * driver) driver->screen_transp = LV_COLOR_SCREEN_TRANSP; driver->dpi = LV_DPI_DEF; driver->color_chroma_key = LV_COLOR_CHROMA_KEY; + + +#if LV_USE_GPU_STM32_DMA2D + driver->draw_ctx_init = lv_draw_stm32_dma2d_ctx_init; + driver->draw_ctx_deinit = lv_draw_stm32_dma2d_ctx_init; + driver->draw_ctx_size = sizeof(lv_draw_stm32_dma2d_ctx_t); +#elif LV_USE_GPU_NXP_PXP + driver->draw_ctx_init = lv_draw_nxp_pxp_init; + driver->draw_ctx_deinit = lv_draw_nxp_pxp_init; + driver->draw_ctx_size = sizeof(lv_draw_nxp_pxp_t); +#elif LV_USE_GPU_NXP_VG_LITE + driver->draw_ctx_init = lv_draw_nxp_vglite_init; + driver->draw_ctx_deinit = lv_draw_nxp_vglite_init; + driver->draw_ctx_size = sizeof(lv_draw_nxp_vglite_t); +#elif LV_USE_GPU_SDL + driver->draw_ctx_init = lv_draw_sdl_init_ctx; + driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx; + driver->draw_ctx_size = sizeof(lv_draw_sdl_ctx_t); +#else + driver->draw_ctx_init = lv_draw_sw_init_ctx; + driver->draw_ctx_deinit = lv_draw_sw_init_ctx; + driver->draw_ctx_size = sizeof(lv_draw_sw_ctx_t); +#endif + } /** @@ -126,6 +155,15 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver) return NULL; } + /*Create a draw context if not created yet*/ + if(driver->draw_ctx == NULL) { + lv_draw_ctx_t * draw_ctx = lv_mem_alloc(driver->draw_ctx_size); + LV_ASSERT_MALLOC(draw_ctx); + if(draw_ctx == NULL) return NULL; + driver->draw_ctx_init(driver, draw_ctx); + driver->draw_ctx = draw_ctx; + } + lv_memset_00(disp, sizeof(lv_disp_t)); disp->driver = driver; @@ -462,7 +500,12 @@ LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv) /*If the screen is transparent initialize it when the flushing is ready*/ #if LV_COLOR_SCREEN_TRANSP if(disp_drv->screen_transp) { - lv_memset_00(disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size * sizeof(lv_color32_t)); + if(disp_drv->clear_cb) { + disp_drv->clear_cb(disp_drv, disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size); + } + else { + lv_memset_00(disp_drv->draw_buf->buf_act, disp_drv->draw_buf->size * sizeof(lv_color32_t)); + } } #endif diff --git a/src/hal/lv_hal_disp.h b/src/hal/lv_hal_disp.h index 76679b1fc..6abbab1f9 100644 --- a/src/hal/lv_hal_disp.h +++ b/src/hal/lv_hal_disp.h @@ -18,7 +18,7 @@ extern "C" { #include #include #include "lv_hal.h" -#include "../draw/lv_img_buf.h" +#include "../draw/lv_draw.h" #include "../misc/lv_color.h" #include "../misc/lv_area.h" #include "../misc/lv_ll.h" @@ -54,7 +54,6 @@ typedef struct _lv_disp_draw_buf_t { /*Internal, used by the library*/ void * buf_act; uint32_t size; /*In pixel count*/ - lv_area_t area; /*1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/ volatile int flushing; /*1: It was the last chunk to flush. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/ @@ -116,6 +115,9 @@ typedef struct _lv_disp_drv_t { void (*set_px_cb)(struct _lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); + void (*clear_cb)(struct _lv_disp_drv_t * disp_drv, uint8_t * buf, uint32_t size); + + /** OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the * number of flushed pixels*/ void (*monitor_cb)(struct _lv_disp_drv_t * disp_drv, uint32_t time, uint32_t px); @@ -128,20 +130,18 @@ typedef struct _lv_disp_drv_t { /** OPTIONAL: Called when lvgl needs any CPU cache that affects rendering to be cleaned*/ void (*clean_dcache_cb)(struct _lv_disp_drv_t * disp_drv); - /** OPTIONAL: called to wait while the gpu is working*/ - void (*gpu_wait_cb)(struct _lv_disp_drv_t * disp_drv); - /** OPTIONAL: called when driver parameters are updated */ void (*drv_update_cb)(struct _lv_disp_drv_t * disp_drv); - /** OPTIONAL: Fill a memory with a color (GPU only)*/ - void (*gpu_fill_cb)(struct _lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, - const lv_area_t * fill_area, lv_color_t color); - /** On CHROMA_KEYED images this color will be transparent. * `LV_COLOR_CHROMA_KEY` by default. (lv_conf.h)*/ lv_color_t color_chroma_key; + lv_draw_ctx_t * draw_ctx; + void (*draw_ctx_init)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + void (*draw_ctx_deinit)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + size_t draw_ctx_size; + #if LV_USE_USER_DATA void * user_data; /**< Custom display driver user data*/ #endif @@ -176,7 +176,6 @@ uint8_t del_prev : lv_opa_t bg_opa; /** #endif #endif + #ifndef LV_GPU_SDL_LRU_SIZE + #ifdef CONFIG_LV_GPU_SDL_LRU_SIZE + #define LV_GPU_SDL_LRU_SIZE CONFIG_LV_GPU_SDL_LRU_SIZE + #else + #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) + #endif + #endif #endif /*------------- diff --git a/src/draw/sdl/lv_draw_sdl_lru.c b/src/misc/lv_lru.c similarity index 84% rename from src/draw/sdl/lv_draw_sdl_lru.c rename to src/misc/lv_lru.c index e75b2a48e..8446ef717 100644 --- a/src/draw/sdl/lv_draw_sdl_lru.c +++ b/src/misc/lv_lru.c @@ -1,17 +1,15 @@ /** - * @file lv_draw_sdl_lru.c + * @file lv_lru.c * + * @see https://github.com/willcannings/C-LRU-Cache */ /********************* * INCLUDES *********************/ -#include "../../lv_conf_internal.h" - -#if LV_USE_GPU_SDL -#include "../../misc/lv_log.h" -#include "lv_draw_sdl_lru.h" +#include "lv_lru.h" +#include "lv_log.h" #include #include @@ -66,23 +64,11 @@ static lruc_item * lv_lru_pop_or_create_item(lv_lru_t * cache); #define test_for_missing_value() error_for(!value || value_length == 0, LV_LRU_MISSING_VALUE) #define test_for_value_too_large() error_for(value_length > cache->total_memory, LV_LRU_VALUE_TOO_LARGE) -/* lock helpers */ -#define lock_cache() if(SDL_LockMutex(cache->mutex)) {\ - LV_LOG_WARN("LRU Cache unable to obtain mutex lock");\ - return LV_LRU_LOCK_ERROR;\ - } - -#define unlock_cache() if(SDL_UnlockMutex(cache->mutex)) {\ - LV_LOG_WARN("LRU Cache unable to release mutex lock");\ - return LV_LRU_LOCK_ERROR;\ - } - - /********************** * GLOBAL FUNCTIONS **********************/ -lv_lru_t * lv_lru_new(uint64_t cache_size, uint32_t average_length, lv_lru_free_t * value_free, +lv_lru_t * lv_lru_new(size_t cache_size, size_t average_length, lv_lru_free_t * value_free, lv_lru_free_t * key_free) { // create the cache @@ -106,15 +92,6 @@ lv_lru_t * lv_lru_new(uint64_t cache_size, uint32_t average_length, lv_lru_free_ free(cache); return NULL; } - - // all cache calls are guarded by a mutex - cache->mutex = SDL_CreateMutex(); - if(!cache->mutex) { - LV_LOG_WARN("LRU Cache unable to initialise mutex"); - free(cache->items); - free(cache); - return NULL; - } return cache; } @@ -151,9 +128,6 @@ lruc_error lv_lru_free(lv_lru_t * cache) } // free the cache - if(cache->mutex) { - SDL_DestroyMutex(cache->mutex); - } free(cache); return LV_LRU_NO_ERROR; @@ -166,11 +140,10 @@ lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, voi test_for_missing_key(); test_for_missing_value(); test_for_value_too_large(); - lock_cache(); // see if the key already exists uint32_t hash_index = lv_lru_hash(cache, key, key_length); - int64_t required = 0; + ssize_t required = 0; lruc_item * item = NULL, *prev = NULL; item = cache->items[hash_index]; @@ -181,7 +154,7 @@ lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, voi if(item) { // update the value and value_lengths - required = (int)(value_length - item->value_length); + required = (ssize_t)(value_length - item->value_length); cache->value_free(item->value); item->value = value; item->value_length = value_length; @@ -195,7 +168,7 @@ lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, voi memcpy(item->key, key, key_length); item->value_length = value_length; item->key_length = key_length; - required = value_length; + required = (ssize_t) value_length; if(prev) prev->next = item; @@ -205,12 +178,11 @@ lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, voi item->access_count = ++cache->access_count; // remove as many items as necessary to free enough space - if(required > 0 && required > cache->free_memory) { - while(cache->free_memory < required) + if(required > 0 && (size_t) required > cache->free_memory) { + while(cache->free_memory < (size_t) required) lv_lru_remove_lru_item(cache); } cache->free_memory -= required; - unlock_cache(); return LV_LRU_NO_ERROR; } @@ -219,7 +191,6 @@ lruc_error lv_lru_get(lv_lru_t * cache, const void * key, size_t key_size, void { test_for_missing_cache(); test_for_missing_key(); - lock_cache(); // loop until we find the item, or hit the end of a chain uint32_t hash_index = lv_lru_hash(cache, key, key_size); @@ -236,7 +207,6 @@ lruc_error lv_lru_get(lv_lru_t * cache, const void * key, size_t key_size, void *value = NULL; } - unlock_cache(); return LV_LRU_NO_ERROR; } @@ -244,7 +214,6 @@ lruc_error lv_lru_delete(lv_lru_t * cache, const void * key, size_t key_size) { test_for_missing_cache(); test_for_missing_key(); - lock_cache(); // loop until we find the item, or hit the end of a chain lruc_item * item = NULL, *prev = NULL; @@ -260,7 +229,6 @@ lruc_error lv_lru_delete(lv_lru_t * cache, const void * key, size_t key_size) lv_lru_remove_item(cache, prev, item, hash_index); } - unlock_cache(); return LV_LRU_NO_ERROR; } @@ -286,16 +254,16 @@ static uint32_t lv_lru_hash(lv_lru_t * cache, const void * key, uint32_t key_len key_length -= 4; } - switch(key_length) { - case 3: - h ^= data[2] << 16; - case 2: - h ^= data[1] << 8; - case 1: - h ^= data[0]; - h *= m; - break; - }; + if(key_length >= 3) { + h ^= data[2] << 16; + } + if(key_length >= 2) { + h ^= data[1] << 8; + } + if(key_length >= 1) { + h ^= data[0]; + h *= m; + } h ^= h >> 13; h *= m; @@ -341,7 +309,7 @@ static void lv_lru_remove_lru_item(lv_lru_t * cache) prev = NULL; while(item) { - if(item->access_count < min_access_count || min_access_count == -1) { + if(item->access_count < min_access_count || (int64_t) min_access_count == -1) { min_access_count = item->access_count; min_item = item; min_prev = prev; @@ -371,5 +339,3 @@ static lruc_item * lv_lru_pop_or_create_item(lv_lru_t * cache) return item; } - -#endif /*LV_USE_GPU_SDL*/ diff --git a/src/draw/sdl/lv_draw_sdl_lru.h b/src/misc/lv_lru.h similarity index 81% rename from src/draw/sdl/lv_draw_sdl_lru.h rename to src/misc/lv_lru.h index c2597e967..92dcc4033 100644 --- a/src/draw/sdl/lv_draw_sdl_lru.h +++ b/src/misc/lv_lru.h @@ -1,5 +1,5 @@ /** - * @file lv_draw_sdl_lru.h + * @file lv_lru.h * */ @@ -14,9 +14,7 @@ extern "C" { * INCLUDES *********************/ -#include "../../lv_conf_internal.h" - -#include LV_GPU_SDL_INCLUDE_PATH +#include "../lv_conf_internal.h" #include #include @@ -53,15 +51,14 @@ typedef struct lruc_item { typedef struct { lruc_item ** items; uint64_t access_count; - uint64_t free_memory; - uint64_t total_memory; - uint64_t average_item_length; - uint32_t hash_table_size; + size_t free_memory; + size_t total_memory; + size_t average_item_length; + size_t hash_table_size; time_t seed; lv_lru_free_t * value_free; lv_lru_free_t * key_free; lruc_item * free_items; - SDL_mutex * mutex; } lv_lru_t; @@ -69,7 +66,7 @@ typedef struct { * GLOBAL PROTOTYPES **********************/ -lv_lru_t * lv_lru_new(uint64_t cache_size, uint32_t average_length, lv_lru_free_t * value_free, +lv_lru_t * lv_lru_new(size_t cache_size, size_t average_length, lv_lru_free_t * value_free, lv_lru_free_t * key_free); lruc_error lv_lru_free(lv_lru_t * cache); diff --git a/src/misc/lv_misc.mk b/src/misc/lv_misc.mk index 5e053f877..1dfd4eec9 100644 --- a/src/misc/lv_misc.mk +++ b/src/misc/lv_misc.mk @@ -8,6 +8,7 @@ CSRCS += lv_fs.c CSRCS += lv_gc.c CSRCS += lv_ll.c CSRCS += lv_log.c +CSRCS += lv_lru.c CSRCS += lv_math.c CSRCS += lv_mem.c CSRCS += lv_printf.c diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h index fc445f80d..6561a9471 100644 --- a/src/misc/lv_style.h +++ b/src/misc/lv_style.h @@ -63,6 +63,7 @@ enum { LV_BLEND_MODE_ADDITIVE, /**< Add the respective color channels*/ LV_BLEND_MODE_SUBTRACTIVE,/**< Subtract the foreground from the background*/ LV_BLEND_MODE_MULTIPLY, /**< Multiply the foreground and background*/ + LV_BLEND_MODE_REPLACE, /**< Replace background with foreground in the area*/ }; typedef uint8_t lv_blend_mode_t; diff --git a/src/widgets/lv_arc.c b/src/widgets/lv_arc.c index e7fd037b5..6f0a00720 100644 --- a/src/widgets/lv_arc.c +++ b/src/widgets/lv_arc.c @@ -549,14 +549,14 @@ static void lv_arc_draw(lv_event_t * e) lv_obj_t * obj = lv_event_get_target(e); lv_arc_t * arc = (lv_arc_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_point_t center; lv_coord_t arc_r; get_center(obj, ¢er, &arc_r); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); /*Draw the background arc*/ lv_draw_arc_dsc_t arc_dsc; @@ -572,14 +572,13 @@ static void lv_arc_draw(lv_event_t * e) part_draw_dsc.arc_dsc = &arc_dsc; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_arc(center.x, center.y, part_draw_dsc.radius, arc->bg_angle_start + arc->rotation, - arc->bg_angle_end + arc->rotation, clip_area, - &arc_dsc); + lv_draw_arc(draw_ctx, &arc_dsc, ¢er, part_draw_dsc.radius, arc->bg_angle_start + arc->rotation, + arc->bg_angle_end + arc->rotation); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } - /*make the indicator arc smaller or larger according to its greatest padding value*/ + /*Make the indicator arc smaller or larger according to its greatest padding value*/ lv_coord_t left_indic = lv_obj_get_style_pad_left(obj, LV_PART_INDICATOR); lv_coord_t right_indic = lv_obj_get_style_pad_right(obj, LV_PART_INDICATOR); lv_coord_t top_indic = lv_obj_get_style_pad_top(obj, LV_PART_INDICATOR); @@ -599,9 +598,8 @@ static void lv_arc_draw(lv_event_t * e) lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); if(arc_dsc.width > part_draw_dsc.radius) arc_dsc.width = part_draw_dsc.radius; - lv_draw_arc(center.x, center.y, part_draw_dsc.radius, arc->indic_angle_start + arc->rotation, - arc->indic_angle_end + arc->rotation, clip_area, - &arc_dsc); + lv_draw_arc(draw_ctx, &arc_dsc, ¢er, part_draw_dsc.radius, arc->indic_angle_start + arc->rotation, + arc->indic_angle_end + arc->rotation); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } @@ -620,7 +618,7 @@ static void lv_arc_draw(lv_event_t * e) part_draw_dsc.rect_dsc = &knob_rect_dsc; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&knob_area, clip_area, &knob_rect_dsc); + lv_draw_rect(draw_ctx, &knob_rect_dsc, &knob_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } diff --git a/src/widgets/lv_bar.c b/src/widgets/lv_bar.c index 5037f4288..ea1113cb3 100644 --- a/src/widgets/lv_bar.c +++ b/src/widgets/lv_bar.c @@ -237,7 +237,7 @@ static void draw_indic(lv_event_t * e) lv_obj_t * obj = lv_event_get_target(e); lv_bar_t * bar = (lv_bar_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t bar_coords; lv_obj_get_coords(obj, &bar_coords); @@ -381,7 +381,7 @@ static void draw_indic(lv_event_t * e) if(!sym && indic_length_calc(&bar->indic_area) <= 1) { lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_INDICATOR; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_BAR_DRAW_PART_INDICATOR; @@ -404,7 +404,7 @@ static void draw_indic(lv_event_t * e) lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &draw_rect_dsc); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_INDICATOR; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_BAR_DRAW_PART_INDICATOR; @@ -425,7 +425,7 @@ static void draw_indic(lv_event_t * e) draw_rect_dsc.bg_img_opa = LV_OPA_TRANSP; draw_rect_dsc.border_opa = LV_OPA_TRANSP; - lv_draw_rect(&bar->indic_area, clip_area, &draw_rect_dsc); + lv_draw_rect(draw_ctx, &draw_rect_dsc, &bar->indic_area); draw_rect_dsc.bg_opa = bg_opa; draw_rect_dsc.bg_img_opa = bg_img_opa; @@ -473,7 +473,7 @@ static void draw_indic(lv_event_t * e) int16_t mask_indic_id = lv_draw_mask_add(&mask_indic_param, NULL); #endif - lv_draw_rect(&mask_indic_max_area, clip_area, &draw_rect_dsc); + lv_draw_rect(draw_ctx, &draw_rect_dsc, &mask_indic_max_area); draw_rect_dsc.border_opa = border_opa; draw_rect_dsc.shadow_opa = shadow_opa; @@ -481,7 +481,7 @@ static void draw_indic(lv_event_t * e) draw_rect_dsc.bg_opa = LV_OPA_TRANSP; draw_rect_dsc.bg_img_opa = LV_OPA_TRANSP; draw_rect_dsc.shadow_opa = LV_OPA_TRANSP; - lv_draw_rect(&bar->indic_area, clip_area, &draw_rect_dsc); + lv_draw_rect(draw_ctx, &draw_rect_dsc, &bar->indic_area); #if LV_DRAW_COMPLEX lv_draw_mask_free_param(&mask_indic_param); diff --git a/src/widgets/lv_btnmatrix.c b/src/widgets/lv_btnmatrix.c index 9ef0ec33f..0038d1bc8 100644 --- a/src/widgets/lv_btnmatrix.c +++ b/src/widgets/lv_btnmatrix.c @@ -652,7 +652,7 @@ static void draw_main(lv_event_t * e) lv_btnmatrix_t * btnm = (lv_btnmatrix_t *)obj; if(btnm->btn_cnt == 0) return; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); obj->skip_trans = 1; lv_area_t area_obj; @@ -690,7 +690,7 @@ static void draw_main(lv_event_t * e) #endif lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_ITEMS; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_BTNMATRIX_DRAW_PART_BTN; @@ -768,7 +768,7 @@ static void draw_main(lv_event_t * e) } /*Draw the background*/ - lv_draw_rect(&btn_area, clip_area, &draw_rect_dsc_act); + lv_draw_rect(draw_ctx, &draw_rect_dsc_act, &btn_area); /*Calculate the size of the text*/ const lv_font_t * font = draw_label_dsc_act.font; @@ -800,7 +800,7 @@ static void draw_main(lv_event_t * e) } /*Draw the text*/ - lv_draw_label(&btn_area, clip_area, &draw_label_dsc_act, txt, NULL); + lv_draw_label(draw_ctx, &draw_label_dsc_act, &btn_area, txt, NULL); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } diff --git a/src/widgets/lv_canvas.c b/src/widgets/lv_canvas.c index d5efc402d..6fc27989a 100644 --- a/src/widgets/lv_canvas.c +++ b/src/widgets/lv_canvas.c @@ -28,6 +28,8 @@ **********************/ static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); +static void init_fake_disp(lv_obj_t * canvas, lv_disp_t * disp, lv_disp_drv_t * drv, lv_area_t * clip_area); +static void deinit_fake_disp(lv_obj_t * canvas, lv_disp_t * disp); /********************** * STATIC VARIABLES @@ -560,11 +562,20 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord /*Create a dummy display to fool the lv_draw function. *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; + lv_disp_t fake_disp; + lv_disp_drv_t driver; + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); + + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); + + /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ + lv_color_t ctransp = LV_COLOR_CHROMA_KEY; + if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && + draw_dsc->bg_color.full == ctransp.full) { + fake_disp.driver->antialiasing = 0; + } lv_area_t coords; coords.x1 = x; @@ -572,38 +583,12 @@ void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord coords.x2 = x + w - 1; coords.y2 = y + h - 1; - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ - lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; - - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); - - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); - - /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ - lv_color_t ctransp = LV_COLOR_CHROMA_KEY; - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && - draw_dsc->bg_color.full == ctransp.full) { - disp.driver->antialiasing = 0; - } - - lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); - - lv_draw_rect(&coords, &mask, draw_dsc); + lv_draw_rect(driver.draw_ctx, draw_dsc, &coords); _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); } @@ -621,43 +606,25 @@ void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord /*Create a dummy display to fool the lv_draw function. *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; + lv_disp_t fake_disp; + lv_disp_drv_t driver; + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); + + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); lv_area_t coords; coords.x1 = x; coords.y1 = y; coords.x2 = x + max_w - 1; coords.y2 = dsc->header.h - 1; - - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ - lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; - - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); - - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); - - lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); - - lv_draw_label(&coords, &mask, draw_dsc, txt, NULL); + lv_draw_label(driver.draw_ctx, draw_dsc, &coords, txt, NULL); _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); } @@ -673,20 +640,21 @@ void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const voi return; } - /*Create a dummy display to fool the lv_draw function. - *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; - lv_img_header_t header; lv_res_t res = lv_img_decoder_get_info(src, &header); if(res != LV_RES_OK) { LV_LOG_WARN("lv_canvas_draw_img: Couldn't get the image data."); return; } + /*Create a dummy display to fool the lv_draw function. + *It will think it draws to real screen.*/ + lv_disp_t fake_disp; + lv_disp_drv_t driver; + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); + + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); lv_area_t coords; coords.x1 = x; @@ -694,31 +662,12 @@ void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const voi coords.x2 = x + header.w - 1; coords.y2 = y + header.h - 1; - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ - lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; - - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); - - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); - - lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); - - lv_draw_img(&coords, &mask, src, draw_dsc); + lv_draw_img(driver.draw_ctx, draw_dsc, &coords, src); _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); } @@ -733,49 +682,34 @@ void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t points[], uint32_t LV_LOG_WARN("lv_canvas_draw_line: can't draw to LV_IMG_CF_INDEXED canvas"); return; } + /*Create a dummy display to fool the lv_draw function. *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; - - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ + lv_disp_t fake_disp; lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_CHROMA_KEY; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && draw_dsc->color.full == ctransp.full) { - disp.driver->antialiasing = 0; + fake_disp.driver->antialiasing = 0; } - lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); - uint32_t i; for(i = 0; i < point_cnt - 1; i++) { - lv_draw_line(&points[i], &points[i + 1], &mask, draw_dsc); + lv_draw_line(driver.draw_ctx, draw_dsc, &points[i], &points[i + 1]); } _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); } @@ -793,44 +727,27 @@ void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t points[], uint32 /*Create a dummy display to fool the lv_draw function. *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; - - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ + lv_disp_t fake_disp; lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); - - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); + lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); + _lv_refr_set_disp_refreshing(&fake_disp); /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ lv_color_t ctransp = LV_COLOR_CHROMA_KEY; if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && draw_dsc->bg_color.full == ctransp.full) { - disp.driver->antialiasing = 0; + fake_disp.driver->antialiasing = 0; } - lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); - - lv_draw_polygon(points, point_cnt, &mask, draw_dsc); + lv_draw_polygon(driver.draw_ctx, draw_dsc, points, point_cnt); _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); } @@ -849,44 +766,21 @@ void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_ /*Create a dummy display to fool the lv_draw function. *It will think it draws to real screen.*/ - lv_area_t mask; - mask.x1 = 0; - mask.x2 = dsc->header.w - 1; - mask.y1 = 0; - mask.y2 = dsc->header.h - 1; - - lv_disp_t disp; - /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ + lv_disp_t fake_disp; lv_disp_drv_t driver; - lv_memset_00(&disp, sizeof(lv_disp_t)); - disp.driver = &driver; - - lv_disp_draw_buf_t draw_buf; - lv_disp_draw_buf_init(&draw_buf, (void *)dsc->data, NULL, dsc->header.w * dsc->header.h); - lv_area_copy(&draw_buf.area, &mask); - - lv_disp_drv_init(disp.driver); - - disp.driver->draw_buf = &draw_buf; - disp.driver->hor_res = dsc->header.w; - disp.driver->ver_res = dsc->header.h; - - lv_disp_drv_use_generic_set_px_cb(disp.driver, dsc->header.cf); - - /*Disable anti-aliasing if drawing with transparent color to chroma keyed canvas*/ - lv_color_t ctransp = LV_COLOR_CHROMA_KEY; - if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED && - draw_dsc->color.full == ctransp.full) { - disp.driver->antialiasing = 0; - } + lv_area_t clip_area; + init_fake_disp(canvas, &fake_disp, &driver, &clip_area); lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing(); - _lv_refr_set_disp_refreshing(&disp); + _lv_refr_set_disp_refreshing(&fake_disp); - lv_draw_arc(x, y, r, start_angle, end_angle, &mask, draw_dsc); + lv_point_t p = {x, y}; + lv_draw_arc(driver.draw_ctx, draw_dsc, &p, r, start_angle, end_angle); _lv_refr_set_disp_refreshing(refr_ori); + deinit_fake_disp(canvas, &fake_disp); + lv_obj_invalidate(canvas); #else LV_UNUSED(canvas); @@ -932,4 +826,44 @@ static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_img_cache_invalidate_src(&canvas->dsc); } + +static void init_fake_disp(lv_obj_t * canvas, lv_disp_t * disp, lv_disp_drv_t * drv, lv_area_t * clip_area) +{ + lv_img_dsc_t * dsc = lv_canvas_get_img(canvas); + + clip_area->x1 = 0; + clip_area->x2 = dsc->header.w - 1; + clip_area->y1 = 0; + clip_area->y2 = dsc->header.h - 1; + + /*Allocate the fake driver on the stack as the entire display doesn't outlive this function*/ + lv_memset_00(disp, sizeof(lv_disp_t)); + disp->driver = drv; + + lv_disp_drv_init(disp->driver); + disp->driver->hor_res = dsc->header.w; + disp->driver->ver_res = dsc->header.h; + + lv_disp_t * canvas_disp = lv_obj_get_disp(canvas); + + lv_draw_ctx_t * draw_ctx = lv_mem_alloc(canvas_disp->driver->draw_ctx_size); + LV_ASSERT_MALLOC(draw_ctx); + if(draw_ctx == NULL) return; + canvas_disp->driver->draw_ctx_init(disp->driver, draw_ctx); + disp->driver->draw_ctx = draw_ctx; + draw_ctx->clip_area = clip_area; + draw_ctx->buf_area = clip_area; + draw_ctx->buf = (void *)dsc->data; + + lv_disp_drv_use_generic_set_px_cb(disp->driver, dsc->header.cf); +} + +static void deinit_fake_disp(lv_obj_t * canvas, lv_disp_t * disp) +{ + lv_disp_t * canvas_disp = lv_obj_get_disp(canvas); + canvas_disp->driver->draw_ctx_deinit(disp->driver, disp->driver->draw_ctx); +} + + + #endif diff --git a/src/widgets/lv_checkbox.c b/src/widgets/lv_checkbox.c index 59b6b0e4c..dd3b3d157 100644 --- a/src/widgets/lv_checkbox.c +++ b/src/widgets/lv_checkbox.c @@ -195,7 +195,7 @@ static void lv_checkbox_draw(lv_event_t * e) lv_obj_t * obj = lv_event_get_target(e); lv_checkbox_t * cb = (lv_checkbox_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN); lv_coord_t font_h = lv_font_get_line_height(font); @@ -229,7 +229,7 @@ static void lv_checkbox_draw(lv_event_t * e) marker_area_transf.y2 += transf_h; lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.rect_dsc = &indic_dsc; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_CHECKBOX_DRAW_PART_BOX; @@ -237,7 +237,7 @@ static void lv_checkbox_draw(lv_event_t * e) part_draw_dsc.part = LV_PART_INDICATOR; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&marker_area_transf, clip_area, &indic_dsc); + lv_draw_rect(draw_ctx, &indic_dsc, &marker_area_transf); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN); @@ -257,6 +257,6 @@ static void lv_checkbox_draw(lv_event_t * e) txt_area.y1 = obj->coords.y1 + bg_topp + y_ofs; txt_area.y2 = txt_area.y1 + txt_size.y; - lv_draw_label(&txt_area, clip_area, &txt_dsc, cb->txt, NULL); + lv_draw_label(draw_ctx, &txt_dsc, &txt_area, cb->txt, NULL); } #endif diff --git a/src/widgets/lv_dropdown.c b/src/widgets/lv_dropdown.c index a4382602e..5c97a1637 100644 --- a/src/widgets/lv_dropdown.c +++ b/src/widgets/lv_dropdown.c @@ -47,8 +47,8 @@ static void lv_dropdownlist_destructor(const lv_obj_class_t * class_p, lv_obj_t static void lv_dropdown_list_event(const lv_obj_class_t * class_p, lv_event_t * e); static void draw_list(lv_event_t * e); -static void draw_box(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, uint16_t id, lv_state_t state); -static void draw_box_label(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, uint16_t id, lv_state_t state); +static void draw_box(lv_obj_t * dropdown_obj, lv_draw_ctx_t * draw_ctx, uint16_t id, lv_state_t state); +static void draw_box_label(lv_obj_t * dropdown_obj, lv_draw_ctx_t * draw_ctx, uint16_t id, lv_state_t state); static lv_res_t btn_release_handler(lv_obj_t * obj); static lv_res_t list_release_handler(lv_obj_t * list_obj); static void list_press_handler(lv_obj_t * page); @@ -754,7 +754,7 @@ static void draw_main(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_dropdown_t * dropdown = (lv_dropdown_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_MAIN); lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN) + border_width; @@ -815,7 +815,7 @@ static void draw_main(lv_event_t * e) if(symbol_type == LV_IMG_SRC_SYMBOL) { symbol_area.y1 = obj->coords.y1 + top; symbol_area.y2 = symbol_area.y1 + symbol_h - 1; - lv_draw_label(&symbol_area, clip_area, &symbol_dsc, dropdown->symbol, NULL); + lv_draw_label(draw_ctx, &symbol_dsc, &symbol_area, dropdown->symbol, NULL); } else { symbol_area.y1 = obj->coords.y1 + (lv_obj_get_height(obj) - symbol_h) / 2; @@ -826,7 +826,7 @@ static void draw_main(lv_event_t * e) img_dsc.pivot.x = symbol_w / 2; img_dsc.pivot.y = symbol_h / 2; img_dsc.angle = lv_obj_get_style_transform_angle(obj, LV_PART_INDICATOR); - lv_draw_img(&symbol_area, clip_area, dropdown->symbol, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &symbol_area, dropdown->symbol); } } @@ -857,7 +857,7 @@ static void draw_main(lv_event_t * e) txt_area.x2 = txt_area.x1 + size.x; } } - lv_draw_label(&txt_area, clip_area, &label_dsc, opt_txt, NULL); + lv_draw_label(draw_ctx, &label_dsc, &txt_area, opt_txt, NULL); if(dropdown->text == NULL) { lv_mem_buf_release((char *)opt_txt); @@ -870,34 +870,37 @@ static void draw_list(lv_event_t * e) lv_dropdown_list_t * list = (lv_dropdown_list_t *)list_obj; lv_obj_t * dropdown_obj = list->dropdown; lv_dropdown_t * dropdown = (lv_dropdown_t *)dropdown_obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); /* Clip area might be too large too to shadow but * the selected option can be drawn on only the background*/ lv_area_t clip_area_core; bool has_common; - has_common = _lv_area_intersect(&clip_area_core, clip_area, &dropdown->list->coords); + has_common = _lv_area_intersect(&clip_area_core, draw_ctx->clip_area, &dropdown->list->coords); if(has_common) { + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area_core; if(dropdown->selected_highlight) { if(dropdown->pr_opt_id == dropdown->sel_opt_id) { - draw_box(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_CHECKED | LV_STATE_PRESSED); - draw_box_label(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_CHECKED | LV_STATE_PRESSED); + draw_box(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_CHECKED | LV_STATE_PRESSED); + draw_box_label(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_CHECKED | LV_STATE_PRESSED); } else { - draw_box(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_PRESSED); - draw_box_label(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_PRESSED); - draw_box(dropdown_obj, &clip_area_core, dropdown->sel_opt_id, LV_STATE_CHECKED); - draw_box_label(dropdown_obj, &clip_area_core, dropdown->sel_opt_id, LV_STATE_CHECKED); + draw_box(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_PRESSED); + draw_box_label(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_PRESSED); + draw_box(dropdown_obj, draw_ctx, dropdown->sel_opt_id, LV_STATE_CHECKED); + draw_box_label(dropdown_obj, draw_ctx, dropdown->sel_opt_id, LV_STATE_CHECKED); } } else { - draw_box(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_PRESSED); - draw_box_label(dropdown_obj, &clip_area_core, dropdown->pr_opt_id, LV_STATE_PRESSED); + draw_box(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_PRESSED); + draw_box_label(dropdown_obj, draw_ctx, dropdown->pr_opt_id, LV_STATE_PRESSED); } + draw_ctx->clip_area = clip_area_ori; } } -static void draw_box(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, uint16_t id, lv_state_t state) +static void draw_box(lv_obj_t * dropdown_obj, lv_draw_ctx_t * draw_ctx, uint16_t id, lv_state_t state) { if(id == LV_DROPDOWN_PR_NONE) return; @@ -929,13 +932,13 @@ static void draw_box(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, uint1 lv_draw_rect_dsc_t sel_rect; lv_draw_rect_dsc_init(&sel_rect); lv_obj_init_draw_rect_dsc(list_obj, LV_PART_SELECTED, &sel_rect); - lv_draw_rect(&rect_area, clip_area, &sel_rect); + lv_draw_rect(draw_ctx, &sel_rect, &rect_area); list_obj->state = state_ori; list_obj->skip_trans = 0; } -static void draw_box_label(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, uint16_t id, lv_state_t state) +static void draw_box_label(lv_obj_t * dropdown_obj, lv_draw_ctx_t * draw_ctx, uint16_t id, lv_state_t state) { if(id == LV_DROPDOWN_PR_NONE) return; @@ -970,9 +973,12 @@ static void draw_box_label(lv_obj_t * dropdown_obj, const lv_area_t * clip_area, area_sel.x2 = list_obj->coords.x2; lv_area_t mask_sel; bool area_ok; - area_ok = _lv_area_intersect(&mask_sel, clip_area, &area_sel); + area_ok = _lv_area_intersect(&mask_sel, draw_ctx->clip_area, &area_sel); if(area_ok) { - lv_draw_label(&label->coords, &mask_sel, &label_dsc, lv_label_get_text(label), NULL); + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &mask_sel; + lv_draw_label(draw_ctx, &label_dsc, &label->coords, lv_label_get_text(label), NULL); + draw_ctx->clip_area = clip_area_ori; } list_obj->state = state_orig; list_obj->skip_trans = 0; diff --git a/src/widgets/lv_img.c b/src/widgets/lv_img.c index b851a8dc1..7a1f255e9 100644 --- a/src/widgets/lv_img.c +++ b/src/widgets/lv_img.c @@ -638,7 +638,7 @@ static void draw_img(lv_event_t * e) if(img->h == 0 || img->w == 0) return; if(zoom_final == 0) return; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t img_max_area; lv_area_copy(&img_max_area, &obj->coords); @@ -677,8 +677,10 @@ static void draw_img(lv_event_t * e) img_clip_area.y1 = bg_coords.y1 + ptop; img_clip_area.x2 = bg_coords.x2 - pright; img_clip_area.y2 = bg_coords.y2 - pbottom; + const lv_area_t * clip_area_ori = draw_ctx->clip_area; - _lv_area_intersect(&img_clip_area, clip_area, &img_clip_area); + if(!_lv_area_intersect(&img_clip_area, draw_ctx->clip_area, &img_clip_area)) return; + draw_ctx->clip_area = &img_clip_area; lv_area_t coords_tmp; coords_tmp.y1 = img_max_area.y1 + img->offset.y; @@ -691,21 +693,22 @@ static void draw_img(lv_event_t * e) coords_tmp.x2 = coords_tmp.x1 + img->w - 1; for(; coords_tmp.x1 < img_max_area.x2; coords_tmp.x1 += img_size_final.x, coords_tmp.x2 += img_size_final.x) { - lv_draw_img(&coords_tmp, &img_clip_area, img->src, &img_dsc); + lv_draw_img(draw_ctx, &img_dsc, &coords_tmp, img->src); } } + draw_ctx->clip_area = clip_area_ori; } else if(img->src_type == LV_IMG_SRC_SYMBOL) { lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); lv_obj_init_draw_label_dsc(obj, LV_PART_MAIN, &label_dsc); - lv_draw_label(&obj->coords, clip_area, &label_dsc, img->src, NULL); + lv_draw_label(draw_ctx, &label_dsc, &obj->coords, img->src, NULL); } else { /*Trigger the error handler of image draw*/ LV_LOG_WARN("draw_img: image source type is unknown"); - lv_draw_img(&obj->coords, clip_area, NULL, NULL); + lv_draw_img(draw_ctx, NULL, &obj->coords, NULL); } } } diff --git a/src/widgets/lv_label.c b/src/widgets/lv_label.c index 8505382b4..675964893 100644 --- a/src/widgets/lv_label.c +++ b/src/widgets/lv_label.c @@ -792,7 +792,7 @@ static void draw_main(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_label_t * label = (lv_label_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t txt_coords; lv_obj_get_content_coords(obj, &txt_coords); @@ -841,7 +841,7 @@ static void draw_main(lv_event_t * e) #endif lv_area_t txt_clip; - bool is_common = _lv_area_intersect(&txt_clip, &txt_coords, clip_area); + bool is_common = _lv_area_intersect(&txt_clip, &txt_coords, draw_ctx->clip_area); if(!is_common) return; if(label->long_mode == LV_LABEL_LONG_WRAP) { @@ -849,14 +849,19 @@ static void draw_main(lv_event_t * e) lv_area_move(&txt_coords, 0, -s); txt_coords.y2 = obj->coords.y2; } - if(label->long_mode == LV_LABEL_LONG_SCROLL || label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) { - lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &txt_clip; + lv_draw_label(draw_ctx, &label_draw_dsc, &txt_coords, label->text, hint); + draw_ctx->clip_area = clip_area_ori; } else { - lv_draw_label(&txt_coords, clip_area, &label_draw_dsc, label->text, hint); + lv_draw_label(draw_ctx, &label_draw_dsc, &txt_coords, label->text, hint); } + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &txt_clip; + if(label->long_mode == LV_LABEL_LONG_SCROLL_CIRCULAR) { lv_point_t size; lv_txt_get_size(&size, label->text, label_draw_dsc.font, label_draw_dsc.letter_space, label_draw_dsc.line_space, @@ -868,7 +873,7 @@ static void draw_main(lv_event_t * e) lv_font_get_glyph_width(label_draw_dsc.font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; label_draw_dsc.ofs_y = label->offset.y; - lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); + lv_draw_label(draw_ctx, &label_draw_dsc, &txt_coords, label->text, hint); } /*Draw the text again below the original to make a circular effect */ @@ -876,9 +881,11 @@ static void draw_main(lv_event_t * e) label_draw_dsc.ofs_x = label->offset.x; label_draw_dsc.ofs_y = label->offset.y + size.y + lv_font_get_line_height(label_draw_dsc.font); - lv_draw_label(&txt_coords, &txt_clip, &label_draw_dsc, label->text, hint); + lv_draw_label(draw_ctx, &label_draw_dsc, &txt_coords, label->text, hint); } } + + draw_ctx->clip_area = clip_area_ori; } /** diff --git a/src/widgets/lv_line.c b/src/widgets/lv_line.c index e73e6e89e..6bb6cd975 100644 --- a/src/widgets/lv_line.c +++ b/src/widgets/lv_line.c @@ -162,7 +162,7 @@ static void lv_line_event(const lv_obj_class_t * class_p, lv_event_t * e) } else if(code == LV_EVENT_DRAW_MAIN) { lv_line_t * line = (lv_line_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); if(line->point_num == 0 || line->point_array == NULL) return; @@ -193,7 +193,7 @@ static void lv_line_event(const lv_obj_class_t * class_p, lv_event_t * e) p1.y = h - line->point_array[i].y + y_ofs; p2.y = h - line->point_array[i + 1].y + y_ofs; } - lv_draw_line(&p1, &p2, clip_area, &line_dsc); + lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); line_dsc.round_start = 0; /*Draw the rounding only on the end points after the first line*/ } } diff --git a/src/widgets/lv_roller.c b/src/widgets/lv_roller.c index 34b50f8e4..0850f3abd 100644 --- a/src/widgets/lv_roller.c +++ b/src/widgets/lv_roller.c @@ -450,17 +450,17 @@ static void draw_main(lv_event_t * e) lv_obj_t * obj = lv_event_get_target(e); if(code == LV_EVENT_DRAW_MAIN) { /*Draw the selected rectangle*/ - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t sel_area; get_sel_area(obj, &sel_area); lv_draw_rect_dsc_t sel_dsc; lv_draw_rect_dsc_init(&sel_dsc); lv_obj_init_draw_rect_dsc(obj, LV_PART_SELECTED, &sel_dsc); - lv_draw_rect(&sel_area, clip_area, &sel_dsc); + lv_draw_rect(draw_ctx, &sel_dsc, &sel_area); } /*Post draw when the children are drawn*/ else if(code == LV_EVENT_DRAW_POST) { - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); @@ -471,7 +471,7 @@ static void draw_main(lv_event_t * e) get_sel_area(obj, &sel_area); lv_area_t mask_sel; bool area_ok; - area_ok = _lv_area_intersect(&mask_sel, clip_area, &sel_area); + area_ok = _lv_area_intersect(&mask_sel, draw_ctx->clip_area, &sel_area); if(area_ok) { lv_obj_t * label = get_label(obj); @@ -509,7 +509,10 @@ static void draw_main(lv_event_t * e) label_sel_area.y2 = label_sel_area.y1 + res_p.y; label_dsc.flag |= LV_TEXT_FLAG_EXPAND; - lv_draw_label(&label_sel_area, &mask_sel, &label_dsc, lv_label_get_text(label), NULL); + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &mask_sel; + lv_draw_label(draw_ctx, &label_dsc, &label_sel_area, lv_label_get_text(label), NULL); + draw_ctx->clip_area = clip_area_ori; } } } @@ -523,7 +526,7 @@ static void draw_label(lv_event_t * e) lv_draw_label_dsc_t label_draw_dsc; lv_draw_label_dsc_init(&label_draw_dsc); lv_obj_init_draw_label_dsc(roller, LV_PART_MAIN, &label_draw_dsc); - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t sel_area; get_sel_area(roller, &sel_area); @@ -533,16 +536,22 @@ static void draw_label(lv_event_t * e) clip2.y1 = label_obj->coords.y1; clip2.x2 = label_obj->coords.x2; clip2.y2 = sel_area.y1; - if(_lv_area_intersect(&clip2, clip_area, &clip2)) { - lv_draw_label(&label_obj->coords, &clip2, &label_draw_dsc, lv_label_get_text(label_obj), NULL); + if(_lv_area_intersect(&clip2, draw_ctx->clip_area, &clip2)) { + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip2; + lv_draw_label(draw_ctx, &label_draw_dsc, &label_obj->coords, lv_label_get_text(label_obj), NULL); + draw_ctx->clip_area = clip_area_ori; } clip2.x1 = label_obj->coords.x1; clip2.y1 = sel_area.y2; clip2.x2 = label_obj->coords.x2; clip2.y2 = label_obj->coords.y2; - if(_lv_area_intersect(&clip2, clip_area, &clip2)) { - lv_draw_label(&label_obj->coords, &clip2, &label_draw_dsc, lv_label_get_text(label_obj), NULL); + if(_lv_area_intersect(&clip2, draw_ctx->clip_area, &clip2)) { + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip2; + lv_draw_label(draw_ctx, &label_draw_dsc, &label_obj->coords, lv_label_get_text(label_obj), NULL); + draw_ctx->clip_area = clip_area_ori; } } diff --git a/src/widgets/lv_slider.c b/src/widgets/lv_slider.c index 79b43719f..6779fb7b0 100644 --- a/src/widgets/lv_slider.c +++ b/src/widgets/lv_slider.c @@ -323,7 +323,7 @@ static void draw_knob(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_slider_t * slider = (lv_slider_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN); lv_coord_t objw = lv_obj_get_width(obj); @@ -372,7 +372,7 @@ static void draw_knob(lv_event_t * e) lv_area_copy(&slider->right_knob_area, &knob_area); lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_KNOB; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_SLIDER_DRAW_PART_KNOB; @@ -382,7 +382,7 @@ static void draw_knob(lv_event_t * e) if(lv_slider_get_mode(obj) != LV_SLIDER_MODE_RANGE) { lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&slider->right_knob_area, clip_area, &knob_rect_dsc); + lv_draw_rect(draw_ctx, &knob_rect_dsc, &slider->right_knob_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } else { @@ -391,7 +391,7 @@ static void draw_knob(lv_event_t * e) lv_memcpy(&knob_rect_dsc_tmp, &knob_rect_dsc, sizeof(lv_draw_rect_dsc_t)); lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&slider->right_knob_area, clip_area, &knob_rect_dsc); + lv_draw_rect(draw_ctx, &knob_rect_dsc, &slider->right_knob_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); /*Draw a second knob for the start_value side*/ @@ -411,7 +411,7 @@ static void draw_knob(lv_event_t * e) part_draw_dsc.id = 1; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&slider->left_knob_area, clip_area, &knob_rect_dsc); + lv_draw_rect(draw_ctx, &knob_rect_dsc, &slider->left_knob_area); lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc); } } diff --git a/src/widgets/lv_switch.c b/src/widgets/lv_switch.c index 4362f8eb6..ced76fcf0 100644 --- a/src/widgets/lv_switch.c +++ b/src/widgets/lv_switch.c @@ -148,7 +148,7 @@ static void draw_main(lv_event_t * e) lv_obj_t * obj = lv_event_get_target(e); lv_switch_t * sw = (lv_switch_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); /*Calculate the indicator area*/ lv_coord_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN); @@ -168,7 +168,7 @@ static void draw_main(lv_event_t * e) lv_draw_rect_dsc_t draw_indic_dsc; lv_draw_rect_dsc_init(&draw_indic_dsc); lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &draw_indic_dsc); - lv_draw_rect(&indic_area, clip_area, &draw_indic_dsc); + lv_draw_rect(draw_ctx, &draw_indic_dsc, &indic_area); /*Draw the knob*/ lv_coord_t anim_value_x = 0; @@ -211,7 +211,7 @@ static void draw_main(lv_event_t * e) lv_draw_rect_dsc_init(&knob_rect_dsc); lv_obj_init_draw_rect_dsc(obj, LV_PART_KNOB, &knob_rect_dsc); - lv_draw_rect(&knob_area, clip_area, &knob_rect_dsc); + lv_draw_rect(draw_ctx, &knob_rect_dsc, &knob_area); } static void lv_switch_anim_exec_cb(void * var, int32_t value) diff --git a/src/widgets/lv_table.c b/src/widgets/lv_table.c index a07c3249b..adfb391c1 100644 --- a/src/widgets/lv_table.c +++ b/src/widgets/lv_table.c @@ -589,9 +589,12 @@ static void draw_main(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_table_t * table = (lv_table_t *)obj; - const lv_area_t * clip_area_ori = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_area_t clip_area; - if(!_lv_area_intersect(&clip_area, &obj->coords, clip_area_ori)) return; + if(!_lv_area_intersect(&clip_area, &obj->coords, draw_ctx->clip_area)) return; + + const lv_area_t * clip_area_ori = draw_ctx->clip_area; + draw_ctx->clip_area = &clip_area; lv_point_t txt_size; lv_area_t cell_area; @@ -634,7 +637,7 @@ static void draw_main(lv_event_t * e) /*Handle custom drawer*/ lv_obj_draw_part_dsc_t part_draw_dsc; - lv_obj_draw_dsc_init(&part_draw_dsc, &clip_area); + lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx); part_draw_dsc.part = LV_PART_ITEMS; part_draw_dsc.class_p = MY_CLASS; part_draw_dsc.type = LV_TABLE_DRAW_PART_CELL; @@ -647,7 +650,7 @@ static void draw_main(lv_event_t * e) cell_area.y1 = cell_area.y2 + 1; cell_area.y2 = cell_area.y1 + h_row - 1; - if(cell_area.y1 > clip_area.y2) return; + if(cell_area.y1 > clip_area.y2) break; if(rtl) cell_area.x1 = obj->coords.x2 - bg_right - 1 - scroll_x - border_width; else cell_area.x2 = obj->coords.x1 + bg_left - 1 - scroll_x + border_width; @@ -734,7 +737,7 @@ static void draw_main(lv_event_t * e) part_draw_dsc.id = row * table->col_cnt + col; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); - lv_draw_rect(&cell_area_border, &clip_area, &rect_dsc_act); + lv_draw_rect(draw_ctx, &rect_dsc_act, &cell_area_border); if(table->cell_data[cell]) { txt_area.x1 = cell_area.x1 + cell_left; @@ -757,11 +760,13 @@ static void draw_main(lv_event_t * e) txt_area.y2 = cell_area.y1 + h_row / 2 + txt_size.y / 2; } - lv_area_t label_mask; + lv_area_t label_clip_area; bool label_mask_ok; - label_mask_ok = _lv_area_intersect(&label_mask, &clip_area, &cell_area); + label_mask_ok = _lv_area_intersect(&label_clip_area, &clip_area, &cell_area); if(label_mask_ok) { - lv_draw_label(&txt_area, &label_mask, &label_dsc_act, table->cell_data[cell] + 1, NULL); + draw_ctx->clip_area = &label_clip_area; + lv_draw_label(draw_ctx, &label_dsc_act, &txt_area, table->cell_data[cell] + 1, NULL); + draw_ctx->clip_area = &clip_area; } } @@ -771,6 +776,8 @@ static void draw_main(lv_event_t * e) col += col_merge; } } + + draw_ctx->clip_area = clip_area_ori; } static void refr_size(lv_obj_t * obj, uint32_t strat_row) diff --git a/src/widgets/lv_textarea.c b/src/widgets/lv_textarea.c index 6be921b50..ea99be4d6 100644 --- a/src/widgets/lv_textarea.c +++ b/src/widgets/lv_textarea.c @@ -1271,7 +1271,7 @@ static void draw_placeholder(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_textarea_t * ta = (lv_textarea_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); const char * txt = lv_label_get_text(ta->label); /*Draw the place holder*/ @@ -1288,7 +1288,7 @@ static void draw_placeholder(lv_event_t * e) lv_area_t ph_coords; lv_area_copy(&ph_coords, &obj->coords); lv_area_move(&ph_coords, left + border_width, top + border_width); - lv_draw_label(&ph_coords, clip_area, &ph_dsc, ta->placeholder_txt, NULL); + lv_draw_label(draw_ctx, &ph_dsc, &ph_coords, ta->placeholder_txt, NULL); } } @@ -1296,7 +1296,7 @@ static void draw_cursor(lv_event_t * e) { lv_obj_t * obj = lv_event_get_target(e); lv_textarea_t * ta = (lv_textarea_t *)obj; - const lv_area_t * clip_area = lv_event_get_param(e); + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); const char * txt = lv_label_get_text(ta->label); if(ta->cursor.show == 0) return; @@ -1315,7 +1315,7 @@ static void draw_cursor(lv_event_t * e) cur_area.x2 += ta->label->coords.x1; cur_area.y2 += ta->label->coords.y1; - lv_draw_rect(&cur_area, clip_area, &cur_dsc); + lv_draw_rect(draw_ctx, &cur_dsc, &cur_area); lv_coord_t border_width = lv_obj_get_style_border_width(obj, LV_PART_CURSOR); lv_coord_t left = lv_obj_get_style_pad_left(obj, LV_PART_CURSOR) + border_width; @@ -1334,7 +1334,7 @@ static void draw_cursor(lv_event_t * e) lv_draw_label_dsc_init(&cur_label_dsc); lv_obj_init_draw_label_dsc(obj, LV_PART_CURSOR, &cur_label_dsc); if(cur_dsc.bg_opa > LV_OPA_MIN || cur_label_dsc.color.full != label_color.full) { - lv_draw_label(&cur_area, clip_area, &cur_label_dsc, letter_buf, NULL); + lv_draw_label(draw_ctx, &cur_label_dsc, &cur_area, letter_buf, NULL); } }