mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-14 06:42:58 +08:00
start a brand new line drawing algorithm
This commit is contained in:
parent
6bf1a8ffda
commit
eba3105cae
@ -21,10 +21,6 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LINE_WIDTH_CORR_BASE 64
|
||||
#define LINE_WIDTH_CORR_SHIFT 6
|
||||
|
||||
#define LABEL_RECOLOR_PAR_LENGTH 6
|
||||
|
||||
/**********************
|
||||
@ -37,43 +33,12 @@ typedef enum
|
||||
CMD_STATE_IN,
|
||||
}cmd_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
lv_point_t p_act;
|
||||
lv_coord_t dx;
|
||||
lv_coord_t sx;
|
||||
lv_coord_t dy;
|
||||
lv_coord_t sy;
|
||||
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);
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style);
|
||||
static void line_draw_skew(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style);
|
||||
static void line_draw_perpendicular_ending(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_coord_t width, lv_coord_t width_half, lv_coord_t width_1);
|
||||
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);
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
lv_opa_t antialias_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t line_opa);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static uint8_t hex_char_to_num(char hex);
|
||||
@ -480,466 +445,11 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param p1 first point of the line
|
||||
* @param p2 second point of the line
|
||||
* @param maskthe line will be drawn only on this area
|
||||
* @param lines_p pointer to a line style
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
|
||||
const lv_style_t * style)
|
||||
{
|
||||
|
||||
if(style->line.width == 0) return;
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
line_draw_t main_line;
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
|
||||
/*Be sure always x1 < x2*/
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
/*Special case draw a vertical line*/
|
||||
else if(main_line.p1.x == main_line.p2.x ) {
|
||||
line_draw_ver(&main_line, mask, style);
|
||||
}
|
||||
/*Arbitrary skew line*/
|
||||
else {
|
||||
line_draw_skew(&main_line, mask, style);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void line_draw_hor(line_draw_t * line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = line->p1.x;
|
||||
act_area.x2 = line->p2.x;
|
||||
act_area.y1 = line->p1.y - width_half - width_1;
|
||||
act_area.y2 = line->p2.y + width_half ;
|
||||
|
||||
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);
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
static void line_draw_ver(line_draw_t * line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_area_t act_area;
|
||||
|
||||
act_area.x1 = line->p1.x - width_half;
|
||||
act_area.x2 = line->p2.x + width_half + width_1;
|
||||
act_area.y1 = line->p1.y;
|
||||
act_area.y2 = line->p2.y;
|
||||
|
||||
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);
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
static void line_draw_skew(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
|
||||
lv_coord_t width;
|
||||
width = style->line.width - 1;
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
bool aa_invert = false;
|
||||
aa_invert = main_line->p1.y < main_line->p2.y ? false : true; /*Direction of opacity increase on the edges*/
|
||||
width--; /*Because of anti aliasing*/
|
||||
#endif
|
||||
|
||||
static const uint8_t width_corr_array[] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66,
|
||||
67, 67, 67, 68, 68, 68, 69, 69, 69, 70, 70, 71, 71, 72, 72, 72, 73, 73, 74,
|
||||
74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 81, 81, 82, 82, 83, 84, 84, 85,
|
||||
86, 86, 87, 88, 88, 89, 90, 91,
|
||||
};
|
||||
|
||||
lv_coord_t width_half;
|
||||
lv_coord_t width_1;
|
||||
uint16_t wcor;
|
||||
if(main_line->hor == false) {
|
||||
wcor = (main_line->dx * LINE_WIDTH_CORR_BASE) / main_line->dy;
|
||||
} else {
|
||||
wcor = (main_line->dy * LINE_WIDTH_CORR_BASE) / main_line->dx;
|
||||
}
|
||||
|
||||
/*Make the correction on line width*/
|
||||
if(width > 0) {
|
||||
width = (width * width_corr_array[wcor]);
|
||||
width = width >> LINE_WIDTH_CORR_SHIFT;
|
||||
width_half = width >> 1;
|
||||
width_1 = width & 0x1;
|
||||
} else {
|
||||
width_1 = 0;
|
||||
width_half = 0;
|
||||
}
|
||||
|
||||
line_draw_perpendicular_ending(main_line, mask, style, width, width_half, width_1);
|
||||
|
||||
|
||||
lv_coord_t perp_height = main_line->p_act.y - main_line->p1.y; /*Height of the perpendicular "triangle"*/
|
||||
|
||||
lv_coord_t last_x = main_line->p_act.x;
|
||||
lv_coord_t last_y = main_line->p_act.y;
|
||||
lv_area_t draw_area;
|
||||
do {
|
||||
if(main_line->hor == true && last_y != main_line->p_act.y) {
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = last_x;
|
||||
act_area.x2 = main_line->p_act.x - main_line->sx;
|
||||
act_area.y1 = last_y - width_half;
|
||||
act_area.y2 = main_line->p_act.y - main_line->sy + width_half + width_1;
|
||||
last_y = main_line->p_act.y;
|
||||
last_x = main_line->p_act.x;
|
||||
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);
|
||||
if(width >= 0) {
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
lv_coord_t seg_w = lv_area_get_width(&draw_area); /*Segment width*/
|
||||
lv_point_t aa_p1;
|
||||
lv_point_t aa_p2;
|
||||
|
||||
aa_p1.x = draw_area.x1;
|
||||
aa_p1.y = draw_area.y1 - 1;
|
||||
|
||||
aa_p2.x = draw_area.x1;
|
||||
aa_p2.y = draw_area.y1 + width + 1;
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < seg_w; i++) {
|
||||
lv_opa_t aa_opa = antialias_get_opa(seg_w, i, style->line.opa);
|
||||
|
||||
px_fp(aa_p1.x + i, aa_p1.y, mask, style->line.color, aa_invert ? aa_opa : style->line.opa - aa_opa);
|
||||
px_fp(aa_p2.x + i, aa_p2.y, mask, style->line.color, aa_invert ? style->line.opa - aa_opa : aa_opa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (main_line->hor == false && last_x != main_line->p_act.x) {
|
||||
lv_area_t act_area;
|
||||
lv_area_t draw_area;
|
||||
act_area.x1 = last_x - width_half;
|
||||
act_area.x2 = main_line->p_act.x - main_line->sx + width_half + width_1;
|
||||
act_area.y1 = last_y;
|
||||
act_area.y2 = main_line->p_act.y - main_line->sy;
|
||||
last_y = main_line->p_act.y;
|
||||
last_x = main_line->p_act.x;
|
||||
|
||||
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);
|
||||
|
||||
if(width >= 0) {
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_coord_t seg_h = lv_area_get_height(&draw_area); /*Segment height*/
|
||||
lv_point_t aa_p1;
|
||||
lv_point_t aa_p2;
|
||||
|
||||
aa_p1.x = draw_area.x1 - 1;
|
||||
aa_p1.y = draw_area.y1;
|
||||
|
||||
aa_p2.x = draw_area.x1 + width + 1;
|
||||
aa_p2.y = draw_area.y1;
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < seg_h; i++) {
|
||||
lv_opa_t aa_opa = antialias_get_opa(seg_h, i, style->line.opa);
|
||||
px_fp(aa_p1.x, aa_p1.y + i, mask, style->line.color, aa_invert ? aa_opa : style->line.opa - aa_opa);
|
||||
px_fp(aa_p2.x, aa_p2.y + i, mask, style->line.color, aa_invert ? style->line.opa - aa_opa : aa_opa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*Calc. the next point of the line*/
|
||||
if(!line_next(main_line)) break; /*In case error. It should stop because of the condition in "while(...)"*/
|
||||
|
||||
} while(main_line->p_act.y + perp_height <= main_line->p2.y);
|
||||
|
||||
/*Draw the last part of the line*/
|
||||
if(main_line->hor == true) {
|
||||
lv_area_t act_area;
|
||||
lv_area_t draw_area;
|
||||
act_area.x1 = last_x;
|
||||
act_area.x2 = main_line->p_act.x;
|
||||
act_area.y1 = last_y - width_half ;
|
||||
act_area.y2 = main_line->p_act.y + width_half + width_1;
|
||||
|
||||
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);
|
||||
if(width >= 0) {
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
lv_coord_t seg_w = lv_area_get_width(&draw_area); /*Segment width*/
|
||||
lv_point_t aa_p1;
|
||||
lv_point_t aa_p2;
|
||||
|
||||
aa_p1.x = draw_area.x1;
|
||||
aa_p1.y = draw_area.y1 - 1;
|
||||
|
||||
aa_p2.x = draw_area.x1;
|
||||
aa_p2.y = draw_area.y1 + width + 1;
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < seg_w; i++) {
|
||||
lv_opa_t aa_opa = antialias_get_opa(seg_w, i, style->line.opa);
|
||||
|
||||
px_fp(aa_p1.x + i, aa_p1.y, mask, style->line.color, aa_invert ? aa_opa : style->line.opa - aa_opa);
|
||||
px_fp(aa_p2.x + i, aa_p2.y, mask, style->line.color, aa_invert ? style->line.opa - aa_opa : aa_opa);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
if (main_line->hor == false) {
|
||||
lv_area_t act_area;
|
||||
lv_area_t draw_area;
|
||||
act_area.x1 = last_x - width_half;
|
||||
act_area.x2 = main_line->p_act.x + width_half + width_1;
|
||||
act_area.y1 = last_y;
|
||||
act_area.y2 = main_line->p_act.y - 1;
|
||||
|
||||
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);
|
||||
if(width >= 0) {
|
||||
fill_fp(&draw_area, mask, LV_COLOR_BLUE, style->line.opa);
|
||||
}
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
lv_coord_t seg_h = lv_area_get_height(&draw_area); /*Segment height*/
|
||||
lv_point_t aa_p1;
|
||||
lv_point_t aa_p2;
|
||||
|
||||
aa_p1.x = draw_area.x1 - 1;
|
||||
aa_p1.y = draw_area.y1;
|
||||
|
||||
aa_p2.x = draw_area.x1 + width + 1;
|
||||
aa_p2.y = draw_area.y1;
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < seg_h; i++) {
|
||||
lv_opa_t aa_opa = antialias_get_opa(seg_h, i, style->line.opa);
|
||||
|
||||
px_fp(aa_p1.x, aa_p1.y + i, mask, LV_COLOR_GREEN, aa_invert ? aa_opa : style->line.opa - aa_opa);
|
||||
px_fp(aa_p2.x, aa_p2.y + i, mask, LV_COLOR_GREEN, aa_invert ? style->line.opa - aa_opa : aa_opa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void line_draw_perpendicular_ending(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
|
||||
lv_coord_t width, lv_coord_t width_half, lv_coord_t width_1)
|
||||
{
|
||||
lv_coord_t main_vx = main_line->p2.x - main_line->p1.x;
|
||||
lv_coord_t main_vy = main_line->p2.y - main_line->p1.y;
|
||||
|
||||
lv_point_t pp_1 = {main_line->p1.x - main_line->sx + width_half + width_1 + 1, main_line->p1.y};
|
||||
lv_point_t pp_2 = {pp_1.x - main_vy, pp_1.y + main_vx}; /*Was - ... + */
|
||||
line_draw_t end_line;
|
||||
line_init(&end_line, &pp_1, &pp_2);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_coord_t aa_main_y_seg_cnt = 1;
|
||||
px_fp(end_line.p_act.x, end_line.p_act.y - 1, mask, LV_COLOR_YELLOW, LV_OPA_40); /*One px above the perpendicular corner*/
|
||||
#endif
|
||||
|
||||
lv_area_t draw_area;
|
||||
volatile lv_area_t act_area;
|
||||
do {
|
||||
lv_coord_t last_y;
|
||||
lv_coord_t last_x_main;
|
||||
lv_coord_t last_x_end;
|
||||
|
||||
last_x_main = main_line->p_act.x;
|
||||
last_y = main_line->p_act.y;
|
||||
while(main_line->p_act.y == last_y){
|
||||
line_next(main_line);
|
||||
#if LV_ANTIALIAS
|
||||
if(last_x_main != main_line->p_act.x) {
|
||||
printf("seg_w: %d\n", aa_main_y_seg_cnt);
|
||||
lv_coord_t aa_px_id;
|
||||
for(aa_px_id = 0; aa_px_id < aa_main_y_seg_cnt; aa_px_id++) {
|
||||
lv_opa_t px_opa = LV_OPA_100 - antialias_get_opa(aa_main_y_seg_cnt, aa_px_id, LV_OPA_100);
|
||||
px_fp(last_x_main - main_line->sx + width_half + width_1 + 2, main_line->p_act.y - aa_px_id - 1, mask, LV_COLOR_GREEN, px_opa);
|
||||
}
|
||||
aa_main_y_seg_cnt = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
aa_main_y_seg_cnt++;
|
||||
|
||||
last_x_end = end_line.p_act.x;
|
||||
last_y = end_line.p_act.y;
|
||||
while(end_line.p_act.y == last_y){
|
||||
if(!line_next(&end_line)) break;
|
||||
}
|
||||
|
||||
/*Rather vertical, direction: "\" */
|
||||
if(!main_line->hor && main_line->p1.y < main_line->p2.y)
|
||||
{
|
||||
act_area.x1 = last_x_end;
|
||||
act_area.y1 = main_line->p_act.y - 1;
|
||||
act_area.x2 = last_x_main - main_line->sx + width_half + width_1 + 1;
|
||||
act_area.y2 = act_area.y1;
|
||||
|
||||
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);
|
||||
printf("TOP x1: %d, y1: %d, x2: %d, y2: %d\n", draw_area.x1, draw_area.y1, draw_area.x2, draw_area.y2);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_RED, LV_OPA_40);
|
||||
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_coord_t aa_seg_w = last_x_end - end_line.p_act.x;
|
||||
lv_coord_t act_w = main_line->p_act.x - main_line->sx + width_half + width_1 + 1 - end_line.p_act.x;
|
||||
if(act_w >= width) { /*In the last row limit the segment length to the main line*/
|
||||
aa_seg_w = 1;
|
||||
}
|
||||
|
||||
lv_coord_t aa_px_id;
|
||||
for(aa_px_id = 0; aa_px_id < aa_seg_w; aa_px_id++) {
|
||||
lv_opa_t px_opa = LV_OPA_100 - antialias_get_opa(aa_seg_w, aa_px_id, LV_OPA_100);
|
||||
px_fp(draw_area.x1 - aa_px_id - 1, draw_area.y1, mask, LV_COLOR_BLUE, px_opa);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
act_area.x1 = main_line->p2.x - width_half - (act_area.x2 - end_line.p1.x);
|
||||
act_area.y1 = main_line->p2.y - (draw_area.y1 - main_line->p1.y);
|
||||
act_area.x2 = main_line->p2.x - width_half - (last_x_end - end_line.p1.x);
|
||||
act_area.y2 = act_area.y1;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
printf("BOT x1: %d, y1: %d, x2: %d, y2: %d\n", draw_area.x1, draw_area.y1, draw_area.x2, draw_area.y2);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_RED, LV_OPA_100);
|
||||
|
||||
|
||||
}
|
||||
/*Rather vertical, direction: "/" */
|
||||
if(!main_line->hor && main_line->p2.y < main_line->p1.y)
|
||||
{
|
||||
act_area.x1 = last_x_end;
|
||||
act_area.y1 = main_line->p_act.y + 1;
|
||||
act_area.x2 = last_x_main - main_line->sx + width_half + width_1 + 1;
|
||||
act_area.y2 = act_area.y1;
|
||||
|
||||
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);
|
||||
printf("TOP x1: %d, y1: %d, x2: %d, y2: %d\n", draw_area.x1, draw_area.y1, draw_area.x2, draw_area.y2);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_RED, LV_OPA_40);
|
||||
|
||||
act_area.x1 = main_line->p2.x - width_half - (last_x_end - end_line.p1.x);
|
||||
act_area.y1 = main_line->p2.y - (draw_area.y1 - main_line->p1.y);
|
||||
act_area.x2 = main_line->p2.x - width_half - (act_area.x2 - end_line.p1.x);
|
||||
act_area.y2 = act_area.y1;
|
||||
|
||||
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);
|
||||
|
||||
printf("BOT x1: %d, y1: %d, x2: %d, y2: %d\n", draw_area.x1, draw_area.y1, draw_area.x2, draw_area.y2);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_RED, LV_OPA_40);
|
||||
|
||||
}
|
||||
} while(lv_area_get_width(&draw_area) < width);
|
||||
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
|
@ -128,6 +128,9 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
|
||||
void lv_draw_line(const lv_point_t * p1, const lv_point_t * p2, const lv_area_t * mask_p,
|
||||
const lv_style_t * style_p);
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
lv_opa_t antialias_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t line_opa);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL VARIABLES
|
||||
|
@ -0,0 +1,477 @@
|
||||
/**
|
||||
* @file lv_draw_line.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "lv_draw.h"
|
||||
#include "../lv_misc/lv_math.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define LINE_WIDTH_CORR_BASE 64
|
||||
#define LINE_WIDTH_CORR_SHIFT 6
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
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);
|
||||
static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style);
|
||||
static void line_draw_skew(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style);
|
||||
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 void line_ver_aa(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
static void line_hor_aa(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Draw a line
|
||||
* @param p1 first point of the line
|
||||
* @param p2 second point of the line
|
||||
* @param maskthe line will be drawn only on this area
|
||||
* @param lines_p pointer to a line style
|
||||
*/
|
||||
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
|
||||
const lv_style_t * style)
|
||||
{
|
||||
|
||||
if(style->line.width == 0) return;
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
line_draw_t main_line;
|
||||
lv_point_t p1;
|
||||
lv_point_t p2;
|
||||
|
||||
/*Be sure always x1 < x2*/
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
/*Special case draw a vertical line*/
|
||||
else if(main_line.p1.x == main_line.p2.x ) {
|
||||
line_draw_ver(&main_line, mask, style);
|
||||
}
|
||||
/*Arbitrary skew line*/
|
||||
else {
|
||||
line_draw_skew(&main_line, mask, style);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
static void line_draw_hor(line_draw_t * line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
|
||||
lv_area_t act_area;
|
||||
act_area.x1 = line->p1.x;
|
||||
act_area.x2 = line->p2.x;
|
||||
act_area.y1 = line->p1.y - width_half - width_1;
|
||||
act_area.y2 = line->p2.y + width_half ;
|
||||
|
||||
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);
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
static void line_draw_ver(line_draw_t * line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
lv_coord_t width = style->line.width - 1;
|
||||
lv_coord_t width_half = width >> 1;
|
||||
lv_coord_t width_1 = width & 0x1;
|
||||
lv_area_t act_area;
|
||||
|
||||
act_area.x1 = line->p1.x - width_half;
|
||||
act_area.x2 = line->p2.x + width_half + width_1;
|
||||
act_area.y1 = line->p1.y;
|
||||
act_area.y2 = line->p2.y;
|
||||
|
||||
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);
|
||||
fill_fp(&draw_area, mask, style->line.color, style->line.opa);
|
||||
}
|
||||
|
||||
static void line_draw_skew(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style)
|
||||
{
|
||||
|
||||
lv_coord_t width;
|
||||
width = style->line.width - 1;
|
||||
|
||||
|
||||
#if LV_ANTIALIAS != 0
|
||||
width--; /*Because of anti aliasing*/
|
||||
#endif
|
||||
|
||||
static const uint8_t width_corr_array[] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66,
|
||||
67, 67, 67, 68, 68, 68, 69, 69, 69, 70, 70, 71, 71, 72, 72, 72, 73, 73, 74,
|
||||
74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 81, 81, 82, 82, 83, 84, 84, 85,
|
||||
86, 86, 87, 88, 88, 89, 90, 91,
|
||||
};
|
||||
|
||||
lv_coord_t width_half;
|
||||
lv_coord_t width_1;
|
||||
uint16_t wcor;
|
||||
if(main_line->hor == false) {
|
||||
wcor = (main_line->dx * LINE_WIDTH_CORR_BASE) / main_line->dy;
|
||||
} else {
|
||||
wcor = (main_line->dy * LINE_WIDTH_CORR_BASE) / main_line->dx;
|
||||
}
|
||||
|
||||
/*Make the correction on line width*/
|
||||
if(width > 0) {
|
||||
width = (width * width_corr_array[wcor]);
|
||||
width = width >> LINE_WIDTH_CORR_SHIFT;
|
||||
width_half = width >> 1;
|
||||
width_1 = width & 0x1;
|
||||
} else {
|
||||
width_1 = 0;
|
||||
width_half = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
if(main_line->p1.y < main_line->p2.y) {
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
line_draw_t line_neg;
|
||||
line_draw_t line_pos;
|
||||
line_draw_t line_end;
|
||||
lv_point_t p1_neg, p2_neg, p1_pos, p2_pos, p1_end, p2_end;
|
||||
p1_neg.x = main_line->p1.x - width_half;
|
||||
p1_neg.y = main_line->p1.y;
|
||||
p2_neg.x = main_line->p2.x - width_half;
|
||||
p2_neg.y = main_line->p2.y;
|
||||
p1_pos.x = main_line->p1.x + width_half + width_1;
|
||||
p1_pos.y = main_line->p1.y;
|
||||
p2_pos.x = main_line->p2.x + width_half + width_1;
|
||||
p2_pos.y = main_line->p2.y;
|
||||
p1_end.x = p1_pos.x;
|
||||
p1_end.y = p1_pos.y;
|
||||
p2_end.x = p1_end.x + vect_norm.x;
|
||||
p2_end.y = p1_end.y + vect_norm.y;
|
||||
|
||||
line_init(&line_pos, &p1_pos, &p2_pos);
|
||||
line_init(&line_end, &p1_end, &p2_end);
|
||||
|
||||
lv_area_t draw_area;
|
||||
|
||||
/*Top perpendicular end*/
|
||||
#if LV_ANTIALIAS
|
||||
volatile lv_point_t aa_last_step_pos; /*The point where the last step in x occurred*/
|
||||
volatile lv_point_t aa_last_step_end;
|
||||
aa_last_step_pos.x = line_pos.p_act.x;
|
||||
aa_last_step_pos.y = line_pos.p_act.y;
|
||||
aa_last_step_end.x = line_end.p_act.x;
|
||||
aa_last_step_end.y = line_end.p_act.y;
|
||||
//
|
||||
// /*On pixel at the top and bottom*/
|
||||
// px_fp(aa_last_step_pos.x, aa_last_step_pos.y - 1, mask, LV_COLOR_AQUA, LV_OPA_80 / 2);
|
||||
#endif
|
||||
do {
|
||||
draw_area.x1 = LV_MATH_MIN(line_end.p_act.x, line_pos.p_act.x);
|
||||
draw_area.y1 = LV_MATH_MIN(line_end.p_act.y, line_pos.p_act.y);
|
||||
draw_area.x2 = LV_MATH_MAX(line_end.p_act.x, line_pos.p_act.x);
|
||||
draw_area.y2 = LV_MATH_MAX(line_pos.p_act.y, line_pos.p_act.y);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa_last_step_pos.x != line_pos.p_act.x) {
|
||||
line_ver_aa(aa_last_step_pos.x + 1, aa_last_step_pos.y, line_pos.p_act.y - aa_last_step_pos.y, mask, LV_COLOR_BLUE, LV_OPA_50);
|
||||
aa_last_step_pos.x = line_pos.p_act.x;
|
||||
aa_last_step_pos.y = line_pos.p_act.y;
|
||||
}
|
||||
|
||||
if(aa_last_step_end.y != line_end.p_act.y) {
|
||||
lv_coord_t seg_w = aa_last_step_end.x - line_end.p_act.x; /*Segment width*/
|
||||
if(line_pos.p_act.x - (aa_last_step_end.x - seg_w) >= width) {
|
||||
seg_w = width - (line_pos.p_act.x - aa_last_step_end.x);
|
||||
}
|
||||
line_hor_aa(aa_last_step_end.x - seg_w, aa_last_step_end.y, seg_w , mask, LV_COLOR_RED, LV_OPA_50);
|
||||
aa_last_step_end.x = line_end.p_act.x;
|
||||
aa_last_step_end.y = line_end.p_act.y;
|
||||
}
|
||||
#endif
|
||||
/*Be sure the area is not wide ("x" can be more then where the intersection should be)*/
|
||||
if(lv_area_get_width(&draw_area) > width) {
|
||||
draw_area.x1 = draw_area.x2 - width;
|
||||
}
|
||||
fill_fp(&draw_area, mask, LV_COLOR_MAGENTA, LV_OPA_50);
|
||||
|
||||
line_next_y(&line_end);
|
||||
line_next_y(&line_pos);
|
||||
|
||||
}while(lv_area_get_width(&draw_area) < width);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Anti-aliasing of the last perpendicular segment (only one pixel)*/
|
||||
px_fp(draw_area.x1 - 1, draw_area.y1, mask, LV_COLOR_AQUA, LV_OPA_80 / 2);
|
||||
#endif
|
||||
|
||||
/*Middle part*/
|
||||
if(line_end.p_act.x == line_end.p2.x) line_end.p_act.y ++; /*If the the perpendicular line is finished (very steep line) then the last y step is missing */
|
||||
lv_coord_t perp_height = line_end.p_act.y - line_pos.p1.y; /*Height of the perpendicular area*/
|
||||
p1_neg.x = draw_area.x1 = draw_area.x2 - width;
|
||||
p1_neg.y = line_end.p_act.y;
|
||||
line_init(&line_neg, &p1_neg, &p2_neg);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
lv_point_t aa_last_step_neg;
|
||||
aa_last_step_neg.x = line_neg.p_act.x;
|
||||
aa_last_step_neg.y = line_neg.p_act.y;
|
||||
#endif
|
||||
|
||||
do {
|
||||
draw_area.x1 = LV_MATH_MIN(line_neg.p_act.x, line_pos.p_act.x);
|
||||
draw_area.y1 = LV_MATH_MIN(line_neg.p_act.y, line_pos.p_act.y);
|
||||
draw_area.x2 = LV_MATH_MAX(line_neg.p_act.x, line_pos.p_act.x);
|
||||
draw_area.y2 = LV_MATH_MAX(line_neg.p_act.y, line_pos.p_act.y);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_GREEN, LV_OPA_50);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa_last_step_neg.x != line_neg.p_act.x) {
|
||||
line_ver_aa(aa_last_step_neg.x - 1, aa_last_step_neg.y, aa_last_step_neg.y - line_neg.p_act.y, mask, LV_COLOR_BLUE, LV_OPA_50);
|
||||
aa_last_step_neg.x = line_neg.p_act.x;
|
||||
aa_last_step_neg.y = line_neg.p_act.y;
|
||||
}
|
||||
|
||||
if(aa_last_step_pos.x != line_pos.p_act.x) {
|
||||
line_ver_aa(aa_last_step_pos.x + 1, aa_last_step_pos.y, line_pos.p_act.y - aa_last_step_pos.y, mask, LV_COLOR_ORANGE, LV_OPA_50);
|
||||
aa_last_step_pos.x = line_pos.p_act.x;
|
||||
aa_last_step_pos.y = line_pos.p_act.y;
|
||||
}
|
||||
#endif
|
||||
if(!line_next_y(&line_neg)) break;
|
||||
if(!line_next_y(&line_pos)) break;
|
||||
}while(LV_MATH_ABS(line_pos.p_act.y - line_pos.p2.y) >= LV_MATH_ABS(perp_height));
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
/*Anti-aliasing of the last segment*/
|
||||
line_ver_aa(aa_last_step_pos.x + 1, aa_last_step_pos.y, line_pos.p2.y - aa_last_step_pos.y - perp_height + 1, mask, LV_COLOR_RED, LV_OPA_50);
|
||||
|
||||
#endif
|
||||
/*Bottom perpendicular end*/
|
||||
p1_end.x = line_pos.p_act.x;
|
||||
p1_end.y = line_pos.p_act.y;
|
||||
line_init(&line_end, &p1_end, &line_neg.p2);
|
||||
#if LV_ANTIALIAS
|
||||
aa_last_step_end.x = line_end.p_act.x;
|
||||
aa_last_step_end.y = line_end.p_act.y;
|
||||
#endif
|
||||
|
||||
do {
|
||||
draw_area.x1 = LV_MATH_MIN(line_neg.p_act.x, line_end.p_act.x);
|
||||
draw_area.y1 = LV_MATH_MIN(line_neg.p_act.y, line_end.p_act.y);
|
||||
draw_area.x2 = LV_MATH_MAX(line_neg.p_act.x, line_end.p_act.x);
|
||||
draw_area.y2 = LV_MATH_MAX(line_neg.p_act.y, line_end.p_act.y);
|
||||
fill_fp(&draw_area, mask, LV_COLOR_MAGENTA, LV_OPA_50);
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
if(aa_last_step_neg.x != line_neg.p_act.x) {
|
||||
line_ver_aa(aa_last_step_neg.x - 1, aa_last_step_neg.y, aa_last_step_neg.y - line_neg.p_act.y, mask, LV_COLOR_BLUE, LV_OPA_50);
|
||||
aa_last_step_neg.x = line_neg.p_act.x;
|
||||
aa_last_step_neg.y = line_neg.p_act.y;
|
||||
}
|
||||
|
||||
if(aa_last_step_end.y != line_end.p_act.y) {
|
||||
lv_coord_t seg_w = aa_last_step_end.x - line_end.p_act.x; /*Segment width*/
|
||||
if(line_neg.p_act.x - (aa_last_step_end.x - seg_w) >= width) {
|
||||
seg_w = width - (line_neg.p_act.x - aa_last_step_end.x);
|
||||
}
|
||||
line_hor_aa(aa_last_step_end.x - seg_w + 1, aa_last_step_end.y + 1, -seg_w , mask, LV_COLOR_RED, LV_OPA_50);
|
||||
aa_last_step_end.x = line_end.p_act.x;
|
||||
aa_last_step_end.y = line_end.p_act.y;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(!line_next_y(&line_neg)) break;
|
||||
if(!line_next_y(&line_end)) break;
|
||||
|
||||
}while(1);
|
||||
|
||||
|
||||
#if LV_ANTIALIAS
|
||||
line_ver_aa(aa_last_step_neg.x - 1, aa_last_step_neg.y, aa_last_step_neg.y - line_neg.p2.y - 1, mask, LV_COLOR_BLUE, LV_OPA_50);
|
||||
lv_coord_t seg_w = aa_last_step_end.x - line_neg.p2.x; /*Segment width*/
|
||||
if(line_neg.p2.x - (aa_last_step_end.x - seg_w) >= width) {
|
||||
seg_w = width - (line_neg.p2.x - aa_last_step_end.x);
|
||||
}
|
||||
line_hor_aa(line_neg.p2.x, line_neg.p2.y + 1, -seg_w , mask, LV_COLOR_LIME, LV_OPA_50);
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vertical anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
static void line_ver_aa(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
bool aa_inv = false;
|
||||
if(length < 0) {
|
||||
aa_inv = true;
|
||||
length = -length;
|
||||
}
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
lv_opa_t px_opa = antialias_get_opa(length, i, opa);
|
||||
if(aa_inv) px_opa = opa - px_opa;
|
||||
px_fp(x, y + i, mask, color, px_opa);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a horizontal anti-aliasing segment (pixels with decreasing opacity)
|
||||
* @param x start point x coordinate
|
||||
* @param y start point y coordinate
|
||||
* @param length length of segment (negative value to start from 0 opacity)
|
||||
* @param mask draw only in this area
|
||||
* @param color color of pixels
|
||||
* @param opa maximum opacity
|
||||
*/
|
||||
static void line_hor_aa(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
bool aa_inv = false;
|
||||
if(length < 0) {
|
||||
aa_inv = true;
|
||||
length = -length;
|
||||
}
|
||||
|
||||
lv_coord_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
lv_opa_t px_opa = antialias_get_opa(length, i, opa);
|
||||
if(aa_inv) px_opa = opa - px_opa;
|
||||
px_fp(x + i, y, mask, color, px_opa);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file lv_draw_line.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_LINE_H
|
||||
#define LV_DRAW_LINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_LINE_H*/
|
Loading…
x
Reference in New Issue
Block a user