BigW Consortium Gitlab

Commit 2237ebd4 by Gabor Kiss-Vamosi

work in progress with new anti aliasing

parent 133bfe16
......@@ -28,23 +28,23 @@ extern "C" {
/*Error check of lv_conf.h*/
#if LV_HOR_RES == 0 || LV_VER_RES == 0
#error "LV: LV_HOR_RES and LV_VER_RES must be greater then 0"
#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater then 0"
#endif
#if LV_ANTIALIAS != 0 && LV_ANTIALIAS != 1
#error "LV: LV_ATIALIAS can be only 0 or 1"
#if LV_ANTIALIAS > 1
#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1"
#endif
#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0
#error "LV: If LV_VDB_SIZE == 0 the antialaissing must be disabled"
#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled"
#endif
#if LV_VDB_SIZE != 0 && LV_VDB_SIZE < LV_HOR_RES && LV_ANTIALIAS == 0
#error "LV: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)"
#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES
#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)"
#endif
#if LV_VDB_SIZE != 0 && LV_VDB_SIZE < 2 *LV_HOR_RES && LV_ANTIALIAS != 0
#error "LV: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= (2 * LV_HOR_RES))"
#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= (2 * LV_HOR_RES))"
#endif
#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/
......
......@@ -98,14 +98,6 @@ void lv_inv_area(const lv_area_t * area_p)
/*The area is truncated to the screen*/
if(suc != false)
{
#if LV_ANTIALIAS == 1
/*Rounding*/
com_area.x1 = com_area.x1 & (~0x1);
com_area.y1 = com_area.y1 & (~0x1);
com_area.x2 = com_area.x2 | 0x1;
com_area.y2 = com_area.y2 | 0x1;
#endif
/*Save only if this area is not in one of the saved areas*/
uint16_t i;
for(i = 0; i < inv_buf_p; i++) {
......@@ -262,10 +254,8 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p)
lv_coord_t h = lv_area_get_height(area_p);
lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2;
uint32_t max_row = (uint32_t) LV_VDB_SIZE / (w << LV_AA);
if(max_row > (h << LV_AA)) max_row = (h << LV_AA);
max_row = max_row >> LV_AA ;
uint32_t max_row = (uint32_t) LV_VDB_SIZE / w;
if(max_row > h) max_row = h;
/*Always use the full row*/
uint32_t row;
......@@ -312,13 +302,6 @@ static void lv_refr_area_part_vdb(const lv_area_t * area_p)
lv_area_t start_mask;
lv_area_union(&start_mask, area_p, &vdb_p->area);
#if LV_ANTIALIAS
vdb_p->area.x1 = vdb_p->area.x1 << LV_AA;
vdb_p->area.x2 = (vdb_p->area.x2 << LV_AA) + 1;
vdb_p->area.y1 = (vdb_p->area.y1 << LV_AA);
vdb_p->area.y2 = (vdb_p->area.y2 << LV_AA) + 1;
#endif
/*Get the most top object which is not covered by others*/
top_p = lv_refr_get_top_obj(&start_mask, lv_scr_act());
......
......@@ -23,7 +23,6 @@ extern "C" {
* DEFINES
*********************/
#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/
#define LV_AA LV_ANTIALIAS /*Just a shorter form of LV_ANTIALIAS*/
/**********************
* TYPEDEFS
......
......@@ -119,59 +119,9 @@ void lv_vdb_flush(void)
if(vdb_state[1] == LV_VDB_STATE_ACTIVE) vdb_state[1] = LV_VDB_STATE_FLUSH;
#endif
#if LV_ANTIALIAS == 0
/*Flush the rendered content to the display*/
lv_disp_flush(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);
#else
/* Get the average of 2x2 pixels and put the result back to the VDB
* The reading goes much faster then the write back
* so useful data won't be overwritten
* Example:
* -----------------------------
* in1_buf |2,2|6,8| 3,7
* in2_buf |4,4|7,7| 1,2
* --------- ==>
* in1_buf |1,1|1,3|
* in2_buf |1,1|1,3|
* */
lv_coord_t x;
lv_coord_t y;
lv_coord_t w = lv_area_get_width(&vdb_act->area);
lv_color_t * in1_buf = vdb_act->buf; /*Pointer to the first row*/
lv_color_t * in2_buf = vdb_act->buf + w; /*Pointer to the second row*/
lv_color_t * out_buf = vdb_act->buf; /*Store the result here*/
for(y = vdb_act->area.y1; y < vdb_act->area.y2; y += 2) {
for(x = vdb_act->area.x1; x < vdb_act->area.x2; x += 2) {
/*If the pixels are the same do not calculate the average */
if(in1_buf->full == (in1_buf + 1)->full &&
in1_buf->full == in2_buf->full &&
in1_buf->full == (in2_buf + 1)->full) {
out_buf->full = in1_buf->full;
} else {
/*Get the average of 2x2 red*/
out_buf->red = (in1_buf->red + (in1_buf + 1)->red +
in2_buf->red + (in2_buf+ 1)->red) >> 2;
/*Get the average of 2x2 green*/
out_buf->green = (in1_buf->green + (in1_buf + 1)->green +
in2_buf->green + (in2_buf + 1)->green) >> 2;
/*Get the average of 2x2 blue*/
out_buf->blue = (in1_buf->blue + (in1_buf + 1)->blue +
in2_buf->blue + (in2_buf + 1)->blue) >> 2;
}
in1_buf += 2; /*Skip the next pixel because it is already used above*/
in2_buf += 2;
out_buf ++;
}
/*2 row is ready so go the next 2*/
in1_buf += w; /*Skip the next row because it is processed from in2_buf*/
in2_buf += w;
}
/* Now the full the VDB is filtered and the result is stored in the first quarter of it
* Write out the filtered map to the display*/
lv_disp_flush(vdb_act->area.x1 >> 1, vdb_act->area.y1 >> 1, vdb_act->area.x2 >> 1, vdb_act->area.y2 >> 1, vdb_act->buf);
#endif
}
/**
......
......@@ -22,10 +22,12 @@
/*********************
* DEFINES
*********************/
#define CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD 5 /*Circle segment greater then this value will be anti-aliased by a non-linear (cos) opacity mapping*/
#define LINE_WIDTH_CORR_BASE 64
#define LINE_WIDTH_CORR_SHIFT 6
#define LABEL_RELV_COLOR_PAR_LENGTH 6
#define LABEL_RECOLOR_PAR_LENGTH 6
/**********************
* TYPEDEFS
......@@ -52,6 +54,10 @@ static void lv_draw_cont_shadow_bottom(const lv_area_t * coords, const lv_area_t
static void lv_draw_cont_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map);
#endif
static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h);
#if LV_ANTIALIAS != 0
static lv_opa_t antialias_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t line_opa);
static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa);
#endif
#if USE_LV_TRIANGLE != 0
......@@ -102,41 +108,24 @@ void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_sty
{
if(lv_area_get_height(coords) < 1 || lv_area_get_width(coords) < 1) return;
lv_area_t coord_aa;
lv_area_t mask_aa;
#if LV_ANTIALIAS == 0
lv_area_copy(&coord_aa, coords);
lv_area_copy(&mask_aa, mask);
#else
coord_aa.x1 = coords->x1 << LV_AA;
coord_aa.y1 = coords->y1 << LV_AA;
coord_aa.x2 = (coords->x2 << LV_AA) + 1;
coord_aa.y2 = (coords->y2 << LV_AA) + 1;
mask_aa.x1 = mask->x1 << LV_AA;
mask_aa.y1 = mask->y1 << LV_AA;
mask_aa.x2 = (mask->x2 << LV_AA) + 1;
mask_aa.y2 = (mask->y2 << LV_AA) + 1;
#endif
#if USE_LV_SHADOW && LV_VDB_SIZE
if(style->body.shadow.width != 0) {
lv_draw_rect_shadow(&coord_aa, &mask_aa, style);
lv_draw_rect_shadow(coords, mask, style);
}
#endif
if(style->body.empty == 0){
lv_draw_rect_main_mid(&coord_aa, &mask_aa, style);
lv_draw_rect_main_mid(coords, mask, style);
if(style->body.radius != 0) {
lv_draw_rect_main_corner(&coord_aa, &mask_aa, style);
lv_draw_rect_main_corner(coords, mask, style);
}
}
if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE) {
lv_draw_rect_border_straight(&coord_aa, &mask_aa, style);
lv_draw_rect_border_straight(coords, mask, style);
if(style->body.radius != 0) {
lv_draw_rect_border_corner(&coord_aa, &mask_aa, style);
lv_draw_rect_border_corner(coords, mask, style);
}
}
}
......@@ -262,23 +251,6 @@ void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_colo
void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style,
const char * txt, lv_txt_flag_t flag, lv_point_t * offset)
{
lv_area_t coord_aa;
lv_area_t mask_aa;
#if LV_ANTIALIAS == 0
lv_area_copy(&coord_aa, coords);
lv_area_copy(&mask_aa, mask);
#else
coord_aa.x1 = coords->x1 << LV_AA;
coord_aa.y1 = coords->y1 << LV_AA;
coord_aa.x2 = (coords->x2 << LV_AA) + 1;
coord_aa.y2 = (coords->y2 << LV_AA) + 1;
mask_aa.x1 = mask->x1 << LV_AA;
mask_aa.y1 = mask->y1 << LV_AA;
mask_aa.x2 = (mask->x2 << LV_AA) + 1;
mask_aa.y2 = (mask->y2 << LV_AA) + 1;
#endif
const lv_font_t * font = style->text.font;
lv_coord_t w;
......@@ -296,14 +268,14 @@ void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_sty
uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag);
lv_point_t pos;
pos.x = coord_aa.x1;
pos.y = coord_aa.y1;
pos.x = coords->x1;
pos.y = coords->y1;
/*Align the line to middle if enabled*/
if(flag & LV_TXT_FLAG_CENTER) {
line_length = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += ((w - line_length) / 2) << LV_AA;
pos.x += (w - line_length) / 2;
}
cmd_state_t cmd_state = CMD_STATE_WAIT;
......@@ -315,8 +287,8 @@ void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_sty
lv_coord_t x_ofs = 0;
lv_coord_t y_ofs = 0;
if(offset != NULL) {
x_ofs = offset->x << LV_ANTIALIAS << LV_FONT_ANTIALIAS;
y_ofs = offset->y << LV_ANTIALIAS << LV_FONT_ANTIALIAS;
x_ofs = offset->x;
y_ofs = offset->y;
pos.y += y_ofs;
}
......@@ -350,10 +322,10 @@ void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_sty
if(cmd_state == CMD_STATE_PAR) {
if(letter == ' ') {
/*Get the parameter*/
if(i - par_start == LABEL_RELV_COLOR_PAR_LENGTH + 1) {
char buf[LABEL_RELV_COLOR_PAR_LENGTH + 1];
memcpy(buf, &txt[par_start], LABEL_RELV_COLOR_PAR_LENGTH);
buf[LABEL_RELV_COLOR_PAR_LENGTH] = '\0';
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
int r,g,b;
sscanf(buf, "%02x%02x%02x", &r, &g, &b);
recolor = LV_COLOR_MAKE(r, g, b);
......@@ -369,10 +341,10 @@ void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_sty
lv_color_t color = style->text.color;
if(cmd_state == CMD_STATE_IN) color = recolor;
letter_fp(&pos, &mask_aa, font, letter, color, style->text.opa);
letter_w = lv_font_get_width(font, letter) >> LV_FONT_ANTIALIAS;
letter_fp(&pos, mask, font, letter, color, style->text.opa);
letter_w = lv_font_get_width(font, letter);
pos.x += letter_w + (style->text.letter_space << LV_AA);
pos.x += letter_w + style->text.letter_space;
/* Round error occurs in x position
* When odd widths are scaled down the last 1 is lost. So the letters seems shorter.
* Now calculate according to it to be consequent */
......@@ -382,16 +354,16 @@ void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_sty
line_start = line_end;
line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag);
pos.x = coord_aa.x1;
pos.x = coords->x1;
/*Align to middle*/
if(flag & LV_TXT_FLAG_CENTER) {
line_length = lv_txt_get_width(&txt[line_start], line_end - line_start,
font, style->text.letter_space, flag);
pos.x += ((w - line_length) / 2) << LV_AA;
pos.x += (w - line_length) / 2;
}
/*Go the next line position*/
pos.y += lv_font_get_height(font) >> LV_FONT_ANTIALIAS;
pos.y += style->text.line_space << LV_AA;
pos.y += lv_font_get_height(font);
pos.y += style->text.line_space;
}
}
......@@ -526,53 +498,47 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask,
* @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 * p1, const lv_point_t * p2, const lv_area_t * mask,
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(p1->x == p2->x && p1->y == p2->y) return;
lv_point_t p1_aa;
lv_point_t p2_aa;
if(style->line.width == 0) return;
if(point1->x == point2->x && point1->y == point2->y) return;
p1_aa.x = p1->x << LV_AA;
p1_aa.y = p1->y << LV_AA;
p2_aa.x = p2->x << LV_AA;
p2_aa.y = p2->y << LV_AA;
lv_area_t mask_aa;
#if LV_ANTIALIAS == 0
lv_area_copy(&mask_aa, mask);
#else
mask_aa.x1 = mask->x1 << LV_AA;
mask_aa.y1 = mask->y1 << LV_AA;
mask_aa.x2 = (mask->x2 << LV_AA) + 1;
mask_aa.y2 = (mask->y2 << LV_AA) + 1;
#endif
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;
}
lv_coord_t dx = LV_MATH_ABS(p2_aa.x - p1_aa.x);
lv_coord_t sx = p1_aa.x < p2_aa.x ? 1 : -1;
lv_coord_t dy = LV_MATH_ABS(p2_aa.y - p1_aa.y);
lv_coord_t sy = p1_aa.y < p2_aa.y ? 1 : -1;
lv_coord_t err = (dx > dy ? dx : -dy) / 2;
lv_coord_t e2;
bool hor = dx > dy ? true : false; /*Rather horizontal or vertical*/
lv_coord_t last_x = p1_aa.x;
lv_coord_t last_y = p1_aa.y;
lv_point_t act_point;
act_point.x = p1_aa.x;
act_point.y = p1_aa.y;
uint16_t width;
uint16_t wcor;
uint16_t width_half;
uint16_t width_1;
lv_coord_t dx = LV_MATH_ABS(p2.x - p1.x);
lv_coord_t sx = p1.x < p2.x ? 1 : -1;
lv_coord_t dy = LV_MATH_ABS(p2.y - p1.y);
lv_coord_t sy = p1.y < p2.y ? 1 : -1;
lv_coord_t err = (dx > dy ? dx : -dy) / 2;
lv_coord_t e2;
bool hor = dx > dy ? true : false; /*Rather horizontal or vertical*/
lv_coord_t last_x = p1.x;
lv_coord_t last_y = p1.y;
lv_point_t act_point;
act_point.x = p1.x;
act_point.y = p1.y;
lv_coord_t width;
uint16_t wcor;
uint16_t width_half = 0;
uint16_t width_1 = 0;
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,
......@@ -580,93 +546,229 @@ void lv_draw_line(const lv_point_t * p1, const lv_point_t * p2, const lv_area_t
86, 86, 87, 88, 88, 89, 90, 91,
};
if(hor == false) {
wcor = (dx * LINE_WIDTH_CORR_BASE) / dy;
} else {
wcor = (dy * LINE_WIDTH_CORR_BASE) / dx;
}
if(hor == false) {
wcor = (dx * LINE_WIDTH_CORR_BASE) / dy;
} else {
wcor = (dy * LINE_WIDTH_CORR_BASE) / dx;
}
width = style->line.width - 1;
#if LV_ANTIALIAS != 0
bool aa_invert = false;
aa_invert = p1.y < p2.y ? false : true; /*Direction of opacity increase on the edges*/
if(p1.x != p2.x && p1.y != p2.y) width--; /*Because of anti aliasing (no anti aliasing on hor. and ver. lines)*/
#endif
/*Make the correction on lie width*/
width = ((style->line.width - 1) * width_corr_array[wcor]) >> LINE_WIDTH_CORR_SHIFT;
width = width << LV_ANTIALIAS;
width_half = width >> 1;
width_1 = width & 0x1 ? 1 : 0;
while(1){
if(hor == true && last_y != act_point.y) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x;
act_area.x2 = act_point.x - sx;
act_area.y1 = last_y - width_half ;
act_area.y2 = act_point.y - sy + width_half + width_1;
last_y = act_point.y;
last_x = act_point.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);
fill_fp(&draw_area, &mask_aa, style->line.color, style->line.opa);
}
if (hor == false && last_x != act_point.x) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x - width_half;
act_area.x2 = act_point.x - sx + width_half + width_1;
act_area.y1 = last_y ;
act_area.y2 = act_point.y - sy;
last_y = act_point.y;
last_x = act_point.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);
fill_fp(&draw_area, &mask_aa, style->line.color, style->line.opa);
}
/*Calc. the next point of the line*/
if (act_point.x == p2_aa.x && act_point.y == p2_aa.y) break;
e2 = err;
if (e2 >-dx) {
err -= dy;
act_point.x += sx;
}
if (e2 < dy) {
err += dx;
act_point.y += sy;
}
}
/*Draw the last part of the line*/
if(hor == true) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x;
act_area.x2 = act_point.x;
act_area.y1 = last_y - width_half ;
act_area.y2 = act_point.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);
fill_fp(&draw_area, &mask_aa, style->line.color, style->line.opa);
}
if (hor == false) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x - width_half;
act_area.x2 = act_point.x + width_half + width_1;
act_area.y1 = last_y;
act_area.y2 = act_point.y;
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_aa, style->line.color, style->line.opa);
}
if(width > 0) {
width = (width * width_corr_array[wcor]);
width = width >> LINE_WIDTH_CORR_SHIFT;
width_half = width >> 1;
width_1 = width & 0x1 ? 1 : 0;
}
/*Special case draw a horizontal line*/
if(p1.y == p2.y ) {
lv_area_t act_area;
act_area.x1 = p1.x;
act_area.x2 = p2.x;
act_area.y1 = p1.y - width_half - width_1;
act_area.y2 = 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);
return;
}
/*Special case draw a vertical line*/
if(p1.x == p2.x ) {
lv_area_t act_area;
act_area.x1 = p1.x - width_half;
act_area.x2 = p2.x + width_half + width_1;
act_area.y1 = p1.y;
act_area.y2 = 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);
return;
}
while(1){
if(hor == true && last_y != act_point.y) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x;
act_area.x2 = act_point.x - sx;
act_area.y1 = last_y - width_half ;
act_area.y2 = act_point.y - sy + width_half + width_1;
last_y = act_point.y;
last_x = act_point.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 (hor == false && last_x != act_point.x) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x - width_half;
act_area.x2 = act_point.x - sx + width_half + width_1;
act_area.y1 = last_y ;
act_area.y2 = act_point.y - sy;
last_y = act_point.y;
last_x = act_point.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_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 (act_point.x == p2.x && act_point.y == p2.y) break;
e2 = err;
if (e2 >-dx) {
err -= dy;
act_point.x += sx;
}
if (e2 < dy) {
err += dx;
act_point.y += sy;
}
}
/*Draw the last part of the line*/
if(hor == true) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x;
act_area.x2 = act_point.x;
act_area.y1 = last_y - width_half ;
act_area.y2 = act_point.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 (hor == false) {
lv_area_t act_area;
lv_area_t draw_area;
act_area.x1 = last_x - width_half;
act_area.x2 = act_point.x + width_half + width_1;
act_area.y1 = last_y;
act_area.y2 = act_point.y;
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_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
}
}
......@@ -682,7 +784,8 @@ void lv_draw_line(const lv_point_t * p1, const lv_point_t * p2, const lv_area_t
*/
static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
uint16_t radius = style->body.radius << LV_AA;
uint16_t radius = style->body.radius;
lv_color_t mcolor = style->body.main_color;
lv_color_t gcolor = style->body.grad_color;
......@@ -703,17 +806,29 @@ static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * ma
if(mcolor.full == gcolor.full) {
work_area.y1 = coords->y1 + radius;
work_area.y2 = coords->y2 - radius;
#if LV_ANTIALIAS
if(style->body.radius != 0) {
work_area.y1 += LV_ANTIALIAS * 2;
work_area.y2 -= LV_ANTIALIAS * 2;
}
#endif
fill_fp(&work_area, mask, mcolor, opa);
} else {
lv_coord_t row;
lv_coord_t row_start = coords->y1 + radius;
lv_coord_t row_end = coords->y2 - radius;
lv_color_t act_color;
#if LV_ANTIALIAS
if(style->body.radius != 0) {
row_start += LV_ANTIALIAS * 2;
row_end -= LV_ANTIALIAS * 2;
}
#endif
if(row_start < 0) row_start = 0;
for(row = row_start ;
row <= row_end;
row ++)
for(row = row_start; row <= row_end; row ++)
{
work_area.y1 = row;
work_area.y2 = row;
......@@ -732,7 +847,7 @@ static void lv_draw_rect_main_mid(const lv_area_t * coords, const lv_area_t * ma
*/
static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
uint16_t radius = style->body.radius << LV_AA;
uint16_t radius = style->body.radius;
lv_color_t mcolor = style->body.main_color;
lv_color_t gcolor = style->body.grad_color;
......@@ -749,25 +864,23 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
lv_point_t rt_origo; /*Right Top origo*/
lv_point_t rb_origo; /*Left Bottom origo*/
lt_origo.x = coords->x1 + radius;
lt_origo.y = coords->y1 + radius;
lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;
lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
lb_origo.x = coords->x1 + radius;
lb_origo.y = coords->y2 - radius;
lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;
lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
rt_origo.x = coords->x2 - radius;
rt_origo.y = coords->y1 + radius;
rb_origo.x = coords->x2 - radius;
rb_origo.y = coords->y2 - radius;
rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;
rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;
rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
lv_area_t edge_top_area;
lv_area_t mid_top_area;
lv_area_t mid_bot_area;
lv_area_t edge_bot_area;
lv_point_t cir;
lv_coord_t cir_tmp;
lv_circ_init(&cir, &cir_tmp, radius);
......@@ -792,40 +905,76 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
lt_origo.y + LV_CIRC_OCT6_Y(cir),
rt_origo.x + LV_CIRC_OCT7_X(cir),
rt_origo.y + LV_CIRC_OCT7_Y(cir));
#if LV_ANTIALIAS
/*Store some internal states for anti-aliasing*/
lv_coord_t out_y_seg_start = 0;
lv_coord_t out_y_seg_end = 0;
lv_coord_t out_x_last = radius;
lv_color_t aa_color_hor_top;
lv_color_t aa_color_hor_bottom;
lv_color_t aa_color_ver;
#endif
while(lv_circ_cont(&cir)) {
#if LV_ANTIALIAS != 0
/*New step in y on the outter circle*/
if(out_x_last != cir.x) {
out_y_seg_end = cir.y;
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
lv_point_t aa_p;
printf("x: %d, y:%d\n", out_x_last, out_y_seg_start);
aa_p.x = out_x_last;
aa_p.y = out_y_seg_start;
mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;
aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);
aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);
lv_coord_t i;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa;
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
aa_opa = antialias_get_opa_circ(seg_size, i, style->body.opa);
} else {
aa_opa = opa - antialias_get_opa(seg_size, i, style->body.opa);
}
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_bottom, aa_opa);
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_top, aa_opa);
mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;
aa_color_ver = lv_color_mix(mcolor, gcolor, mix);
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
aa_color_ver = lv_color_mix(gcolor, mcolor, mix);
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
}
out_x_last = cir.x;
out_y_seg_start = out_y_seg_end;
}
#endif
uint8_t edge_top_refr = 0;
uint8_t mid_top_refr = 0;
uint8_t mid_bot_refr = 0;
uint8_t edge_bot_refr = 0;
/*If a new row coming draw the previous
* The x coordinate can grow on the same y so wait for the last x*/
if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y ) {
mid_bot_refr = 1;
}
if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) {
edge_bot_refr = 1;
}
if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) {
mid_top_refr = 1;
}
/* If a new row coming draw the previous
* The y coordinate can remain the same so wait for a new*/
if(mid_bot_area.y1 != LV_CIRC_OCT4_Y(cir) + lb_origo.y ) mid_bot_refr = 1;
if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) {
edge_top_refr = 1;
}
if(edge_bot_area.y1 != LV_CIRC_OCT2_Y(cir) + lb_origo.y) edge_bot_refr = 1;
/* Do not refresh the first row in the middle
* because the body drawer makes it*/
if(mid_bot_area.y1 == coords->y2 - radius){
mid_bot_refr = 0;
}
if(mid_top_area.y1 != LV_CIRC_OCT8_Y(cir) + lt_origo.y) mid_top_refr = 1;
if(mid_top_area.y1 == coords->y1 + radius){
mid_top_refr = 0;
}
if(edge_top_area.y1 != LV_CIRC_OCT7_Y(cir) + lt_origo.y) edge_top_refr = 1;
/*Draw the areas which are not disabled*/
if(edge_top_refr != 0){
......@@ -864,6 +1013,7 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
}
fill_fp(&edge_bot_area, mask, act_color, opa);
}
/*Save the current coordinates*/
lv_area_set(&mid_bot_area, lb_origo.x + LV_CIRC_OCT4_X(cir),
lb_origo.y + LV_CIRC_OCT4_Y(cir),
......@@ -888,7 +1038,6 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
lv_circ_next(&cir, &cir_tmp);
}
if(mcolor.full == gcolor.full) act_color = mcolor;
else {
mix = (uint32_t)((uint32_t)(coords->y2 - edge_top_area.y1) * 255) / height;
......@@ -923,6 +1072,69 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
fill_fp(&edge_bot_area, mask, act_color, opa);
}
#if LV_ANTIALIAS
/*The first and the last line is not drawn*/
edge_top_area.x1 = coords->x1 + radius + 2;
edge_top_area.x2 = coords->x2 - radius - 2;
edge_top_area.y1 = coords->y1;
edge_top_area.y2 = coords->y1;
fill_fp(&edge_top_area, mask, style->body.main_color, opa);
edge_top_area.y1 = coords->y2;
edge_top_area.y2 = coords->y2;
fill_fp(&edge_top_area, mask, style->body.grad_color, opa);
/*Last parts of the anti-alias*/
out_y_seg_end = cir.y;
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
lv_point_t aa_p;
aa_p.x = out_x_last;
aa_p.y = out_y_seg_start;
mix = (uint32_t)((uint32_t)(radius - out_x_last) * 255) / height;
aa_color_hor_bottom = lv_color_mix(gcolor, mcolor, mix);
aa_color_hor_top = lv_color_mix(mcolor, gcolor, mix);
lv_coord_t i;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa = opa - antialias_get_opa(seg_size, i, opa);
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, aa_color_hor_top, aa_opa);
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, aa_color_hor_bottom, aa_opa);
mix = (uint32_t)((uint32_t)(radius - out_y_seg_start + i) * 255) / height;
aa_color_ver = lv_color_mix(mcolor, gcolor, mix);
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, aa_color_ver, aa_opa);
aa_color_ver = lv_color_mix(gcolor, mcolor, mix);
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, aa_color_ver, aa_opa);
}
/*In some cases the last pixel is not drawn*/
if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {
printf("body out miss\n");
aa_p.x = out_x_last;
aa_p.y = out_x_last;
mix = (uint32_t)((uint32_t)(out_x_last) * 255) / height;
aa_color_hor_top = lv_color_mix(gcolor, mcolor, mix);
aa_color_hor_bottom = lv_color_mix(mcolor, gcolor, mix);
lv_opa_t aa_opa = style->body.opa >> 1;
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, aa_color_hor_bottom, aa_opa);
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, aa_color_hor_top, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, aa_color_hor_top, aa_opa);
}
#endif
}
/**
......@@ -933,11 +1145,11 @@ static void lv_draw_rect_main_corner(const lv_area_t * coords, const lv_area_t *
*/
static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
uint16_t radius = style->body.radius << LV_AA;
uint16_t radius = style->body.radius;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
uint16_t bwidth = style->body.border.width << LV_AA;
uint16_t bwidth = style->body.border.width;
lv_opa_t opa = style->body.border.opa;
lv_border_part_t part = style->body.border.part;
lv_color_t color = style->body.border.color;
......@@ -951,16 +1163,15 @@ static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area
radius = lv_draw_cont_radius_corr(radius, width, height);
if(radius < bwidth) {
length_corr = bwidth - radius;
length_corr = bwidth - radius - LV_ANTIALIAS;
corner_size = bwidth;
} else {
corner_size = radius;
corner_size = radius + LV_ANTIALIAS;
}
/* Modify the corner_size if corner is drawn */
corner_size ++;
/*Depending one which part's are drawn modify the area lengths */
if(part & LV_BORDER_TOP) work_area.y1 = coords->y1 + corner_size;
else work_area.y1 = coords->y1 + radius;
......@@ -999,22 +1210,22 @@ static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area
fill_fp(&work_area, mask, color, opa);
}
/*Draw the a remaining rectangles if the radius is smaller then b_width */
/*Draw the a remaining rectangles if the radius is smaller then bwidth */
if(length_corr != 0) {
/*Left top correction*/
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
work_area.x1 = coords->x1;
work_area.x2 = coords->x1 + radius;
work_area.y1 = coords->y1 + radius + 1;
work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;
work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;
work_area.y2 = coords->y1 + bwidth;
fill_fp(&work_area, mask, color, opa);
}
/*Right top correction*/
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
work_area.x1 = coords->x2 - radius;
work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;
work_area.x2 = coords->x2;
work_area.y1 = coords->y1 + radius + 1;
work_area.y1 = coords->y1 + radius + 1 + LV_ANTIALIAS;
work_area.y2 = coords->y1 + bwidth;
fill_fp(&work_area, mask, color, opa);
}
......@@ -1022,23 +1233,23 @@ static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area
/*Left bottom correction*/
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
work_area.x1 = coords->x1;
work_area.x2 = coords->x1 + radius;
work_area.x2 = coords->x1 + radius + LV_ANTIALIAS;
work_area.y1 = coords->y2 - bwidth;
work_area.y2 = coords->y2 - radius - 1;
work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;
fill_fp(&work_area, mask, color, opa);
}
/*Right bottom correction*/
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
work_area.x1 = coords->x2 - radius;
work_area.x1 = coords->x2 - radius - LV_ANTIALIAS;
work_area.x2 = coords->x2;
work_area.y1 = coords->y2 - bwidth;
work_area.y2 = coords->y2 - radius - 1;
work_area.y2 = coords->y2 - radius - 1 - LV_ANTIALIAS;
fill_fp(&work_area, mask, color, opa);
}
}
/*If radius == 0 one px on the corners are not drawn*/
/*If radius == 0 one px on the corners are not drawn by main drawer*/
if(radius == 0) {
/*Left top corner*/
......@@ -1089,8 +1300,8 @@ static void lv_draw_rect_border_straight(const lv_area_t * coords, const lv_area
*/
static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
uint16_t radius = style->body.radius << LV_AA;
uint16_t bwidth = style->body.border.width << LV_AA;
uint16_t radius = style->body.radius ;
uint16_t bwidth = style->body.border.width;
lv_color_t color = style->body.border.color;
lv_opa_t opa = style->body.border.opa;
lv_border_part_t part = style->body.border.part;
......@@ -1098,6 +1309,10 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
/*0 px border width drawn as 1 px, so decrement the bwidth*/
bwidth--;
#if LV_ANTIALIAS
bwidth--; /*Because of anti-aliasing the border seems one pixel ticker*/
#endif
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
......@@ -1108,17 +1323,17 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
lv_point_t rt_origo; /*Right Top origo*/
lv_point_t rb_origo; /*Left Bottom origo*/
lt_origo.x = coords->x1 + radius;
lt_origo.y = coords->y1 + radius;
lt_origo.x = coords->x1 + radius + LV_ANTIALIAS;
lt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
lb_origo.x = coords->x1 + radius;
lb_origo.y = coords->y2 - radius;
lb_origo.x = coords->x1 + radius + LV_ANTIALIAS;
lb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
rt_origo.x = coords->x2 - radius;
rt_origo.y = coords->y1 + radius;
rt_origo.x = coords->x2 - radius - LV_ANTIALIAS;
rt_origo.y = coords->y1 + radius + LV_ANTIALIAS;
rb_origo.x = coords->x2 - radius;
rb_origo.y = coords->y2 - radius;
rb_origo.x = coords->x2 - radius - LV_ANTIALIAS;
rb_origo.y = coords->y2 - radius - LV_ANTIALIAS;
lv_point_t cir_out;
lv_coord_t tmp_out;
......@@ -1138,6 +1353,18 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
lv_coord_t act_w1;
lv_coord_t act_w2;
#if LV_ANTIALIAS
/*Store some internal states for anti-aliasing*/
lv_coord_t out_y_seg_start = 0;
lv_coord_t out_y_seg_end = 0;
lv_coord_t out_x_last = radius;
lv_coord_t in_y_seg_start = 0;
lv_coord_t in_y_seg_end = 0;
lv_coord_t in_x_last = radius - bwidth;
#endif
while( cir_out.y <= cir_out.x) {
/*Calculate the actual width to avoid overwriting pixels*/
......@@ -1149,6 +1376,116 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
act_w2 = act_w1 - 1;
}
#if LV_ANTIALIAS != 0
/*New step in y on the outter circle*/
if(out_x_last != cir_out.x) {
out_y_seg_end = cir_out.y;
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
lv_point_t aa_p;
aa_p.x = out_x_last;
aa_p.y = out_y_seg_start;
lv_coord_t i;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa;
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
aa_opa = antialias_get_opa_circ(seg_size, i, style->body.border.opa);
} else {
aa_opa = style->body.border.opa - antialias_get_opa(seg_size, i, style->body.border.opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
}
out_x_last = cir_out.x;
out_y_seg_start = out_y_seg_end;
}
/*New step in y on the inner circle*/
if(in_x_last != cir_in.x) {
in_y_seg_end = cir_out.y;
lv_coord_t seg_size = in_y_seg_end - in_y_seg_start;
lv_point_t aa_p;
aa_p.x = in_x_last;
aa_p.y = in_y_seg_start;
lv_coord_t i;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa;
if(seg_size > CIRCLE_AA_NON_LINEAR_OPA_THRESHOLD) { /*Use non-linear opa mapping on the first segment*/
aa_opa = style->body.border.opa - antialias_get_opa_circ(seg_size, i, style->body.border.opa);
} else {
aa_opa = antialias_get_opa(seg_size, i, style->body.border.opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
/*Be sure the pixels on the middle are not drawn twice*/
if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
}
}
in_x_last = cir_in.x;
in_y_seg_start = in_y_seg_end;
}
#endif
/*Draw the octets to the right bottom corner*/
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
circ_area.x1 = rb_origo.x + LV_CIRC_OCT1_X(cir_out) - act_w2;
......@@ -1178,7 +1515,7 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
circ_area.y2 = lb_origo.y + LV_CIRC_OCT4_Y(cir_out);
fill_fp(&circ_area, mask, color, opa);
}
/*Draw the octets to the left top corner*/
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
if(lb_origo.y + LV_CIRC_OCT4_Y(cir_out) > lt_origo.y + LV_CIRC_OCT5_Y(cir_out)) {
......@@ -1196,7 +1533,7 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
circ_area.y2 = lt_origo.y + LV_CIRC_OCT6_Y(cir_out) + act_w1;
fill_fp(&circ_area, mask, color, opa);
}
/*Draw the octets to the right top corner*/
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
circ_area.x1 = rt_origo.x + LV_CIRC_OCT7_X(cir_out);
......@@ -1222,6 +1559,111 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
lv_circ_next(&cir_in, &tmp_in);
}
}
#if LV_ANTIALIAS != 0
/*Last parts of the outer anti-alias*/
out_y_seg_end = cir_out.y;
lv_coord_t seg_size = out_y_seg_end - out_y_seg_start;
lv_point_t aa_p;
aa_p.x = out_x_last;
aa_p.y = out_y_seg_start;
lv_coord_t i;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa = style->body.border.opa - antialias_get_opa(seg_size, i, style->body.border.opa);
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) + 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) - 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) - 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) + 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
}
/*In some cases the last pixel in the outer middle is not drawn*/
if(LV_MATH_ABS(aa_p.x - aa_p.y) == seg_size) {
aa_p.x = out_x_last;
aa_p.y = out_x_last;
lv_opa_t aa_opa = style->body.border.opa >> 1;
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p), rb_origo.y + LV_CIRC_OCT2_Y(aa_p), mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p), lb_origo.y + LV_CIRC_OCT4_Y(aa_p), mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p), lt_origo.y + LV_CIRC_OCT6_Y(aa_p), mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p), rt_origo.y + LV_CIRC_OCT8_Y(aa_p), mask, style->body.border.color, aa_opa);
}
}
/*Last parts of the inner anti-alias*/
in_y_seg_end = cir_in.y;
aa_p.x = in_x_last;
aa_p.y = in_y_seg_start;
seg_size = in_y_seg_end - in_y_seg_start;
for(i = 0; i < seg_size; i++) {
lv_opa_t aa_opa = antialias_get_opa(seg_size, i, style->body.border.opa);
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT1_X(aa_p) - 1, rb_origo.y + LV_CIRC_OCT1_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT3_X(aa_p) - i, lb_origo.y + LV_CIRC_OCT3_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT5_X(aa_p) + 1, lt_origo.y + LV_CIRC_OCT5_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT7_X(aa_p) + i, rt_origo.y + LV_CIRC_OCT7_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
if(LV_CIRC_OCT1_X(aa_p) - 1 != LV_CIRC_OCT2_X(aa_p) + i) {
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_RIGHT)) {
px_fp(rb_origo.x + LV_CIRC_OCT2_X(aa_p) + i, rb_origo.y + LV_CIRC_OCT2_Y(aa_p) - 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_BOTTOM) && (part & LV_BORDER_LEFT)) {
px_fp(lb_origo.x + LV_CIRC_OCT4_X(aa_p) + 1, lb_origo.y + LV_CIRC_OCT4_Y(aa_p) + i, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_LEFT)) {
px_fp(lt_origo.x + LV_CIRC_OCT6_X(aa_p) - i, lt_origo.y + LV_CIRC_OCT6_Y(aa_p) + 1, mask, style->body.border.color, aa_opa);
}
if((part & LV_BORDER_TOP) && (part & LV_BORDER_RIGHT)) {
px_fp(rt_origo.x + LV_CIRC_OCT8_X(aa_p) - 1, rt_origo.y + LV_CIRC_OCT8_Y(aa_p) - i, mask, style->body.border.color, aa_opa);
}
}
}
#endif
}
#if USE_LV_SHADOW && LV_VDB_SIZE
......@@ -1234,7 +1676,7 @@ static void lv_draw_rect_border_corner(const lv_area_t * coords, const lv_area_t
static void lv_draw_rect_shadow(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
/* If mask is in the middle of cords do not draw shadow*/
lv_coord_t radius = style->body.radius << LV_AA;
lv_coord_t radius = style->body.radius;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
radius = lv_draw_cont_radius_corr(radius, width, height);
......@@ -1262,35 +1704,35 @@ static void lv_draw_rect_shadow(const lv_area_t * coords, const lv_area_t * mask
static void lv_draw_cont_shadow_full(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
lv_coord_t radius = style->body.radius << LV_AA;
lv_coord_t swidth = style->body.shadow.width << LV_AA;
lv_coord_t radius = style->body.radius;
lv_coord_t swidth = style->body.shadow.width;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
radius = lv_draw_cont_radius_corr(radius, width, height);
lv_coord_t cruve_x[radius + swidth]; /*Stores the 'x' coordinates of a quarter circle.*/
memset(cruve_x, 0, sizeof(cruve_x));
lv_coord_t curve_x[radius + swidth]; /*Stores the 'x' coordinates of a quarter circle.*/
memset(curve_x, 0, sizeof(curve_x));
lv_point_t circ;
lv_coord_t circ_tmp;
lv_circ_init(&circ, &circ_tmp, radius);
while(lv_circ_cont(&circ)) {
cruve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);
cruve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);
curve_x[LV_CIRC_OCT1_Y(circ)] = LV_CIRC_OCT1_X(circ);
curve_x[LV_CIRC_OCT2_Y(circ)] = LV_CIRC_OCT2_X(circ);
lv_circ_next(&circ, &circ_tmp);
}
int16_t row;
int16_t line;
int16_t filter_size = 2 * swidth + 1;
uint16_t opa_h_result[filter_size];
uint16_t line_1d_blur[filter_size];
for(row = 0; row < filter_size; row++) {
opa_h_result[row] = (uint32_t)((uint32_t)(filter_size - row) * style->body.opa * 2) / (filter_size);
/*1D Blur horizontally*/
for(line = 0; line < filter_size; line++) {
line_1d_blur[line] = (uint32_t)((uint32_t)(filter_size - line) * style->body.opa * 2) / filter_size;
}
uint16_t p;
lv_opa_t opa_v_result[radius + swidth];
uint16_t col;
lv_opa_t line_2d_blur[radius + swidth];
lv_point_t point_rt;
lv_point_t point_rb;
......@@ -1312,77 +1754,64 @@ static void lv_draw_cont_shadow_full(const lv_area_t * coords, const lv_area_t *
ofs_lt.x = coords->x1 + radius;
ofs_lt.y = coords->y1 + radius;
for(row = 0; row < radius + swidth; row++) {
for(p = 0; p < radius + swidth; p++) {
int16_t v;
uint32_t opa_tmp = 0;
int16_t row_v;
bool swidth_out = false;
for(v = -swidth; v < swidth; v++) {
row_v = row + v;
if(row_v < 0) row_v = 0; /*Rows above the corner*/
/*Rows below the bottom are empty so they won't modify the filter*/
if(row_v > radius) {
break;
}
else
{
int16_t p_tmp = p - (cruve_x[row_v] - cruve_x[row]);
if(p_tmp < -swidth) { /*Cols before the filtered shadow (still not blurred)*/
opa_tmp += style->body.opa * 2;
}
/*Cols after the filtered shadow (already no effect) */
else if (p_tmp > swidth) {
/* If on the current point the filter top point is already out of swidth then
* the remaining part will not do not anything on this point*/
if(v == -swidth) { /*Is the first point?*/
swidth_out = true;
}
break;
} else {
opa_tmp += opa_h_result[p_tmp + swidth];
}
}
}
if(swidth_out == false) {
opa_tmp = opa_tmp / (filter_size);
opa_v_result[p] = opa_tmp > LV_OPA_COVER ? LV_OPA_COVER : opa_tmp;
}
else {
break;
}
}
for(line = 0; line <= radius + swidth; line++) { /*Check all rows and make the 1D blur to 2D*/
for(col = 0; col < radius + swidth; col++) { /*Check all pixels in a 1D blur line (from the origo to last shadow pixel (radius + swidth))*/
/*Sum the opacities from the lines above and below this 'row'*/
int16_t line_rel;
int16_t col_rel;
uint32_t px_opa_sum = 0;
for(line_rel = -swidth; line_rel <= swidth; line_rel ++) {
int16_t x_shift;
if(line + line_rel < 0) { /*Below the radius, here is the blur of the edge */
x_shift = curve_x[line] + col;
if(x_shift - radius <= -swidth) px_opa_sum += style->body.opa * 2; /*Pointing inside, where no blur*/
else if(x_shift - radius >= swidth) px_opa_sum += 0; /*Already no blurred pixels here*/
else px_opa_sum += line_1d_blur[x_shift - radius + swidth]; /*On the 1D blur*/
}
else if(line + line_rel > radius) { /*Above the radius, here won't be more 1D blur*/
break;
} else { /*Blur from the curve*/
x_shift = curve_x[line_rel] - curve_x[line_rel] + col;
if(x_shift <= -swidth) px_opa_sum += style->body.opa * 2; /*Inside the not blurred area*/
else if (x_shift >= swidth) px_opa_sum += 0; /*Outside of the burred area*/
else px_opa_sum += line_1d_blur[x_shift + swidth]; /*In the blur (+ swidth to align to the center)*/
}
}
point_rt.x = cruve_x[row] + ofs_rt.x;
point_rt.y = ofs_rt.y - row;
line_2d_blur[col] = px_opa_sum / (radius + swidth);
}
/*Flush the line*/
point_rt.x = curve_x[line] + ofs_rt.x;
point_rt.y = ofs_rt.y - line;
point_rb.x = cruve_x[row] + ofs_rb.x;
point_rb.y = ofs_rb.y + row;
point_rb.x = curve_x[line] + ofs_rb.x;
point_rb.y = ofs_rb.y + line;
point_lt.x = ofs_lt.x - cruve_x[row];
point_lt.y = ofs_lt.y - row;
point_lt.x = ofs_lt.x - curve_x[line];
point_lt.y = ofs_lt.y - line;
point_lb.x = ofs_lb.x - cruve_x[row];
point_lb.y = ofs_lb.y + row;
point_lb.x = ofs_lb.x - curve_x[line];
point_lb.y = ofs_lb.y + line;
uint16_t d;
for(d = 0; d < p; d++) {
for(d = 0; d < col; d++) {
if(point_rt.x != point_lt.x) {
px_fp(point_lt.x,point_lt.y , mask, style->body.shadow.color, opa_v_result[d]);
px_fp(point_lt.x,point_lt.y , mask, style->body.shadow.color, line_2d_blur[d]);
}
if(point_rb.x != point_lb.x && point_lt.y != point_lb.y) {
px_fp(point_lb.x,point_lb.y , mask, style->body.shadow.color, opa_v_result[d]);
px_fp(point_lb.x,point_lb.y , mask, style->body.shadow.color, line_2d_blur[d]);
}
if(point_lt.y != point_lb.y) {
px_fp(point_rb.x,point_rb.y , mask, style->body.shadow.color, opa_v_result[d]);
px_fp(point_rb.x,point_rb.y , mask, style->body.shadow.color, line_2d_blur[d]);
}
px_fp(point_rt.x,point_rt.y , mask, style->body.shadow.color, opa_v_result[d]);
px_fp(point_rt.x,point_rt.y , mask, style->body.shadow.color, line_2d_blur[d]);
point_rb.x++;
......@@ -1391,19 +1820,99 @@ static void lv_draw_cont_shadow_full(const lv_area_t * coords, const lv_area_t *
point_rt.x++;
point_lt.x--;
}
/*When the first row is known draw the straight pars with same opa. map*/
if(row == 0) {
lv_draw_cont_shadow_full_straight(coords, mask, style, opa_v_result);
}
// for(p = 0; p < radius + swidth; p++) { /*Check all pixels in a row (from the origo to last shadow pixel (radius + swidth))*/
// int16_t v;
// uint32_t opa_tmp = 0;
// int16_t row_v;
// bool swidth_out = false;
//
// /* Count the sum of 1D blur 'lines'
// * v: relative 1D blur 'line' to this 'row' */
// for(v = -swidth; v <= swidth; v++) {
// row_v = row + v;
// if(row_v < 0) row_v = 0; /*Rows below the corner are the same as the last 1D blur (they are blurred from a straight edge)*/
//
// /*Rows above the bottom are empty so they won't modify the filter*/
// if(row_v > radius) {
// break;
// }
// else
// {
// int16_t p_tmp = p - (cruve_x[row_v] - cruve_x[row]); /*cruve_x[row_v]: 1D blur line start*/
// if(p_tmp < -swidth) { /*Cols before the filtered shadow (still not blurred)*/
// opa_tmp += style->body.opa * 2;
// }
// /*Cols after the filtered shadow (already no effect) */
// else if (p_tmp > swidth) {
// /* If on the current point the filter top point is already out of swidth then
// * the remaining part will not do not anything on this point*/
// if(v == -swidth) { /*Is the first point?*/
// swidth_out = true;
// }
// break;
// } else {
// opa_tmp += opa_h_result[p_tmp + swidth];
// }
// }
// }
// if(swidth_out == false) {
// opa_tmp = opa_tmp / (filter_size);
// opa_v_result[p] = opa_tmp > LV_OPA_COVER ? LV_OPA_COVER : opa_tmp;
// }
// else {
// break;
// }
// }
//
// point_rt.x = cruve_x[row] + ofs_rt.x;
// point_rt.y = ofs_rt.y - row;
//
// point_rb.x = cruve_x[row] + ofs_rb.x;
// point_rb.y = ofs_rb.y + row;
//
// point_lt.x = ofs_lt.x - cruve_x[row];
// point_lt.y = ofs_lt.y - row;
//
// point_lb.x = ofs_lb.x - cruve_x[row];
// point_lb.y = ofs_lb.y + row;
//
// uint16_t d;
// for(d = 0; d < p; d++) {
//
// if(point_rt.x != point_lt.x) {
// px_fp(point_lt.x,point_lt.y , mask, style->body.shadow.color, opa_v_result[d]);
// }
//
// if(point_rb.x != point_lb.x && point_lt.y != point_lb.y) {
// px_fp(point_lb.x,point_lb.y , mask, style->body.shadow.color, opa_v_result[d]);
// }
//
// if(point_lt.y != point_lb.y) {
// px_fp(point_rb.x,point_rb.y , mask, style->body.shadow.color, opa_v_result[d]);
// }
//
// px_fp(point_rt.x,point_rt.y , mask, style->body.shadow.color, opa_v_result[d]);
//
//
// point_rb.x++;
// point_lb.x--;
//
// point_rt.x++;
// point_lt.x--;
// }
//
// /*When the first row is known draw the straight pars with same opa. map*/
// if(row == 0) {
// lv_draw_cont_shadow_full_straight(coords, mask, style, opa_v_result);
// }
}
}
static void lv_draw_cont_shadow_bottom(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style)
{
lv_coord_t radius = style->body.radius << LV_AA;
lv_coord_t swidth = style->body.shadow.width << LV_AA;
lv_coord_t radius = style->body.radius;
lv_coord_t swidth = style->body.shadow.width;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
......@@ -1474,8 +1983,8 @@ static void lv_draw_cont_shadow_bottom(const lv_area_t * coords, const lv_area_t
static void lv_draw_cont_shadow_full_straight(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, const lv_opa_t * map)
{
lv_coord_t radius = style->body.radius << LV_AA;
lv_coord_t swidth = style->body.shadow.width << LV_AA;
lv_coord_t radius = style->body.radius;
lv_coord_t swidth = style->body.shadow.width;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);
......@@ -1494,7 +2003,7 @@ static void lv_draw_cont_shadow_full_straight(const lv_area_t * coords, const lv
sidel_area.y2 = coords->y2 - radius - 1;
lv_area_t sidet_area;
sidet_area.x1 = coords->x1 + radius + 1;
sidet_area.x1 = coords->x1 + radius + 1 + LV_ANTIALIAS;
sidet_area.y1 = coords->y1;
sidet_area.x2 = coords->x2 - radius - 1;
sidet_area.y2 = sidet_area.y1;
......@@ -1539,9 +2048,77 @@ static uint16_t lv_draw_cont_radius_corr(uint16_t r, lv_coord_t w, lv_coord_t h)
if(r != 0) r--;
}
if(r > 0) r -= LV_ANTIALIAS;
return r;
}
#if LV_ANTIALIAS != 0
static lv_opa_t antialias_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t line_opa)
{
/* How to calculate the opacity of pixels on the edges which makes the anti-aliasing?
* For example we have a line like this (y = -0.5 * x):
*
* | _ _
* * * |
*
* Anti-aliased pixels come to the '*' characters
* Calculate what percentage of the pixels should be covered if real line (not rasterized) would be drawn:
* 1. A real line should start on (0;0) and end on (2;1)
* 2. So the line intersection coordinates on the first pixel: (0;0) (1;0.5) -> 25% covered pixel in average
* 3. For the second pixel: (1;0.5) (2;1) -> 75% covered pixel in average
* 4. The equation: (px_id * 2 + 1) / (segment_width * 2)
* segment_width: the line segment which is being anti-aliased (was 2 in the example)
* px_id: pixel ID from 0 to (segment_width - 1)
* result: [0..1] coverage of the pixel
*/
/*Accelerate the common segment sizes to avoid division*/
static const lv_opa_t seg1[1] = {128};
static const lv_opa_t seg2[2] = {64, 192};
static const lv_opa_t seg3[3] = {42, 128, 212};
static const lv_opa_t seg4[4] = {32, 96, 159, 223};
static const lv_opa_t seg5[5] = {26, 76, 128, 178, 230};
static const lv_opa_t seg6[6] = {21, 64, 106, 148, 191, 234};
static const lv_opa_t seg7[7] = {18, 55, 91, 128, 164, 200, 237};
static const lv_opa_t seg8[8] = {16, 48, 80, 112, 143, 175, 207, 239};
static const lv_opa_t * seg_map[] = {seg1, seg2, seg3, seg4,
seg5, seg6, seg7, seg8};
if(seg == 0) return LV_OPA_TRANSP;
else if(seg < 8) return (uint32_t)((uint32_t)seg_map[seg - 1][px_id] * line_opa) >> 8;
else {
return ((px_id * 2 + 1) * line_opa) / (2 * seg);
}
}
/**
* Approximate the opacity for anti-aliasing.
* Used the first segment of a circle which is the longest and have the most non-linearity (cos)
* @param seg
* @param px_id
* @param line_opa
* @return
*/
static lv_opa_t antialias_get_opa_circ(lv_coord_t seg, lv_coord_t px_id, lv_opa_t opa)
{
static const lv_opa_t opa_map[8] = {250, 242, 221, 196, 163, 122, 74, 18};
if(seg == 0) return LV_OPA_TRANSP;
else if(seg == 1) return LV_OPA_80;
else {
uint8_t id = (uint32_t) ((uint32_t)px_id * (sizeof(opa_map) - 1)) / (seg - 1);
printf("id: %d, px/seg: %d/%d\n", id, px_id, seg);
return (uint32_t) ((uint32_t) opa_map[id] * opa) >> 8;
}
}
#endif
#if USE_LV_TRIANGLE != 0
/**
......
......@@ -109,7 +109,6 @@ void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const uint8_t * bitmap_p = lv_font_get_bitmap(font_p, letter);
uint8_t col, col_sub, row;
#if LV_FONT_ANTIALIAS == 0
for(row = 0; row < font_p->h_px; row ++) {
for(col = 0, col_sub = 7; col < w; col ++, col_sub--) {
if(*bitmap_p & (1 << col_sub)) {
......@@ -124,50 +123,7 @@ void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
/*Go to the next row*/
if(col_sub != 7) bitmap_p ++; /*Go to the next byte if it not done in the last step*/
}
#else
uint8_t width_byte = w >> 3; /*Width in bytes (e.g. w = 11 -> 2 bytes wide)*/
if(w & 0x7) width_byte++;
const uint8_t * map1_p = bitmap_p;
const uint8_t * map2_p = bitmap_p + width_byte;
uint8_t px_cnt;
uint8_t col_byte_cnt;
for(row = 0; row < (font_p->h_px >> 1); row ++) {
col_byte_cnt = 0;
col_sub = 7;
for(col = 0; col < (w >> 1); col ++) {
px_cnt = 0;
if((*map1_p & (1 << col_sub)) != 0) px_cnt++;
if((*map2_p & (1 << col_sub)) != 0) px_cnt++;
if(col_sub != 0) col_sub --;
else {
col_sub = 7;
col_byte_cnt ++;
map1_p ++;
map2_p ++;
}
if((*map1_p & (1 << col_sub)) != 0) px_cnt++;
if((*map2_p & (1 << col_sub)) != 0) px_cnt++;
if(col_sub != 0) col_sub --;
else {
col_sub = 7;
col_byte_cnt ++;
map1_p ++;
map2_p ++;
}
if(px_cnt != 0) {
lv_rpx(pos_p->x + col, pos_p->y + row, mask_p, lv_color_mix(color, LV_COLOR_SILVER, 63 * px_cnt), LV_OPA_COVER);
}
}
map1_p += width_byte;
map2_p += width_byte;
map1_p += width_byte - col_byte_cnt;
map2_p += width_byte - col_byte_cnt;
}
#endif
}
/**
......
......@@ -128,7 +128,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
#if USE_LV_GPU
static lv_color_t color_array_tmp[LV_HOR_RES << LV_ANTIALIAS]; /*Used by 'sw_color_fill'*/
static lv_color_t color_array_tmp[LV_HOR_RES]; /*Used by 'lv_disp_mem_blend'*/
static lv_coord_t last_width = -1;
lv_coord_t w = lv_area_get_width(&vdb_rel_a);
......
......@@ -19,7 +19,8 @@ extern "C" {
/*********************
* DEFINES
*********************/
#define TRIGO_SIN_MAX 32767
#define LV_TRIGO_SIN_MAX 32767
#define LV_TRIGO_SHIFT 15 /* >> LV_TRIGO_SHIFT to normalize*/
/**********************
* TYPEDEFS
......
......@@ -337,10 +337,10 @@ static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask)
/*Calculate the position a scale label*/
int16_t angle = (i * scale_angle) / (label_num - 1) + angle_ofs;
lv_coord_t y = (int32_t)((int32_t)lv_trigo_sin(angle) * r) / TRIGO_SIN_MAX;
lv_coord_t y = (int32_t)((int32_t)lv_trigo_sin(angle) * r) / LV_TRIGO_SIN_MAX;
y += y_ofs;
lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / TRIGO_SIN_MAX;
lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX;
x += x_ofs;
int16_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1);
......@@ -390,8 +390,8 @@ static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * mask)
for(i = 0; i < ext->needle_count; i++) {
/*Calculate the end point of a needle*/
int16_t needle_angle = (ext->values[i] - min) * angle / (max - min) + angle_ofs;
p_end.y = (lv_trigo_sin(needle_angle) * r) / TRIGO_SIN_MAX + y_ofs;
p_end.x = (lv_trigo_sin(needle_angle + 90) * r) / TRIGO_SIN_MAX + x_ofs;
p_end.y = (lv_trigo_sin(needle_angle) * r) / LV_TRIGO_SIN_MAX + y_ofs;
p_end.x = (lv_trigo_sin(needle_angle + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;
/*Draw the needle with the corresponding color*/
if(ext->needle_colors == NULL) style_needle.line.color = LV_GAUGE_DEF_NEEDLE_COLOR;
......
......@@ -74,7 +74,6 @@ lv_obj_t * lv_img_create(lv_obj_t * par, lv_obj_t * copy)
ext->w = lv_obj_get_width(new_img);
ext->h = lv_obj_get_height(new_img);
ext->transp = 0;
ext->upscale = 0;
ext->auto_size = 1;
/*Init the new object*/
......@@ -92,7 +91,6 @@ lv_obj_t * lv_img_create(lv_obj_t * par, lv_obj_t * copy)
} else {
lv_img_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
ext->auto_size = copy_ext->auto_size;
ext->upscale = copy_ext->upscale;
lv_img_set_file(new_img, copy_ext->fn);
/*Refresh the style with new signal function*/
......@@ -175,12 +173,6 @@ void lv_img_set_file(lv_obj_t * img, const char * fn)
ext->w = header.w;
ext->h = header.h;
ext->transp = header.transp;
#if LV_ANTIALIAS
if(ext->upscale == false) {
ext->w = ext->w >> LV_AA;
ext->h = ext->h >> LV_AA;
}
#endif
}
/*Handle symbol texts*/
else {
......@@ -225,25 +217,6 @@ void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en)
ext->auto_size = (autosize_en == false ? 0 : 1);
}
/**
* Enable the upscaling if LV_ANTIALIAS is enabled.
* If enabled the object size will be same as the picture size.
* @param img pointer to an image
* @param upscale_en true: upscale enable, false: upscale disable
*/
void lv_img_set_upscale(lv_obj_t * img, bool upscale_en)
{
lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
/*Upscale works only if antialiassing is enabled*/
#if LV_ANTIALIAS == 0
upscale_en = false;
#endif
ext->upscale = (upscale_en == false ? 0 : 1);
/*Refresh the image with the new size*/
lv_img_set_file(img, ext->fn);
}
/*=====================
* Getter functions
......@@ -275,18 +248,6 @@ bool lv_img_get_auto_size(lv_obj_t * img)
return ext->auto_size == 0 ? false : true;
}
/**
* Get the upscale enable attribute
* @param img pointer to an image
* @return true: upscale is enabled, false: upscale is disabled
*/
bool lv_img_get_upscale(lv_obj_t * img)
{
lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
return ext->upscale == 0 ? false : true;
}
/**********************
* STATIC FUNCTIONS
**********************/
......
......@@ -41,7 +41,6 @@ typedef struct
lv_coord_t w; /*Width of the image (doubled when upscaled) (Handled by the library)*/
lv_coord_t h; /*Height of the image (doubled when upscaled) (Handled by the library)*/
uint8_t auto_size :1; /*1: automatically set the object size to the image size*/
uint8_t upscale :1; /*1: upscale to double size with antialaissing*/
uint8_t transp :1; /*Transp. bit in the image header (Handled by the library)*/
uint8_t alpha_byte :1; /*Extra byte for every pixel to define opacity*/
}lv_img_ext_t;
......@@ -86,14 +85,6 @@ void lv_img_set_file(lv_obj_t * img, const char * fn);
void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en);
/**
* Enable the upscaling if LV_ANTIALIAS is enabled.
* If enabled the object size will be same as the picture size.
* @param img pointer to an image
* @param en true: upscale enable, false: upscale disable
*/
void lv_img_set_upscale(lv_obj_t * img, bool en);
/**
* Set the style of an image
* @param img pointer to an image object
* @param style pointer to a style
......@@ -123,13 +114,6 @@ const char * lv_img_get_file_name(lv_obj_t * img);
bool lv_img_get_auto_size(lv_obj_t * img);
/**
* Get the upscale enable attribute
* @param img pointer to an image
* @return true: upscale is enabled, false: upscale is disabled
*/
bool lv_img_get_upscale(lv_obj_t * img);
/**
* Get the style of an image object
* @param img pointer to an image object
* @return pointer to the image's style
......
......@@ -112,9 +112,11 @@ void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t po
ymax = LV_MATH_MAX(point_a[i].y, ymax);
}
lv_style_t * lines = lv_obj_get_style(line);
lv_obj_set_size(line, xmax + lines->line.width, ymax + lines->line.width);
lv_style_t * style = lv_line_get_style(line);
lv_obj_set_size(line, xmax + style->line.width, ymax + style->line.width);
}
lv_obj_invalidate(line);
}
/**
......
......@@ -18,6 +18,8 @@
/*********************
* DEFINES
*********************/
#define LV_LMETER_LINE_UPSCALE 5 /*2^x upscale of line to make rounding*/
#define LV_LMETER_LINE_UPSCALE_MASK ((1 << LV_LMETER_LINE_UPSCALE) - 1)
/**********************
* TYPEDEFS
......@@ -28,6 +30,7 @@
**********************/
static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_design_mode_t mode);
static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param);
static lv_coord_t lv_lmeter_coord_round(int32_t x);
/**********************
* STATIC VARIABLES
......@@ -237,7 +240,6 @@ static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_desig
else if(mode == LV_DESIGN_DRAW_MAIN) {
lv_lmeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
lv_style_t * style = lv_obj_get_style(lmeter);
lv_style_t style_tmp;
memcpy(&style_tmp, style, sizeof(lv_style_t));
......@@ -251,6 +253,8 @@ static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_desig
lv_coord_t r_out = lv_obj_get_width(lmeter) / 2;
lv_coord_t r_in = r_out - style->body.padding.hor;
if(r_in < 1) r_in = 1;
lv_coord_t x_ofs = lv_obj_get_width(lmeter) / 2 + lmeter->coords.x1;
lv_coord_t y_ofs = lv_obj_get_height(lmeter) / 2 + lmeter->coords.y1;
int16_t angle_ofs = 90 + (360 - ext->scale_angle) / 2;
......@@ -259,14 +263,24 @@ static bool lv_lmeter_design(lv_obj_t * lmeter, const lv_area_t * mask, lv_desig
style_tmp.line.color = style->body.main_color;
/*Calculate every coordinate in x32 size to make rounding later*/
r_out = r_out << LV_LMETER_LINE_UPSCALE;
r_in = r_in << LV_LMETER_LINE_UPSCALE;
for(i = 0; i < ext->line_cnt; i++) {
/*Calculate the position a scale label*/
int16_t angle = (i * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs;
lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) / TRIGO_SIN_MAX;
lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) / TRIGO_SIN_MAX;
lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) / TRIGO_SIN_MAX;
lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) / TRIGO_SIN_MAX;
lv_coord_t y_out = (int32_t)((int32_t)lv_trigo_sin(angle) * r_out) >> LV_TRIGO_SHIFT;
lv_coord_t x_out = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_out) >> LV_TRIGO_SHIFT;
lv_coord_t y_in = (int32_t)((int32_t)lv_trigo_sin(angle) * r_in) >> LV_TRIGO_SHIFT;
lv_coord_t x_in = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r_in) >> LV_TRIGO_SHIFT;
/*Rounding*/
x_out = lv_lmeter_coord_round(x_out);
x_in = lv_lmeter_coord_round(x_in);
y_out = lv_lmeter_coord_round(y_out);
y_in = lv_lmeter_coord_round(y_in);
lv_point_t p1;
lv_point_t p2;
......@@ -316,5 +330,30 @@ static lv_res_t lv_lmeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * par
return res;
}
/**
* Round a coordinate which is upscaled (>=x.5 -> x + 1; <x.5 -> x)
* @param x a coordinate which is greater then it should be
* @return the downscaled and rounded coordinate (+-1)
*/
static lv_coord_t lv_lmeter_coord_round(int32_t x)
{
#if LV_LMETER_LINE_UPSCALE > 0
bool was_negative;
if(x < 0) {
was_negative = true;
x = -x;
} else {
was_negative = false;
}
x = (x >> LV_LMETER_LINE_UPSCALE) + ((x & LV_LMETER_LINE_UPSCALE_MASK) >> (LV_LMETER_LINE_UPSCALE - 1));
if(was_negative) x = -x;
return x;
#else
return x;
#endif
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment