feat(draw_sw): implemented radial gradient background (#6170)

Co-authored-by: Zoltan Janosy <zjanosy@fishman.com>
Co-authored-by: Liam <30486941+liamHowatt@users.noreply.github.com>
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Zoltan Janosy 2024-05-26 17:17:16 +02:00 committed by GitHub
parent b8b7e29156
commit 48caa8d772
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
57 changed files with 1449 additions and 57 deletions

View File

@ -229,6 +229,14 @@ menu "LVGL configuration"
0: use a simple renderer capable of drawing only simple rectangles with gradient, images, texts, and straight lines only,
1: use a complex renderer capable of drawing rounded corners, shadow, skew lines, and arcs too.
config LV_USE_DRAW_SW_COMPLEX_GRADIENTS
bool "Enable drawing complex gradients in software"
default n
depends on LV_USE_DRAW_SW
help
0: do not enable complex gradients
1: enable complex gradients (linear at an angle, radial or conical)
config LV_DRAW_SW_SHADOW_CACHE_SIZE
int "Allow buffering some shadow calculation"
depends on LV_DRAW_SW_COMPLEX

View File

@ -834,6 +834,238 @@ static void blend_mode_cb(lv_obj_t * parent)
}
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
static lv_obj_t * create_linear_gradient_obj(lv_obj_t * parent, int32_t col, int32_t row, lv_grad_dsc_t * grad,
int32_t x1, int32_t y1, lv_grad_extend_t extend, bool use_opa_map, int32_t radius)
{
const lv_color_t grad_color[2] = {
LV_COLOR_MAKE(0xd5, 0x03, 0x47),
LV_COLOR_MAKE(0x00, 0x00, 0x00),
};
const lv_opa_t grad_opa[2] = {
LV_OPA_100, LV_OPA_0,
};
/*init gradient color map*/
lv_gradient_init_stops(grad, grad_color, use_opa_map ? grad_opa : NULL, NULL, sizeof(grad_color) / sizeof(lv_color_t));
/*init gradient parameters*/
grad->dir = LV_GRAD_DIR_LINEAR;
grad->params.linear.start.x = 0; /*vector start x position*/
grad->params.linear.start.y = 0; /*vector start y position*/
grad->params.linear.end.x = x1; /*vector end x position*/
grad->params.linear.end.y = y1; /*vector end y position*/
grad->extend = extend; /*color pattern outside the vector*/
/*create rectangle*/
lv_obj_t * obj = lv_obj_create(parent);
lv_obj_remove_style_all(obj);
lv_obj_set_size(obj, 70, 50);
lv_obj_set_style_radius(obj, radius, 0);
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
lv_obj_set_style_opa(obj, opa_saved, 0);
/*set gradient as background*/
lv_obj_set_style_bg_grad(obj, grad, 0);
add_to_cell(obj, col, row);
return obj;
}
static void linear_gradient_cb(lv_obj_t * parent)
{
static const int32_t grid_cols[] = { 53, 53, 53, 53, 53, 53, 53, 53, 53, LV_GRID_TEMPLATE_LAST };
static const int32_t grid_rows[] = { 32, 40, 40, 40, 40, 40, 40, LV_GRID_TEMPLATE_LAST };
lv_obj_set_grid_dsc_array(parent, grid_cols, grid_rows);
const char * opa_txt[] = { "no opa", "no opa round", "stop opa", "stop opa round" };
int32_t radius_values[] = { 0, 20, 0, 20 };
bool opa_map_values[] = { false, false, true, true };
const char * offs_txt[] = { "pad", "repeat", "reflect" };
int32_t x1_values[] = { lv_pct(100), lv_pct(15), lv_pct(30)};
int32_t y1_values[] = { lv_pct(100), lv_pct(30), lv_pct(15) };
lv_grad_extend_t extend_values[] = { LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT, LV_GRAD_EXTEND_REFLECT };
static lv_grad_dsc_t grad_values[3][4];
uint32_t y;
for(y = 0; y < 3; y++) {
lv_obj_t * offs_label = lv_label_create(parent);
lv_label_set_text(offs_label, offs_txt[y]);
lv_obj_set_grid_cell(offs_label, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 1 + y * 2, 2);
}
uint32_t x;
for(x = 0; x < 4; x++) {
lv_obj_t * op_label = lv_label_create(parent);
lv_label_set_text(op_label, opa_txt[x]);
lv_obj_set_grid_cell(op_label, LV_GRID_ALIGN_CENTER, 1 + x * 2, 2, LV_GRID_ALIGN_CENTER, 0, 1);
for(y = 0; y < 3; y++) {
create_linear_gradient_obj(parent, 1 + x * 2, 1 + y * 2, &grad_values[y][x], x1_values[y], y1_values[y],
extend_values[y], opa_map_values[x], radius_values[x]);
}
}
}
static lv_obj_t * create_radial_gradient_obj(lv_obj_t * parent, int32_t col, int32_t row, lv_grad_dsc_t * grad,
int32_t offs, int32_t r0, lv_grad_extend_t extend, bool use_opa_map, int32_t radius)
{
const lv_color_t grad_color[2] = {
LV_COLOR_MAKE(0xd5, 0x03, 0x47),
LV_COLOR_MAKE(0x00, 0x00, 0x00),
};
const lv_opa_t grad_opa[2] = {
LV_OPA_100, LV_OPA_0,
};
/*init gradient color map*/
lv_gradient_init_stops(grad, grad_color, use_opa_map ? grad_opa : NULL, NULL, sizeof(grad_color) / sizeof(lv_color_t));
/*init gradient parameters*/
grad->dir = LV_GRAD_DIR_RADIAL;
grad->params.radial.focal.x = lv_pct(50); /*start circle center x position*/
grad->params.radial.focal.y = lv_pct(50); /*start circle center y position*/
grad->params.radial.focal_extent.x = grad->params.radial.focal.x + r0; /*start circle point x coordinate*/
grad->params.radial.focal_extent.y = grad->params.radial.focal.y; /*start circle point y coordinate*/
grad->params.radial.end.x = grad->params.radial.focal.x + offs; /*end circle center x position*/
grad->params.radial.end.y = grad->params.radial.focal.y + offs; /*end circle center y position*/
grad->params.radial.end_extent.x = grad->params.radial.end.x; /*end circle point x coordinate*/
grad->params.radial.end_extent.y = lv_pct(85); /*end circle point y coordinate*/
grad->extend = extend; /*color pattern outside the border circles*/
/*create rectangle*/
lv_obj_t * obj = lv_obj_create(parent);
lv_obj_remove_style_all(obj);
lv_obj_set_size(obj, 70, 50);
lv_obj_set_style_radius(obj, radius, 0);
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
lv_obj_set_style_opa(obj, opa_saved, 0);
/*set gradient as background*/
lv_obj_set_style_bg_grad(obj, grad, 0);
add_to_cell(obj, col, row);
return obj;
}
static void radial_gradient_cb(lv_obj_t * parent)
{
static const int32_t grid_cols[] = { 53, 53, 53, 53, 53, 53, 53, 53, 53, LV_GRID_TEMPLATE_LAST };
static const int32_t grid_rows[] = { 32, 40, 40, 40, 40, 40, 40, LV_GRID_TEMPLATE_LAST };
lv_obj_set_grid_dsc_array(parent, grid_cols, grid_rows);
const char * opa_txt[] = { "no opa", "no opa round", "stop opa", "stop opa round" };
int32_t radius_values[] = { 0, 20, 0, 20 };
bool opa_map_values[] = { false, false, true, true };
const char * offs_txt[] = { "pad", "repeat", "reflect" };
lv_grad_extend_t extend_values[] = { LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT, LV_GRAD_EXTEND_REFLECT};
static lv_grad_dsc_t grad_values[3][4];
uint32_t y;
for(y = 0; y < 3; y++) {
lv_obj_t * offs_label = lv_label_create(parent);
lv_label_set_text(offs_label, offs_txt[y]);
lv_obj_set_grid_cell(offs_label, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 1 + y * 2, 2);
}
uint32_t x;
for(x = 0; x < 4; x++) {
lv_obj_t * op_label = lv_label_create(parent);
lv_label_set_text(op_label, opa_txt[x]);
lv_obj_set_grid_cell(op_label, LV_GRID_ALIGN_CENTER, 1 + x * 2, 2, LV_GRID_ALIGN_CENTER, 0, 1);
for(y = 0; y < 3; y++) {
create_radial_gradient_obj(parent, 1 + x * 2, 1 + y * 2, &grad_values[y][x], y * 5, 0, extend_values[y],
opa_map_values[x], radius_values[x]);
}
}
}
static lv_obj_t * create_conical_gradient_obj(lv_obj_t * parent, int32_t col, int32_t row, lv_grad_dsc_t * grad,
int32_t a0, int32_t a1, lv_grad_extend_t extend, bool use_opa_map, int32_t radius)
{
const lv_color_t grad_color[2] = {
LV_COLOR_MAKE(0xd5, 0x03, 0x47),
LV_COLOR_MAKE(0x00, 0x00, 0x00),
};
const lv_opa_t grad_opa[2] = {
LV_OPA_100, LV_OPA_0,
};
/*init gradient color map*/
lv_gradient_init_stops(grad, grad_color, use_opa_map ? grad_opa : NULL, NULL, sizeof(grad_color) / sizeof(lv_color_t));
/*init gradient parameters*/
grad->dir = LV_GRAD_DIR_CONICAL;
grad->params.conical.center.x = lv_pct(50); /*center x position*/
grad->params.conical.center.y = lv_pct(50); /*center y position*/
grad->params.conical.start_angle = a0; /*start angle*/
grad->params.conical.end_angle = a1; /*end angle*/
grad->extend = extend; /*color pattern outside the vector*/
/*create rectangle*/
lv_obj_t * obj = lv_obj_create(parent);
lv_obj_remove_style_all(obj);
lv_obj_set_size(obj, 70, 50);
lv_obj_set_style_radius(obj, radius, 0);
lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
lv_obj_set_style_opa(obj, opa_saved, 0);
/*set gradient as background*/
lv_obj_set_style_bg_grad(obj, grad, 0);
add_to_cell(obj, col, row);
return obj;
}
static void conical_gradient_cb(lv_obj_t * parent)
{
static const int32_t grid_cols[] = { 53, 53, 53, 53, 53, 53, 53, 53, 53, LV_GRID_TEMPLATE_LAST };
static const int32_t grid_rows[] = { 32, 40, 40, 40, 40, 40, 40, LV_GRID_TEMPLATE_LAST };
lv_obj_set_grid_dsc_array(parent, grid_cols, grid_rows);
const char * opa_txt[] = { "no opa", "no opa round", "stop opa", "stop opa round" };
int32_t radius_values[] = { 0, 20, 0, 20 };
bool opa_map_values[] = { false, false, true, true };
const char * offs_txt[] = { "pad", "repeat", "reflect" };
lv_grad_extend_t extend_values[] = { LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT, LV_GRAD_EXTEND_REFLECT };
static lv_grad_dsc_t grad_values[3][4];
uint32_t y;
for(y = 0; y < 3; y++) {
lv_obj_t * offs_label = lv_label_create(parent);
lv_label_set_text(offs_label, offs_txt[y]);
lv_obj_set_grid_cell(offs_label, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 1 + y * 2, 2);
}
uint32_t x;
for(x = 0; x < 4; x++) {
lv_obj_t * op_label = lv_label_create(parent);
lv_label_set_text(op_label, opa_txt[x]);
lv_obj_set_grid_cell(op_label, LV_GRID_ALIGN_CENTER, 1 + x * 2, 2, LV_GRID_ALIGN_CENTER, 0, 1);
for(y = 0; y < 3; y++) {
create_conical_gradient_obj(parent, 1 + x * 2, 1 + y * 2, &grad_values[y][x], 10, 100, extend_values[y],
opa_map_values[x], radius_values[x]);
}
}
}
#endif
/**********************
* STATIC VARIABLES
**********************/
@ -854,6 +1086,12 @@ static scene_dsc_t scenes[] = {
{.name = "layer_normal", .create_cb = layer_normal_cb},
{.name = "blend_mode", .create_cb = blend_mode_cb},
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
{.name = "linear_gradient", .create_cb = linear_gradient_cb},
{.name = "radial_gradient", .create_cb = radial_gradient_cb},
{.name = "conical_gradient", .create_cb = conical_gradient_cb},
#endif
{.name = "", .create_cb = NULL}
};

