mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-21 06:53:01 +08:00
add real draw functions
This commit is contained in:
parent
82e3ee3e76
commit
1b5b2bfb4f
@ -126,7 +126,7 @@ void lv_style_init(void)
|
||||
lv_style_pretty.text.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.image.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.line.color = lv_color_make(0x20, 0x20, 0x20);
|
||||
lv_style_pretty.body.main_color = LV_COLOR_RED;
|
||||
lv_style_pretty.body.main_color = LV_COLOR_WHITE;
|
||||
lv_style_pretty.body.grad_color = LV_COLOR_SILVER;
|
||||
lv_style_pretty.body.radius = LV_DPI / 15;
|
||||
lv_style_pretty.body.border.color = lv_color_make(0x40, 0x40, 0x40);
|
||||
|
79
src/lv_draw/lv_blend.c
Normal file
79
src/lv_draw/lv_blend.c
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file lv_blend.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_blend.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_blend_color(lv_color_t * dest_buf, lv_img_cf_t dest_cf, lv_coord_t len,
|
||||
lv_color_t color, lv_img_cf_t src_cf,
|
||||
lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode)
|
||||
{
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(mask_res == LV_MASK_RES_FULL_TRANSP) return;
|
||||
|
||||
lv_coord_t i;
|
||||
if(dest_cf == LV_IMG_CF_TRUE_COLOR && src_cf == LV_IMG_CF_TRUE_COLOR) {
|
||||
/*Simple fill (maybe with opacity), no masking*/
|
||||
if(mask_res == LV_MASK_RES_FULL_COVER) {
|
||||
if(opa > LV_OPA_MAX) {
|
||||
for(i = 0; i < len; i++) {
|
||||
dest_buf[i].full = color.full;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(i = 0; i < len; i++) {
|
||||
dest_buf[i] = lv_color_mix(color, dest_buf[i], opa);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Masked*/
|
||||
else {
|
||||
/*Only the mask matters*/
|
||||
if(opa > LV_OPA_MAX) {
|
||||
for(i = 0; i < len; i++) {
|
||||
dest_buf[i] = lv_color_mix(color, dest_buf[i], mask[i]);
|
||||
}
|
||||
} else {
|
||||
for(i = 0; i < len; i++) {
|
||||
if(mask[i] > LV_OPA_MAX) {
|
||||
dest_buf[i] = lv_color_mix(color, dest_buf[i], opa);
|
||||
} else {
|
||||
dest_buf[i] = lv_color_mix(color, dest_buf[i], (mask[i] * opa) >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
@ -15,6 +15,8 @@ extern "C" {
|
||||
*********************/
|
||||
#include "../lv_misc/lv_color.h"
|
||||
#include "../lv_misc/lv_area.h"
|
||||
#include "lv_img_decoder.h"
|
||||
#include "lv_mask.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -26,12 +28,15 @@ extern "C" {
|
||||
typedef enum {
|
||||
LV_BLIT_MODE_NORMAL,
|
||||
LV_BLIT_MODE_ADDITIVE,
|
||||
}lv_blit_mode_t;
|
||||
}lv_blend_mode_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_blit_color(lv_color_t * dest_buf, lv_color_t * bg_buf, lv_coord_t len, lv_color_t color, lv_blit_mode_t mode);
|
||||
|
||||
void lv_blend_color(lv_color_t * dest_buf, lv_img_cf_t dest_cf, lv_coord_t len,
|
||||
lv_color_t color, lv_img_cf_t src_cf,
|
||||
lv_opa_t * mask, lv_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* @file lv_blit.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_blit.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_blit_color(lv_color_t * dest_buf, lv_color_t * bg_buf, lv_coord_t len, lv_color_t color, lv_blit_mode_t mode)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
dest_buf[i].full = color.full;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
@ -9,6 +9,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw.h"
|
||||
#include "lv_mask.h"
|
||||
#include "lv_blend.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
@ -20,111 +22,16 @@
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/*
|
||||
* 8192
|
||||
8193
|
||||
8196
|
||||
8201
|
||||
8208
|
||||
8217
|
||||
8228
|
||||
8241
|
||||
8256
|
||||
8273
|
||||
8291
|
||||
8312
|
||||
8335
|
||||
8359
|
||||
8386
|
||||
8414
|
||||
8444
|
||||
8476
|
||||
8510
|
||||
8545
|
||||
8583
|
||||
8622
|
||||
8662
|
||||
8705
|
||||
8749
|
||||
8795
|
||||
8842
|
||||
8891
|
||||
8942
|
||||
8994
|
||||
9047
|
||||
9102
|
||||
9159
|
||||
9217
|
||||
9276
|
||||
9337
|
||||
9399
|
||||
9462
|
||||
9527
|
||||
9593
|
||||
9660
|
||||
9729
|
||||
9798
|
||||
9869
|
||||
9941
|
||||
10014
|
||||
10088
|
||||
10164
|
||||
10240
|
||||
10317
|
||||
10396
|
||||
10475
|
||||
10555
|
||||
10636
|
||||
10718
|
||||
10801
|
||||
10885
|
||||
10970
|
||||
11056
|
||||
11142
|
||||
11229
|
||||
11317
|
||||
11406
|
||||
11495
|
||||
11585
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
lv_point_t p_act;
|
||||
lv_coord_t dx;
|
||||
lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/
|
||||
lv_coord_t dy;
|
||||
lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/
|
||||
lv_coord_t err;
|
||||
lv_coord_t e2;
|
||||
bool hor; /*Rather horizontal or vertical*/
|
||||
} line_draw_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_coord_t width;
|
||||
lv_coord_t width_1;
|
||||
lv_coord_t width_half;
|
||||
} line_width_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_opa_t opa_scale);
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_opa_t opa_scale);
|
||||
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_opa_t opa_scale);
|
||||
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);
|
||||
static bool line_next(line_draw_t * line);
|
||||
static bool line_next_y(line_draw_t * line);
|
||||
static bool line_next_x(line_draw_t * line);
|
||||
static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale);
|
||||
static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale);
|
||||
static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale);
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -146,563 +53,285 @@ static bool line_next_x(line_draw_t * line);
|
||||
* @param style pointer to a line's style
|
||||
* @param opa_scale scale down all opacities by the factor
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
|
||||
if(style->line.width == 0) return;
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
/*Return if the points are out of the mask*/
|
||||
if(point1->x < mask->x1 - style->line.width && point2->x < mask->x1 - style->line.width) return;
|
||||
if(point1->x > mask->x2 + style->line.width && point2->x > mask->x2 + style->line.width) return;
|
||||
if(point1->y < mask->y1 - style->line.width && point2->y < mask->y1 - style->line.width) return;
|
||||
if(point1->y > mask->y2 + style->line.width && point2->y > mask->y2 + style->line.width) return;
|
||||
|
||||
line_draw_t main_line;
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
|
||||
/*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/
|
||||
|
||||
if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {
|
||||
|
||||
/*Steps less in y then x -> rather horizontal*/
|
||||
if(point1->x < point2->x) {
|
||||
p1.x = point1->x;
|
||||
p1.y = point1->y;
|
||||
p2.x = point2->x;
|
||||
p2.y = point2->y;
|
||||
} else {
|
||||
p1.x = point2->x;
|
||||
p1.y = point2->y;
|
||||
p2.x = point1->x;
|
||||
p2.y = point1->y;
|
||||
}
|
||||
} else {
|
||||
/*Steps less in x then y -> rather vertical*/
|
||||
if(point1->y < point2->y) {
|
||||
p1.x = point1->x;
|
||||
p1.y = point1->y;
|
||||
p2.x = point2->x;
|
||||
p2.y = point2->y;
|
||||
} else {
|
||||
p1.x = point2->x;
|
||||
p1.y = point2->y;
|
||||
p2.x = point1->x;
|
||||
p2.y = point1->y;
|
||||
}
|
||||
}
|
||||
|
||||
line_init(&main_line, &p1, &p2);
|
||||
|
||||
/*Special case draw a horizontal line*/
|
||||
if(main_line.p1.y == main_line.p2.y) {
|
||||
line_draw_hor(&main_line, mask, style, opa_scale);
|
||||
}
|
||||
/*Special case draw a vertical line*/
|
||||
else if(main_line.p1.x == main_line.p2.x) {
|
||||
line_draw_ver(&main_line, mask, style, opa_scale);
|
||||
}
|
||||
/*Arbitrary skew line*/
|
||||
else {
|
||||
bool dir_ori = false;
|
||||
#if LV_ANTIALIAS
|
||||
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
|
||||
if(aa) {
|
||||
lv_point_t p_tmp;
|
||||
|
||||
if(main_line.hor) {
|
||||
if(main_line.p1.y < main_line.p2.y) {
|
||||
dir_ori = true;
|
||||
p_tmp.x = main_line.p2.x;
|
||||
p_tmp.y = main_line.p2.y - 1;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
|
||||
} else if(main_line.p1.y > main_line.p2.y) {
|
||||
dir_ori = false;
|
||||
p_tmp.x = main_line.p2.x;
|
||||
p_tmp.y = main_line.p2.y + 1;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
|
||||
}
|
||||
} else {
|
||||
if(main_line.p1.x < main_line.p2.x) {
|
||||
dir_ori = true;
|
||||
p_tmp.x = main_line.p2.x - 1;
|
||||
p_tmp.y = main_line.p2.y;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
|
||||
} else if(main_line.p1.x > main_line.p2.x) {
|
||||
dir_ori = false;
|
||||
p_tmp.x = main_line.p2.x + 1;
|
||||
p_tmp.y = main_line.p2.y;
|
||||
line_init(&main_line, &p1, &p_tmp);
|
||||
main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);
|
||||
}
|
||||
if(point1->y == point2->y) draw_line_hor(point1, point2, clip, style, opa_scale);
|
||||
else if(point1->x == point2->x) draw_line_ver(point1, point2, clip, style, opa_scale);
|
||||
else draw_line_skew(point1, point2, clip, style, opa_scale);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
|
||||
lv_opa_t opa = style->body.opa;
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = main_line->p1.x;
|
||||
act_area.x2 = main_line->p2.x;
|
||||
act_area.y1 = main_line->p1.y - width_half - width_1;
|
||||
act_area.y2 = main_line->p2.y + width_half;
|
||||
/*Keep the great y in p1*/
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
if(point1->y < point2->y) {
|
||||
p1.y = point1->y;
|
||||
p2.y = point2->y;
|
||||
p1.x = point1->x;
|
||||
p2.x = point2->x;
|
||||
} else {
|
||||
p1.y = point2->y;
|
||||
p2.y = point1->y;
|
||||
p1.x = point2->x;
|
||||
p2.x = point1->x;
|
||||
}
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
|
||||
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
|
||||
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
|
||||
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
lv_coord_t xdiff = p2.x - p1.x;
|
||||
lv_coord_t ydiff = p2.y - p1.y;
|
||||
|
||||
lv_coord_t w = style->line.width - 1;
|
||||
lv_coord_t w_half0 = w >> 1;
|
||||
lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
lv_area_t draw_a;
|
||||
draw_a.x1 = LV_MATH_MIN(p1.x, p2.x);
|
||||
draw_a.x2 = LV_MATH_MAX(p1.x, p2.x);
|
||||
draw_a.y1 = LV_MATH_MIN(p1.y, p2.y) - w_half1;
|
||||
draw_a.y2 = LV_MATH_MAX(p1.y, p2.y) + w_half0;
|
||||
|
||||
/* Get the union of `coords` and `clip`*/
|
||||
/* `clip` is already truncated to the `vdb` size
|
||||
* in 'lv_refr_area' function */
|
||||
bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip);
|
||||
|
||||
/*If there are common part of `clip` and `vdb` then draw*/
|
||||
if(union_ok == false) return;
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
/*Store the coordinates of the `draw_a` relative to the VDB */
|
||||
lv_area_t draw_rel_a;
|
||||
draw_rel_a.x1 = draw_a.x1 - vdb->area.x1;
|
||||
draw_rel_a.y1 = draw_a.y1 - vdb->area.y1;
|
||||
draw_rel_a.x2 = draw_a.x2 - vdb->area.x1;
|
||||
draw_rel_a.y2 = draw_a.y2 - vdb->area.y1;
|
||||
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
uint32_t draw_a_width = lv_area_get_width(&draw_rel_a);
|
||||
|
||||
/*Move the vdb_buf_tmp to the first row*/
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += vdb_width * draw_rel_a.y1;
|
||||
|
||||
lv_opa_t mask_buf[LV_HOR_RES_MAX];
|
||||
|
||||
/*Draw line by line*/
|
||||
lv_coord_t h;
|
||||
lv_mask_res_t mask_res;
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
memset(mask_buf, LV_OPA_COVER, draw_a_width);
|
||||
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width);
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
style->line.color, LV_IMG_CF_TRUE_COLOR,
|
||||
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
|
||||
|
||||
static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
|
||||
lv_opa_t opa = style->body.opa;
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = main_line->p1.x - width_half;
|
||||
act_area.x2 = main_line->p2.x + width_half + width_1;
|
||||
act_area.y1 = main_line->p1.y;
|
||||
act_area.y2 = main_line->p2.y;
|
||||
/*Keep the great y in p1*/
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
if(point1->y < point2->y) {
|
||||
p1.y = point1->y;
|
||||
p2.y = point2->y;
|
||||
p1.x = point1->x;
|
||||
p2.x = point2->x;
|
||||
} else {
|
||||
p1.y = point2->y;
|
||||
p2.y = point1->y;
|
||||
p1.x = point2->x;
|
||||
p2.x = point1->x;
|
||||
}
|
||||
|
||||
lv_area_t draw_area;
|
||||
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
|
||||
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
|
||||
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
|
||||
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
lv_coord_t w = style->line.width - 1;
|
||||
lv_coord_t w_half0 = w >> 1;
|
||||
lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
lv_area_t draw_a;
|
||||
draw_a.x1 = LV_MATH_MIN(p1.x, p2.x) - w_half0;
|
||||
draw_a.x2 = LV_MATH_MAX(p1.x, p2.x) + w_half1;
|
||||
draw_a.y1 = LV_MATH_MIN(p1.y, p2.y);
|
||||
draw_a.y2 = LV_MATH_MAX(p1.y, p2.y);
|
||||
|
||||
/* Get the union of `coords` and `clip`*/
|
||||
/* `clip` is already truncated to the `vdb` size
|
||||
* in 'lv_refr_area' function */
|
||||
bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip);
|
||||
|
||||
/*If there are common part of `clip` and `vdb` then draw*/
|
||||
if(union_ok == false) return;
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
/*Store the coordinates of the `draw_a` relative to the VDB */
|
||||
lv_area_t draw_rel_a;
|
||||
draw_rel_a.x1 = draw_a.x1 - vdb->area.x1;
|
||||
draw_rel_a.y1 = draw_a.y1 - vdb->area.y1;
|
||||
draw_rel_a.x2 = draw_a.x2 - vdb->area.x1;
|
||||
draw_rel_a.y2 = draw_a.y2 - vdb->area.y1;
|
||||
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
uint32_t draw_a_width = lv_area_get_width(&draw_rel_a);
|
||||
|
||||
/*Move the vdb_buf_tmp to the first row*/
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += vdb_width * draw_rel_a.y1;
|
||||
|
||||
lv_opa_t mask_buf[LV_HOR_RES_MAX];
|
||||
|
||||
/*Draw the background line by line*/
|
||||
lv_coord_t h;
|
||||
lv_mask_res_t mask_res;
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
memset(mask_buf, LV_OPA_COVER, draw_a_width);
|
||||
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width);
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
style->line.color, LV_IMG_CF_TRUE_COLOR,
|
||||
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_opa_t opa_scale)
|
||||
|
||||
static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_style_t * style, lv_opa_t opa_scale)
|
||||
{
|
||||
lv_opa_t opa = style->body.opa;
|
||||
|
||||
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
|
||||
#if LV_ANTIALIAS
|
||||
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
|
||||
#endif
|
||||
lv_point_t vect_main, vect_norm;
|
||||
vect_main.x = main_line->p2.x - main_line->p1.x;
|
||||
vect_main.y = main_line->p2.y - main_line->p1.y;
|
||||
/*Keep the great y in p1*/
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
if(point1->y < point2->y) {
|
||||
p1.y = point1->y;
|
||||
p2.y = point2->y;
|
||||
p1.x = point1->x;
|
||||
p2.x = point2->x;
|
||||
} else {
|
||||
p1.y = point2->y;
|
||||
p2.y = point1->y;
|
||||
p1.x = point2->x;
|
||||
p2.x = point1->x;
|
||||
}
|
||||
|
||||
if(main_line->hor) {
|
||||
if(main_line->p1.y < main_line->p2.y + dir_ori) {
|
||||
vect_norm.x = -vect_main.y;
|
||||
vect_norm.y = vect_main.x;
|
||||
lv_coord_t xdiff = p2.x - p1.x;
|
||||
lv_coord_t ydiff = p2.y - p1.y;
|
||||
bool flat = LV_MATH_ABS(xdiff) > LV_MATH_ABS(ydiff) ? true : false;
|
||||
|
||||
static const uint8_t wcorr[] = {
|
||||
128, 128, 128, 129, 129, 130, 130, 131,
|
||||
132, 133, 134, 135, 137, 138, 140, 141,
|
||||
143, 145, 147, 149, 151, 153, 155, 158,
|
||||
160, 162, 165, 167, 170, 173, 175, 178,
|
||||
181,
|
||||
};
|
||||
|
||||
lv_coord_t w = style->line.width;
|
||||
lv_coord_t wcorr_i = 0;
|
||||
if(flat) wcorr_i = (LV_MATH_ABS(ydiff) << 5) / LV_MATH_ABS(xdiff);
|
||||
else wcorr_i = (LV_MATH_ABS(xdiff) << 5) / LV_MATH_ABS(ydiff);
|
||||
|
||||
w = (w * wcorr[wcorr_i]) >> 7;
|
||||
printf("w:%d\n", w);
|
||||
lv_coord_t w_half0 = w >> 1;
|
||||
lv_coord_t w_half1 = w_half0 + (w & 0x1); /*Compensate rounding error*/
|
||||
|
||||
lv_area_t draw_a;
|
||||
draw_a.x1 = LV_MATH_MIN(p1.x, p2.x) - w;
|
||||
draw_a.x2 = LV_MATH_MAX(p1.x, p2.x) + w;
|
||||
draw_a.y1 = LV_MATH_MIN(p1.y, p2.y) - w;
|
||||
draw_a.y2 = LV_MATH_MAX(p1.y, p2.y) + w;
|
||||
|
||||
/* Get the union of `coords` and `clip`*/
|
||||
/* `clip` is already truncated to the `vdb` size
|
||||
* in 'lv_refr_area' function */
|
||||
bool union_ok = lv_area_intersect(&draw_a, &draw_a, clip);
|
||||
|
||||
/*If there are common part of `clip` and `vdb` then draw*/
|
||||
if(union_ok == false) return;
|
||||
|
||||
lv_mask_param_t mask_left_param;
|
||||
lv_mask_param_t mask_right_param;
|
||||
lv_mask_param_t mask_top_param;
|
||||
lv_mask_param_t mask_bottom_param;
|
||||
|
||||
if(flat) {
|
||||
if(xdiff > 0) {
|
||||
lv_mask_line_points_init(&mask_left_param, p1.x, p1.y - w_half0, p2.x, p2.y - w_half0, LV_LINE_MASK_SIDE_LEFT);
|
||||
lv_mask_line_points_init(&mask_right_param, p1.x, p1.y + w_half1, p2.x, p2.y + w_half1, LV_LINE_MASK_SIDE_RIGHT);
|
||||
} else {
|
||||
vect_norm.x = vect_main.y;
|
||||
vect_norm.y = -vect_main.x;
|
||||
lv_mask_line_points_init(&mask_left_param, p1.x, p1.y + w_half0, p2.x, p2.y + w_half0, LV_LINE_MASK_SIDE_LEFT);
|
||||
lv_mask_line_points_init(&mask_right_param, p1.x, p1.y - w_half1, p2.x, p2.y - w_half1, LV_LINE_MASK_SIDE_RIGHT);
|
||||
}
|
||||
} else {
|
||||
if(main_line->p1.x < main_line->p2.x + dir_ori) {
|
||||
vect_norm.x = vect_main.y;
|
||||
vect_norm.y = -vect_main.x;
|
||||
} else {
|
||||
vect_norm.x = -vect_main.y;
|
||||
vect_norm.y = vect_main.x;
|
||||
}
|
||||
lv_mask_line_points_init(&mask_left_param, p1.x + w_half0, p1.y, p2.x + w_half0, p2.y, LV_LINE_MASK_SIDE_LEFT);
|
||||
lv_mask_line_points_init(&mask_right_param, p1.x - w_half1, p1.y, p2.x - w_half1, p2.y, LV_LINE_MASK_SIDE_RIGHT);
|
||||
|
||||
}
|
||||
/*Use the normal vector for the endings*/
|
||||
lv_mask_line_points_init(&mask_top_param, p1.x, p1.y, p1.x - ydiff, p1.y + xdiff, LV_LINE_MASK_SIDE_BOTTOM);
|
||||
lv_mask_line_points_init(&mask_bottom_param, p2.x, p2.y,p2.x - ydiff, p2.y + xdiff, LV_LINE_MASK_SIDE_TOP);
|
||||
|
||||
int16_t mask_left_id = lv_mask_add(lv_mask_line, &mask_left_param, NULL);
|
||||
int16_t mask_right_id = lv_mask_add(lv_mask_line, &mask_right_param, NULL);
|
||||
int16_t mask_top_id = lv_mask_add(lv_mask_line, &mask_top_param, NULL);
|
||||
int16_t mask_bottom_id = lv_mask_add(lv_mask_line, &mask_bottom_param, NULL);
|
||||
|
||||
lv_disp_t * disp = lv_refr_get_disp_refreshing();
|
||||
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
|
||||
|
||||
/*Store the coordinates of the `draw_a` relative to the VDB */
|
||||
lv_area_t draw_rel_a;
|
||||
draw_rel_a.x1 = draw_a.x1 - vdb->area.x1;
|
||||
draw_rel_a.y1 = draw_a.y1 - vdb->area.y1;
|
||||
draw_rel_a.x2 = draw_a.x2 - vdb->area.x1;
|
||||
draw_rel_a.y2 = draw_a.y2 - vdb->area.y1;
|
||||
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
uint32_t draw_a_width = lv_area_get_width(&draw_rel_a);
|
||||
|
||||
/*Move the vdb_buf_tmp to the first row*/
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += vdb_width * draw_rel_a.y1;
|
||||
|
||||
lv_opa_t mask_buf[LV_HOR_RES_MAX];
|
||||
|
||||
/*Draw the background line by line*/
|
||||
lv_coord_t h;
|
||||
lv_mask_res_t mask_res;
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
memset(mask_buf, LV_OPA_COVER, draw_a_width);
|
||||
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width);
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
style->line.color, LV_IMG_CF_TRUE_COLOR,
|
||||
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
|
||||
/* In case of a short but tick line the perpendicular ending is longer then the real line.
|
||||
* it would break the calculations so make the normal vector larger*/
|
||||
vect_norm.x = vect_norm.x << 4;
|
||||
vect_norm.y = vect_norm.y << 4;
|
||||
|
||||
lv_coord_t width;
|
||||
width = style->line.width;
|
||||
|
||||
/* The pattern stores the points of the line ending. It has the good direction and length.
|
||||
* The worth case is the 45° line where pattern can have 1.41 x `width` points*/
|
||||
|
||||
lv_coord_t pattern_size = width * 2;
|
||||
lv_point_t * pattern = lv_draw_get_buf(pattern_size * sizeof(lv_point_t));
|
||||
lv_coord_t i = 0;
|
||||
|
||||
/*Create a perpendicular pattern (a small line)*/
|
||||
if(width != 0) {
|
||||
line_draw_t pattern_line;
|
||||
lv_point_t p0 = {0, 0};
|
||||
line_init(&pattern_line, &p0, &vect_norm);
|
||||
|
||||
uint32_t width_sqr = width * width;
|
||||
/* Run for a lot of times. Meanwhile the real width will be determined as well */
|
||||
for(i = 0; i < (lv_coord_t)pattern_size - 1; i++) {
|
||||
pattern[i].x = pattern_line.p_act.x;
|
||||
pattern[i].y = pattern_line.p_act.y;
|
||||
|
||||
/*Finish the pattern line if it's length equal to the desired width (Use Pythagoras
|
||||
* theorem)*/
|
||||
uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;
|
||||
if(sqr >= width_sqr) {
|
||||
width = i;
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) width--;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
line_next(&pattern_line);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_coord_t aa_last_corner;
|
||||
lv_coord_t width_safe = width;
|
||||
if(aa) {
|
||||
if(width == 0) width_safe = 1;
|
||||
|
||||
aa_last_corner = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_coord_t x_center_ofs = 0;
|
||||
lv_coord_t y_center_ofs = 0;
|
||||
|
||||
if(width != 0) {
|
||||
x_center_ofs = pattern[width - 1].x / 2;
|
||||
y_center_ofs = pattern[width - 1].y / 2;
|
||||
} else {
|
||||
if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y--;
|
||||
if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x--;
|
||||
}
|
||||
|
||||
/* Make the coordinates relative to the center */
|
||||
for(i = 0; i < width; i++) {
|
||||
pattern[i].x -= x_center_ofs;
|
||||
pattern[i].y -= y_center_ofs;
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) {
|
||||
if(i != 0) {
|
||||
if(main_line->hor) {
|
||||
if(pattern[i - 1].x != pattern[i].x) {
|
||||
lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;
|
||||
if(main_line->sy < 0) {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
|
||||
main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, seg_w, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, -seg_w, mask,
|
||||
style->line.color, opa);
|
||||
} else {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
|
||||
main_line->p1.y + pattern[aa_last_corner].y, seg_w, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
|
||||
main_line->p2.y + pattern[aa_last_corner].y, -seg_w, mask,
|
||||
style->line.color, opa);
|
||||
}
|
||||
aa_last_corner = i;
|
||||
}
|
||||
} else {
|
||||
if(pattern[i - 1].y != pattern[i].y) {
|
||||
lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;
|
||||
if(main_line->sx < 0) {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1,
|
||||
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
|
||||
style->line.color, opa);
|
||||
} else {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
|
||||
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
|
||||
style->line.color, opa);
|
||||
}
|
||||
aa_last_corner = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Add the last part of anti-aliasing for the perpendicular ending*/
|
||||
if(width != 0 && aa) { /*Due to rounding error with very thin lines it looks ugly*/
|
||||
if(main_line->hor) {
|
||||
lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;
|
||||
if(main_line->sy < 0) {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
|
||||
main_line->p1.y + pattern[aa_last_corner].y + seg_w, seg_w + main_line->sy, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + seg_w, -(seg_w + main_line->sy), mask,
|
||||
style->line.color, opa);
|
||||
|
||||
} else {
|
||||
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
|
||||
main_line->p1.y + pattern[aa_last_corner].y, seg_w + main_line->sy, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
|
||||
main_line->p2.y + pattern[aa_last_corner].y, -(seg_w + main_line->sy), mask,
|
||||
style->line.color, opa);
|
||||
}
|
||||
} else {
|
||||
lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;
|
||||
if(main_line->sx < 0) {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w,
|
||||
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
|
||||
style->line.color, opa);
|
||||
|
||||
} else {
|
||||
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
|
||||
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
|
||||
style->line.color, opa);
|
||||
|
||||
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
|
||||
main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
|
||||
style->line.color, opa);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
|
||||
/*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/
|
||||
lv_coord_t aa_shift1 = 0;
|
||||
lv_coord_t aa_shift2 = 0;
|
||||
if(aa) {
|
||||
if(main_line->hor == false) {
|
||||
if(main_line->sx < 0) {
|
||||
aa_shift1 = -1;
|
||||
aa_shift2 = width == 0 ? 0 : aa_shift1;
|
||||
} else {
|
||||
aa_shift2 = 1;
|
||||
aa_shift1 = width == 0 ? 0 : aa_shift2;
|
||||
}
|
||||
} else {
|
||||
if(main_line->sy < 0) {
|
||||
aa_shift1 = -1;
|
||||
aa_shift2 = width == 0 ? 0 : aa_shift1;
|
||||
} else {
|
||||
aa_shift2 = 1;
|
||||
aa_shift1 = width == 0 ? 0 : aa_shift2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
volatile lv_point_t prev_p;
|
||||
prev_p.x = main_line->p1.x;
|
||||
prev_p.y = main_line->p1.y;
|
||||
lv_area_t draw_area;
|
||||
bool first_run = true;
|
||||
|
||||
if(main_line->hor) {
|
||||
while(line_next_y(main_line)) {
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;
|
||||
draw_area.y2 = draw_area.y1;
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in y one pixel remains empty on every corner (don't do this on the
|
||||
* first segment ) */
|
||||
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
|
||||
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) {
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
|
||||
-(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x,
|
||||
prev_p.y + pattern[width_safe - 1].y + aa_shift2, main_line->p_act.x - prev_p.x,
|
||||
mask, style->line.color, opa);
|
||||
}
|
||||
#endif
|
||||
|
||||
first_run = false;
|
||||
|
||||
prev_p.x = main_line->p_act.x;
|
||||
prev_p.y = main_line->p_act.y;
|
||||
}
|
||||
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;
|
||||
draw_area.y2 = draw_area.y1;
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in y one pixel remains empty on every corner */
|
||||
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
|
||||
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) {
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
|
||||
-(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);
|
||||
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
|
||||
main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*Rather a vertical line*/
|
||||
else {
|
||||
|
||||
while(line_next_x(main_line)) {
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1;
|
||||
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;
|
||||
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in x one pixel remains empty on every corner (don't do this on the
|
||||
* first segment ) */
|
||||
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
|
||||
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) {
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
|
||||
-(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2,
|
||||
prev_p.y + pattern[width_safe - 1].y, main_line->p_act.y - prev_p.y, mask,
|
||||
style->line.color, opa);
|
||||
}
|
||||
#endif
|
||||
|
||||
first_run = false;
|
||||
|
||||
prev_p.x = main_line->p_act.x;
|
||||
prev_p.y = main_line->p_act.y;
|
||||
}
|
||||
|
||||
/*Draw the last part*/
|
||||
for(i = 0; i < width; i++) {
|
||||
draw_area.x1 = prev_p.x + pattern[i].x;
|
||||
draw_area.y1 = prev_p.y + pattern[i].y;
|
||||
draw_area.x2 = draw_area.x1;
|
||||
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;
|
||||
|
||||
lv_draw_fill(&draw_area, mask, style->line.color, opa);
|
||||
|
||||
/* Fill the gaps
|
||||
* When stepping in x one pixel remains empty on every corner */
|
||||
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
|
||||
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa) {
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
|
||||
-(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);
|
||||
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
|
||||
main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)
|
||||
{
|
||||
line->p1.x = p1->x;
|
||||
line->p1.y = p1->y;
|
||||
line->p2.x = p2->x;
|
||||
line->p2.y = p2->y;
|
||||
|
||||
line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);
|
||||
line->sx = line->p1.x < line->p2.x ? 1 : -1;
|
||||
line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);
|
||||
line->sy = line->p1.y < line->p2.y ? 1 : -1;
|
||||
line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;
|
||||
line->e2 = 0;
|
||||
line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/
|
||||
|
||||
line->p_act.x = line->p1.x;
|
||||
line->p_act.y = line->p1.y;
|
||||
}
|
||||
|
||||
static bool line_next(line_draw_t * line)
|
||||
{
|
||||
if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;
|
||||
line->e2 = line->err;
|
||||
if(line->e2 > -line->dx) {
|
||||
line->err -= line->dy;
|
||||
line->p_act.x += line->sx;
|
||||
}
|
||||
if(line->e2 < line->dy) {
|
||||
line->err += line->dx;
|
||||
line->p_act.y += line->sy;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate until step one in y direction.
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
static bool line_next_y(line_draw_t * line)
|
||||
{
|
||||
lv_coord_t last_y = line->p_act.y;
|
||||
|
||||
do {
|
||||
if(!line_next(line)) return false;
|
||||
} while(last_y == line->p_act.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate until step one in x direction.
|
||||
* @param line
|
||||
* @return
|
||||
*/
|
||||
static bool line_next_x(line_draw_t * line)
|
||||
{
|
||||
lv_coord_t last_x = line->p_act.x;
|
||||
|
||||
do {
|
||||
if(!line_next(line)) return false;
|
||||
} while(last_x == line->p_act.x);
|
||||
|
||||
return true;
|
||||
lv_mask_remove_id(mask_left_id);
|
||||
lv_mask_remove_id(mask_right_id);
|
||||
lv_mask_remove_id(mask_top_id);
|
||||
lv_mask_remove_id(mask_bottom_id);
|
||||
}
|
||||
|
@ -6,11 +6,11 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <lvgl/src/lv_draw/lv_blend.h>
|
||||
#include "lv_draw_rect.h"
|
||||
#include "../lv_misc/lv_circ.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_core/lv_refr.h"
|
||||
#include "lv_blit.h"
|
||||
#include "lv_mask.h"
|
||||
|
||||
/*********************
|
||||
@ -63,7 +63,6 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
{
|
||||
lv_opa_t opa = style->body.opa;
|
||||
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
lv_area_t draw_a;
|
||||
@ -87,81 +86,97 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
|
||||
draw_rel_a.x2 = draw_a.x2 - vdb->area.x1;
|
||||
draw_rel_a.y2 = draw_a.y2 - vdb->area.y1;
|
||||
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
uint32_t vdb_width = lv_area_get_width(&vdb->area);
|
||||
uint32_t draw_a_width = lv_area_get_width(&draw_rel_a);
|
||||
|
||||
/*Move the vdb_buf_tmp to the first row*/
|
||||
lv_color_t * vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += vdb_width * draw_rel_a.y1;
|
||||
|
||||
|
||||
lv_color_t line_buf[LV_HOR_RES_MAX];
|
||||
lv_opa_t mask_buf[LV_HOR_RES_MAX];
|
||||
lv_mask_line_param_t line_mask_param1;
|
||||
// lv_mask_line_points_init(&line_mask_param1, 100, 0, -50, 100, LV_LINE_MASK_SIDE_LEFT);
|
||||
lv_mask_line_angle_init(&line_mask_param1, 0, 0, 60, LV_LINE_MASK_SIDE_LEFT);
|
||||
lv_coord_t short_side = LV_MATH_MIN(lv_area_get_width(coords), lv_area_get_height(coords));
|
||||
lv_coord_t rout = style->body.radius;
|
||||
if(rout > short_side >> 1) rout = short_side >> 1;
|
||||
|
||||
lv_mask_line_param_t line_mask_param2;
|
||||
lv_mask_line_points_init(&line_mask_param2, 100, 0, 0, 100, LV_LINE_MASK_SIDE_LEFT);
|
||||
// lv_mask_line_angle_init(&line_mask_param2, 0, 0, 45, LV_LINE_MASK_SIDE_LEFT);
|
||||
/*Create the outer mask*/
|
||||
lv_mask_param_t mask_rout_param;
|
||||
lv_mask_radius_init(&mask_rout_param, coords, rout, false);
|
||||
int16_t mask_rout_id = lv_mask_add(lv_mask_radius, &mask_rout_param, NULL);
|
||||
|
||||
lv_area_t t;
|
||||
t.x1 = 10;
|
||||
t.y1 = 20;
|
||||
t.x2 = 30;
|
||||
t.y2 = 50;
|
||||
lv_mask_param_t tp;
|
||||
lv_mask_radius_init(&tp, &t, 5, false);
|
||||
// int16_t tpid = lv_mask_add(lv_mask_radius, &tp, NULL);
|
||||
|
||||
lv_mask_radius_param_t param1;
|
||||
lv_area_copy(¶m1.rect, coords);
|
||||
param1.radius = 50;
|
||||
param1.inv = 0;
|
||||
|
||||
lv_coord_t w = 20;
|
||||
lv_mask_radius_param_t param2;
|
||||
lv_area_copy(¶m2.rect, coords);
|
||||
param2.rect.x1 += w;
|
||||
param2.rect.x2 -= w;
|
||||
param2.rect.y1 += w;
|
||||
param2.rect.y2 -= w;
|
||||
param2.radius = param1.radius - w;
|
||||
param2.inv = 1;
|
||||
|
||||
|
||||
lv_mask_angle_param_t pa;
|
||||
lv_mask_angle_init(&pa, coords->x1 + lv_area_get_width(coords) / 2, coords->y1 + lv_area_get_height(coords) / 2, 60, 30);
|
||||
// lv_mask_angle_init(&pa, 0, 0, 60, 30);
|
||||
|
||||
// line_mask_param1.origo.x = 0;
|
||||
// line_mask_param1.origo.y = 0;
|
||||
// line_mask_param1.steep = 300;
|
||||
// line_mask_param1.flat = 1;
|
||||
// line_mask_param1.side = LV_LINE_MASK_SIDE_RIGHT;
|
||||
// line_mask_param1.inv = 0;
|
||||
|
||||
|
||||
/*Fill with a color line-by-line*/
|
||||
/*Draw the background line by line*/
|
||||
lv_coord_t h;
|
||||
lv_mask_res_t mask_res;
|
||||
lv_color_t grad_color;
|
||||
|
||||
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
if(opa >= LV_OPA_MIN) {
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
|
||||
if(style->body.main_color.full != style->body.grad_color.full) {
|
||||
// 3
|
||||
lv_blit_color(line_buf, &vdb_buf_tmp[draw_rel_a.x1], draw_a_width, style->body.main_color, LV_BLIT_MODE_NORMAL);
|
||||
lv_opa_t mix = ((uint32_t)((uint32_t)h + vdb->area.y1-coords->y1)*255) / lv_area_get_height(coords);
|
||||
grad_color = lv_color_mix(style->body.grad_color, style->body.main_color, mix);
|
||||
|
||||
if(style->body.main_color.full != style->body.grad_color.full) {
|
||||
memset(mask_buf, LV_OPA_COVER, draw_a_width);
|
||||
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width);
|
||||
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
grad_color, LV_IMG_CF_TRUE_COLOR,
|
||||
mask_buf, mask_res, style->body.opa, LV_BLIT_MODE_NORMAL);
|
||||
} else {
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
style->body.main_color, LV_IMG_CF_TRUE_COLOR,
|
||||
NULL, LV_MASK_RES_FULL_COVER, style->body.opa, LV_BLIT_MODE_NORMAL);
|
||||
}
|
||||
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*Draw the border if any*/
|
||||
lv_coord_t border_width = style->body.border.width;
|
||||
if(border_width) {
|
||||
/*Move the vdb_buf_tmp to the first row*/
|
||||
vdb_buf_tmp = vdb->buf_act;
|
||||
vdb_buf_tmp += vdb_width * draw_rel_a.y1;
|
||||
|
||||
lv_mask_param_t mask_rsmall_param;
|
||||
lv_coord_t rin = rout - border_width;
|
||||
if(rin < 0) rin = 0;
|
||||
lv_area_t area_small;
|
||||
lv_area_copy(&area_small, coords);
|
||||
area_small.x1 += border_width;
|
||||
area_small.x2 -= border_width;
|
||||
area_small.y1 += border_width;
|
||||
area_small.y2 -= border_width;
|
||||
lv_mask_radius_init(&mask_rsmall_param, &area_small, style->body.radius - border_width, true);
|
||||
int16_t mask_rsmall_id = lv_mask_add(lv_mask_radius, &mask_rsmall_param, NULL);
|
||||
|
||||
/*Fill the first row with 'color'*/
|
||||
for(h = draw_rel_a.y1; h <= draw_rel_a.y2; h++) {
|
||||
memset(mask_buf, LV_OPA_COVER, draw_a_width);
|
||||
// lv_mask_line(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &line_mask_param1);
|
||||
// lv_mask_line(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &line_mask_param2);
|
||||
mask_res = lv_mask_apply(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width);
|
||||
|
||||
//4
|
||||
lv_mask_radius(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, ¶m1);
|
||||
lv_mask_radius(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, ¶m2);
|
||||
lv_blend_color(&vdb_buf_tmp[draw_rel_a.x1], LV_IMG_CF_TRUE_COLOR, draw_a_width,
|
||||
style->body.border.color, LV_IMG_CF_TRUE_COLOR,
|
||||
mask_buf, mask_res, style->body.border.opa, LV_BLIT_MODE_NORMAL);
|
||||
|
||||
lv_mask_angle(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, &pa);
|
||||
|
||||
//9
|
||||
lv_mask_apply(&vdb_buf_tmp[draw_rel_a.x1], line_buf, mask_buf, draw_a_width);
|
||||
// memcpy(&vdb_buf_tmp[draw_rel_a.x1], line_buf, draw_a_width * sizeof(lv_color_t));
|
||||
} else {
|
||||
//1
|
||||
lv_blit_color(&vdb_buf_tmp[draw_rel_a.x1], &vdb_buf_tmp[draw_rel_a.x1], draw_a_width, style->body.main_color, LV_BLIT_MODE_NORMAL);
|
||||
// memcpy(&vdb_buf_tmp[draw_rel_a.x1], line_buf, draw_a_width * sizeof(lv_color_t));
|
||||
vdb_buf_tmp += vdb_width;
|
||||
}
|
||||
|
||||
vdb_buf_tmp += vdb_width;
|
||||
lv_mask_remove_id(mask_rsmall_id);
|
||||
}
|
||||
|
||||
lv_mask_remove_id(mask_rout_id);
|
||||
// lv_mask_remove_id(tpid);
|
||||
}
|
||||
|
@ -8,26 +8,36 @@
|
||||
*********************/
|
||||
#include "lv_mask.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
#include "../lv_misc/lv_log.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MASK_MAX_NUM 8
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef struct
|
||||
{
|
||||
lv_mask_cb_t cb;
|
||||
lv_mask_param_t param;
|
||||
void * custom_id;
|
||||
}lv_mask_saved_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p);
|
||||
static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p);
|
||||
static lv_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p);
|
||||
static lv_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p);
|
||||
|
||||
static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static lv_mask_saved_t mask_list[LV_MASK_MAX_NUM];
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -37,20 +47,64 @@ static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new);
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
void lv_mask_apply(lv_color_t * dest_buf, lv_color_t * src_buf, lv_opa_t * mask_buf, lv_coord_t len)
|
||||
int16_t lv_mask_add(lv_mask_cb_t mask_cb, lv_mask_param_t * param, void * custom_id)
|
||||
{
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
// if(mask_buf[i] > LV_OPA_MAX) dest_buf[i] = src_buf[i];
|
||||
// else if(mask_buf[i] > LV_OPA_MIN) dest_buf[i] = lv_color_mix(src_buf[i], dest_buf[i], mask_buf[i]);
|
||||
dest_buf[i] = lv_color_mix(src_buf[i], dest_buf[i], mask_buf[i]);
|
||||
/*Search a free entry*/
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MASK_MAX_NUM; i++) {
|
||||
if(mask_list[i].cb == NULL) break;
|
||||
}
|
||||
|
||||
if(i >= LV_MASK_MAX_NUM) {
|
||||
LV_LOG_WARN("lv_mask_add: no place to add the mask");
|
||||
return LV_MASK_ID_INV;
|
||||
}
|
||||
|
||||
mask_list[i].cb = mask_cb;
|
||||
memcpy(&mask_list[i].param, param, sizeof(lv_mask_param_t));
|
||||
mask_list[i].custom_id = custom_id;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side)
|
||||
lv_mask_res_t lv_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len)
|
||||
{
|
||||
|
||||
bool changed = false;
|
||||
lv_mask_res_t res;
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MASK_MAX_NUM; i++) {
|
||||
if(mask_list[i].cb) {
|
||||
res = mask_list[i].cb(mask_buf, abs_x, abs_y, len, (void*)&mask_list[i].param);
|
||||
if(res == LV_MASK_RES_FULL_TRANSP) return LV_MASK_RES_FULL_TRANSP;
|
||||
else if(res == LV_MASK_RES_CHANGED) changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed ? LV_MASK_RES_CHANGED : LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
|
||||
void lv_mask_remove_id(int16_t id)
|
||||
{
|
||||
if(id != LV_MASK_ID_INV) {
|
||||
mask_list[id].cb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_mask_remove_custom(void * custom_id)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i = 0; i < LV_MASK_MAX_NUM; i++) {
|
||||
if(mask_list[i].custom_id == custom_id) {
|
||||
mask_list[i].cb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lv_mask_line_points_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side)
|
||||
{
|
||||
lv_mask_line_param_t * p = ¶m->line;
|
||||
memset(p, 0x00, sizeof(lv_mask_line_param_t));
|
||||
|
||||
if(p1y > p2y) {
|
||||
@ -107,13 +161,13 @@ void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord
|
||||
if(p->side == LV_LINE_MASK_SIDE_LEFT) p->inv = 0;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_RIGHT) p->inv = 1;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_TOP) {
|
||||
if(p->steep > 0) p->inv = 0;
|
||||
else p->inv = 1;
|
||||
}
|
||||
else if(p->side == LV_LINE_MASK_SIDE_BOTTOM) {
|
||||
if(p->steep > 0) p->inv = 1;
|
||||
else p->inv = 0;
|
||||
}
|
||||
else if(p->side == LV_LINE_MASK_SIDE_BOTTOM) {
|
||||
if(p->steep > 0) p->inv = 0;
|
||||
else p->inv = 1;
|
||||
}
|
||||
|
||||
p->spx = p->steep >> 2;
|
||||
if(p->steep < 0) p->spx = -p->spx;
|
||||
@ -127,8 +181,11 @@ void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord
|
||||
* @param deg right 0 deg, bottom: 90
|
||||
* @param side
|
||||
*/
|
||||
void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side)
|
||||
void lv_mask_line_angle_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side)
|
||||
{
|
||||
|
||||
lv_mask_angle_param_t * p = ¶m->angle;
|
||||
|
||||
/* Find an optimal degree.
|
||||
* lv_mask_line_points_init will swap the points to keep the smaller y in p1
|
||||
* Theoretically a line with `deg` or `deg+180` is the same only the points are swapped
|
||||
@ -147,9 +204,9 @@ void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_
|
||||
lv_mask_line_points_init(p, p1x, p1y, p2x, p2y, side);
|
||||
}
|
||||
|
||||
void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, void * param)
|
||||
lv_mask_res_t lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param)
|
||||
{
|
||||
lv_mask_line_param_t * p = (lv_mask_line_param_t *)param;
|
||||
lv_mask_line_param_t * p = ¶m->line;
|
||||
|
||||
/*Make to points relative to the origo*/
|
||||
abs_y -= p->origo.y;
|
||||
@ -160,44 +217,48 @@ void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_co
|
||||
/*Horizontal*/
|
||||
if(p->flat) {
|
||||
/*Non sense: Can't be on the right/left of a horizontal line*/
|
||||
if(p->side == LV_LINE_MASK_SIDE_LEFT || p->side == LV_LINE_MASK_SIDE_RIGHT) return;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_TOP && abs_y+1 < p->origo.y) return;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_BOTTOM && abs_y > p->origo.y) return;
|
||||
if(p->side == LV_LINE_MASK_SIDE_LEFT || p->side == LV_LINE_MASK_SIDE_RIGHT) return LV_MASK_RES_FULL_COVER;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_TOP && abs_y+1 < p->origo.y) return LV_MASK_RES_FULL_COVER;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_BOTTOM && abs_y > p->origo.y) return LV_MASK_RES_FULL_COVER;
|
||||
else {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
}
|
||||
/*Vertical*/
|
||||
else {
|
||||
/*Non sense: Can't be on the top/bottom of a vertical line*/
|
||||
if(p->side == LV_LINE_MASK_SIDE_TOP || p->side == LV_LINE_MASK_SIDE_BOTTOM) return;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_RIGHT && abs_x > 0) return;
|
||||
if(p->side == LV_LINE_MASK_SIDE_TOP || p->side == LV_LINE_MASK_SIDE_BOTTOM) return LV_MASK_RES_FULL_COVER;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_RIGHT && abs_x > 0) return LV_MASK_RES_FULL_COVER;
|
||||
else if(p->side == LV_LINE_MASK_SIDE_LEFT) {
|
||||
if(abs_x + len < 0) return;
|
||||
if(abs_x + len < 0) return LV_MASK_RES_FULL_COVER;
|
||||
else {
|
||||
int32_t k = - abs_x;
|
||||
if(k < 0) k = 0;
|
||||
if(k >= 0 && k < len) memset(&mask_buf[k], 0x00, len - k);
|
||||
return;
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lv_mask_res_t res;
|
||||
if(p->flat) {
|
||||
line_mask_flat(mask_buf, abs_x, abs_y, len, p);
|
||||
res = line_mask_flat(mask_buf, abs_x, abs_y, len, p);
|
||||
} else {
|
||||
line_mask_steep(mask_buf, abs_x, abs_y, len, p);
|
||||
res = line_mask_steep(mask_buf, abs_x, abs_y, len, p);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origo_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle)
|
||||
|
||||
void lv_mask_angle_init(lv_mask_param_t * param, lv_coord_t origo_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle)
|
||||
{
|
||||
lv_mask_angle_param_t * p = ¶m->line;
|
||||
|
||||
lv_line_mask_side_t start_side;
|
||||
lv_line_mask_side_t end_side;
|
||||
|
||||
@ -224,13 +285,14 @@ void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origo_x, lv_coord_
|
||||
}
|
||||
}
|
||||
|
||||
lv_mask_line_angle_init(&p->start_line, origo_x, origo_y, start_angle, start_side);
|
||||
lv_mask_line_angle_init(&p->end_line, origo_x, origo_y, end_angle, end_side);
|
||||
lv_mask_line_angle_init((lv_mask_param_t*)&p->start_line, origo_x, origo_y, start_angle, start_side);
|
||||
lv_mask_line_angle_init((lv_mask_param_t*)&p->end_line, origo_x, origo_y, end_angle, end_side);
|
||||
}
|
||||
|
||||
|
||||
void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_angle_param_t * p)
|
||||
lv_mask_res_t lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param)
|
||||
{
|
||||
lv_mask_angle_param_t * p = ¶m->line;
|
||||
// if(p->delta_deg <= 180) {
|
||||
// if((p->start_angle <= 180 && abs_y >= p->origo.y) ||
|
||||
// (p->start_angle >= 180 && abs_y <= p->origo.y)) {
|
||||
@ -238,7 +300,7 @@ void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_c
|
||||
|
||||
if(abs_y < p->origo.y) {
|
||||
// memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
|
||||
|
||||
@ -251,36 +313,68 @@ void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_c
|
||||
|
||||
int32_t dist = (end_angle_first - start_angle_last) >> 1;
|
||||
|
||||
|
||||
lv_mask_res_t res1 = LV_MASK_RES_FULL_COVER;
|
||||
lv_mask_res_t res2 = LV_MASK_RES_FULL_COVER;
|
||||
|
||||
int32_t tmp = start_angle_last + dist - rel_x;
|
||||
if(tmp > len) tmp = len;
|
||||
if(tmp > 0) {
|
||||
lv_mask_line(&mask_buf[0], abs_x, abs_y, tmp, &p->start_line);
|
||||
res1 = lv_mask_line(&mask_buf[0], abs_x, abs_y, tmp, (lv_mask_param_t*)&p->start_line);
|
||||
if(res1 == LV_MASK_RES_FULL_TRANSP) {
|
||||
memset(&mask_buf[0], 0x00, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if(tmp > len) tmp = len;
|
||||
if(tmp < 0) tmp = 0;
|
||||
lv_mask_line(&mask_buf[tmp], abs_x+tmp, abs_y, len-tmp, &p->end_line);
|
||||
|
||||
res2 = lv_mask_line(&mask_buf[tmp], abs_x+tmp, abs_y, len-tmp, (lv_mask_param_t*)&p->end_line);
|
||||
if(res2 == LV_MASK_RES_FULL_TRANSP) {
|
||||
memset(&mask_buf[tmp], 0x00, len-tmp);
|
||||
}
|
||||
if(res1 == res2) return res1;
|
||||
else return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_radius_param_t * p)
|
||||
void lv_mask_radius_init(lv_mask_param_t * param, lv_area_t * rect, lv_coord_t radius, bool inv)
|
||||
{
|
||||
lv_mask_radius_param_t * p = ¶m->radius;
|
||||
|
||||
lv_area_copy(&p->rect, rect);
|
||||
p->radius = radius;
|
||||
p->inv = inv ? 1 : 0;
|
||||
}
|
||||
|
||||
lv_mask_res_t lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param)
|
||||
{
|
||||
lv_mask_radius_param_t * p = ¶m->radius;
|
||||
|
||||
if(p->inv == 0) {
|
||||
if(abs_y < p->rect.y1 || abs_y > p->rect.y2) {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
} else {
|
||||
if(abs_y < p->rect.y1 || abs_y > p->rect.y2) {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
}
|
||||
|
||||
if((abs_x >= p->rect.x1 + p->radius && abs_x + len <= p->rect.x2 - p->radius) ||
|
||||
(abs_y >= p->rect.y1 + p->radius && abs_y <= p->rect.y2 - p->radius+1)) {
|
||||
if(p->inv == 0) return;
|
||||
if(p->inv == 0) {
|
||||
/*Remove the edges*/
|
||||
int32_t last = p->rect.x1 - abs_x;
|
||||
if(last > len) last = len;
|
||||
if(last >= 0) {
|
||||
memset(&mask_buf[0], 0x00, last);
|
||||
}
|
||||
|
||||
int32_t first = p->rect.x2 - abs_x + 1;
|
||||
if(first < len) {
|
||||
memset(&mask_buf[first], 0x00, len-first);
|
||||
}
|
||||
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
else {
|
||||
int32_t first = p->rect.x1 - abs_x;
|
||||
if(first < 0) first = 0;
|
||||
@ -292,12 +386,9 @@ void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int32_t k = p->rect.x1 -abs_x; /*First relevant coordinate on the of the mask*/
|
||||
lv_coord_t w = lv_area_get_width(&p->rect);
|
||||
lv_coord_t h = lv_area_get_height(&p->rect);
|
||||
@ -446,18 +537,16 @@ void lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_
|
||||
if(kr < len) memset(&mask_buf[kr], 0x00, len - kr);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p)
|
||||
static lv_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p)
|
||||
{
|
||||
lv_coord_t y_at_x;
|
||||
|
||||
@ -468,19 +557,17 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs
|
||||
if(p->yx_steep > 0) {
|
||||
if(y_at_x > abs_y) {
|
||||
if(p->inv) {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
} else {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y_at_x < abs_y) {
|
||||
if(p->inv) {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
} else {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -491,19 +578,17 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs
|
||||
if(p->yx_steep > 0) {
|
||||
if(y_at_x < abs_y) {
|
||||
if(p->inv) {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
} else {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y_at_x > abs_y) {
|
||||
if(p->inv) {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
} else {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -562,9 +647,11 @@ static void line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs
|
||||
memset(&mask_buf[k], 0x00, len - k);
|
||||
}
|
||||
}
|
||||
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p)
|
||||
static lv_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_line_param_t * p)
|
||||
{
|
||||
int32_t k;
|
||||
lv_coord_t x_at_y;
|
||||
@ -574,10 +661,9 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab
|
||||
if(p->xy_steep > 0) x_at_y++;
|
||||
if(x_at_y < abs_x) {
|
||||
if(p->inv) {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
} else {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,10 +672,9 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab
|
||||
x_at_y = (int32_t)((int32_t)p->xy_steep * (abs_y)) >> 10;
|
||||
if(x_at_y > abs_x + len) {
|
||||
if(p->inv) {
|
||||
memset(mask_buf, 0x00, len);
|
||||
return;
|
||||
return LV_MASK_RES_FULL_TRANSP;
|
||||
} else {
|
||||
return;
|
||||
return LV_MASK_RES_FULL_COVER;
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,6 +775,8 @@ static void line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t ab
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return LV_MASK_RES_CHANGED;
|
||||
}
|
||||
|
||||
static inline lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new)
|
||||
|
@ -20,10 +20,21 @@ extern "C" {
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LV_MASK_ID_INV (-1)
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
enum {
|
||||
LV_MASK_RES_FULL_COVER,
|
||||
LV_MASK_RES_FULL_TRANSP,
|
||||
LV_MASK_RES_CHANGED,
|
||||
};
|
||||
|
||||
typedef uint8_t lv_mask_res_t;
|
||||
|
||||
|
||||
enum {
|
||||
LV_LINE_MASK_SIDE_LEFT = 0,
|
||||
LV_LINE_MASK_SIDE_RIGHT,
|
||||
@ -36,13 +47,13 @@ typedef uint8_t lv_line_mask_side_t;
|
||||
typedef struct {
|
||||
lv_point_t origo;
|
||||
/* X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/
|
||||
lv_coord_t xy_steep;
|
||||
int32_t xy_steep;
|
||||
|
||||
/* Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/
|
||||
lv_coord_t yx_steep;
|
||||
int32_t yx_steep;
|
||||
|
||||
/*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines */
|
||||
lv_coord_t steep;
|
||||
int32_t steep;
|
||||
|
||||
/*Steepness in 1 px in 0..255 range. Used only by flat lines. */
|
||||
int32_t spx;
|
||||
@ -68,7 +79,6 @@ typedef struct {
|
||||
uint16_t delta_deg;
|
||||
}lv_mask_angle_param_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lv_area_t rect;
|
||||
lv_coord_t radius;
|
||||
@ -77,18 +87,36 @@ typedef struct {
|
||||
uint8_t inv:1;
|
||||
}lv_mask_radius_param_t;
|
||||
|
||||
|
||||
typedef union {
|
||||
lv_mask_line_param_t line;
|
||||
lv_mask_radius_param_t radius;
|
||||
lv_mask_angle_param_t angle;
|
||||
}lv_mask_param_t;
|
||||
|
||||
typedef lv_mask_res_t (*lv_mask_cb_t)(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * p);
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_mask_apply(lv_color_t * dest_buf, lv_color_t * src_buf, lv_opa_t * mask_buf, lv_coord_t len);
|
||||
|
||||
void lv_mask_line_points_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side);
|
||||
void lv_mask_line_angle_init(lv_mask_line_param_t * p, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side);
|
||||
void lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, void * param);
|
||||
int16_t lv_mask_add(lv_mask_cb_t mask_cb, lv_mask_param_t * param, void * custom_id);
|
||||
void lv_mask_remove_id(int16_t id);
|
||||
void lv_mask_remove_custom(void * custom_id);
|
||||
|
||||
lv_mask_res_t lv_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len);
|
||||
|
||||
void lv_mask_line_points_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, lv_coord_t p2y, lv_line_mask_side_t side);
|
||||
void lv_mask_line_angle_init(lv_mask_param_t * param, lv_coord_t p1x, lv_coord_t p1y, int16_t deg, lv_line_mask_side_t side);
|
||||
lv_mask_res_t lv_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param);
|
||||
|
||||
|
||||
void lv_mask_angle_init(lv_mask_angle_param_t * p, lv_coord_t origio_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle);
|
||||
void lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_angle_param_t * p);
|
||||
void lv_mask_radius_init(lv_mask_param_t * param, lv_area_t * rect, lv_coord_t radius, bool inv);
|
||||
lv_mask_res_t lv_mask_radius(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param);
|
||||
|
||||
void lv_mask_angle_init(lv_mask_param_t * param, lv_coord_t origio_x, lv_coord_t origo_y, lv_coord_t start_angle, lv_coord_t end_angle);
|
||||
lv_mask_res_t lv_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, lv_mask_param_t * param);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
@ -75,8 +75,8 @@ enum {
|
||||
LV_OPA_COVER = 255,
|
||||
};
|
||||
|
||||
#define LV_OPA_MIN 16 /*Opacities below this will be transparent*/
|
||||
#define LV_OPA_MAX 251 /*Opacities above this will fully cover*/
|
||||
#define LV_OPA_MIN 5 /*Opacities below this will be transparent*/
|
||||
#define LV_OPA_MAX 250 /*Opacities above this will fully cover*/
|
||||
|
||||
#if LV_COLOR_DEPTH == 1
|
||||
#define LV_COLOR_SIZE 8
|
||||
|
Loading…
x
Reference in New Issue
Block a user