add arc drawing and restructure draw functions

This commit is contained in:
Gabor Kiss-Vamosi
2018-06-07 15:32:19 +02:00
parent 3890e85527
commit cc1c20d6fe
14 changed files with 1007 additions and 480 deletions

View File

@@ -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

View File

@@ -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" */

View File

@@ -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

241
lv_draw/lv_draw_arc.c Normal file
View File

@@ -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);
}

52
lv_draw/lv_draw_arc.h Normal file
View File

@@ -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*/

View File

@@ -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
**********************/

View File

@@ -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*/

View File

@@ -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;
}

View File

@@ -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*/

View File

@@ -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
**********************/

View File

@@ -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
**********************/

169
lv_draw/lv_draw_triangle.c Normal file
View File

@@ -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

View File

@@ -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*/