View File

@ -43,6 +43,11 @@ typedef enum {
LV_DEMO_RENDER_SCENE_TRIANGLE,
LV_DEMO_RENDER_SCENE_LAYER_NORMAL,
LV_DEMO_RENDER_SCENE_BLEND_MODE,
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
LV_DEMO_RENDER_SCENE_LINEAR_GRADIENT,
LV_DEMO_RENDER_SCENE_RADIAL_GRADIENT,
LV_DEMO_RENDER_SCENE_CONICAL_GRADIENT,
#endif
_LV_DEMO_RENDER_SCENE_NUM,
} lv_demo_render_scene_t;

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_example_style.h
*
*/
@ -40,6 +40,9 @@ void lv_example_style_12(void);
void lv_example_style_13(void);
void lv_example_style_14(void);
void lv_example_style_15(void);
void lv_example_style_16(void);
void lv_example_style_17(void);
void lv_example_style_18(void);
/**********************
* MACROS

View File

@ -0,0 +1,73 @@
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/**
* Simulate metallic knob using conical gradient
* For best effect set LV_GRADIENT_MAX_STOPS to 8 or at least 3
*/
void lv_example_style_16(void)
{
#if LV_GRADIENT_MAX_STOPS >= 8
static const lv_color_t grad_colors[8] = {
LV_COLOR_MAKE(0xe8, 0xe8, 0xe8),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0xfa, 0xfa, 0xfa),
LV_COLOR_MAKE(0x79, 0x79, 0x79),
LV_COLOR_MAKE(0x48, 0x48, 0x48),
LV_COLOR_MAKE(0x4b, 0x4b, 0x4b),
LV_COLOR_MAKE(0x70, 0x70, 0x70),
LV_COLOR_MAKE(0xe8, 0xe8, 0xe8),
};
#elif LV_GRADIENT_MAX_STOPS >= 3
static const lv_color_t grad_colors[3] = {
LV_COLOR_MAKE(0xe8, 0xe8, 0xe8),
LV_COLOR_MAKE(0xff, 0xff, 0xff),
LV_COLOR_MAKE(0x79, 0x79, 0x79),
};
#else
static const lv_color_t grad_colors[2] = {
LV_COLOR_MAKE(0xe8, 0xe8, 0xe8),
LV_COLOR_MAKE(0x79, 0x79, 0x79),
};
#endif
/*Create a style with gradient background and shadow*/
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 500);
lv_style_set_bg_opa(&style, LV_OPA_COVER);
lv_style_set_shadow_color(&style, lv_color_black());
lv_style_set_shadow_width(&style, 50);
lv_style_set_shadow_offset_x(&style, 20);
lv_style_set_shadow_offset_y(&style, 20);
lv_style_set_shadow_opa(&style, LV_OPA_50);
/*First define a color gradient. In this example we use a gray color map with random values.*/
static lv_grad_dsc_t grad;
lv_gradient_init_stops(&grad, grad_colors, NULL, NULL, sizeof(grad_colors) / sizeof(lv_color_t));
/*Make a conical gradient with the center in the middle of the object*/
#if LV_GRADIENT_MAX_STOPS >= 8
lv_grad_conical_init(&grad, LV_GRAD_CENTER, LV_GRAD_CENTER, 0, 120, LV_GRAD_EXTEND_REFLECT);
#elif LV_GRADIENT_MAX_STOPS >= 3
lv_grad_conical_init(&grad, LV_GRAD_CENTER, LV_GRAD_CENTER, 45, 125, LV_GRAD_EXTEND_REFLECT);
#else
lv_grad_conical_init(&grad, LV_GRAD_CENTER, LV_GRAD_CENTER, 45, 110, LV_GRAD_EXTEND_REFLECT);
#endif
/*Set gradient as background*/
lv_style_set_bg_grad(&style, &grad);
/*Create an object with the new style*/
lv_obj_t * obj = lv_obj_create(lv_screen_active());
lv_obj_add_style(obj, &style, 0);
lv_obj_set_size(obj, 200, 200);
lv_obj_center(obj);
}
#endif /*LV_USE_DRAW_SW_COMPLEX_GRADIENTS*/
#endif /*LV_BUILD_EXAMPLES*/

