diff --git a/lv_draw/lv_draw.c b/lv_draw/lv_draw.c index eb236836ee..6cb561c5b4 100644 --- a/lv_draw/lv_draw.c +++ b/lv_draw/lv_draw.c @@ -21,37 +21,19 @@ /********************* * DEFINES *********************/ -#define LABEL_RECOLOR_PAR_LENGTH 6 /********************** * TYPEDEFS **********************/ -typedef enum -{ - CMD_STATE_WAIT, - CMD_STATE_PAR, - CMD_STATE_IN, -}cmd_state_t; - - /********************** * STATIC PROTOTYPES **********************/ - - -static uint8_t hex_char_to_num(char hex); - -#if USE_LV_TRIANGLE != 0 -static void point_swap(lv_point_t * p1, lv_point_t * p2); -#endif - - - /********************** * STATIC VARIABLES **********************/ + #if LV_VDB_SIZE != 0 void (*px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vpx; void (*fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa) = lv_vfill; @@ -91,361 +73,6 @@ static void (*map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, * GLOBAL FUNCTIONS **********************/ - -#if USE_LV_TRIANGLE != 0 -/** - * - * @param points pointer to an array with 3 points - * @param mask the triangle will be drawn only in this mask - * @param color color of the triangle - */ -void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color) -{ - lv_point_t tri[3]; - - memcpy(tri, points, sizeof(tri)); - - /*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/ - if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); - if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]); - if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); - - /*Return is the triangle is degenerated*/ - if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return; - if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return; - if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return; - - if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return; - if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return; - - /*Draw the triangle*/ - lv_point_t edge1; - lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x); - lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1; - lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y); - lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1; - lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; - lv_coord_t err_tmp1; - - lv_point_t edge2; - lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x); - lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1; - lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y); - lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1; - lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2; - lv_coord_t err_tmp2; - - lv_coord_t y1_tmp; - lv_coord_t y2_tmp; - - edge1.x = tri[0].x; - edge1.y = tri[0].y; - edge2.x = tri[0].x; - edge2.y = tri[0].y; - lv_area_t act_area; - lv_area_t draw_area; - - while(1) { - act_area.x1 = edge1.x; - act_area.x2 = edge2.x ; - act_area.y1 = edge1.y; - act_area.y2 = edge2.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); - draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/ - fill_fp(&draw_area, mask, color, LV_OPA_50); - - /*Calc. the next point of edge1*/ - y1_tmp = edge1.y; - do { - if (edge1.x == tri[1].x && edge1.y == tri[1].y) { - - dx1 = LV_MATH_ABS(tri[1].x - tri[2].x); - sx1 = tri[1].x < tri[2].x ? 1 : -1; - dy1 = LV_MATH_ABS(tri[1].y - tri[2].y); - sy1 = tri[1].y < tri[2].y ? 1 : -1; - err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; - } - else if (edge1.x == tri[2].x && edge1.y == tri[2].y) return; - err_tmp1 = err1; - if (err_tmp1 >-dx1) { - err1 -= dy1; - edge1.x += sx1; - } - if (err_tmp1 < dy1) { - err1 += dx1; - edge1.y += sy1; - } - } while(edge1.y == y1_tmp); - - /*Calc. the next point of edge2*/ - y2_tmp = edge2.y; - do { - if (edge2.x == tri[2].x && edge2.y == tri[2].y) return; - err_tmp2 = err2; - if (err_tmp2 > -dx2) { - err2 -= dy2; - edge2.x += sx2; - } - if (err_tmp2 < dy2) { - err2 += dx2; - edge2.y += sy2; - } - } while(edge2.y == y2_tmp); - } -} -#endif - -/** - * Write a text - * @param coords coordinates of the label - * @param mask the label will be drawn only in this area - * @param style pointer to a style - * @param txt 0 terminated text to write - * @param flag settings for the text from 'txt_flag_t' enum - * @param offset text offset in x and y direction (NULL if unused) - * - */ -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) -{ - - const lv_font_t * font = style->text.font; - lv_coord_t w; - if((flag & LV_TXT_FLAG_EXPAND) == 0) { - w = lv_area_get_width(coords); - } else { - lv_point_t p; - lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); - w = p.x; - } - - /*Init variables for the first line*/ - lv_coord_t line_length = 0; - uint32_t line_start = 0; - uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag); - - lv_point_t pos; - 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; - } - - cmd_state_t cmd_state = CMD_STATE_WAIT; - uint32_t i; - uint16_t par_start = 0; - lv_color_t recolor; - lv_coord_t letter_w; - - lv_coord_t x_ofs = 0; - lv_coord_t y_ofs = 0; - if(offset != NULL) { - x_ofs = offset->x; - y_ofs = offset->y; - pos.y += y_ofs; - } - - /*Real draw need a background color for higher bpp letter*/ -#if LV_VDB_SIZE == 0 - lv_rletter_set_background(style->body.main_color); -#endif - - /*Write out all lines*/ - while(txt[line_start] != '\0') { - if(offset != NULL) { - pos.x += x_ofs; - } - /*Write all letter of a line*/ - cmd_state = CMD_STATE_WAIT; - i = line_start; - uint32_t letter; - while(i < line_end) { - letter = lv_txt_utf8_next(txt, &i); - /*Handle the re-color command*/ - if((flag & LV_TXT_FLAG_RECOLOR) != 0) { - if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) { - if(cmd_state == CMD_STATE_WAIT) { /*Start char*/ - par_start = i;// + lv_txt_utf8_size(txt[i]); - cmd_state = CMD_STATE_PAR; - continue; - } else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */ - cmd_state = CMD_STATE_WAIT; - }else if(cmd_state == CMD_STATE_IN) { /*Command end */ - cmd_state = CMD_STATE_WAIT; - continue; - } - } - - /*Skip the color parameter and wait the space after it*/ - if(cmd_state == CMD_STATE_PAR) { - if(letter == ' ') { - /*Get the parameter*/ - 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; - r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]); - g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]); - b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]); - recolor = LV_COLOR_MAKE(r, g, b); - } else { - recolor.full = style->text.color.full; - } - cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ - } - continue; - } - } - - lv_color_t color = style->text.color; - - if(cmd_state == CMD_STATE_IN) color = recolor; - - 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; - } - /*Go to next line*/ - line_start = line_end; - line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); - - 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; - } - /*Go the next line position*/ - pos.y += lv_font_get_height(font); - pos.y += style->text.line_space; - } -} - -#if USE_LV_IMG -/** - * Draw an image - * @param coords the coordinates of the image - * @param mask the image will be drawn only in this area - * @param map_p pointer to a lv_color_t array which contains the pixels of the image - * @param opa opacity of the image (0..255) - */ -void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, - const lv_style_t * style, const void * src) -{ - - if(src == NULL) { - lv_draw_rect(coords, mask, &lv_style_plain); - lv_draw_label(coords, mask, &lv_style_plain, "No\ndata", LV_TXT_FLAG_NONE, NULL); - return; - } - - const uint8_t * u8_p = (uint8_t*) src; - if(u8_p[0] >= 'A' && u8_p[0] <= 'Z') { /*It will be a path of a file*/ -#if USE_LV_FILESYSTEM - lv_fs_file_t file; - lv_fs_res_t res = lv_fs_open(&file, src, LV_FS_MODE_RD); - if(res == LV_FS_RES_OK) { - lv_img_t img_data; - uint32_t br; - res = lv_fs_read(&file, &img_data, sizeof(lv_img_t), &br); - - lv_area_t mask_com; /*Common area of mask and cords*/ - bool union_ok; - union_ok = lv_area_union(&mask_com, mask, coords); - if(union_ok == false) { - lv_fs_close(&file); - return; - } - - uint8_t px_size = 0; - switch(img_data.header.format) { - case LV_IMG_FORMAT_FILE_RAW_RGB332: px_size = 1; break; - case LV_IMG_FORMAT_FILE_RAW_RGB565: px_size = 2; break; - case LV_IMG_FORMAT_FILE_RAW_RGB888: px_size = 4; break; - default: return; - } - - if(img_data.header.alpha_byte) { /*Correction with the alpha byte*/ - px_size++; - if(img_data.header.format == LV_IMG_FORMAT_FILE_RAW_RGB888) px_size--; /*Stored in the 4 byte anyway*/ - } - - - /* Move the file pointer to the start address according to mask*/ - uint32_t start_offset = sizeof(img_data.header); - start_offset += (lv_area_get_width(coords)) * (mask_com.y1 - coords->y1) * px_size; /*First row*/ - start_offset += (mask_com.x1 - coords->x1) * px_size; /*First col*/ - lv_fs_seek(&file, start_offset); - - uint32_t useful_data = lv_area_get_width(&mask_com) * px_size; - uint32_t next_row = lv_area_get_width(coords) * px_size - useful_data; - - lv_area_t line; - lv_area_copy(&line, &mask_com); - lv_area_set_height(&line, 1); - - lv_coord_t row; - uint32_t act_pos; -#if LV_COMPILER_VLA_SUPPORTED - uint8_t buf[lv_area_get_width(&mask_com) * px_size]; -#else -# if LV_HOR_RES > LV_VER_RES - uint8_t buf[LV_HOR_RES * px_size]; -# else - uint8_t buf[LV_VER_RES * px_size]; -# endif -#endif - for(row = mask_com.y1; row <= mask_com.y2; row ++) { - res = lv_fs_read(&file, buf, useful_data, &br); - - map_fp(&line, &mask_com, (uint8_t *)buf, style->image.opa, img_data.header.chroma_keyed, img_data.header.alpha_byte, - style->image.color, style->image.intense); - - lv_fs_tell(&file, &act_pos); - lv_fs_seek(&file, act_pos + next_row); - line.y1++; /*Go down a line*/ - line.y2++; - } - - lv_fs_close(&file); - - if(res != LV_FS_RES_OK) { - lv_draw_rect(coords, mask, &lv_style_plain); - lv_draw_label(coords, mask, &lv_style_plain, "No data", LV_TXT_FLAG_NONE, NULL); - } - } -#endif - } - else { - const lv_img_t * img_var = src; - lv_area_t mask_com; /*Common area of mask and coords*/ - bool union_ok; - union_ok = lv_area_union(&mask_com, mask, coords); - if(union_ok == false) { - return; /*Out of mask*/ - } - - map_fp(coords, mask, img_var->pixel_map, style->image.opa, img_var->header.chroma_keyed, img_var->header.alpha_byte, style->image.color, style->image.intense); - - } - -} -#endif - - - /********************** * STATIC FUNCTIONS **********************/ @@ -497,52 +124,3 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, #endif - -/** - * Convert a hexadecimal characters to a number (0..15) - * @param hex Pointer to a hexadecimal character (0..9, A..F) - * @return the numerical value of `hex` or 0 on error - */ -static uint8_t hex_char_to_num(char hex) -{ - if(hex >= '0' && hex <= '9') { - return hex - '0'; - } - - if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ - - switch(hex) { - case 'A': return 10; - case 'B': return 11; - case 'C': return 12; - case 'D': return 13; - case 'E': return 14; - case 'F': return 15; - default: return 0; - } - - return 0; - -} - -#if USE_LV_TRIANGLE != 0 -/** - * Swap two points - * p1 pointer to the first point - * p2 pointer to the second point - */ -static void point_swap(lv_point_t * p1, lv_point_t * p2) -{ - lv_point_t tmp; - tmp.x = p1->x; - tmp.y = p1->y; - - p1->x = p2->x; - p1->y = p2->y; - - p2->x = tmp.x; - p2->y = tmp.y; - -} - -#endif diff --git a/lv_draw/lv_draw.h b/lv_draw/lv_draw.h index 2c1b0959eb..51ed18e19d 100644 --- a/lv_draw/lv_draw.h +++ b/lv_draw/lv_draw.h @@ -74,60 +74,6 @@ typedef enum { * GLOBAL PROTOTYPES **********************/ -/** - * Draw a rectangle - * @param cords_p the coordinates of the rectangle - * @param mask_p the rectangle will be drawn only in this mask - * @param style_p pointer to a style - */ -void lv_draw_rect(const lv_area_t * cords_p, const lv_area_t * mask_p, const lv_style_t * style_p); - - -/*Experimental use for 3D modeling*/ -#define USE_LV_TRIANGLE 1 -#if USE_LV_TRIANGLE != 0 -/** - * - * @param points pointer to an array with 3 points - * @param mask_p the triangle will be drawn only in this mask - * @param color color of the triangle - */ -void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask_p, lv_color_t color); -#endif - -/** - * Write a text - * @param cords_p coordinates of the label - * @param mask_p the label will be drawn only in this area - * @param style_p pointer to a style - * @param txt 0 terminated text to write - * @param flags settings for the text from 'txt_flag_t' enum - * @param offset text offset in x and y direction (NULL if unused) - */ -void lv_draw_label(const lv_area_t * cords_p,const lv_area_t * mask_p, const lv_style_t * style_p, - const char * txt, lv_txt_flag_t flag, lv_point_t * offset); - -#if USE_LV_IMG -/** - * Draw an image - * @param cords_p the coordinates of the image - * @param mask_p the image will be drawn only in this area - * @param map_p pointer to a lv_color_t array which contains the pixels of the image - */ -void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, - const lv_style_t * style, const void * src); -#endif - -/** - * Draw a line - * @param p1 first point of the line - * @param p2 second point of the line - * @param mask_pthe line will be drawn only on this area - * @param style_p pointer to a style - */ -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 @@ -146,6 +92,14 @@ void (*map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, * MACROS **********************/ +/********************** + * POST INCLUDES + *********************/ +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" #ifdef __cplusplus } /* extern "C" */ diff --git a/lv_draw/lv_draw.mk b/lv_draw/lv_draw.mk index 5fcf2b056e..f56e4aa7bd 100644 --- a/lv_draw/lv_draw.mk +++ b/lv_draw/lv_draw.mk @@ -1,6 +1,12 @@ CSRCS += lv_draw_vbasic.c -CSRCS += lv_draw.c CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c DEPPATH += --dep-path lvgl/lv_draw VPATH += :lvgl/lv_draw diff --git a/lv_draw/lv_draw_arc.c b/lv_draw/lv_draw_arc.c new file mode 100644 index 0000000000..168a1e63c6 --- /dev/null +++ b/lv_draw/lv_draw_arc.c @@ -0,0 +1,241 @@ +/** + * @file lv_draw_arc.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_arc.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint16_t fast_atan2(int x, int y); +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param mask the arc will be drawn only in this mask + * @param radius the radius of the arc + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param thickness the thickness of the arc (set the `radius` to draw pie) + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, const lv_area_t * mask, uint16_t radius, + uint16_t start_angle, uint16_t end_angle, uint16_t tickness) +{ + lv_coord_t r_out = radius; + lv_coord_t r_in = r_out - tickness; + int16_t deg_base; + int16_t deg; + lv_coord_t x_start[4]; + lv_coord_t x_end[4]; + + lv_color_t color = LV_COLOR_RED; + lv_opa_t opa = LV_OPA_50; + + // Good, may not be the fastest + // Does not draw overlapping pixels + deg = 270;//BSP_LCD_FastAtan2(-r_out, 0); + if ((270 >= start_angle) && (270 <= end_angle)) hor_line(center_x - r_out + 1, center_y, mask, tickness - 1, color, opa); // Left Middle + if ((90 >= start_angle) && (90 <= end_angle)) hor_line(center_x + r_in, center_y, mask, tickness - 1, color, opa); // Right Middle + if ((180 >= start_angle) && (180 <= end_angle)) ver_line(center_x, center_y - r_out + 1, mask, tickness - 1, color, opa); // Top Middle + if ((0 >= start_angle) && (0 <= end_angle)) ver_line(center_x, center_y + r_in, mask, tickness - 1, color, opa); // Bottom middle + + uint32_t r_out_sqr = r_out * r_out; + uint32_t r_in_sqr = r_in * r_in; + int16_t xi; + int16_t yi; + for(yi = -r_out; yi < 0; yi++) { + x_start[0] = LV_COORD_MIN; + x_start[1] = LV_COORD_MIN; + x_start[2] = LV_COORD_MIN; + x_start[3] = LV_COORD_MIN; + x_end[0] = LV_COORD_MIN; + x_end[1] = LV_COORD_MIN; + x_end[2] = LV_COORD_MIN; + x_end[3] = LV_COORD_MIN; + for(xi= -r_out; xi < 0; xi++) { + + uint32_t r_act_sqr = xi * xi + yi * yi; + if(r_act_sqr > r_out_sqr) continue; + + deg_base = fast_atan2(xi, yi) - 180; + + deg = 180 + deg_base; + if ((deg >= start_angle) && (deg <= end_angle)) { + if(x_start[0] == LV_COORD_MIN) x_start[0] = xi; + } else if(x_start[0] != LV_COORD_MIN && x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1; + + + deg = 360 - deg_base; //BSP_LCD_FastAtan2(x, -y); + if ((deg >= start_angle) && (deg <= end_angle)) { + if(x_start[1] == LV_COORD_MIN) x_start[1] = xi; + } else if(x_start[1] != LV_COORD_MIN && x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1; + + deg = 180 - deg_base; //BSP_LCD_FastAtan2(-x, y); + if ((deg >= start_angle) && (deg <= end_angle)) { + if(x_start[2] == LV_COORD_MIN) x_start[2] = xi; + } else if(x_start[2] != LV_COORD_MIN && x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1; + + deg = deg_base; //BSP_LCD_FastAtan2(-x, -y); + if ((deg >= start_angle) && (deg <= end_angle)) { + if(x_start[3] == LV_COORD_MIN) x_start[3] = xi; + } else if(x_start[3] != LV_COORD_MIN && x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1; + + if(r_act_sqr < r_in_sqr) break; /*No need to continue the iteration in x once we found the inner edge of the arc*/ + } + + + if(x_start[0] != LV_COORD_MIN) { + if(x_end[0] == LV_COORD_MIN) x_end[0] = xi - 1; + hor_line(center_x+x_start[0], center_y+yi, mask, x_end[0] - x_start[0], color, opa); + } + + if(x_start[1] != LV_COORD_MIN) { + if(x_end[1] == LV_COORD_MIN) x_end[1] = xi - 1; + hor_line(center_x+x_start[1], center_y-yi, mask, x_end[1] - x_start[1], color, opa); + } + + if(x_start[2] != LV_COORD_MIN) { + if(x_end[2] == LV_COORD_MIN) x_end[2] = xi - 1; + hor_line(center_x-x_end[2], center_y+yi, mask, LV_MATH_ABS(x_end[2] - x_start[2]), color, opa); + } + + if(x_start[3] != LV_COORD_MIN) { + if(x_end[3] == LV_COORD_MIN) x_end[3] = xi - 1; + hor_line(center_x-x_end[3], center_y-yi, mask, LV_MATH_ABS(x_end[3] - x_start[3]), color, opa); + } + + } +} + +static uint16_t fast_atan2(int x, int y) +{ + // Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com + // Converts any XY values including 0 to a degree value that should be + // within +/- 1 degree of the accurate value without needing + // large slow trig functions like ArcTan() or ArcCos(). + // NOTE! at least one of the X or Y values must be non-zero! + // This is the full version, for all 4 quadrants and will generate + // the angle in integer degrees from 0-360. + // Any values of X and Y are usable including negative values provided + // they are between -1456 and 1456 so the 16bit multiply does not overflow. + + unsigned char negflag; + unsigned char tempdegree; + unsigned char comp; + unsigned int degree; // this will hold the result + //signed int x; // these hold the XY vector at the start + //signed int y; // (and they will be destroyed) + unsigned int ux; + unsigned int uy; + + // Save the sign flags then remove signs and get XY as unsigned ints + negflag = 0; + if(x < 0) + { + negflag += 0x01; // x flag bit + x = (0 - x); // is now + + } + ux = x; // copy to unsigned var before multiply + if(y < 0) + { + negflag += 0x02; // y flag bit + y = (0 - y); // is now + + } + uy = y; // copy to unsigned var before multiply + + // 1. Calc the scaled "degrees" + if(ux > uy) + { + degree = (uy * 45) / ux; // degree result will be 0-45 range + negflag += 0x10; // octant flag bit + } + else + { + degree = (ux * 45) / uy; // degree result will be 0-45 range + } + + // 2. Compensate for the 4 degree error curve + comp = 0; + tempdegree = degree; // use an unsigned char for speed! + if(tempdegree > 22) // if top half of range + { + if(tempdegree <= 44) comp++; + if(tempdegree <= 41) comp++; + if(tempdegree <= 37) comp++; + if(tempdegree <= 32) comp++; // max is 4 degrees compensated + } + else // else is lower half of range + { + if(tempdegree >= 2) comp++; + if(tempdegree >= 6) comp++; + if(tempdegree >= 10) comp++; + if(tempdegree >= 15) comp++; // max is 4 degrees compensated + } + degree += comp; // degree is now accurate to +/- 1 degree! + + // Invert degree if it was X>Y octant, makes 0-45 into 90-45 + if(negflag & 0x10) degree = (90 - degree); + + // 3. Degree is now 0-90 range for this quadrant, + // need to invert it for whichever quadrant it was in + if(negflag & 0x02) // if -Y + { + if(negflag & 0x01) // if -Y -X + degree = (180 + degree); + else // else is -Y +X + degree = (180 - degree); + } + else // else is +Y + { + if(negflag & 0x01) // if +Y -X + degree = (360 - degree); + } + return degree; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void ver_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x, y + len); + + fill_fp(&area, mask, color, opa); +} + +static void hor_line(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_coord_t len, lv_color_t color, lv_opa_t opa) +{ + lv_area_t area; + lv_area_set(&area, x, y, x + len, y); + + fill_fp(&area, mask, color, opa); +} diff --git a/lv_draw/lv_draw_arc.h b/lv_draw/lv_draw_arc.h new file mode 100644 index 0000000000..2e8b358db7 --- /dev/null +++ b/lv_draw/lv_draw_arc.h @@ -0,0 +1,52 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param mask the arc will be drawn only in this mask + * @param radius the radius of the arc + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param thickness the thickness of the arc (set the `radius` to draw pie) + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, const lv_area_t * mask, uint16_t radius, + uint16_t start_angle, uint16_t end_angle, uint16_t tickness); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/lv_draw/lv_draw_img.c b/lv_draw/lv_draw_img.c index e69de29bb2..ad74963e75 100644 --- a/lv_draw/lv_draw_img.c +++ b/lv_draw/lv_draw_img.c @@ -0,0 +1,149 @@ +/** + * @file lv_draw_img.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_img.h" +#include "../lv_misc/lv_fs.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +#if USE_LV_IMG +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param map_p pointer to a lv_color_t array which contains the pixels of the image + * @param opa opacity of the image (0..255) + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const lv_style_t * style, const void * src) +{ + + if(src == NULL) { + lv_draw_rect(coords, mask, &lv_style_plain); + lv_draw_label(coords, mask, &lv_style_plain, "No\ndata", LV_TXT_FLAG_NONE, NULL); + return; + } + + const uint8_t * u8_p = (uint8_t*) src; + if(u8_p[0] >= 'A' && u8_p[0] <= 'Z') { /*It will be a path of a file*/ +#if USE_LV_FILESYSTEM + lv_fs_file_t file; + lv_fs_res_t res = lv_fs_open(&file, src, LV_FS_MODE_RD); + if(res == LV_FS_RES_OK) { + lv_img_t img_data; + uint32_t br; + res = lv_fs_read(&file, &img_data, sizeof(lv_img_t), &br); + + lv_area_t mask_com; /*Common area of mask and cords*/ + bool union_ok; + union_ok = lv_area_union(&mask_com, mask, coords); + if(union_ok == false) { + lv_fs_close(&file); + return; + } + + uint8_t px_size = 0; + switch(img_data.header.format) { + case LV_IMG_FORMAT_FILE_RAW_RGB332: px_size = 1; break; + case LV_IMG_FORMAT_FILE_RAW_RGB565: px_size = 2; break; + case LV_IMG_FORMAT_FILE_RAW_RGB888: px_size = 4; break; + default: return; + } + + if(img_data.header.alpha_byte) { /*Correction with the alpha byte*/ + px_size++; + if(img_data.header.format == LV_IMG_FORMAT_FILE_RAW_RGB888) px_size--; /*Stored in the 4 byte anyway*/ + } + + + /* Move the file pointer to the start address according to mask*/ + uint32_t start_offset = sizeof(img_data.header); + start_offset += (lv_area_get_width(coords)) * (mask_com.y1 - coords->y1) * px_size; /*First row*/ + start_offset += (mask_com.x1 - coords->x1) * px_size; /*First col*/ + lv_fs_seek(&file, start_offset); + + uint32_t useful_data = lv_area_get_width(&mask_com) * px_size; + uint32_t next_row = lv_area_get_width(coords) * px_size - useful_data; + + lv_area_t line; + lv_area_copy(&line, &mask_com); + lv_area_set_height(&line, 1); + + lv_coord_t row; + uint32_t act_pos; +#if LV_COMPILER_VLA_SUPPORTED + uint8_t buf[lv_area_get_width(&mask_com) * px_size]; +#else +# if LV_HOR_RES > LV_VER_RES + uint8_t buf[LV_HOR_RES * px_size]; +# else + uint8_t buf[LV_VER_RES * px_size]; +# endif +#endif + for(row = mask_com.y1; row <= mask_com.y2; row ++) { + res = lv_fs_read(&file, buf, useful_data, &br); + + map_fp(&line, &mask_com, (uint8_t *)buf, style->image.opa, img_data.header.chroma_keyed, img_data.header.alpha_byte, + style->image.color, style->image.intense); + + lv_fs_tell(&file, &act_pos); + lv_fs_seek(&file, act_pos + next_row); + line.y1++; /*Go down a line*/ + line.y2++; + } + + lv_fs_close(&file); + + if(res != LV_FS_RES_OK) { + lv_draw_rect(coords, mask, &lv_style_plain); + lv_draw_label(coords, mask, &lv_style_plain, "No data", LV_TXT_FLAG_NONE, NULL); + } + } +#endif + } + else { + const lv_img_t * img_var = src; + lv_area_t mask_com; /*Common area of mask and coords*/ + bool union_ok; + union_ok = lv_area_union(&mask_com, mask, coords); + if(union_ok == false) { + return; /*Out of mask*/ + } + + map_fp(coords, mask, img_var->pixel_map, style->image.opa, img_var->header.chroma_keyed, img_var->header.alpha_byte, style->image.color, style->image.intense); + + } + +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/lv_draw/lv_draw_img.h b/lv_draw/lv_draw_img.h index e69de29bb2..99199c500e 100644 --- a/lv_draw/lv_draw_img.h +++ b/lv_draw/lv_draw_img.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if USE_LV_IMG +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param map_p pointer to a lv_color_t array which contains the pixels of the image + * @param opa opacity of the image (0..255) + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const lv_style_t * style, const void * src); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/lv_draw/lv_draw_label.c b/lv_draw/lv_draw_label.c index e69de29bb2..03c5feac5c 100644 --- a/lv_draw/lv_draw_label.c +++ b/lv_draw/lv_draw_label.c @@ -0,0 +1,206 @@ +/** + * @file lv_draw_label.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_label.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LABEL_RECOLOR_PAR_LENGTH 6 + +/********************** + * TYPEDEFS + **********************/ +typedef enum +{ + CMD_STATE_WAIT, + CMD_STATE_PAR, + CMD_STATE_IN, +}cmd_state_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint8_t hex_char_to_num(char hex); + +/********************** + * STATIC VARIABLES + **********************/ + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +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) +{ + + const lv_font_t * font = style->text.font; + lv_coord_t w; + if((flag & LV_TXT_FLAG_EXPAND) == 0) { + w = lv_area_get_width(coords); + } else { + lv_point_t p; + lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, flag); + w = p.x; + } + + /*Init variables for the first line*/ + lv_coord_t line_length = 0; + uint32_t line_start = 0; + uint32_t line_end = lv_txt_get_next_line(txt, font, style->text.letter_space, w, flag); + + lv_point_t pos; + 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; + } + + cmd_state_t cmd_state = CMD_STATE_WAIT; + uint32_t i; + uint16_t par_start = 0; + lv_color_t recolor; + lv_coord_t letter_w; + + lv_coord_t x_ofs = 0; + lv_coord_t y_ofs = 0; + if(offset != NULL) { + x_ofs = offset->x; + y_ofs = offset->y; + pos.y += y_ofs; + } + + /*Real draw need a background color for higher bpp letter*/ +#if LV_VDB_SIZE == 0 + lv_rletter_set_background(style->body.main_color); +#endif + + /*Write out all lines*/ + while(txt[line_start] != '\0') { + if(offset != NULL) { + pos.x += x_ofs; + } + /*Write all letter of a line*/ + cmd_state = CMD_STATE_WAIT; + i = line_start; + uint32_t letter; + while(i < line_end) { + letter = lv_txt_utf8_next(txt, &i); + /*Handle the re-color command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) { + if(cmd_state == CMD_STATE_WAIT) { /*Start char*/ + par_start = i;// + lv_txt_utf8_size(txt[i]); + cmd_state = CMD_STATE_PAR; + continue; + } else if(cmd_state == CMD_STATE_PAR) { /*Other start char in parameter escaped cmd. char */ + cmd_state = CMD_STATE_WAIT; + }else if(cmd_state == CMD_STATE_IN) { /*Command end */ + cmd_state = CMD_STATE_WAIT; + continue; + } + } + + /*Skip the color parameter and wait the space after it*/ + if(cmd_state == CMD_STATE_PAR) { + if(letter == ' ') { + /*Get the parameter*/ + 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; + r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]); + g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]); + b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]); + recolor = LV_COLOR_MAKE(r, g, b); + } else { + recolor.full = style->text.color.full; + } + cmd_state = CMD_STATE_IN; /*After the parameter the text is in the command*/ + } + continue; + } + } + + lv_color_t color = style->text.color; + + if(cmd_state == CMD_STATE_IN) color = recolor; + + 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; + } + /*Go to next line*/ + line_start = line_end; + line_end += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); + + 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; + } + /*Go the next line position*/ + pos.y += lv_font_get_height(font); + pos.y += style->text.line_space; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert a hexadecimal characters to a number (0..15) + * @param hex Pointer to a hexadecimal character (0..9, A..F) + * @return the numerical value of `hex` or 0 on error + */ +static uint8_t hex_char_to_num(char hex) +{ + if(hex >= '0' && hex <= '9') { + return hex - '0'; + } + + if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ + + switch(hex) { + case 'A': return 10; + case 'B': return 11; + case 'C': return 12; + case 'D': return 13; + case 'E': return 14; + case 'F': return 15; + default: return 0; + } + + return 0; +} diff --git a/lv_draw/lv_draw_label.h b/lv_draw/lv_draw_label.h index e69de29bb2..ab0905ad22 100644 --- a/lv_draw/lv_draw_label.h +++ b/lv_draw/lv_draw_label.h @@ -0,0 +1,52 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +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); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/lv_draw/lv_draw_line.h b/lv_draw/lv_draw_line.h index 604d1140f0..03efc81805 100644 --- a/lv_draw/lv_draw_line.h +++ b/lv_draw/lv_draw_line.h @@ -26,6 +26,16 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +/** + * 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); + /********************** * MACROS **********************/ diff --git a/lv_draw/lv_draw_rect.h b/lv_draw/lv_draw_rect.h index 3c876fd348..9e1b9f4cfa 100644 --- a/lv_draw/lv_draw_rect.h +++ b/lv_draw/lv_draw_rect.h @@ -27,6 +27,14 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style); + /********************** * MACROS **********************/ diff --git a/lv_draw/lv_draw_triangle.c b/lv_draw/lv_draw_triangle.c new file mode 100644 index 0000000000..729039b2eb --- /dev/null +++ b/lv_draw/lv_draw_triangle.c @@ -0,0 +1,169 @@ +/** + * @file lv_draw_triangle.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_triangle.h" +#include "../lv_misc/lv_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static void point_swap(lv_point_t * p1, lv_point_t * p2); + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color) +{ + lv_point_t tri[3]; + + memcpy(tri, points, sizeof(tri)); + + /*Sort the vertices according to their y coordinate (0: y max, 1: y mid, 2:y min)*/ + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + if(tri[2].y < tri[1].y) point_swap(&tri[2], &tri[1]); + if(tri[1].y < tri[0].y) point_swap(&tri[1], &tri[0]); + + /*Return is the triangle is degenerated*/ + if(tri[0].x == tri[1].x && tri[0].y == tri[1].y) return; + if(tri[1].x == tri[2].x && tri[1].y == tri[2].y) return; + if(tri[0].x == tri[2].x && tri[0].y == tri[2].y) return; + + if(tri[0].x == tri[1].x && tri[1].x == tri[2].x) return; + if(tri[0].y == tri[1].y && tri[1].y == tri[2].y) return; + + /*Draw the triangle*/ + lv_point_t edge1; + lv_coord_t dx1 = LV_MATH_ABS(tri[0].x - tri[1].x); + lv_coord_t sx1 = tri[0].x < tri[1].x ? 1 : -1; + lv_coord_t dy1 = LV_MATH_ABS(tri[0].y - tri[1].y); + lv_coord_t sy1 = tri[0].y < tri[1].y ? 1 : -1; + lv_coord_t err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + lv_coord_t err_tmp1; + + lv_point_t edge2; + lv_coord_t dx2 = LV_MATH_ABS(tri[0].x - tri[2].x); + lv_coord_t sx2 = tri[0].x < tri[2].x ? 1 : -1; + lv_coord_t dy2 = LV_MATH_ABS(tri[0].y - tri[2].y); + lv_coord_t sy2 = tri[0].y < tri[2].y ? 1 : -1; + lv_coord_t err2 = (dx1 > dy2 ? dx2 : -dy2) / 2; + lv_coord_t err_tmp2; + + lv_coord_t y1_tmp; + lv_coord_t y2_tmp; + + edge1.x = tri[0].x; + edge1.y = tri[0].y; + edge2.x = tri[0].x; + edge2.y = tri[0].y; + lv_area_t act_area; + lv_area_t draw_area; + + while(1) { + act_area.x1 = edge1.x; + act_area.x2 = edge2.x ; + act_area.y1 = edge1.y; + act_area.y2 = edge2.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); + draw_area.x2--; /*Do not draw most right pixel because it will be drawn by the adjacent triangle*/ + fill_fp(&draw_area, mask, color, LV_OPA_50); + + /*Calc. the next point of edge1*/ + y1_tmp = edge1.y; + do { + if (edge1.x == tri[1].x && edge1.y == tri[1].y) { + + dx1 = LV_MATH_ABS(tri[1].x - tri[2].x); + sx1 = tri[1].x < tri[2].x ? 1 : -1; + dy1 = LV_MATH_ABS(tri[1].y - tri[2].y); + sy1 = tri[1].y < tri[2].y ? 1 : -1; + err1 = (dx1 > dy1 ? dx1 : -dy1) / 2; + } + else if (edge1.x == tri[2].x && edge1.y == tri[2].y) return; + err_tmp1 = err1; + if (err_tmp1 >-dx1) { + err1 -= dy1; + edge1.x += sx1; + } + if (err_tmp1 < dy1) { + err1 += dx1; + edge1.y += sy1; + } + } while(edge1.y == y1_tmp); + + /*Calc. the next point of edge2*/ + y2_tmp = edge2.y; + do { + if (edge2.x == tri[2].x && edge2.y == tri[2].y) return; + err_tmp2 = err2; + if (err_tmp2 > -dx2) { + err2 -= dy2; + edge2.x += sx2; + } + if (err_tmp2 < dy2) { + err2 += dx2; + edge2.y += sy2; + } + } while(edge2.y == y2_tmp); + } +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + + +#if USE_LV_TRIANGLE != 0 +/** + * Swap two points + * p1 pointer to the first point + * p2 pointer to the second point + */ +static void point_swap(lv_point_t * p1, lv_point_t * p2) +{ + lv_point_t tmp; + tmp.x = p1->x; + tmp.y = p1->y; + + p1->x = p2->x; + p1->y = p2->y; + + p2->x = tmp.x; + p2->y = tmp.y; + +} + +#endif diff --git a/lv_draw/lv_draw_triangle.h b/lv_draw/lv_draw_triangle.h new file mode 100644 index 0000000000..c3c6208dac --- /dev/null +++ b/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/lv_objx/lv_ddlist.h b/lv_objx/lv_ddlist.h index 539c7773e0..f5110b70ec 100644 --- a/lv_objx/lv_ddlist.h +++ b/lv_objx/lv_ddlist.h @@ -48,8 +48,8 @@ typedef struct uint16_t sel_opt_id; /*Index of the current option*/ uint16_t sel_opt_id_ori; /*Store the original index on focus*/ uint16_t anim_time; /*Open/Close animation time [ms]*/ - uint8_t opened :1; /*1: The list is opened*/ - lv_coord_t fix_height; /*Height if the ddlist is opened. (0: auto-size)*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ }lv_ddlist_ext_t; typedef enum {