perf(draw) reimplement circle drawing algorithms (#2374)
* perf(draw) reimplement circle drawing algorithms Imporve the speed of circle drawing Add circle draw caching Various other speed improvements * docs describe how to use masks * fix(draw) add missing GC root usage
This commit is contained in:
committed by
GitHub
parent
e23701e2c2
commit
637b706ddc
@@ -54,13 +54,13 @@ The difference between buffering modes regarding the drawing mechanism is the fo
|
||||
To use LVGL it's not required to know about the mechanisms described here, but you might find interesting to know how drawing works under hood.
|
||||
Knowing about masking comes in handy if you want to customize drawing.
|
||||
|
||||
To learn masking let's learn the steps of drawing first.
|
||||
To learn masking let's see the steps of drawing first.
|
||||
LVGL performs the following steps to render any shape, image or text. It can be considered as a drawing pipeline.
|
||||
|
||||
1. **Prepare the draw descriptors** Create a draw descriptor from an object's styles (e.g. `lv_draw_rect_dsc_t`). This gives us the parameters for drawing, for example the colors, widths, opacity, fonts, radius, etc.
|
||||
2. **Call the draw function** Call the draw function with the draw descriptor and some other parameters (e.g. `lv_draw_rect()`). It renders the primitive shape to the current draw buffer.
|
||||
3. **Create masks** If the shape is very simple and doesn't require masks go to #5. Else create the required masks (e.g. a rounded rectangle mask)
|
||||
4. **Calculate all the added mask**. It creates 0..255 values into a *mask buffer* with the "shape" of the created masks.
|
||||
2. **Call the draw function** Call the draw function with the draw descriptor and some other parameters (e.g. `lv_draw_rect()`). It will render the primitive shape to the current draw buffer.
|
||||
3. **Create masks** If the shape is very simple and doesn't require masks go to #5. Else create the required masks in the draw function. (e.g. a rounded rectangle mask)
|
||||
4. **Calculate all the added mask** It creates 0..255 values into a *mask buffer* with the "shape" of the created masks.
|
||||
E.g. in case of a "line mask" according to the parameters of the mask, keep one side of the buffer as it is (255 by default) and set the rest to 0 to indicate that this side should be removed.
|
||||
5. **Blend a color or image** During blending masks (make some pixels transparent or opaque), blending modes (additive, subtractive, etc) and opacity are handled.
|
||||
|
||||
@@ -81,6 +81,25 @@ Masks are used the create almost every basic primitives:
|
||||
- **arc drawing** A circle border is drawn, but an arc mask is applied too.
|
||||
- **ARGB images** The alpha channel is separated into a mask and the image is drawn as a normal RGB image.
|
||||
|
||||
### Using masks
|
||||
|
||||
Every mask type has a related paramter to describe the mask's data. The following paramater types exist:
|
||||
- `lv_draw_mask_line_param_t`
|
||||
- `lv_draw_mask_radius_param_t`
|
||||
- `lv_draw_mask_angle_param_t`
|
||||
- `lv_draw_mask_fade_param_t`
|
||||
- `lv_draw_mask_map_param_t`
|
||||
|
||||
1. Initialize a mask parameter with `lv_draw_mask_<type>_init`. See `lv_draw_mask.h` for the whole API.
|
||||
2. Add the mask parameter to the draw engine with `int16_t mask_id = lv_draw_mask_add(¶m, ptr)`. `ptr` can be any pointer to identify the mask, (`NULL` if unused).
|
||||
3. Call the draw functions
|
||||
4. Remove the mask from the draw engine with `lv_draw_mask_remove_id(mask_id)` of `lv_draw_mask_remove_custom(ptr)`.
|
||||
5. Free the parameter with `lv_draw_mask_free_param(¶m)`.
|
||||
|
||||
A parameter can be added and removed any number of times but it needs to be freed when not required anymore.
|
||||
|
||||
`lv_draw_mask_add` saves only the pointer of the mask so the parameter needs to be valid while in use.
|
||||
|
||||
## Hook drawing
|
||||
Although widgets can be very well customized by styles there might be cases when something really custom is required.
|
||||
To ensure a great level of flexibility LVGL sends a lot events during drawing with parameters that tell what LVGL is about to draw.
|
||||
|
||||
@@ -39,6 +39,8 @@ static void draw_event_cb(lv_event_t * e)
|
||||
lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc);
|
||||
|
||||
/*Remove the masks*/
|
||||
lv_draw_mask_free_param(&line_mask_param);
|
||||
lv_draw_mask_free_param(&fade_mask_param);
|
||||
lv_draw_mask_remove_id(line_mask_id);
|
||||
lv_draw_mask_remove_id(fade_mask_id);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ static void mask_event_cb(lv_event_t * e)
|
||||
lv_draw_mask_fade_param_t * fade_mask_bottom = lv_draw_mask_remove_id(mask_bottom_id);
|
||||
lv_mem_buf_release(fade_mask_top);
|
||||
lv_mem_buf_release(fade_mask_bottom);
|
||||
lv_draw_mask_free_param(&fade_mask_top);
|
||||
lv_draw_mask_free_param(&fade_mask_bottom);
|
||||
mask_top_id = -1;
|
||||
mask_bottom_id = -1;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,13 @@
|
||||
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
|
||||
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
|
||||
#define LV_SHADOW_CACHE_SIZE 0
|
||||
|
||||
/* Set number of maximally cached circle data.
|
||||
* The circumference of 1/4 circle are saved for anti-aliasing
|
||||
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
|
||||
* 0: to disable caching */
|
||||
#define LV_CIRCLE_CACHE_SIZE 4
|
||||
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
/*Default image cache size. Image caching keeps the images opened.
|
||||
|
||||
@@ -290,8 +290,9 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
|
||||
/*If the point is on this object check its children too*/
|
||||
if(lv_obj_hit_test(obj, point)) {
|
||||
int32_t i;
|
||||
for(i = lv_obj_get_child_cnt(obj) - 1; i >= 0; i--) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = child_cnt - 1; i >= 0; i--) {
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
found_p = lv_indev_search_obj(child, point);
|
||||
|
||||
/*If a child was found then break*/
|
||||
|
||||
@@ -421,7 +421,7 @@ static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coo
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPPABLE)) {
|
||||
lv_coord_t x_child = 0;
|
||||
@@ -476,7 +476,7 @@ static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coo
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPPABLE)) {
|
||||
lv_coord_t y_child = 0;
|
||||
|
||||
@@ -533,6 +533,7 @@ static void lv_obj_draw(lv_event_t * e)
|
||||
#if LV_DRAW_COMPLEX
|
||||
if(lv_obj_get_style_clip_corner(obj, LV_PART_MAIN)) {
|
||||
lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(obj + 8);
|
||||
lv_draw_mask_free_param(param);
|
||||
lv_mem_buf_release(param);
|
||||
}
|
||||
#endif
|
||||
@@ -781,7 +782,7 @@ static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
lv_obj_mark_layout_as_dirty(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,7 +754,7 @@ void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_dif
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(ignore_floating && lv_obj_has_flag(child, LV_OBJ_FLAG_FLOATING)) continue;
|
||||
child->coords.x1 += x_diff;
|
||||
child->coords.y1 += y_diff;
|
||||
@@ -937,7 +937,7 @@ static void layout_update_core(lv_obj_t * obj)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
layout_update_core(child);
|
||||
}
|
||||
|
||||
@@ -948,7 +948,7 @@ static void layout_update_core(lv_obj_t * obj)
|
||||
lv_obj_refr_size(obj);
|
||||
lv_obj_refr_pos(obj);
|
||||
|
||||
if(lv_obj_get_child_cnt(obj) > 0) {
|
||||
if(child_cnt > 0) {
|
||||
uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN);
|
||||
if(layout_id > 0 && layout_id <= layout_cnt) {
|
||||
void * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id -1].user_data;
|
||||
|
||||
@@ -139,7 +139,7 @@ lv_coord_t lv_obj_get_scroll_bottom(lv_obj_t * obj)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
child_res = LV_MAX(child_res, child->coords.y2);
|
||||
}
|
||||
@@ -180,8 +180,8 @@ lv_coord_t lv_obj_get_scroll_left(lv_obj_t * obj)
|
||||
lv_coord_t x1 = LV_COORD_MAX;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
x1 = LV_MIN(x1, child->coords.x1);
|
||||
|
||||
}
|
||||
@@ -216,7 +216,7 @@ lv_coord_t lv_obj_get_scroll_right(lv_obj_t * obj)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
|
||||
child_res = LV_MAX(child_res, child->coords.x2);
|
||||
}
|
||||
|
||||
@@ -623,7 +623,7 @@ static void report_style_change_core(void * style, lv_obj_t * obj)
|
||||
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
report_style_change_core(style, lv_obj_get_child(obj, i));
|
||||
report_style_change_core(style, obj->spec_attr->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ static void refresh_children_style(lv_obj_t * obj)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
lv_obj_invalidate(child);
|
||||
lv_event_send(child, LV_EVENT_STYLE_CHANGED, NULL);
|
||||
lv_obj_invalidate(child);
|
||||
|
||||
@@ -236,6 +236,10 @@ void _lv_disp_refr_timer(lv_timer_t * tmr)
|
||||
lv_mem_buf_free_all();
|
||||
_lv_font_clean_up_fmt_txt();
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
_lv_draw_mask_cleanup();
|
||||
#endif
|
||||
|
||||
#if LV_USE_PERF_MONITOR && LV_USE_LABEL
|
||||
static lv_obj_t * perf_label = NULL;
|
||||
if(perf_label == NULL) {
|
||||
@@ -586,7 +590,7 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, i);
|
||||
lv_obj_t * child = obj->spec_attr->children[i];
|
||||
found_p = lv_refr_get_top_obj(area_p, child);
|
||||
|
||||
/*If a children is ok then break*/
|
||||
@@ -634,7 +638,7 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(par);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(par, i);
|
||||
lv_obj_t * child = par->spec_attr->children[i];
|
||||
if(!go) {
|
||||
if(child == border_p) go = true;
|
||||
} else {
|
||||
@@ -707,7 +711,7 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
|
||||
uint32_t i;
|
||||
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
|
||||
for(i = 0; i < child_cnt; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(obj, 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;
|
||||
|
||||
@@ -159,6 +159,11 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
|
||||
else {
|
||||
lv_draw_rect(&area_out, clip_area, &cir_dsc);
|
||||
}
|
||||
|
||||
lv_draw_mask_free_param(&mask_angle_param);
|
||||
lv_draw_mask_free_param(&mask_out_param);
|
||||
lv_draw_mask_free_param(&mask_in_param);
|
||||
|
||||
lv_draw_mask_remove_id(mask_angle_id);
|
||||
lv_draw_mask_remove_id(mask_out_id);
|
||||
lv_draw_mask_remove_id(mask_in_id);
|
||||
@@ -180,6 +185,7 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
|
||||
|
||||
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
|
||||
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);
|
||||
@@ -193,6 +199,7 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
|
||||
|
||||
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
|
||||
lv_draw_mask_remove_id(mask_end_id);
|
||||
lv_draw_mask_free_param(&mask_end_param);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -73,22 +73,21 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#if LV_COLOR_SCREEN_TRANSP == 0
|
||||
#define FILL_NORMAL_MASK_PX(color) \
|
||||
if(*mask == LV_OPA_COVER) *disp_buf_first = color; \
|
||||
else *disp_buf_first = lv_color_mix(color, *disp_buf_first, *mask); \
|
||||
mask++; \
|
||||
disp_buf_first++;
|
||||
|
||||
#define FILL_NORMAL_MASK_PX(out_x, color) \
|
||||
if(*mask_tmp_x) { \
|
||||
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \
|
||||
else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_x); \
|
||||
} \
|
||||
mask_tmp_x++;
|
||||
|
||||
#define FILL_NORMAL_MASK_PX_SCR_TRANSP(out_x, color) \
|
||||
if(*mask_tmp_x) { \
|
||||
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \
|
||||
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(disp_buf_first[out_x], disp_buf_first[out_x].ch.alpha, \
|
||||
color, *mask_tmp_x, &disp_buf_first[out_x], &disp_buf_first[out_x].ch.alpha); \
|
||||
else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_x); \
|
||||
} \
|
||||
mask_tmp_x++;
|
||||
#else
|
||||
#define FILL_NORMAL_MASK_PX(color) \
|
||||
if(*mask == LV_OPA_COVER) *disp_buf_first = color; \
|
||||
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*disp_buf_first, disp_buf_first->ch.alpha, color, *mask, disp_buf_first, &disp_buf_first->ch.alpha); \
|
||||
else *disp_buf_first = lv_color_mix(color, *disp_buf_first, *mask); \
|
||||
mask++; \
|
||||
disp_buf_first++;
|
||||
#endif
|
||||
|
||||
#define MAP_NORMAL_MASK_PX(x) \
|
||||
if(*mask_tmp_x) { \
|
||||
@@ -326,7 +325,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
|
||||
if(lv_gpu_nxp_vglite_fill(disp_buf, disp_w, lv_area_get_height(disp_area), draw_area, color, opa) == LV_RES_OK) {
|
||||
return;
|
||||
}
|
||||
/*Fall down to SW render in case of error*/
|
||||
}
|
||||
#elif LV_USE_GPU_STM32_DMA2D
|
||||
if(lv_area_get_size(draw_area) >= 240) {
|
||||
@@ -401,65 +399,55 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
|
||||
|
||||
int32_t x_end4 = draw_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 < draw_area_h; y++) {
|
||||
const lv_opa_t * mask_tmp_x = mask;
|
||||
#if 0
|
||||
for(x = 0; x < draw_area_w; x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
|
||||
#else
|
||||
FILL_NORMAL_MASK_PX(x, color)
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
for(x = 0; x < draw_area_w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
|
||||
#else
|
||||
FILL_NORMAL_MASK_PX(x, color)
|
||||
#endif
|
||||
for(x = 0; x < draw_area_w && ((lv_uintptr_t)(mask) & 0x3); x++) {
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
}
|
||||
|
||||
uint32_t * mask32 = (uint32_t *)mask_tmp_x;
|
||||
for(; x <= x_end4; x += 4) {
|
||||
if(*mask32) {
|
||||
if((*mask32) == 0xFFFFFFFF) {
|
||||
disp_buf_first[x] = color;
|
||||
disp_buf_first[x + 1] = color;
|
||||
disp_buf_first[x + 2] = color;
|
||||
disp_buf_first[x + 3] = color;
|
||||
uint32_t mask32 = *((uint32_t *)mask);
|
||||
if(mask32 == 0xFFFFFFFF) {
|
||||
#if LV_COLOR_DEPTH == 16
|
||||
if((lv_uintptr_t)disp_buf_first & 0x3) {
|
||||
*(disp_buf_first + 0) = color;
|
||||
uint32_t * d = (uint32_t * )(disp_buf_first + 1);
|
||||
*d = c32;
|
||||
*(disp_buf_first + 3) = color;
|
||||
} else {
|
||||
uint32_t * d = (uint32_t * )disp_buf_first;
|
||||
*d = c32;
|
||||
*(d + 1) = c32;
|
||||
}
|
||||
else {
|
||||
mask_tmp_x = (const lv_opa_t *)mask32;
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 1, color)
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 2, color)
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 3, color)
|
||||
#else
|
||||
FILL_NORMAL_MASK_PX(x, color)
|
||||
FILL_NORMAL_MASK_PX(x + 1, color)
|
||||
FILL_NORMAL_MASK_PX(x + 2, color)
|
||||
FILL_NORMAL_MASK_PX(x + 3, color)
|
||||
disp_buf_first[0] = color;
|
||||
disp_buf_first[1] = color;
|
||||
disp_buf_first[2] = color;
|
||||
disp_buf_first[3] = color;
|
||||
#endif
|
||||
}
|
||||
disp_buf_first+= 4;
|
||||
mask += 4;
|
||||
}
|
||||
else if(mask32) {
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
} else {
|
||||
mask += 4;
|
||||
disp_buf_first += 4;
|
||||
}
|
||||
mask32++;
|
||||
}
|
||||
|
||||
mask_tmp_x = (const lv_opa_t *)mask32;
|
||||
for(; x < draw_area_w ; x++) {
|
||||
#if LV_COLOR_SCREEN_TRANSP
|
||||
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
|
||||
#else
|
||||
FILL_NORMAL_MASK_PX(x, color)
|
||||
#endif
|
||||
FILL_NORMAL_MASK_PX(color)
|
||||
}
|
||||
#endif
|
||||
disp_buf_first += disp_w;
|
||||
mask += draw_area_w;
|
||||
disp_buf_first += (disp_w-draw_area_w);
|
||||
}
|
||||
}
|
||||
/*Handle opa and mask values too*/
|
||||
@@ -701,8 +689,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
|
||||
blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t);
|
||||
blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1));
|
||||
blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1));
|
||||
blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1;
|
||||
blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1;
|
||||
blit.src_area.x2 = blit.src_area.x1 + draw_area_w;
|
||||
blit.src_area.y2 = blit.src_area.y1 + draw_area_h;
|
||||
|
||||
blit.dst = disp_buf;
|
||||
blit.dst_width = lv_area_get_width(disp_area);
|
||||
@@ -710,8 +698,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
|
||||
blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t);
|
||||
blit.dst_area.x1 = draw_area->x1;
|
||||
blit.dst_area.y1 = draw_area->y1;
|
||||
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1;
|
||||
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1;
|
||||
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w;
|
||||
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h;
|
||||
|
||||
blit.opa = opa;
|
||||
|
||||
@@ -751,8 +739,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
|
||||
blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t);
|
||||
blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1));
|
||||
blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1));
|
||||
blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1;
|
||||
blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1;
|
||||
blit.src_area.x2 = blit.src_area.x1 + draw_area_w;
|
||||
blit.src_area.y2 = blit.src_area.y1 + draw_area_h;
|
||||
|
||||
blit.dst = disp_buf;
|
||||
blit.dst_width = lv_area_get_width(disp_area);
|
||||
@@ -760,8 +748,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
|
||||
blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t);
|
||||
blit.dst_area.x1 = draw_area->x1;
|
||||
blit.dst_area.y1 = draw_area->y1;
|
||||
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1;
|
||||
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1;
|
||||
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w;
|
||||
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h;
|
||||
|
||||
blit.opa = opa;
|
||||
|
||||
@@ -933,13 +921,7 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
|
||||
|
||||
for(y = draw_area->y1; y <= draw_area->y2; y++) {
|
||||
for(x = draw_area->x1; x <= draw_area->x2; x++) {
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
if(map_buf_tmp[x].full != 0xff000000) {
|
||||
#else
|
||||
if(map_buf_tmp[x].full != 0) {
|
||||
#endif
|
||||
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa);
|
||||
}
|
||||
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa);
|
||||
}
|
||||
disp_buf_tmp += disp_w;
|
||||
map_buf_tmp += map_w;
|
||||
@@ -957,14 +939,7 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
|
||||
for(x = draw_area->x1; x <= draw_area->x2; x++) {
|
||||
if(mask_tmp[x] == 0) continue;
|
||||
lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8);
|
||||
#if LV_COLOR_DEPTH == 32
|
||||
if(map_buf_tmp[x].full != 0xff000000) {
|
||||
#else
|
||||
if(map_buf_tmp[x].full != 0) {
|
||||
#endif
|
||||
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp);
|
||||
}
|
||||
|
||||
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp);
|
||||
}
|
||||
disp_buf_tmp += disp_w;
|
||||
mask_tmp += draw_area_w;
|
||||
@@ -975,6 +950,9 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
|
||||
|
||||
static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
|
||||
{
|
||||
|
||||
if(opa <= LV_OPA_MIN) return bg;
|
||||
|
||||
uint32_t tmp;
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
tmp = bg.full + fg.full;
|
||||
@@ -990,7 +968,6 @@ static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH == 8
|
||||
tmp = bg.ch.green + fg.ch.green;
|
||||
fg.ch.green = LV_MIN(tmp, 7);
|
||||
#elif LV_COLOR_DEPTH == 16
|
||||
#if LV_COLOR_16_SWAP == 0
|
||||
@@ -1004,7 +981,6 @@ static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color
|
||||
#endif
|
||||
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
tmp = bg.ch.green + fg.ch.green;
|
||||
fg.ch.green = LV_MIN(tmp, 255);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -474,6 +474,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, cons
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
|
||||
lv_draw_mask_free_param(&mask_left_param);
|
||||
lv_draw_mask_free_param(&mask_right_param);
|
||||
if(mask_top_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_top_param);
|
||||
if(mask_bottom_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_bottom_param);
|
||||
lv_draw_mask_remove_id(mask_left_id);
|
||||
lv_draw_mask_remove_id(mask_right_id);
|
||||
lv_draw_mask_remove_id(mask_top_id);
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
|
||||
#include "lv_draw_mask.h"
|
||||
#if LV_DRAW_COMPLEX
|
||||
#include "../misc/lv_math.h"
|
||||
@@ -18,6 +16,8 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define CIRCLE_CACHE_LIFE_MAX 1000
|
||||
#define CIRCLE_CACHE_AGING(life, r) life = LV_MIN(life + (r < 16 ? 1 : (r >> 4)), 1000)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@@ -49,8 +49,12 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t line_mask_steep(lv_opa_t * mask_
|
||||
lv_coord_t len,
|
||||
lv_draw_mask_line_param_t * p);
|
||||
|
||||
static void circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius);
|
||||
static bool circ_cont(lv_point_t * c);
|
||||
static void circ_next(lv_point_t * c, lv_coord_t * tmp);
|
||||
static void circ_calc_aa4(_lv_draw_mask_radius_circle_dsc_t * c, lv_coord_t radius);
|
||||
static lv_opa_t * get_next_line(_lv_draw_mask_radius_circle_dsc_t * c, lv_coord_t y, lv_coord_t * len, lv_coord_t * x_start);
|
||||
LV_ATTRIBUTE_FAST_MEM static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new);
|
||||
LV_ATTRIBUTE_FAST_MEM static inline void sqrt_approx(lv_sqrt_res_t * q, lv_sqrt_res_t * ref, uint32_t x);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@@ -129,7 +133,7 @@ LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf,
|
||||
*/
|
||||
void * lv_draw_mask_remove_id(int16_t id)
|
||||
{
|
||||
void * p = NULL;
|
||||
_lv_draw_mask_common_dsc_t * p = NULL;
|
||||
|
||||
if(id != LV_MASK_ID_INV) {
|
||||
p = LV_GC_ROOT(_lv_draw_mask_list[id]).param;
|
||||
@@ -148,18 +152,51 @@ void * lv_draw_mask_remove_id(int16_t id)
|
||||
*/
|
||||
void * lv_draw_mask_remove_custom(void * custom_id)
|
||||
{
|
||||
void * p = NULL;
|
||||
_lv_draw_mask_common_dsc_t * p = NULL;
|
||||
uint8_t i;
|
||||
for(i = 0; i < _LV_MASK_MAX_NUM; i++) {
|
||||
if(LV_GC_ROOT(_lv_draw_mask_list[i]).custom_id == custom_id) {
|
||||
p = LV_GC_ROOT(_lv_draw_mask_list[i]).param;
|
||||
LV_GC_ROOT(_lv_draw_mask_list[i]).param = NULL;
|
||||
LV_GC_ROOT(_lv_draw_mask_list[i]).custom_id = NULL;
|
||||
lv_draw_mask_remove_id(i);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the data from the parameter.
|
||||
* It's called inside `lv_draw_mask_remove_id` and `lv_draw_mask_remove_custom`
|
||||
* Needs to be called only in special cases when the mask is not added by `lv_draw_mask_add`
|
||||
* and not removed by `lv_draw_mask_remove_id` or `lv_draw_mask_remove_custom`
|
||||
* @param p pointer to a mask parameter
|
||||
*/
|
||||
void lv_draw_mask_free_param(void * p)
|
||||
{
|
||||
_lv_draw_mask_common_dsc_t * pdsc = p;
|
||||
if(pdsc->type == LV_DRAW_MASK_TYPE_RADIUS) {
|
||||
lv_draw_mask_radius_param_t * radius_p = (lv_draw_mask_radius_param_t *) p;
|
||||
if(radius_p->circle) {
|
||||
if(radius_p->circle->life < 0) {
|
||||
lv_mem_free(radius_p->circle->cir_opa);
|
||||
lv_mem_free(radius_p->circle);
|
||||
} else {
|
||||
radius_p->circle->used_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _lv_draw_mask_cleanup(void)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_CIRCLE_CACHE_SIZE; i++) {
|
||||
if(LV_GC_ROOT(_lv_circle_cache[i]).buf) {
|
||||
lv_mem_free(LV_GC_ROOT(_lv_circle_cache[i]).buf);
|
||||
}
|
||||
lv_memset_00(&LV_GC_ROOT(_lv_circle_cache[i]), sizeof(LV_GC_ROOT(_lv_circle_cache[i])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the currently added masks
|
||||
* @return number of active masks
|
||||
@@ -373,6 +410,7 @@ void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area
|
||||
{
|
||||
lv_coord_t w = lv_area_get_width(rect);
|
||||
lv_coord_t h = lv_area_get_height(rect);
|
||||
if(radius < 0) radius = 0;
|
||||
int32_t short_side = LV_MIN(w, h);
|
||||
if(radius > short_side >> 1) radius = short_side >> 1;
|
||||
|
||||
@@ -381,9 +419,47 @@ void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area
|
||||
param->cfg.outer = inv ? 1 : 0;
|
||||
param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_radius;
|
||||
param->dsc.type = LV_DRAW_MASK_TYPE_RADIUS;
|
||||
param->y_prev = INT32_MIN;
|
||||
param->y_prev_x.f = 0;
|
||||
param->y_prev_x.i = 0;
|
||||
|
||||
if(radius == 0) {
|
||||
param->circle = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
|
||||
/*Try to reuse a circle cache entry*/
|
||||
for(i = 0; i < LV_CIRCLE_CACHE_SIZE; i++) {
|
||||
if(LV_GC_ROOT(_lv_circle_cache[i]).radius == radius) {
|
||||
LV_GC_ROOT(_lv_circle_cache[i]).used_cnt++;
|
||||
CIRCLE_CACHE_AGING(LV_GC_ROOT(_lv_circle_cache[i]).life, radius);
|
||||
param->circle = &LV_GC_ROOT(_lv_circle_cache[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*If not found find a free entry with lowest life*/
|
||||
_lv_draw_mask_radius_circle_dsc_t * entry = NULL;
|
||||
for(i = 0; i < LV_CIRCLE_CACHE_SIZE; i++) {
|
||||
if(LV_GC_ROOT(_lv_circle_cache[i]).used_cnt == 0) {
|
||||
if(!entry) entry = &LV_GC_ROOT(_lv_circle_cache[i]);
|
||||
else if(LV_GC_ROOT(_lv_circle_cache[i]).life < entry->life) entry = &LV_GC_ROOT(_lv_circle_cache[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!entry) {
|
||||
entry = lv_mem_alloc(sizeof(_lv_draw_mask_radius_circle_dsc_t));
|
||||
LV_ASSERT_MALLOC(param->circle);
|
||||
lv_memset_00(entry, sizeof(_lv_draw_mask_radius_circle_dsc_t));
|
||||
entry->life = -1;
|
||||
} else {
|
||||
entry->used_cnt++;
|
||||
entry->life = 0;
|
||||
CIRCLE_CACHE_AGING(entry->life, radius);
|
||||
}
|
||||
|
||||
param->circle = entry;
|
||||
|
||||
circ_calc_aa4(param->circle, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -881,6 +957,8 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * ma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x,
|
||||
lv_coord_t abs_y, lv_coord_t len,
|
||||
lv_draw_mask_radius_param_t * p)
|
||||
@@ -891,7 +969,7 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * m
|
||||
lv_area_copy(&rect, &p->cfg.rect);
|
||||
|
||||
if(outer == false) {
|
||||
if(abs_y < rect.y1 || abs_y > rect.y2) {
|
||||
if((abs_y < rect.y1 || abs_y > rect.y2)) {
|
||||
return LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
}
|
||||
@@ -932,6 +1010,13 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * m
|
||||
}
|
||||
return LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
// printf("exec: x:%d.. %d, y:%d: r:%d, %s\n", abs_x, abs_x + len - 1, abs_y, p->cfg.radius, p->cfg.outer ? "inv" : "norm");
|
||||
|
||||
|
||||
// if( abs_x == 276 && abs_x + len - 1 == 479 && abs_y == 63 && p->cfg.radius == 5 && p->cfg.outer == 1) {
|
||||
// char x = 0;
|
||||
// }
|
||||
//exec: x:276.. 479, y:63: r:5, inv)
|
||||
|
||||
int32_t k = rect.x1 - abs_x; /*First relevant coordinate on the of the mask*/
|
||||
int32_t w = lv_area_get_width(&rect);
|
||||
@@ -939,194 +1024,51 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * m
|
||||
abs_x -= rect.x1;
|
||||
abs_y -= rect.y1;
|
||||
|
||||
uint32_t r2 = p->cfg.radius * p->cfg.radius;
|
||||
lv_coord_t aa_len;
|
||||
lv_coord_t x_start;
|
||||
lv_coord_t cir_y;
|
||||
if(abs_y < radius) {
|
||||
cir_y = radius - abs_y - 1;
|
||||
} else {
|
||||
cir_y = abs_y - (h - radius);
|
||||
}
|
||||
lv_opa_t * aa_opa = get_next_line(p->circle, cir_y, &aa_len, &x_start);
|
||||
lv_coord_t cir_x_right = k + w - radius + x_start;
|
||||
lv_coord_t cir_x_left = k + radius - x_start - 1;
|
||||
lv_coord_t i;
|
||||
|
||||
/*Handle corner areas*/
|
||||
if(abs_y < radius || abs_y > h - radius - 1) {
|
||||
|
||||
uint32_t sqrt_mask;
|
||||
if(radius <= 32) sqrt_mask = 0x200;
|
||||
if(radius <= 256) sqrt_mask = 0x800;
|
||||
else sqrt_mask = 0x8000;
|
||||
|
||||
lv_sqrt_res_t x0;
|
||||
lv_sqrt_res_t x1;
|
||||
/*y = 0 should mean the top of the circle*/
|
||||
int32_t y;
|
||||
if(abs_y < radius) {
|
||||
y = radius - abs_y;
|
||||
|
||||
/*Get the x intersection points for `abs_y` and `abs_y-1`
|
||||
*Use the circle's equation x = sqrt(r^2 - y^2)
|
||||
*Try to use the values from the previous run*/
|
||||
if(y == p->y_prev) {
|
||||
x0.f = p->y_prev_x.f;
|
||||
x0.i = p->y_prev_x.i;
|
||||
if(outer == false) {
|
||||
for(i = 0; i < aa_len; i++) {
|
||||
lv_opa_t opa = aa_opa[aa_len - i - 1];
|
||||
if(cir_x_right + i >= 0 && cir_x_right + i < len) {
|
||||
mask_buf[cir_x_right + i] = mask_mix(opa, mask_buf[cir_x_right + i]);
|
||||
}
|
||||
else {
|
||||
lv_sqrt(r2 - (y * y), &x0, sqrt_mask);
|
||||
}
|
||||
lv_sqrt(r2 - ((y - 1) * (y - 1)), &x1, sqrt_mask);
|
||||
p->y_prev = y - 1;
|
||||
p->y_prev_x.f = x1.f;
|
||||
p->y_prev_x.i = x1.i;
|
||||
}
|
||||
else {
|
||||
y = radius - (h - abs_y) + 1;
|
||||
|
||||
/*Get the x intersection points for `abs_y` and `abs_y-1`
|
||||
*Use the circle's equation x = sqrt(r^2 - y^2)
|
||||
*Try to use the values from the previous run*/
|
||||
if((y - 1) == p->y_prev) {
|
||||
x1.f = p->y_prev_x.f;
|
||||
x1.i = p->y_prev_x.i;
|
||||
}
|
||||
else {
|
||||
lv_sqrt(r2 - ((y - 1) * (y - 1)), &x1, sqrt_mask);
|
||||
}
|
||||
|
||||
lv_sqrt(r2 - (y * y), &x0, sqrt_mask);
|
||||
p->y_prev = y;
|
||||
p->y_prev_x.f = x0.f;
|
||||
p->y_prev_x.i = x0.i;
|
||||
}
|
||||
|
||||
/*If x1 is on the next round coordinate (e.g. x0: 3.5, x1:4.0)
|
||||
*then treat x1 as x1: 3.99 to handle them as they were on the same pixel*/
|
||||
if(x0.i == x1.i - 1 && x1.f == 0) {
|
||||
x1.i--;
|
||||
x1.f = 0xFF;
|
||||
}
|
||||
|
||||
/*If the two x intersections are on the same x then just get average of the fractions*/
|
||||
if(x0.i == x1.i) {
|
||||
lv_opa_t m = (x0.f + x1.f) >> 1;
|
||||
if(outer) m = 255 - m;
|
||||
int32_t ofs = radius - x0.i - 1;
|
||||
|
||||
/*Left corner*/
|
||||
int32_t kl = k + ofs;
|
||||
|
||||
if(kl >= 0 && kl < len) {
|
||||
mask_buf[kl] = mask_mix(mask_buf[kl], m);
|
||||
}
|
||||
|
||||
/*Right corner*/
|
||||
int32_t kr = k + (w - ofs - 1);
|
||||
if(kr >= 0 && kr < len) {
|
||||
mask_buf[kr] = mask_mix(mask_buf[kr], m);
|
||||
}
|
||||
|
||||
/*Clear the unused parts*/
|
||||
if(outer == false) {
|
||||
kr++;
|
||||
if(kl > len) {
|
||||
return LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
if(kl >= 0) {
|
||||
lv_memset_00(&mask_buf[0], kl);
|
||||
}
|
||||
if(kr < 0) {
|
||||
return LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
if(kr <= len) {
|
||||
lv_memset_00(&mask_buf[kr], len - kr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
kl++;
|
||||
int32_t first = kl;
|
||||
if(first < 0) first = 0;
|
||||
|
||||
int32_t len_tmp = kr - first;
|
||||
if(len_tmp + first > len) len_tmp = len - first;
|
||||
if(first < len && len_tmp >= 0) {
|
||||
lv_memset_00(&mask_buf[first], len_tmp);
|
||||
}
|
||||
if(cir_x_left - i >= 0 && cir_x_left - i < len) {
|
||||
mask_buf[cir_x_left - i] = mask_mix(opa, mask_buf[cir_x_left - i]);
|
||||
}
|
||||
}
|
||||
/*Multiple pixels are affected. Get y intersection of the pixels*/
|
||||
else {
|
||||
int32_t ofs = radius - (x0.i + 1);
|
||||
int32_t kl = k + ofs;
|
||||
int32_t kr = k + (w - ofs - 1);
|
||||
|
||||
if(outer) {
|
||||
int32_t first = kl + 1;
|
||||
if(first < 0) first = 0;
|
||||
/*Clean the right side*/
|
||||
cir_x_right = LV_CLAMP(0, cir_x_right + i, len);
|
||||
lv_memset_00(&mask_buf[cir_x_right], len - cir_x_right);
|
||||
|
||||
int32_t len_tmp = kr - first;
|
||||
if(len_tmp + first > len) len_tmp = len - first;
|
||||
if(first < len && len_tmp >= 0) {
|
||||
lv_memset_00(&mask_buf[first], len_tmp);
|
||||
}
|
||||
/*Clean the left side*/
|
||||
cir_x_left = LV_CLAMP(0, cir_x_left - aa_len + 1, len);
|
||||
lv_memset_00(&mask_buf[0], cir_x_left);
|
||||
} else {
|
||||
for(i = 0; i < aa_len; i++) {
|
||||
lv_opa_t opa = 255 - (aa_opa[aa_len - 1 - i]);
|
||||
if(cir_x_right + i >= 0 && cir_x_right + i < len) {
|
||||
mask_buf[cir_x_right + i] = mask_mix(opa, mask_buf[cir_x_right + i]);
|
||||
}
|
||||
|
||||
uint32_t i = x0.i + 1;
|
||||
lv_opa_t m;
|
||||
lv_sqrt_res_t y_prev;
|
||||
lv_sqrt_res_t y_next;
|
||||
|
||||
lv_sqrt(r2 - (x0.i * x0.i), &y_prev, sqrt_mask);
|
||||
|
||||
if(y_prev.f == 0) {
|
||||
y_prev.i--;
|
||||
y_prev.f = 0xFF;
|
||||
}
|
||||
|
||||
/*The first y intersection is special as it might be in the previous line*/
|
||||
if(y_prev.i >= y) {
|
||||
lv_sqrt(r2 - (i * i), &y_next, sqrt_mask);
|
||||
m = 255 - (((255 - x0.f) * (255 - y_next.f)) >> 9);
|
||||
|
||||
if(outer) m = 255 - m;
|
||||
if(kl >= 0 && kl < len) mask_buf[kl] = mask_mix(mask_buf[kl], m);
|
||||
if(kr >= 0 && kr < len) mask_buf[kr] = mask_mix(mask_buf[kr], m);
|
||||
kl--;
|
||||
kr++;
|
||||
y_prev.f = y_next.f;
|
||||
i++;
|
||||
}
|
||||
|
||||
/*Set all points which are crossed by the circle*/
|
||||
for(; i <= x1.i; i++) {
|
||||
/*These values are very close to each other. It's enough to approximate sqrt
|
||||
*The non-approximated version is lv_sqrt(r2 - (i * i), &y_next, sqrt_mask);*/
|
||||
sqrt_approx(&y_next, &y_prev, r2 - (i * i));
|
||||
|
||||
m = (y_prev.f + y_next.f) >> 1;
|
||||
if(outer) m = 255 - m;
|
||||
if(kl >= 0 && kl < len) mask_buf[kl] = mask_mix(mask_buf[kl], m);
|
||||
if(kr >= 0 && kr < len) mask_buf[kr] = mask_mix(mask_buf[kr], m);
|
||||
kl--;
|
||||
kr++;
|
||||
y_prev.f = y_next.f;
|
||||
}
|
||||
|
||||
/*If the last pixel was left in its middle therefore
|
||||
* the circle still has parts on the next one*/
|
||||
if(y_prev.f) {
|
||||
m = (y_prev.f * x1.f) >> 9;
|
||||
if(outer) m = 255 - m;
|
||||
if(kl >= 0 && kl < len) mask_buf[kl] = mask_mix(mask_buf[kl], m);
|
||||
if(kr >= 0 && kr < len) mask_buf[kr] = mask_mix(mask_buf[kr], m);
|
||||
kl--;
|
||||
kr++;
|
||||
}
|
||||
|
||||
if(outer == 0) {
|
||||
kl++;
|
||||
if(kl > len) {
|
||||
return LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
if(kl >= 0) lv_memset_00(&mask_buf[0], kl);
|
||||
|
||||
if(kr < 0) {
|
||||
return LV_DRAW_MASK_RES_TRANSP;
|
||||
}
|
||||
if(kr < len) lv_memset_00(&mask_buf[kr], len - kr);
|
||||
if(cir_x_left - i >= 0 && cir_x_left - i < len) {
|
||||
mask_buf[cir_x_left - i] = mask_mix(opa, mask_buf[cir_x_left - i]);
|
||||
}
|
||||
}
|
||||
|
||||
lv_coord_t clr_start = LV_CLAMP(0, cir_x_left + 1, len);
|
||||
lv_coord_t clr_len = LV_CLAMP(0, cir_x_right - clr_start, len - clr_start);
|
||||
lv_memset_00(&mask_buf[clr_start], clr_len);
|
||||
}
|
||||
|
||||
return LV_DRAW_MASK_RES_CHANGED;
|
||||
@@ -1212,6 +1154,191 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_map(lv_opa_t * mask
|
||||
return LV_DRAW_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the circle drawing
|
||||
* @param c pointer to a point. The coordinates will be calculated here
|
||||
* @param tmp point to a variable. It will store temporary data
|
||||
* @param radius radius of the circle
|
||||
*/
|
||||
static void circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius)
|
||||
{
|
||||
c->x = radius;
|
||||
c->y = 0;
|
||||
*tmp = 1 - radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the circle drawing is ready or not
|
||||
* @param c same as in circ_init
|
||||
* @return true if the circle is not ready yet
|
||||
*/
|
||||
static bool circ_cont(lv_point_t * c)
|
||||
{
|
||||
return c->y <= c->x ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next point from the circle
|
||||
* @param c same as in circ_init. The next point stored here.
|
||||
* @param tmp same as in circ_init.
|
||||
*/
|
||||
static void circ_next(lv_point_t * c, lv_coord_t * tmp)
|
||||
{
|
||||
|
||||
if(*tmp <= 0) {
|
||||
(*tmp) += 2 * c->y + 3; /*Change in decision criterion for y -> y+1*/
|
||||
} else {
|
||||
(*tmp) += 2 * (c->y - c->x) + 5; /*Change for y -> y+1, x -> x-1*/
|
||||
c->x--;
|
||||
}
|
||||
c->y++;
|
||||
}
|
||||
|
||||
static void circ_calc_aa4(_lv_draw_mask_radius_circle_dsc_t * c, lv_coord_t radius)
|
||||
{
|
||||
if(radius == 0) return;
|
||||
c->radius = radius;
|
||||
|
||||
/*Allocate buffers*/
|
||||
if(c->buf) lv_mem_free(c->buf);
|
||||
|
||||
c->buf = lv_mem_alloc(radius * 6 + 6); /*Use uint16_t for opa_start_on_y and x_start_on_y*/
|
||||
c->cir_opa = c->buf;
|
||||
c->opa_start_on_y = (uint16_t *) (c->buf + 2 * radius + 2);
|
||||
c->x_start_on_y = (uint16_t *) (c->buf + 4 * radius + 4);
|
||||
|
||||
lv_coord_t * cir_x = lv_mem_buf_get((radius + 1) * 2 * 2 * sizeof(lv_coord_t));
|
||||
lv_coord_t * cir_y = &cir_x[(radius + 1) * 2];
|
||||
|
||||
uint32_t y_8th_cnt = 0;
|
||||
lv_point_t cp;
|
||||
lv_coord_t tmp;
|
||||
circ_init(&cp, &tmp, radius * 4); /*Upscale by 4*/
|
||||
int32_t i;
|
||||
|
||||
uint32_t x_int[4];
|
||||
uint32_t x_fract[4];
|
||||
lv_coord_t cir_size = 0;
|
||||
x_int[0] = cp.x >> 2;
|
||||
x_fract[0] = 0;
|
||||
|
||||
/*Calculate an 1/8 circle*/
|
||||
while(circ_cont(&cp)) {
|
||||
/*Calculate 4 point of the circle */
|
||||
for(i = 0; i < 4; i++) {
|
||||
circ_next(&cp, &tmp);
|
||||
if(circ_cont(&cp) == false) break;
|
||||
x_int[i] = cp.x >> 2;
|
||||
x_fract[i] = cp.x & 0x3;
|
||||
}
|
||||
if(i != 4) break;
|
||||
|
||||
/*All lines on the same x when downscaled*/
|
||||
if(x_int[0] == x_int[3]) {
|
||||
cir_x[cir_size] = x_int[0];
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = x_fract[0] + x_fract[1] + x_fract[2] + x_fract[3];
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
}
|
||||
/*Second line on new x when downscaled*/
|
||||
else if(x_int[0] != x_int[1]) {
|
||||
cir_x[cir_size] = x_int[0];
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = x_fract[0];
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
|
||||
cir_x[cir_size] = x_int[0] - 1;
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = 1 * 4 + x_fract[1] + x_fract[2] + x_fract[3];;
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
}
|
||||
/*Third line on new x when downscaled*/
|
||||
else if(x_int[0] != x_int[2]) {
|
||||
cir_x[cir_size] = x_int[0];
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = x_fract[0] + x_fract[1];
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
|
||||
cir_x[cir_size] = x_int[0] - 1;
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = 2 * 4 + x_fract[2] + x_fract[3];;
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
}
|
||||
/*Forth line on new x when downscaled*/
|
||||
else {
|
||||
cir_x[cir_size] = x_int[0];
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = x_fract[0] + x_fract[1] + x_fract[2];
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
|
||||
cir_x[cir_size] = x_int[0] - 1;
|
||||
cir_y[cir_size] = y_8th_cnt;
|
||||
c->cir_opa[cir_size] = 3 * 4 + x_fract[3];;
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
}
|
||||
|
||||
y_8th_cnt++;
|
||||
}
|
||||
|
||||
/*The point on the 1/8 circle is special, calculate it manually*/
|
||||
int32_t mid = radius * 723;
|
||||
int32_t mid_int = mid >> 10;
|
||||
if(cir_x[cir_size-1] != mid_int || cir_y[cir_size-1] != mid_int) {
|
||||
tmp = mid - (mid_int << 10);
|
||||
if(tmp <= 512) {
|
||||
tmp = tmp * tmp * 2;
|
||||
tmp = tmp >> (10 + 6);
|
||||
} else {
|
||||
tmp = 1024 - tmp;
|
||||
tmp = (int32_t)tmp * tmp * 2;
|
||||
tmp = (int32_t)tmp >> (10 + 6);
|
||||
tmp = 15 - tmp;
|
||||
}
|
||||
|
||||
cir_x[cir_size] = mid_int;
|
||||
cir_y[cir_size] = mid_int;
|
||||
c->cir_opa[cir_size] = tmp;
|
||||
c->cir_opa[cir_size] *= 16;
|
||||
cir_size++;
|
||||
}
|
||||
|
||||
/*Build the second octet by mirroring the first*/
|
||||
for(i = cir_size - 2; i >= 0; i--, cir_size++) {
|
||||
cir_x[cir_size] = cir_y[i];
|
||||
cir_y[cir_size] = cir_x[i];
|
||||
c->cir_opa[cir_size] = c->cir_opa[i];
|
||||
}
|
||||
|
||||
lv_coord_t y = 0;
|
||||
i = 0;
|
||||
c->opa_start_on_y[0] = 0;
|
||||
while(i < cir_size) {
|
||||
c->opa_start_on_y[y] = i;
|
||||
c->x_start_on_y[y] = cir_x[i];
|
||||
for(; cir_y[i] == y && i < (int32_t)cir_size; i++) {
|
||||
c->x_start_on_y[y] = LV_MIN(c->x_start_on_y[y], cir_x[i]);
|
||||
}
|
||||
y++;
|
||||
}
|
||||
|
||||
lv_mem_buf_release(cir_x);
|
||||
}
|
||||
|
||||
static lv_opa_t * get_next_line(_lv_draw_mask_radius_circle_dsc_t * c, lv_coord_t y, lv_coord_t * len, lv_coord_t * x_start)
|
||||
{
|
||||
*len = c->opa_start_on_y[y + 1] - c->opa_start_on_y[y];
|
||||
*x_start = c->x_start_on_y[y];
|
||||
return &c->cir_opa[c->opa_start_on_y[y]];
|
||||
}
|
||||
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new)
|
||||
{
|
||||
if(mask_new >= LV_OPA_MAX) return mask_act;
|
||||
@@ -1220,24 +1347,5 @@ LV_ATTRIBUTE_FAST_MEM static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_
|
||||
return LV_UDIV255(mask_act * mask_new);// >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approximate the sqrt near to an already calculated value
|
||||
* @param q store the result here
|
||||
* @param ref the reference point (already calculated sqrt)
|
||||
* @param x the value which sqrt should be approximated
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM static inline void sqrt_approx(lv_sqrt_res_t * q, lv_sqrt_res_t * ref, uint32_t x)
|
||||
{
|
||||
x = x << 8; /*Upscale for extra precision*/
|
||||
|
||||
uint32_t raw = (ref->i << 4) + (ref->f >> 4);
|
||||
uint32_t raw2 = raw * raw;
|
||||
|
||||
int32_t d = x - raw2;
|
||||
d = (int32_t)d / (int32_t)(2 * raw) + raw;
|
||||
|
||||
q->i = d >> 4;
|
||||
q->f = (d & 0xF) << 4;
|
||||
}
|
||||
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
@@ -147,6 +147,18 @@ typedef struct {
|
||||
uint16_t delta_deg;
|
||||
} lv_draw_mask_angle_param_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t * buf;
|
||||
lv_opa_t * cir_opa; /*Opacity of values on the circumference of an 1/4 circle*/
|
||||
uint16_t * x_start_on_y; /*The x coordinate of the circle for each y value*/
|
||||
uint16_t * opa_start_on_y; /*The index of `cir_opa` for each y value*/
|
||||
int32_t life; /*How many times the entry way used*/
|
||||
uint32_t used_cnt; /*Like a semaphore to count the referencing masks*/
|
||||
lv_coord_t radius; /*The radius of the entry*/
|
||||
} _lv_draw_mask_radius_circle_dsc_t;
|
||||
|
||||
typedef _lv_draw_mask_radius_circle_dsc_t _lv_draw_mask_radius_circle_dsc_arr_t[LV_CIRCLE_CACHE_SIZE];
|
||||
|
||||
typedef struct {
|
||||
/*The first element must be the common descriptor*/
|
||||
_lv_draw_mask_common_dsc_t dsc;
|
||||
@@ -157,9 +169,8 @@ typedef struct {
|
||||
/*Invert the mask. 0: Keep the pixels inside.*/
|
||||
uint8_t outer: 1;
|
||||
} cfg;
|
||||
int32_t y_prev;
|
||||
lv_sqrt_res_t y_prev_x;
|
||||
|
||||
_lv_draw_mask_radius_circle_dsc_t * circle;
|
||||
} lv_draw_mask_radius_param_t;
|
||||
|
||||
|
||||
@@ -235,6 +246,21 @@ void * lv_draw_mask_remove_id(int16_t id);
|
||||
*/
|
||||
void * lv_draw_mask_remove_custom(void * custom_id);
|
||||
|
||||
/**
|
||||
* Free the data from the parameter.
|
||||
* It's called inside `lv_draw_mask_remove_id` and `lv_draw_mask_remove_custom`
|
||||
* Needs to be called only in special cases when the mask is not added by `lv_draw_mask_add`
|
||||
* and not removed by `lv_draw_mask_remove_id` or `lv_draw_mask_remove_custom`
|
||||
* @param p pointer to a mask parameter
|
||||
*/
|
||||
void lv_draw_mask_free_param(void * p);
|
||||
|
||||
/**
|
||||
* Called by LVGL the rendering of a screen is ready to clean up
|
||||
* the temporal (cache) data of the masks
|
||||
*/
|
||||
void _lv_draw_mask_cleanup(void);
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
|
||||
/**
|
||||
|
||||
@@ -228,7 +228,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
|
||||
y < coords_bg.y2 - rout - 1) {
|
||||
mask_res = LV_DRAW_MASK_RES_FULL_COVER;
|
||||
if(simple_mode == false) {
|
||||
lv_memset(mask_buf, opa, draw_area_w);
|
||||
lv_memset(mask_buf, 0xff, draw_area_w);
|
||||
mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, draw_area_w);
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
|
||||
|
||||
/*If mask will taken into account its base opacity was already set by memset above*/
|
||||
if(mask_res == LV_DRAW_MASK_RES_CHANGED) {
|
||||
opa2 = LV_OPA_COVER;
|
||||
// opa2 = LV_OPA_COVER;
|
||||
}
|
||||
|
||||
/*Get the current line color*/
|
||||
@@ -329,6 +329,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
|
||||
if(grad_map) lv_mem_buf_release(grad_map);
|
||||
if(mask_buf) lv_mem_buf_release(mask_buf);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
if(mask_rout_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_rout_param);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -509,8 +510,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_border(const lv_area_t * coords, const lv
|
||||
fill_area.y2++;
|
||||
|
||||
}
|
||||
lv_draw_mask_free_param(&mask_rin_param);
|
||||
lv_draw_mask_free_param(&mask_rout_param);
|
||||
lv_draw_mask_remove_id(mask_rin_id);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
if(mask_rout_id != LV_MASK_ID_INV) lv_draw_mask_remove_id(mask_rout_id);
|
||||
lv_mem_buf_release(mask_buf);
|
||||
}
|
||||
#else /*LV_DRAW_COMPLEX*/
|
||||
@@ -1007,6 +1010,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv
|
||||
}
|
||||
}
|
||||
|
||||
lv_draw_mask_free_param(&mask_rout_param);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_mem_buf_release(sh_buf);
|
||||
@@ -1064,6 +1068,8 @@ LV_ATTRIBUTE_FAST_MEM static void shadow_draw_corner_buf(const lv_area_t * coord
|
||||
}
|
||||
lv_mem_buf_release(mask_line);
|
||||
|
||||
lv_draw_mask_free_param(&mask_param);
|
||||
|
||||
if(sw == 1) {
|
||||
int32_t i;
|
||||
lv_opa_t * res_buf = (lv_opa_t *)sh_buf;
|
||||
@@ -1394,6 +1400,8 @@ static void draw_full_border(const lv_area_t * area_inner, const lv_area_t * are
|
||||
|
||||
}
|
||||
}
|
||||
lv_draw_mask_free_param(&mask_rin_param);
|
||||
lv_draw_mask_free_param(&mask_rout_param);
|
||||
lv_draw_mask_remove_id(mask_rin_id);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
lv_mem_buf_release(mask_buf);
|
||||
|
||||
@@ -287,6 +287,8 @@ static void draw_disc_grad(lv_event_t * e)
|
||||
}
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
lv_draw_mask_free_param(&mask_out_param);
|
||||
lv_draw_mask_free_param(&mask_in_param);
|
||||
lv_draw_mask_remove_id(mask_out_id);
|
||||
lv_draw_mask_remove_id(mask_in_id);
|
||||
#endif
|
||||
|
||||
@@ -414,7 +414,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c
|
||||
lv_draw_mask_radius_init(&outer_mask, &area_outer, LV_RADIUS_CIRCLE, false);
|
||||
int16_t outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
|
||||
|
||||
int16_t inner_act_mask_id = -1; /*Will be added later*/
|
||||
int16_t inner_act_mask_id = LV_MASK_ID_INV; /*Will be added later*/
|
||||
|
||||
uint32_t minor_cnt = scale->tick_major_nth ? scale->tick_major_nth - 1 : 0xFFFF;
|
||||
for(i = 0; i < scale->tick_cnt; i++) {
|
||||
@@ -530,6 +530,9 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c
|
||||
line_dsc.width = line_width_ori;
|
||||
|
||||
}
|
||||
lv_draw_mask_free_param(&inner_minor_mask);
|
||||
lv_draw_mask_free_param(&inner_major_mask);
|
||||
lv_draw_mask_free_param(&outer_mask);
|
||||
lv_draw_mask_remove_id(outer_mask_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +250,19 @@
|
||||
# define LV_SHADOW_CACHE_SIZE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Set number of maximally cached circle data.
|
||||
* The circumference of 1/4 circle are saved for anti-aliasing
|
||||
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
|
||||
* 0: to disable caching */
|
||||
#ifndef LV_CIRCLE_CACHE_SIZE
|
||||
# ifdef CONFIG_LV_CIRCLE_CACHE_SIZE
|
||||
# define LV_CIRCLE_CACHE_SIZE CONFIG_LV_CIRCLE_CACHE_SIZE
|
||||
# else
|
||||
# define LV_CIRCLE_CACHE_SIZE 4
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_COMPLEX*/
|
||||
|
||||
/*Default image cache size. Image caching keeps the images opened.
|
||||
|
||||
@@ -459,7 +459,15 @@ static inline uint32_t lv_color_to32(lv_color_t color)
|
||||
LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
|
||||
{
|
||||
lv_color_t ret;
|
||||
#if LV_COLOR_DEPTH != 1
|
||||
|
||||
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0
|
||||
/*Source: https://stackoverflow.com/a/50012418/1999969*/
|
||||
mix = ( mix + 4 ) >> 3;
|
||||
uint32_t bg = (c2.full | (c2.full << 16)) & 0x7E0F81F; /*0b00000111111000001111100000011111*/
|
||||
uint32_t fg = (c1.full | (c1.full << 16)) & 0x7E0F81F;
|
||||
uint32_t result = ((((fg - bg) * mix) >> 5) + bg) & 0x7E0F81F;
|
||||
ret.full = (uint16_t)((result >> 16) | result);
|
||||
#elif LV_COLOR_DEPTH != 1
|
||||
/*LV_COLOR_DEPTH == 8, 16 or 32*/
|
||||
LV_COLOR_SET_R(ret, LV_UDIV255((uint16_t) LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) *
|
||||
(255 - mix) + LV_COLOR_MIX_ROUND_OFS));
|
||||
|
||||
@@ -53,6 +53,7 @@ extern "C" {
|
||||
LV_DISPATCH_COND(f, _lv_img_cache_entry_t, _lv_img_cache_single, LV_IMG_CACHE_DEF, 0) \
|
||||
LV_DISPATCH(f, lv_timer_t*, _lv_timer_act) \
|
||||
LV_DISPATCH(f, lv_mem_buf_arr_t , lv_mem_buf) \
|
||||
LV_DISPATCH_COND(f, _lv_draw_mask_radius_circle_dsc_arr_t , _lv_circle_cache, LV_DRAW_COMPLEX, 1) \
|
||||
LV_DISPATCH_COND(f, _lv_draw_mask_saved_arr_t , _lv_draw_mask_list, LV_DRAW_COMPLEX, 1) \
|
||||
LV_DISPATCH(f, void * , _lv_theme_default_styles) \
|
||||
LV_DISPATCH_COND(f, uint8_t *, _lv_font_decompr_buf, LV_USE_FONT_COMPRESSED, 1)
|
||||
|
||||
@@ -486,6 +486,8 @@ static void draw_indic(lv_event_t * e)
|
||||
lv_draw_rect(&bar->indic_area, clip_area, &draw_rect_dsc);
|
||||
|
||||
#if LV_DRAW_COMPLEX
|
||||
lv_draw_mask_free_param(&mask_indic_param);
|
||||
lv_draw_mask_free_param(&mask_bg_param);
|
||||
lv_draw_mask_remove_id(mask_indic_id);
|
||||
lv_draw_mask_remove_id(mask_bg_id);
|
||||
#endif
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user