View File

@ -0,0 +1,42 @@
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/**
* Using radial gradient as background
*/
void lv_example_style_17(void)
{
static const lv_color_t grad_colors[2] = {
LV_COLOR_MAKE(0x9B, 0x18, 0x42),
LV_COLOR_MAKE(0x00, 0x00, 0x00),
};
int32_t width = lv_display_get_horizontal_resolution(NULL);
int32_t height = lv_display_get_vertical_resolution(NULL);
static lv_style_t style;
lv_style_init(&style);
/*First define a color gradient. In this example we use a purple to black color map.*/
static lv_grad_dsc_t grad;
lv_gradient_init_stops(&grad, grad_colors, NULL, NULL, sizeof(grad_colors) / sizeof(lv_color_t));
/*Make a radial gradient with the center in the middle of the object, extending to the farthest corner*/
lv_grad_radial_init(&grad, LV_GRAD_CENTER, LV_GRAD_CENTER, LV_GRAD_RIGHT, LV_GRAD_BOTTOM, LV_GRAD_EXTEND_PAD);
/*Set gradient as background*/
lv_style_set_bg_grad(&style, &grad);
/*Create an object with the new style*/
lv_obj_t * obj = lv_obj_create(lv_screen_active());
lv_obj_add_style(obj, &style, 0);
lv_obj_set_size(obj, width, height);
lv_obj_center(obj);
}
#endif /*LV_USE_DRAW_SW_COMPLEX_GRADIENTS*/
#endif /*LV_BUILD_EXAMPLES*/

View File

