1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

line mask: support all direction and inversion

This commit is contained in:
Gabor Kiss-Vamosi 2019-08-14 11:06:04 +02:00
parent 9b91dc057e
commit b1d4d6faef
4 changed files with 448 additions and 163 deletions

View File

@ -20,6 +20,77 @@
* 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;

View File

@ -97,11 +97,22 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
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_param;
line_mask_param.origo.x = 0;
line_mask_param.origo.y = 0;
line_mask_param.steep = 987;
line_mask_param.flat = 1;
lv_mask_line_param_t line_mask_param1;
// lv_mask_line_points_init(&line_mask_param1, 10, 0, 100, 200, LV_LINE_MASK_SIDE_RIGHT);
lv_mask_line_angle_init(&line_mask_param1, 50, 1, -20, LV_LINE_MASK_SIDE_RIGHT);
lv_mask_line_param_t line_mask_param2;
// lv_mask_line_points_init(&line_mask_param2, 10, 0, 100, 200, LV_LINE_MASK_SIDE_LEFT);
lv_mask_line_angle_init(&line_mask_param2, 50, 0, -20, LV_LINE_MASK_SIDE_LEFT);
// 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*/
@ -113,7 +124,8 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, const lv_s
if(style->body.main_color.full != style->body.grad_color.full) {
memset(mask_buf, LV_OPA_COVER, draw_a_width);
lv_mask_line_left(mask_buf, vdb->area.x1 + draw_rel_a.x1, vdb->area.y1 + h, draw_a_width, true, &line_mask_param);
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);
lv_mask_apply(&vdb_buf_tmp[draw_rel_a.x1], line_buf, mask_buf, draw_a_width);
} else {
memcpy(&vdb_buf_tmp[draw_rel_a.x1], line_buf, draw_a_width * sizeof(lv_color_t));

View File

@ -7,6 +7,7 @@
* INCLUDES
*********************/
#include "lv_mask.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
@ -19,6 +20,10 @@
/**********************
* 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_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new);
/**********************
* STATIC VARIABLES
@ -41,15 +46,125 @@ void lv_mask_apply(lv_color_t * dest_buf, lv_color_t * src_buf, lv_opa_t * mask_
}
}
void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, bool inner, void * param)
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)
{
memset(p, 0x00, sizeof(lv_mask_line_param_t));
if(p1y > p2y) {
lv_coord_t t;
t = p2x;
p2x = p1x;
p1x = t;
t = p2y;
p2y = p1y;
p1y = t;
}
p->origo.x = p1x;
p->origo.y = p1y;
p->side = side;
p->flat = (LV_MATH_ABS(p2x-p1x) > LV_MATH_ABS(p2y-p1y)) ? 1 : 0;
if(p->flat) {
/*Normalize the steep. Delta x should be relative to delta x = 1024*/
int32_t m;
m = (1 << 20) / (p2x-p1x); /*m is multiplier to normalize y (upscaled by 1024)*/
p->steep = (m * (p2y-p1y)) >> 10;
} else {
/*Normalize the steep. Delta y should be relative to delta x = 1024*/
int32_t m;
m = (1 << 20) / (p2y-p1y); /*m is multiplier to normalize x (upscaled by 1024)*/
p->steep = (m * (p2x-p1x)) >> 10;
}
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;
}
}
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)
{
lv_coord_t p2x;
lv_coord_t p2y;
p2x = (lv_trigo_sin(deg - 90) >> 5) + p1x;
p2y = (lv_trigo_sin(deg) >> 5) + p1y;
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_line_param_t * p = (lv_mask_line_param_t *)param;
/*make to points absolute to the origo*/
abs_x -= p->origo.x;
/*Make to points relative to the origo*/
abs_y -= p->origo.y;
abs_x -= p->origo.x;
/*Handle special cases*/
if(p->steep == 0) {
/*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;
else {
memset(mask_buf, 0x00, len);
return;
}
}
/*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;
else if(p->side == LV_LINE_MASK_SIDE_LEFT) {
if(abs_x + len < 0) return;
else {
int32_t k = - abs_x;
if(k < 0) k = 0;
if(k >= 0 && k < len) memset(&mask_buf[k], 0x00, len - k);
return;
}
}
else {
memset(mask_buf, 0x00, len);
return;
}
}
}
if(p->flat) {
line_mask_flat(mask_buf, abs_x, abs_y, len, p);
} else {
line_mask_steep(mask_buf, abs_x, abs_y, len, p);
}
}
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 * param)
{
}
/**********************
* 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)
{
lv_coord_t y_at_x;
/* At the beginning of the mask if the limit line is greater then the mask's y.
@ -58,26 +173,44 @@ void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
if(p->steep > 0) {
if(y_at_x > abs_y) {
if(p->inv) {
return;
} else {
memset(mask_buf, 0x00, len);
return;
}
}
} else {
if(y_at_x < abs_y) {
if(p->inv) {
return;
} else {
memset(mask_buf, 0x00, len);
return;
}
}
}
/* At the end of the mask if the limit line is smaller then the mask's y.
* Then the mask is in the "good" area*/
y_at_x = (int32_t)((int32_t)p->steep * (abs_x + len)) >> 10;
if(p->steep > 0) {
if(y_at_x < abs_y) {
if(p->inv) {
memset(mask_buf, 0x00, len);
return;
} else {
return;
}
}
} else {
if(y_at_x > abs_y) {
if(p->inv) {
memset(mask_buf, 0x00, len);
return;
} else {
return;
}
}
}
@ -95,45 +228,78 @@ void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
if(xef == 0) px_h = 255;
else px_h = 255 - (((255 - xef) * sps) >> 8);
int32_t k = xei - abs_x;
lv_opa_t m;
if(xef) {
if(k >= 0) mask_buf[k] = 255 - (((255-xef) * (255 - px_h)) >> 9);
if(k >= 0) {
m = 255 - (((255-xef) * (255 - px_h)) >> 9);
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k++;
}
while(px_h > sps) {
if(k >= 0) mask_buf[k] = px_h - (sps >> 1);
if(k >= 0) {
m = px_h - (sps >> 1);
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
px_h -= sps;
k++;
if(k >= len) return;
if(k >= len) break;
}
if(k < len && k >= 0) {
int32_t x_inters = (px_h << 10) / p->steep;
mask_buf[k] = (x_inters * px_h) >> 9; //px_h >> 1; /*Approximation*/
m = (x_inters * px_h) >> 9;
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k++;
if(k < len && k >= 0)
if(p->inv) {
k = xei - abs_x;
if(k > len) k= len;
if(k >= 0)
{
memset(&mask_buf[k] ,0x00, len - k);
memset(&mask_buf[0], 0x00, k);
}
} else {
k++;
if(k < len && k >= 0) {
memset(&mask_buf[k], 0x00, len - k);
}
}
}
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)
{
int32_t k;
lv_coord_t x_at_y;
/* At the beginning of the mask if the limit line is greater then the mask's y.
* Then the mask is in the "wrong" area*/
x_at_y = (int32_t)((int32_t)p->steep * abs_y) >> 10;
if(x_at_y < abs_x) {
if(p->inv) {
return;
} else {
memset(mask_buf, 0x00, len);
return;
}
}
/* At the end of the mask if the limit line is smaller then the mask's y.
* Then the mask is in the "good" area*/
x_at_y = (int32_t)((int32_t)p->steep * (abs_y)) >> 10;
if(x_at_y > abs_x + len) {
if(p->inv) {
memset(mask_buf, 0x00, len);
return;
} else {
return;
}
}
int32_t xe = ((abs_y << 8) * p->steep) >> 10;
int32_t xei = xe >> 8;
int32_t xef = xe & 0xFF;
@ -142,7 +308,9 @@ void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
int32_t xqi = xq >> 8;
int32_t xqf = xq & 0xFF;
int32_t k = xei - abs_x;
lv_opa_t m;
k = xei - abs_x;
if(xei != xqi && (p->steep < 0 && xef == 0)) {
xef = 0xFF;
xei = xqi;
@ -150,14 +318,20 @@ void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
}
if(xei == xqi) {
if(k >= 0 && k < len) {
mask_buf[k] = (xef + xqf) >> 1;
m = (xef + xqf) >> 1;
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k++;
if(k >= 0 && k < len ) {
memset(&mask_buf[k] ,0x00, len - (k));
if(p->inv) {
k = xei - abs_x;
if(k > len) k= len;
if(k >= 0) memset(&mask_buf[0], 0x00, k);
} else {
if(k >= 0 && k < len ) memset(&mask_buf[k] ,0x00, len - (k));
}
} else {
@ -165,58 +339,67 @@ void lv_mask_line_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
if(p->steep < 0) {
y_inters = (xef << 10) / (-p->steep);
if(k >= 0 && k < len ) {
mask_buf[k] = (y_inters * xef) >> 9;
m = (y_inters * xef) >> 9;
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k--;
int32_t x_inters = ((255-y_inters) * (-p->steep)) >> 10;
if(k >= 0 && k < len ) {
mask_buf[k] = 255-(((255-y_inters) * x_inters) >> 9);
m = 255-(((255-y_inters) * x_inters) >> 9);
if(p->inv) mask_buf[k] = 255 - mask_buf[k];
}
k+=2;
if(p->inv) {
k = xei - abs_x - 1;
if(k >= 0 && k < len ) {
memset(&mask_buf[k] ,0x00, len - (k));
if(k > len) k= len;
if(k >= 0) memset(&mask_buf[0], 0x00, k);
} else {
if(k >= 0 && k < len ) memset(&mask_buf[k] ,0x00, len - (k));
}
} else {
y_inters = ((255-xef) << 10) / p->steep;
if(k >= 0 && k < len ) {
mask_buf[k] = 255 - ((y_inters * (255-xef)) >> 9);
m = 255 - ((y_inters * (255-xef)) >> 9);
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k++;
int32_t x_inters = ((255-y_inters) * p->steep) >> 10;
if(k >= 0 && k < len ) {
mask_buf[k] = ((255-y_inters) * x_inters) >> 9;
m = ((255-y_inters) * x_inters) >> 9;
if(p->inv) m = 255 - m;
mask_buf[k] = mask_mix(mask_buf[k], m);
}
k++;
if(k >= 0 && k < len )
if(p->inv) {
k = xei - abs_x;
if(k > len) k= len;
if(k >= 0) memset(&mask_buf[0], 0x00, k);
} else {
if(k >= 0 && k < len ) memset(&mask_buf[k] ,0x00, len - (k));
}
}
}
}
static lv_opa_t mask_mix(lv_opa_t mask_act, lv_opa_t mask_new)
{
memset(&mask_buf[k] ,0x00, len - (k));
}
}
printf("y: %d, xef: %d, y_inters: %d, %d\n", abs_y, xef, y_inters * 100 / 255);
if(mask_new > LV_OPA_MAX) return mask_act;
if(mask_new < LV_OPA_MIN) return 0;
return (uint16_t)((uint16_t) (mask_act * mask_new) >> 8);
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/

View File

@ -24,17 +24,36 @@ extern "C" {
/**********************
* TYPEDEFS
**********************/
enum {
LV_LINE_MASK_SIDE_LEFT = 0,
LV_LINE_MASK_SIDE_RIGHT,
LV_LINE_MASK_SIDE_TOP,
LV_LINE_MASK_SIDE_BOTTOM,
};
typedef uint8_t lv_line_mask_side_t;
typedef struct {
lv_point_t origo;
lv_coord_t steep;
uint8_t flat :1;
lv_line_mask_side_t side :2;
uint8_t inv:1;
}lv_mask_line_param_t;
typedef struct {
lv_area_t rect;
lv_coord_t radius;
}lv_mask_radius_param_t;
/**********************
* 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_left(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t len, bool inner, void * param);
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);
/**********************
* MACROS