arch(draw): allow replacing the draw engine

BREAKING CHANGE: the API of lv_draw_... function have been changed
This commit is contained in:
Gabor Kiss-Vamosi 2021-11-29 14:54:37 +01:00
parent 0831b6ba76
commit db53ea925c
121 changed files with 3984 additions and 3382 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.");

View File

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

View File

@ -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 <SDL2/SDL.h>
#define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8)
#endif
/*-------------

View File

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

View File

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

View File

@ -27,7 +27,7 @@
#include <string.h>
#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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &param->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*/

View File

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

View File

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

View File

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

View File

@ -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, &center, 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(&param, &round_area, LV_RADIUS_CIRCLE, false);
int16_t mask_id = lv_draw_mask_add(&param, 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*/

View File

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

View File

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

View File

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

View File

@ -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, &center_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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More