@ -0,0 +1,88 @@
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/**
* Using various gradients for button background
*/
void lv_example_style_18(void)
{
static const lv_color_t grad_colors[2] = {
LV_COLOR_MAKE(0x26, 0xa0, 0xda),
LV_COLOR_MAKE(0x31, 0x47, 0x55),
};
/*Create a linear gradient going from the top left corner to the bottom at an angle, with reflected color map*/
static lv_style_t style_with_linear_gradient_bg;
static lv_grad_dsc_t linear_gradient_dsc; /*NOTE: the gradient descriptor must be static or global variable!*/
lv_style_init(&style_with_linear_gradient_bg);
lv_gradient_init_stops(&linear_gradient_dsc, grad_colors, NULL, NULL, sizeof(grad_colors) / sizeof(lv_color_t));
lv_grad_linear_init(&linear_gradient_dsc, lv_pct(0), lv_pct(0), lv_pct(20), lv_pct(100), LV_GRAD_EXTEND_REFLECT);
lv_style_set_bg_grad(&style_with_linear_gradient_bg, &linear_gradient_dsc);
lv_style_set_bg_opa(&style_with_linear_gradient_bg, LV_OPA_COVER);
/*Create a radial gradient with the center in the top left 1/3rd of the object, extending to the bottom right corner, with reflected color map*/
static lv_style_t style_with_radial_gradient_bg;
static lv_grad_dsc_t radial_gradient_dsc; /*NOTE: the gradient descriptor must be static or global variable!*/
lv_style_init(&style_with_radial_gradient_bg);
lv_gradient_init_stops(&radial_gradient_dsc, grad_colors, NULL, NULL, sizeof(grad_colors) / sizeof(lv_color_t));
lv_grad_radial_init(&radial_gradient_dsc, lv_pct(30), lv_pct(30), lv_pct(100), lv_pct(100), LV_GRAD_EXTEND_REFLECT);
lv_style_set_bg_grad(&style_with_radial_gradient_bg, &radial_gradient_dsc);
lv_style_set_bg_opa(&style_with_radial_gradient_bg, LV_OPA_COVER);
/*Create buttons with different gradient styles*/
lv_obj_t * btn;
lv_obj_t * label;
/*Simple horizontal gradient*/
btn = lv_button_create(lv_screen_active());
lv_obj_set_style_bg_color(btn, grad_colors[0], 0);
lv_obj_set_style_bg_grad_color(btn, grad_colors[1], 0);
lv_obj_set_style_bg_grad_dir(btn, LV_GRAD_DIR_HOR, 0);
lv_obj_set_size(btn, 150, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, -100);
label = lv_label_create(btn);
lv_label_set_text(label, "Horizontal");
lv_obj_center(label);
/*Simple vertical gradient*/
btn = lv_button_create(lv_screen_active());
lv_obj_set_style_bg_color(btn, grad_colors[0], 0);
lv_obj_set_style_bg_grad_color(btn, grad_colors[1], 0);
lv_obj_set_style_bg_grad_dir(btn, LV_GRAD_DIR_VER, 0);
lv_obj_set_size(btn, 150, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, -40);
label = lv_label_create(btn);
lv_label_set_text(label, "Vertical");
lv_obj_center(label);
/*Complex linear gradient*/
btn = lv_button_create(lv_screen_active());
lv_obj_add_style(btn, &style_with_linear_gradient_bg, 0);
lv_obj_set_size(btn, 150, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);
label = lv_label_create(btn);
lv_label_set_text(label, "Linear");
lv_obj_center(label);
/*Complex radial gradient*/
btn = lv_button_create(lv_screen_active());
lv_obj_add_style(btn, &style_with_radial_gradient_bg, 0);
lv_obj_set_size(btn, 150, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 80);
label = lv_label_create(btn);
lv_label_set_text(label, "Radial");
lv_obj_center(label);
}
#endif /*LV_USE_DRAW_SW_COMPLEX_GRADIENTS*/
#endif /*LV_BUILD_EXAMPLES*/

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_conf.h
* Configuration file for v9.1.1-dev
*/
@ -154,6 +154,9 @@
#if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_CUSTOM
#define LV_DRAW_SW_ASM_CUSTOM_INCLUDE ""
#endif
/* Enable drawing complex gradients in software: linear at an angle, radial or conical */
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0
#endif
/* Use NXP's VG-Lite GPU on iMX RTxxx platforms. */

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_draw_sw.h
*
*/
@ -72,7 +72,7 @@ void lv_draw_sw_deinit(void);
* @param dsc the draw descriptor
* @param coords the coordinates of the rectangle
*/
void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
/**
* Draw border with SW render.

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_draw_sw_fill.c
*
*/
@ -42,7 +42,7 @@
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN) return;
@ -103,10 +103,10 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
/*Get gradient if appropriate*/
lv_grad_t * grad = lv_gradient_get(&dsc->grad, coords_bg_w, coords_bg_h);
lv_opa_t * grad_opa_map = NULL;
if(grad && grad_dir == LV_GRAD_DIR_HOR) {
bool transp = false;
if(grad && grad_dir >= LV_GRAD_DIR_HOR) {
blend_dsc.src_area = &blend_area;
blend_dsc.src_buf = grad->color_map + clipped_coords.x1 - bg_coords.x1;
bool transp = false;
uint32_t s;
for(s = 0; s < dsc->grad.stops_count; s++) {
if(dsc->grad.stops[s].opa != LV_OPA_COVER) {
@ -114,18 +114,45 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
break;
}
}
if(transp) grad_opa_map = grad->opa_map + clipped_coords.x1 - bg_coords.x1;
if(grad_dir == LV_GRAD_DIR_HOR) {
if(transp) grad_opa_map = grad->opa_map + clipped_coords.x1 - bg_coords.x1;
}
blend_dsc.src_color_format = LV_COLOR_FORMAT_RGB888;
}
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/*Prepare complex gradient*/
if(grad_dir >= LV_GRAD_DIR_LINEAR) {
switch(grad_dir) {
case LV_GRAD_DIR_LINEAR:
lv_gradient_linear_setup(&dsc->grad, coords);
break;
case LV_GRAD_DIR_RADIAL:
lv_gradient_radial_setup(&dsc->grad, coords);
break;
case LV_GRAD_DIR_CONICAL:
lv_gradient_conical_setup(&dsc->grad, coords);
break;
default:
LV_LOG_WARN("Gradient type is not supported");
return;
}
blend_dsc.src_area = &blend_area;
/* For complex gradients we reuse the color map buffer for the pixel data */
blend_dsc.src_buf = grad->color_map;
grad_opa_map = grad->opa_map;
}
#endif
/* Draw the top of the rectangle line by line and mirror it to the bottom. */
for(h = 0; h < rout; h++) {
int32_t top_y = bg_coords.y1 + h;
int32_t bottom_y = bg_coords.y2 - h;
if(top_y < clipped_coords.y1 && bottom_y > clipped_coords.y2) continue; /*This line is clipped now*/
bool preblend = false;
/* Initialize the mask to opa instead of 0xFF and blend with LV_OPA_COVER.
* It saves calculating the final opa in lv_draw_sw_blend*/
lv_memset(mask_buf, opa, clipped_w);
@ -137,19 +164,37 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
blend_area.y1 = top_y;
blend_area.y2 = top_y;
if(grad_dir == LV_GRAD_DIR_VER) {
blend_dsc.color = grad->color_map[top_y - bg_coords.y1];
blend_dsc.opa = grad->opa_map[top_y - bg_coords.y1];
switch(grad_dir) {
case LV_GRAD_DIR_VER:
blend_dsc.color = grad->color_map[top_y - bg_coords.y1];
blend_dsc.opa = grad->opa_map[top_y - bg_coords.y1];
break;
case LV_GRAD_DIR_HOR:
hor_grad_processed = true;
preblend = grad_opa_map != NULL;
break;
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
case LV_GRAD_DIR_LINEAR:
lv_gradient_linear_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, top_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
case LV_GRAD_DIR_RADIAL:
lv_gradient_radial_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, top_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
case LV_GRAD_DIR_CONICAL:
lv_gradient_conical_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, top_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
#endif
}
else if(grad_dir == LV_GRAD_DIR_HOR) {
hor_grad_processed = true;
if(grad_opa_map) {
int32_t i;
for(i = 0; i < clipped_w; i++) {
if(grad_opa_map[i] < LV_OPA_MAX) mask_buf[i] = (mask_buf[i] * grad_opa_map[i]) >> 8;
}
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
/* pre-blend the mask */
if(preblend) {
int32_t i;
for(i = 0; i < clipped_w; i++) {
if(grad_opa_map[i] < LV_OPA_MAX) mask_buf[i] = (mask_buf[i] * grad_opa_map[i]) >> 8;
}
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
}
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
@ -158,18 +203,42 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
blend_area.y1 = bottom_y;
blend_area.y2 = bottom_y;
if(grad_dir == LV_GRAD_DIR_VER) {
blend_dsc.color = grad->color_map[bottom_y - bg_coords.y1];
blend_dsc.opa = grad->opa_map[bottom_y - bg_coords.y1];
switch(grad_dir) {
case LV_GRAD_DIR_VER:
blend_dsc.color = grad->color_map[bottom_y - bg_coords.y1];
blend_dsc.opa = grad->opa_map[bottom_y - bg_coords.y1];
break;
case LV_GRAD_DIR_HOR:
preblend = !hor_grad_processed && (grad_opa_map != NULL);
break;
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
case LV_GRAD_DIR_LINEAR:
lv_gradient_linear_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, bottom_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
case LV_GRAD_DIR_RADIAL:
lv_gradient_radial_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, bottom_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
case LV_GRAD_DIR_CONICAL:
lv_gradient_conical_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, bottom_y - bg_coords.y1, coords_bg_w, grad);
preblend = true;
break;
#endif
}
else if(hor_grad_processed == false && grad_dir == LV_GRAD_DIR_HOR) {
if(grad_opa_map) {
int32_t i;
for(i = 0; i < clipped_w; i++) {
if(grad_opa_map[i] < LV_OPA_MAX) mask_buf[i] = (mask_buf[i] * grad_opa_map[i]) >> 8;
}
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
/* pre-blend the mask */
if(preblend) {
int32_t i;
if(grad_dir >= LV_GRAD_DIR_LINEAR) {
/*Need to generate the mask again, because we have mixed in the upper part of the gradient*/
lv_memset(mask_buf, opa, clipped_w);
blend_dsc.mask_res = lv_draw_sw_mask_apply(mask_list, mask_buf, blend_area.x1, top_y, clipped_w);
if(blend_dsc.mask_res == LV_DRAW_SW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
}
for(i = 0; i < clipped_w; i++) {
if(grad_opa_map[i] < LV_OPA_MAX) mask_buf[i] = (mask_buf[i] * grad_opa_map[i]) >> 8;
}
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
}
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
@ -188,23 +257,44 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
/*With gradient draw line by line*/
else {
blend_dsc.opa = opa;
if(grad_dir == LV_GRAD_DIR_VER) {
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_FULL_COVER;
}
else if(grad_dir == LV_GRAD_DIR_HOR) {
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
blend_dsc.mask_buf = grad_opa_map;
switch(grad_dir) {
case LV_GRAD_DIR_VER:
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_FULL_COVER;
break;
case LV_GRAD_DIR_HOR:
blend_dsc.mask_res = LV_DRAW_SW_MASK_RES_CHANGED;
blend_dsc.mask_buf = grad_opa_map;
break;
case LV_GRAD_DIR_LINEAR:
case LV_GRAD_DIR_RADIAL:
case LV_GRAD_DIR_CONICAL:
blend_dsc.mask_res = transp ? LV_DRAW_SW_MASK_RES_CHANGED : LV_DRAW_SW_MASK_RES_FULL_COVER;
blend_dsc.mask_buf = grad_opa_map;
}
int32_t h_end = bg_coords.y2 - rout;
for(h = bg_coords.y1 + rout; h <= h_end; h++) {
int32_t h_start = LV_MAX(bg_coords.y1 + rout, clipped_coords.y1);
int32_t h_end = LV_MIN(bg_coords.y2 - rout, clipped_coords.y2);
for(h = h_start; h <= h_end; h++) {
blend_area.y1 = h;
blend_area.y2 = h;
if(grad_dir == LV_GRAD_DIR_VER) {
blend_dsc.color = grad->color_map[h - bg_coords.y1];
if(opa >= LV_OPA_MAX) blend_dsc.opa = grad->opa_map[h - bg_coords.y1];
else blend_dsc.opa = LV_OPA_MIX2(grad->opa_map[h - bg_coords.y1], opa);
switch(grad_dir) {
case LV_GRAD_DIR_VER:
blend_dsc.color = grad->color_map[h - bg_coords.y1];
if(opa >= LV_OPA_MAX) blend_dsc.opa = grad->opa_map[h - bg_coords.y1];
else blend_dsc.opa = LV_OPA_MIX2(grad->opa_map[h - bg_coords.y1], opa);
break;
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
case LV_GRAD_DIR_LINEAR:
lv_gradient_linear_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, h - bg_coords.y1, coords_bg_w, grad);
break;
case LV_GRAD_DIR_RADIAL:
lv_gradient_radial_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, h - bg_coords.y1, coords_bg_w, grad);
break;
case LV_GRAD_DIR_CONICAL:
lv_gradient_conical_get_line(&dsc->grad, clipped_coords.x1 - bg_coords.x1, h - bg_coords.y1, coords_bg_w, grad);
break;
#endif
}
lv_draw_sw_blend(draw_unit, &blend_dsc);
}
@ -217,6 +307,21 @@ void lv_draw_sw_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
if(grad) {
lv_gradient_cleanup(grad);
}
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
if(grad_dir >= LV_GRAD_DIR_LINEAR) {
switch(grad_dir) {
case LV_GRAD_DIR_LINEAR:
lv_gradient_linear_cleanup(&dsc->grad);
break;
case LV_GRAD_DIR_RADIAL:
lv_gradient_radial_cleanup(&dsc->grad);
break;
case LV_GRAD_DIR_CONICAL:
lv_gradient_conical_cleanup(&dsc->grad);
break;
}
}
#endif
#endif
}

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_draw_sw_gradient.c
*
*/
@ -11,6 +11,7 @@
#include "../../misc/lv_types.h"
#include "../../osal/lv_os.h"
#include "../../misc/lv_math.h"
/*********************
* DEFINES
@ -25,12 +26,61 @@
#define ALIGN(X) (((X) + 3) & ~3)
#endif
/**********************
* TYPEDEFS
**********************/
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
typedef struct {
/* w = (-b(xp, yp) + sqrt(sqr(b(xp, yp)) - 4 * a * c(xp, yp))) / (2 * a) */
int32_t x0; /* center of the start circle */
int32_t y0; /* center of the start circle */
int32_t r0; /* radius of the start circle */
int32_t inv_dr; /* 1 / (r1 - r0) */
int32_t a4; /* 4 * a */
int32_t inv_a4; /* 1 / (4 * a) */
int32_t dx;
/* b(xp, yp) = xp * bpx + yp * bpy + bc */
int32_t bpx;
int32_t bpy;
int32_t bc;
lv_area_t clip_area;
lv_grad_t * cgrad; /*256 element cache buffer containing the gradient color map*/
} lv_grad_radial_state_t;
typedef struct {
/* w = a * xp + b * yp + c */
int32_t a;
int32_t b;
int32_t c;
lv_grad_t * cgrad; /*256 element cache buffer containing the gradient color map*/
} lv_grad_linear_state_t;
typedef struct {
/* w = a * xp + b * yp + c */
int32_t x0;
int32_t y0;
int32_t a;
int32_t da;
int32_t inv_da;
lv_grad_t * cgrad; /*256 element cache buffer containing the gradient color map*/
} lv_grad_conical_state_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
typedef lv_result_t (*op_cache_t)(lv_grad_t * c, void * ctx);
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, int32_t w, int32_t h);
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
static inline int32_t extend_w(int32_t w, lv_grad_extend_t extend);
#endif
/**********************
* STATIC VARIABLE
**********************/
@ -41,7 +91,20 @@ static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, int32_t w, int32_t h);
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, int32_t w, int32_t h)
{
int32_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
int32_t size;
switch(g->dir) {
case LV_GRAD_DIR_HOR:
case LV_GRAD_DIR_LINEAR:
case LV_GRAD_DIR_RADIAL:
case LV_GRAD_DIR_CONICAL:
size = w;
break;
case LV_GRAD_DIR_VER:
size = h;
break;
default:
size = 64;
}
size_t req_size = ALIGN(sizeof(lv_grad_t)) + ALIGN(size * sizeof(lv_color_t)) + ALIGN(size * sizeof(lv_opa_t));
lv_grad_t * item = lv_malloc(req_size);
@ -55,6 +118,25 @@ static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, int32_t w, int32_t h)
return item;
}
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
static inline int32_t extend_w(int32_t w, lv_grad_extend_t extend)
{
if(extend == LV_GRAD_EXTEND_PAD) { /**< Repeat the same color*/
return w < 0 ? 0 : LV_MIN(w, 255);
}
if(extend == LV_GRAD_EXTEND_REPEAT) { /**< Repeat the pattern*/
return w & 255;
}
/*LV_GRAD_EXTEND_REFLECT*/
w &= 511;
if(w > 255)
w ^= 511; /* 511 - w */
return w;
}
#endif
/**********************
* FUNCTIONS
**********************/
@ -137,4 +219,450 @@ void lv_gradient_cleanup(lv_grad_t * grad)
lv_free(grad);
}
void lv_gradient_init_stops(lv_grad_dsc_t * grad, const lv_color_t colors[], const lv_opa_t opa[],
const uint8_t fracs[], int num_stops)
{
LV_ASSERT(num_stops <= LV_GRADIENT_MAX_STOPS);
grad->stops_count = num_stops;
for(int i = 0; i < num_stops; i++) {
grad->stops[i].color = colors[i];
grad->stops[i].opa = opa != NULL ? opa[i] : LV_OPA_COVER;
grad->stops[i].frac = fracs != NULL ? fracs[i] : 255 * i / (num_stops - 1);
}
}
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/*
Calculate radial gradient based on the following equation:
| P - (C1 - C0)w - C0 | = (r1 - r0)w + r0, where
P: {xp, yp} is the point of interest
C0: {x0, y0} is the center of the start circle
C1: {x1, y1} is the center of the end circle
r0 is the radius of the start circle
r1 is the radius of the end circle
w is the unknown variable
|| is the length of the vector
The above equation can be rewritten as:
((r1-r0)^2 - (x1-x0)^2 - (y1-y0)^2) * w^2 + 2*((xp-x0)*(x1-x0) + (yp-y0)*(y1-y0)) * w + (-(xp-x0)^2 - (yp-y0)^) = 0
The roots of the quadratical equation can be obtained using the well-known formula (-b +- sqrt(b^2 - 4ac)) / 2a
We only need the more positive root.
Let's denote
dx = x1 - x0
dy = y1 - y0
dr = r1 - r0
Thus:
w = (-b(xp, yp) + sqrt(sqr(b(xp, yp)) - 4 * a * c(xp, yp))) / (2 * a), where
b(xp, yp) = 2dx * xp + 2dy * yp + 2(r0 * dr - x0 * dx - y0 * dy)
c(xp, yp) = r0^2 - (xp - x0)^2 - (yp - y0)^2
Rewrite b(xp, yp) as:
b(xp, yp) = xp * bpx + yp * bpy + bc, where
bpx = 2dx
bpy = 2dy
bc = 2(r0 * dr - x0 * dx - y0 * dy)
We can pre-calculate the constants, because they do not depend on the pixel coordinates.
*/
void lv_gradient_radial_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords)
{
lv_point_t start = dsc->params.radial.focal;
lv_point_t end = dsc->params.radial.end;
lv_point_t start_extent = dsc->params.radial.focal_extent;
lv_point_t end_extent = dsc->params.radial.end_extent;
lv_grad_radial_state_t * state = lv_malloc(sizeof(lv_grad_radial_state_t));
dsc->state = state;
/* Convert from percentage coordinates */
int32_t wdt = lv_area_get_width(coords);
int32_t hgt = lv_area_get_height(coords);
start.x = lv_pct_to_px(start.x, wdt);
end.x = lv_pct_to_px(end.x, wdt);
start_extent.x = lv_pct_to_px(start_extent.x, wdt);
end_extent.x = lv_pct_to_px(end_extent.x, wdt);
start.y = lv_pct_to_px(start.y, hgt);
end.y = lv_pct_to_px(end.y, hgt);
start_extent.y = lv_pct_to_px(start_extent.y, hgt);
end_extent.y = lv_pct_to_px(end_extent.y, hgt);
/* Calculate radii */
int16_t r_start = lv_sqrt32(lv_sqr(start_extent.x - start.x) + lv_sqr(start_extent.y - start.y));
int16_t r_end = lv_sqrt32(lv_sqr(end_extent.x - end.x) + lv_sqr(end_extent.y - end.y));
LV_ASSERT(r_end != 0);
/* Create gradient color map */
state->cgrad = lv_gradient_get(dsc, 256, 0);
state->x0 = start.x;
state->y0 = start.y;
state->r0 = r_start;
int32_t dr = r_end - r_start;
if(end.x == start.x && end.y == start.y) {
LV_ASSERT(dr != 0);
state->a4 = lv_sqr(dr) << 2;
state->bpx = 0;
state->bpy = 0;
state->bc = (state->r0 * dr) << 1;
state->dx = 0;
state->inv_dr = (1 << (8 + 16)) / dr;
}
else {
int32_t dx = end.x - start.x;
int32_t dy = end.y - start.y;
state->dx = dx; /* needed for incremental calculation */
state->a4 = (lv_sqr(dr) - lv_sqr(dx) - lv_sqr(dy)) << 2;
/* b(xp, yp) = xp * bpx + yp * bpy + bc */
state->bpx = dx << 1;
state->bpy = dy << 1;
state->bc = (state->r0 * dr - state->x0 * dx - state->y0 * dy) << 1;
}
state->inv_a4 = state->a4 != 0 ? (1 << (13 + 16)) / state->a4 : 0;
/* check for possible clipping */
if(dsc->extend == LV_GRAD_EXTEND_PAD &&
/* if extend mode is 'pad', then we can clip to the end circle's bounding box, if the start circle is entirely within the end circle */
(lv_sqr(start.x - end.x) + lv_sqr(start.y - end.y) < lv_sqr(r_end - r_start))) {
if(r_end > r_start) {
lv_area_set(&state->clip_area, end.x - r_end, end.y - r_end, end.x + r_end, end.y + r_end);
}
else {
lv_area_set(&state->clip_area, start.x - r_start, start.y - r_start, start.x + r_start, start.y + r_start);
}
}
else {
state->clip_area.x1 = -0x7fffffff;
}
}
void lv_gradient_radial_cleanup(lv_grad_dsc_t * dsc)
{
lv_grad_radial_state_t * state = dsc->state;
if(state == NULL)
return;
if(state->cgrad)
lv_gradient_cleanup(state->cgrad);
lv_free(state);
}
void LV_ATTRIBUTE_FAST_MEM lv_gradient_radial_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp,
int32_t width, lv_grad_t * result)
{
lv_grad_radial_state_t * state = (lv_grad_radial_state_t *)dsc->state;
lv_color_t * buf = result->color_map;
lv_opa_t * opa = result->opa_map;
lv_grad_t * grad = state->cgrad;
int32_t w; /* the result: this is an offset into the 256 element gradient color table */
int32_t b, db, c, dc;
/* check for possible clipping */
if(state->clip_area.x1 != -0x7fffffff) {
/* fill line with end color for pixels outside the clipped region */
lv_color_t * _buf = buf;
lv_opa_t * _opa = opa;
lv_color_t _c = grad->color_map[255];
lv_opa_t _o = grad->opa_map[255];
int32_t _w = width;
for(; _w > 0; _w--) {
*_buf++ = _c;
*_opa++ = _o;
}
/* is this line fully outside the clip area? */
if(yp < state->clip_area.y1 ||
yp >= state->clip_area.y2 ||
xp >= state->clip_area.x2 ||
xp + width < state->clip_area.x1) {
return;
}
else { /* not fully outside: clip line to the bounding box */
int32_t _x1 = LV_MAX(xp, state->clip_area.x1);
int32_t _x2 = LV_MIN(xp + width, state->clip_area.x2);
buf += _x1 - xp;
opa += _x1 - xp;
xp = _x1;
width = _x2 - _x1;
}
}
b = xp * state->bpx + yp * state->bpy + state->bc;
c = lv_sqr(state->r0) - lv_sqr(xp - state->x0) - lv_sqr(yp - state->y0);
/* We can save some calculations by using the previous values of b and c */
db = state->dx << 1;
dc = ((xp - state->x0) << 1) + 1;
if(state->a4 == 0) { /* not a quadratic equation: solve linear equation: w = -c/b */
for(; width > 0; width--) {
w = extend_w(b == 0 ? 0 : -(c << 8) / b, dsc->extend);
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
b += db;
c -= dc;
dc += 2;
}
}
else { /* solve quadratical equation */
if(state->bpx ||
state->bpy) { /* general case (circles are not concentric): w = (-b + sqrt(b^2 - 4ac))/2a (we only need the more positive root)*/
int32_t a4 = state->a4 >> 4;
for(; width > 0; width--) {
int32_t det = lv_sqr(b >> 4) - (a4 * (c >> 4)); /* b^2 shifted down by 2*4=8, 4ac shifted down by 8 */
/* check determinant: if negative, then there is no solution: use starting color */
w = det < 0 ? 0 : extend_w(((lv_sqrt32(det) - (b >> 4)) * state->inv_a4) >> 16,
dsc->extend); /* square root shifted down by 4 (includes *256 to set output range) */
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
b += db;
c -= dc;
dc += 2;
}
}
else { /* special case: concentric circles: w = (sqrt((xp-x0)^2 + (yx-y0)^2)-r0)/(r1-r0) */
c = lv_sqr(xp - state->x0) + lv_sqr(yp - state->y0);
for(; width > 0; width--) {
w = extend_w((((lv_sqrt32(c) - state->r0)) * state->inv_dr) >> 16, dsc->extend);
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
c += dc;
dc += 2;
}
}
}
}
/*
Calculate linear gradient based on the following equation:
w = ((P - C0) x (C1 - C0)) / | C1 - C0 |^2, where
P: {xp, yp} is the point of interest
C0: {x0, y0} is the start point of the gradient vector
C1: {x1, y1} is the end point of the gradient vector
w is the unknown variable
|| is the length of the vector
x is a dot product
The above equation can be rewritten as:
w = xp * (dx / (dx^2 + dy^2)) + yp * (dy / (dx^2 + dy^2)) - (x0 * dx + y0 * dy) / (dx^2 + dy^2), where
dx = x1 - x0
dy = y1 - y0
We can pre-calculate the constants, because they do not depend on the pixel coordinates.
*/
void lv_gradient_linear_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords)
{
lv_point_t start = dsc->params.linear.start;
lv_point_t end = dsc->params.linear.end;
lv_grad_linear_state_t * state = lv_malloc(sizeof(lv_grad_linear_state_t));
dsc->state = state;
/* Create gradient color map */
state->cgrad = lv_gradient_get(dsc, 256, 0);
/* Convert from percentage coordinates */
int32_t wdt = lv_area_get_width(coords);
int32_t hgt = lv_area_get_height(coords);
start.x = lv_pct_to_px(start.x, wdt);
end.x = lv_pct_to_px(end.x, wdt);
start.y = lv_pct_to_px(start.y, hgt);
end.y = lv_pct_to_px(end.y, hgt);
/* Precalculate constants */
int32_t dx = end.x - start.x;
int32_t dy = end.y - start.y;
int32_t l2 = lv_sqr(dx) + lv_sqr(dy);
state->a = (dx << 16) / l2;
state->b = (dy << 16) / l2;
state->c = ((start.x * dx + start.y * dy) << 16) / l2;
}
void lv_gradient_linear_cleanup(lv_grad_dsc_t * dsc)
{
lv_grad_linear_state_t * state = dsc->state;
if(state == NULL)
return;
if(state->cgrad)
lv_free(state->cgrad);
lv_free(state);
}
void LV_ATTRIBUTE_FAST_MEM lv_gradient_linear_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp,
int32_t width, lv_grad_t * result)
{
lv_grad_linear_state_t * state = (lv_grad_linear_state_t *)dsc->state;
lv_color_t * buf = result->color_map;
lv_opa_t * opa = result->opa_map;
lv_grad_t * grad = state->cgrad;
int32_t w; /* the result: this is an offset into the 256 element gradient color table */
int32_t x, d;
x = xp * state->a + yp * state->b - state->c;
d = state->a;
for(; width > 0; width--) {
w = extend_w(x >> 8, dsc->extend);
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
x += d;
}
}
/*
Calculate conical gradient based on the following equation:
w = (atan((yp - y0)/(xp - x0)) - alpha) / (beta - alpha), where
P: {xp, yp} is the point of interest
C0: {x0, y0} is the center of the gradient
alpha is the start angle
beta is the end angle
w is the unknown variable
*/
void lv_gradient_conical_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords)
{
lv_point_t c0 = dsc->params.conical.center;
int32_t alpha = dsc->params.conical.start_angle % 360;
int32_t beta = dsc->params.conical.end_angle % 360;
lv_grad_conical_state_t * state = lv_malloc(sizeof(lv_grad_conical_state_t));
dsc->state = state;
/* Create gradient color map */
state->cgrad = lv_gradient_get(dsc, 256, 0);
/* Convert from percentage coordinates */
int32_t wdt = lv_area_get_width(coords);
int32_t hgt = lv_area_get_height(coords);
c0.x = lv_pct_to_px(c0.x, wdt);
c0.y = lv_pct_to_px(c0.y, hgt);
/* Precalculate constants */
if(beta <= alpha)
beta += 360;
state->x0 = c0.x;
state->y0 = c0.y;
state->a = alpha;
state->da = beta - alpha;
state->inv_da = (1 << 16) / (beta - alpha);
}
void lv_gradient_conical_cleanup(lv_grad_dsc_t * dsc)
{
lv_grad_conical_state_t * state = dsc->state;
if(state == NULL)
return;
if(state->cgrad)
lv_free(state->cgrad);
lv_free(state);
}
void LV_ATTRIBUTE_FAST_MEM lv_gradient_conical_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp,
int32_t width, lv_grad_t * result)
{
lv_grad_conical_state_t * state = (lv_grad_conical_state_t *)dsc->state;
lv_color_t * buf = result->color_map;
lv_opa_t * opa = result->opa_map;
lv_grad_t * grad = state->cgrad;
int32_t w; /* the result: this is an offset into the 256 element gradient color table */
int32_t dx = xp - state->x0;
int32_t dy = yp - state->y0;
if(dy == 0) { /* we will eventually go through the center of the conical: need an extra test in the loop to avoid both dx and dy being zero in atan2 */
for(; width > 0; width--) {
if(dx == 0) {
w = 0;
}
else {
int32_t d = lv_atan2(dy, dx) - state->a;
if(d < 0)
d += 360;
w = extend_w((d * state->inv_da) >> 8, dsc->extend);
}
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
dx++;
}
}
else {
for(; width > 0; width--) {
int32_t d = lv_atan2(dy, dx) - state->a;
if(d < 0)
d += 360;
w = extend_w((d * state->inv_da) >> 8, dsc->extend);
*buf++ = grad->color_map[w];
*opa++ = grad->opa_map[w];
dx++;
}
}
}
void lv_grad_linear_init(lv_grad_dsc_t * dsc, int32_t from_x, int32_t from_y, int32_t to_x, int32_t to_y,
lv_grad_extend_t extend)
{
dsc->dir = LV_GRAD_DIR_LINEAR;
dsc->params.linear.start.x = from_x;
dsc->params.linear.start.y = from_y;
dsc->params.linear.end.x = to_x;
dsc->params.linear.end.y = to_y;
dsc->extend = extend;
}
void lv_grad_radial_init(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t to_x, int32_t to_y,
lv_grad_extend_t extend)
{
dsc->dir = LV_GRAD_DIR_RADIAL;
dsc->params.radial.focal.x = center_x;
dsc->params.radial.focal.y = center_y;
dsc->params.radial.focal_extent.x = center_x;
dsc->params.radial.focal_extent.y = center_y;
dsc->params.radial.end.x = center_x;
dsc->params.radial.end.y = center_y;
dsc->params.radial.end_extent.x = to_x;
dsc->params.radial.end_extent.y = to_y;
dsc->extend = extend;
}
void lv_grad_conical_init(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t start_angle,
int32_t end_angle, lv_grad_extend_t extend)
{
dsc->dir = LV_GRAD_DIR_CONICAL;
dsc->params.conical.center.x = center_x;
dsc->params.conical.center.y = center_y;
dsc->params.conical.start_angle = start_angle;
dsc->params.conical.end_angle = end_angle;
dsc->extend = extend;
}
void lv_grad_radial_set_focal(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t radius)
{
dsc->params.radial.focal.x = center_x;
dsc->params.radial.focal.y = center_y;
dsc->params.radial.focal_extent.x = center_x + radius;
dsc->params.radial.focal_extent.y = center_y;
}
#endif /* LV_USE_DRAW_SW_COMPLEX_GRADIENTS */
#endif /*LV_USE_DRAW_SW*/

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_draw_sw_gradient.h
*
*/
@ -25,6 +25,12 @@ extern "C" {
#error LVGL needs at least 2 stops for gradients. Please increase the LV_GRADIENT_MAX_STOPS
#endif
#define LV_GRAD_LEFT LV_PCT(0)
#define LV_GRAD_RIGHT LV_PCT(100)
#define LV_GRAD_TOP LV_PCT(0)
#define LV_GRAD_BOTTOM LV_PCT(100)
#define LV_GRAD_CENTER LV_PCT(50)
/**********************
* TYPEDEFS
**********************/
@ -58,6 +64,140 @@ lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * gradient, int32_t w, int32_t h
*/
void lv_gradient_cleanup(lv_grad_t * grad);
/**
* Initialize gradient color map from a table
* @param grad pointer to a gradient descriptor
* @param colors color array
* @param fracs position array (0..255): if NULL, then colors are distributed evenly
* @param opa opacity array: if NULL, then LV_OPA_COVER is assumed
* @param num_stops number of gradient stops (1..LV_GRADIENT_MAX_STOPS)
*/
void lv_gradient_init_stops(lv_grad_dsc_t * grad, const lv_color_t colors[], const lv_opa_t opa[],
const uint8_t fracs[], int num_stops);
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
/**
* Helper function to initialize linear gradient
* @param dsc gradient descriptor
* @param from_x start x position: can be a coordinate or an lv_pct() value
* predefined constants LV_GRAD_LEFT, LV_GRAD_RIGHT, LV_GRAD_TOP, LV_GRAD_BOTTOM, LV_GRAD_CENTER can be used as well
* @param from_y start y position
* @param to_x end x position
* @param to_y end y position
* @param extend one of LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT or LV_GRAD_EXTEND_REFLECT
*/
void lv_grad_linear_init(lv_grad_dsc_t * dsc, int32_t from_x, int32_t from_y, int32_t to_x, int32_t to_y,
lv_grad_extend_t extend);
/**
* Helper function to initialize radial gradient
* @param dsc gradient descriptor
* @param center_x center x position: can be a coordinate or an lv_pct() value
* predefined constants LV_GRAD_LEFT, LV_GRAD_RIGHT, LV_GRAD_TOP, LV_GRAD_BOTTOM, LV_GRAD_CENTER can be used as well
* @param center_y center y position
* @param to_x point on the end circle x position
* @param to_y point on the end circle y position
* @param extend one of LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT or LV_GRAD_EXTEND_REFLECT
*/
void lv_grad_radial_init(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t to_x, int32_t to_y,
lv_grad_extend_t extend);
/**
* Set focal (starting) circle of a radial gradient
* @param dsc gradient descriptor
* @param center_x center x position: can be a coordinate or an lv_pct() value
* predefined constants LV_GRAD_LEFT, LV_GRAD_RIGHT, LV_GRAD_TOP, LV_GRAD_BOTTOM, LV_GRAD_CENTER can be used as well
* @param center_y center y position
* @param radius radius of the starting circle (NOTE: this must be a scalar number, not percentage)
*/
void lv_grad_radial_set_focal(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t radius);
/**
* Helper function to initialize conical gradient
* @param dsc gradient descriptor
* @param center_x center x position: can be a coordinate or an lv_pct() value
* predefined constants LV_GRAD_LEFT, LV_GRAD_RIGHT, LV_GRAD_TOP, LV_GRAD_BOTTOM, LV_GRAD_CENTER can be used as well
* @param center_y center y position
* @param start_angle start angle in degrees
* @param end_angle end angle in degrees
* @param extend one of LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT or LV_GRAD_EXTEND_REFLECT
*/
void lv_grad_conical_init(lv_grad_dsc_t * dsc, int32_t center_x, int32_t center_y, int32_t start_angle,
int32_t end_angle, lv_grad_extend_t extend);
/**
* Calculate constants from the given parameters that are used during rendering
* @param dsc gradient descriptor
*/
void lv_gradient_linear_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords);
/**
* Free up the allocated memory for the gradient calculation
* @param dsc gradient descriptor
*/
void lv_gradient_linear_cleanup(lv_grad_dsc_t * dsc);
/**
* Calculate a line segment of a linear gradient
* @param dsc gradient descriptor
* @param xp starting point x coordinate in gradient space
* @param yp starting point y coordinate in gradient space
* @param width width of the line segment in pixels
* @param result color buffer for the resulting line segment
*/
void /* LV_ATTRIBUTE_FAST_MEM */ lv_gradient_linear_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp, int32_t width,
lv_grad_t * result);
/**
* Calculate constants from the given parameters that are used during rendering
* @param dsc gradient descriptor
*/
void lv_gradient_radial_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords);
/**
* Free up the allocated memory for the gradient calculation
* @param dsc gradient descriptor
*/
void lv_gradient_radial_cleanup(lv_grad_dsc_t * dsc);
/**
* Calculate a line segment of a radial gradient
* @param dsc gradient descriptor
* @param xp starting point x coordinate in gradient space
* @param yp starting point y coordinate in gradient space
* @param width width of the line segment in pixels
* @param result color buffer for the resulting line segment
*/
void /* LV_ATTRIBUTE_FAST_MEM */ lv_gradient_radial_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp, int32_t width,
lv_grad_t * result);
/**
* Calculate constants from the given parameters that are used during rendering
* @param dsc gradient descriptor
*/
void lv_gradient_conical_setup(lv_grad_dsc_t * dsc, const lv_area_t * coords);
/**
* Free up the allocated memory for the gradient calculation
* @param dsc gradient descriptor
*/
void lv_gradient_conical_cleanup(lv_grad_dsc_t * dsc);
/**
* Calculate a line segment of a conical gradient
* @param dsc gradient descriptor
* @param xp starting point x coordinate in gradient space
* @param yp starting point y coordinate in gradient space
* @param width width of the line segment in pixels
* @param result color buffer for the resulting line segment
*/
void /* LV_ATTRIBUTE_FAST_MEM */ lv_gradient_conical_get_line(lv_grad_dsc_t * dsc, int32_t xp, int32_t yp,
int32_t width,
lv_grad_t * result);
#endif /*LV_USE_DRAW_SW_COMPLEX_GRADIENTS*/
#endif /*LV_USE_DRAW_SW*/
#ifdef __cplusplus

