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>
8
Kconfig
@ -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
|
||||
|
@ -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}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
73
examples/styles/lv_example_style_16.c
Normal 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*/
|
42
examples/styles/lv_example_style_17.c
Normal 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*/
|
88
examples/styles/lv_example_style_18.c
Normal 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*/
|
@ -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. */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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*/
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
{
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 28 KiB |
BIN
tests/ref_imgs/draw/render/argb8888/demo_render__opa_255.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 28 KiB |
BIN
tests/ref_imgs/draw/render/rgb565/demo_render__opa_255.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 29 KiB |
BIN
tests/ref_imgs/draw/render/rgb888/demo_render__opa_255.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 34 KiB |
BIN
tests/ref_imgs/draw/render/xrgb8888/demo_render__opa_255.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 34 KiB |
@ -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
|
||||
|