View File

@ -419,6 +419,15 @@
#endif
#endif
#endif
/* Enable drawing complex gradients in software: linear at an angle, radial or conical */
#ifndef LV_USE_DRAW_SW_COMPLEX_GRADIENTS
#ifdef CONFIG_LV_USE_DRAW_SW_COMPLEX_GRADIENTS
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS CONFIG_LV_USE_DRAW_SW_COMPLEX_GRADIENTS
#else
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0
#endif
#endif
#endif
/* Use NXP's VG-Lite GPU on iMX RTxxx platforms. */

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_math.c
*
*/
@ -222,6 +222,95 @@ void LV_ATTRIBUTE_FAST_MEM lv_sqrt(uint32_t x, lv_sqrt_res_t * q, uint32_t mask)
q->f = (root & 0xf) << 4;
}
/*
// Alternative Integer Square Root function
// Contributors include Arne Steinarson for the basic approximation idea,
// Dann Corbit and Mathew Hendry for the first cut at the algorithm,
// Lawrence Kirby for the rearrangement, improvments and range optimization
// and Paul Hsieh for the round-then-adjust idea.
*/
int32_t LV_ATTRIBUTE_FAST_MEM lv_sqrt32(uint32_t x)
{
static const unsigned char sqq_table[] = {
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102,
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132,
133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145,
146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157,
158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178,
179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188,
189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197,
198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206,
207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215,
215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223,
224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231,
231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246,
246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253,
253, 254, 254, 255
};
int32_t xn;
if(x >= 0x10000)
if(x >= 0x1000000)
if(x >= 0x10000000)
if(x >= 0x40000000) {
if(x >= 65535UL * 65535UL)
return 65535;
xn = sqq_table[x >> 24] << 8;
}
else
xn = sqq_table[x >> 22] << 7;
else if(x >= 0x4000000)
xn = sqq_table[x >> 20] << 6;
else
xn = sqq_table[x >> 18] << 5;
else {
if(x >= 0x100000)
if(x >= 0x400000)
xn = sqq_table[x >> 16] << 4;
else
xn = sqq_table[x >> 14] << 3;
else if(x >= 0x40000)
xn = sqq_table[x >> 12] << 2;
else
xn = sqq_table[x >> 10] << 1;
goto nr1;
}
else if(x >= 0x100) {
if(x >= 0x1000)
if(x >= 0x4000)
xn = (sqq_table[x >> 8] >> 0) + 1;
else
xn = (sqq_table[x >> 6] >> 1) + 1;
else if(x >= 0x400)
xn = (sqq_table[x >> 4] >> 2) + 1;
else
xn = (sqq_table[x >> 2] >> 3) + 1;
goto adj;
}
else
return sqq_table[x] >> 4;
/* Run two iterations of the standard convergence formula */
xn = (xn + 1 + x / xn) / 2;
nr1:
xn = (xn + 1 + x / xn) / 2;
adj:
if(xn * xn > x) /* Correct rounding if necessary */
xn--;
return xn;
}
uint16_t lv_atan2(int x, int y)
{
/**

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_math.h
*
*/
@ -111,6 +111,22 @@ void /* LV_ATTRIBUTE_FAST_MEM */ lv_sqrt(uint32_t x, lv_sqrt_res_t * q, uint32_t
//! @endcond
/**
* Alternative (fast, approximate) implementation for getting the square root of an integer.
* @param x integer which square root should be calculated
*/
int32_t /* LV_ATTRIBUTE_FAST_MEM */ lv_sqrt32(uint32_t x);
/**
* Calculate the square of an integer (input range is 0..32767).
* @param x input
* @return square
*/
static inline int32_t lv_sqr(int32_t x)
{
return x * x;
}
/**
* Calculate the integer exponents.
* @param base

View File

@ -1,4 +1,4 @@
/**
/**
* @file lv_style.h
*
*/
@ -130,15 +130,31 @@ typedef uint8_t lv_border_side_t;
* The direction of the gradient.
*/
enum _lv_grad_dir_t {
LV_GRAD_DIR_NONE, /**< No gradient (the `grad_color` property is ignored)*/
LV_GRAD_DIR_VER, /**< Vertical (top to bottom) gradient*/
LV_GRAD_DIR_HOR, /**< Horizontal (left to right) gradient*/
LV_GRAD_DIR_NONE, /**< No gradient (the `grad_color` property is ignored)*/
LV_GRAD_DIR_VER, /**< Simple vertical (top to bottom) gradient*/
LV_GRAD_DIR_HOR, /**< Simple horizontal (left to right) gradient*/
LV_GRAD_DIR_LINEAR, /**< Linear gradient defined by start and end points. Can be at any angle.*/
LV_GRAD_DIR_RADIAL, /**< Radial gradient defined by start and end circles*/
LV_GRAD_DIR_CONICAL, /**< Conical gradient defined by center point, start and end angles*/
};
/**
* Gradient behavior outside the defined range.
*/
enum _lv_grad_extend_t {
LV_GRAD_EXTEND_PAD, /**< Repeat the same color*/
LV_GRAD_EXTEND_REPEAT, /**< Repeat the pattern*/
LV_GRAD_EXTEND_REFLECT, /**< Repeat the pattern mirrored*/
};
#ifdef DOXYGEN
typedef _lv_grad_dir_t lv_grad_dir_t;
typedef _lv_grad_type_t lv_grad_type_t;
typedef _lv_grad_extend_t lv_grad_extend_t;
#else
typedef uint8_t lv_grad_dir_t;
typedef uint8_t lv_grad_type_t;
typedef uint8_t lv_grad_extend_t;
#endif /*DOXYGEN*/
/** A gradient stop definition.
@ -152,10 +168,37 @@ typedef struct {
/** A descriptor of a gradient. */
typedef struct {
lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */
uint8_t stops_count; /**< The number of used stops in the array */
lv_grad_dir_t dir : 3; /**< The gradient direction.
* Any of LV_GRAD_DIR_HOR, LV_GRAD_DIR_VER, LV_GRAD_DIR_NONE */
lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */
uint8_t stops_count; /**< The number of used stops in the array */
lv_grad_dir_t dir : 3; /**< The gradient direction.
* Any of LV_GRAD_DIR_NONE, LV_GRAD_DIR_VER, LV_GRAD_DIR_HOR,
LV_GRAD_TYPE_LINEAR, LV_GRAD_TYPE_RADIAL, LV_GRAD_TYPE_CONICAL */
lv_grad_extend_t extend : 2; /**< Behaviour outside the defined range.
* LV_GRAD_EXTEND_NONE, LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT, LV_GRAD_EXTEND_REFLECT */
#if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
union {
/*Linear gradient parameters*/
struct {
lv_point_t start; /**< Linear gradient vector start point */
lv_point_t end; /**< Linear gradient vector end point */
} linear;
/*Radial gradient parameters*/
struct {
lv_point_t focal; /**< Center of the focal (starting) circle in local coordinates */
/* (can be the same as the ending circle to create concentric circles) */
lv_point_t focal_extent; /**< Point on the circle (can be the same as the center) */
lv_point_t end; /**< Center of the ending circle in local coordinates */
lv_point_t end_extent; /**< Point on the circle determining the radius of the gradient */
} radial;
/*Conical gradient parameters*/
struct {
lv_point_t center; /**< Conical gradient center point */
int16_t start_angle; /**< Start angle 0..3600 */
int16_t end_angle; /**< End angle 0..3600 */
} conical;
} params;
void * state;
#endif
} lv_grad_dsc_t;
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -138,3 +138,5 @@
#define LV_USE_FREETYPE 1
#define LV_FREETYPE_USE_LVGL_PORT 0
#define LV_FREETYPE_CACHE_FT_GLYPH_CNT 10
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 1