acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_draw_sw_polygon.c (6165B)
1 /** 2 * @file lv_draw_sw_polygon.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_draw_sw.h" 10 #include "../../misc/lv_math.h" 11 #include "../../misc/lv_mem.h" 12 #include "../../misc/lv_area.h" 13 #include "../../misc/lv_color.h" 14 #include "../lv_draw_rect.h" 15 16 /********************* 17 * DEFINES 18 *********************/ 19 20 /********************** 21 * TYPEDEFS 22 **********************/ 23 24 /********************** 25 * STATIC PROTOTYPES 26 **********************/ 27 28 /********************** 29 * STATIC VARIABLES 30 **********************/ 31 32 /********************** 33 * MACROS 34 **********************/ 35 36 /********************** 37 * GLOBAL FUNCTIONS 38 **********************/ 39 40 /** 41 * Draw a polygon. Only convex polygons are supported 42 * @param points an array of points 43 * @param point_cnt number of points 44 * @param clip_area polygon will be drawn only in this area 45 * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable 46 */ 47 void lv_draw_sw_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points, 48 uint16_t point_cnt) 49 { 50 #if LV_DRAW_COMPLEX 51 if(point_cnt < 3) return; 52 if(points == NULL) return; 53 54 /*Join adjacent points if they are on the same coordinate*/ 55 lv_point_t * p = lv_mem_buf_get(point_cnt * sizeof(lv_point_t)); 56 if(p == NULL) return; 57 uint16_t i; 58 uint16_t pcnt = 0; 59 p[0] = points[0]; 60 for(i = 0; i < point_cnt - 1; i++) { 61 if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) { 62 p[pcnt] = points[i]; 63 pcnt++; 64 } 65 } 66 /*The first and the last points are also adjacent*/ 67 if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) { 68 p[pcnt] = points[point_cnt - 1]; 69 pcnt++; 70 } 71 72 point_cnt = pcnt; 73 if(point_cnt < 3) { 74 lv_mem_buf_release(p); 75 return; 76 } 77 78 lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN}; 79 80 for(i = 0; i < point_cnt; i++) { 81 poly_coords.x1 = LV_MIN(poly_coords.x1, p[i].x); 82 poly_coords.y1 = LV_MIN(poly_coords.y1, p[i].y); 83 poly_coords.x2 = LV_MAX(poly_coords.x2, p[i].x); 84 poly_coords.y2 = LV_MAX(poly_coords.y2, p[i].y); 85 } 86 87 bool is_common; 88 lv_area_t clip_area; 89 is_common = _lv_area_intersect(&clip_area, &poly_coords, draw_ctx->clip_area); 90 if(!is_common) { 91 lv_mem_buf_release(p); 92 return; 93 } 94 95 const lv_area_t * clip_area_ori = draw_ctx->clip_area; 96 draw_ctx->clip_area = &clip_area; 97 98 /*Find the lowest point*/ 99 lv_coord_t y_min = p[0].y; 100 int16_t y_min_i = 0; 101 102 for(i = 1; i < point_cnt; i++) { 103 if(p[i].y < y_min) { 104 y_min = p[i].y; 105 y_min_i = i; 106 } 107 } 108 109 lv_draw_mask_line_param_t * mp = lv_mem_buf_get(sizeof(lv_draw_mask_line_param_t) * point_cnt); 110 lv_draw_mask_line_param_t * mp_next = mp; 111 112 int32_t i_prev_left = y_min_i; 113 int32_t i_prev_right = y_min_i; 114 int32_t i_next_left; 115 int32_t i_next_right; 116 uint32_t mask_cnt = 0; 117 118 /*Get the index of the left and right points*/ 119 i_next_left = y_min_i - 1; 120 if(i_next_left < 0) i_next_left = point_cnt + i_next_left; 121 122 i_next_right = y_min_i + 1; 123 if(i_next_right > point_cnt - 1) i_next_right = 0; 124 125 /** 126 * Check if the order of points is inverted or not. 127 * The normal case is when the left point is on `y_min_i - 1` 128 * Explanation: 129 * if angle(p_left) < angle(p_right) -> inverted 130 * dy_left/dx_left < dy_right/dx_right 131 * dy_left * dx_right < dy_right * dx_left 132 */ 133 lv_coord_t dxl = p[i_next_left].x - p[y_min_i].x; 134 lv_coord_t dxr = p[i_next_right].x - p[y_min_i].x; 135 lv_coord_t dyl = p[i_next_left].y - p[y_min_i].y; 136 lv_coord_t dyr = p[i_next_right].y - p[y_min_i].y; 137 138 bool inv = false; 139 if(dyl * dxr < dyr * dxl) inv = true; 140 141 do { 142 if(!inv) { 143 i_next_left = i_prev_left - 1; 144 if(i_next_left < 0) i_next_left = point_cnt + i_next_left; 145 146 i_next_right = i_prev_right + 1; 147 if(i_next_right > point_cnt - 1) i_next_right = 0; 148 } 149 else { 150 i_next_left = i_prev_left + 1; 151 if(i_next_left > point_cnt - 1) i_next_left = 0; 152 153 i_next_right = i_prev_right - 1; 154 if(i_next_right < 0) i_next_right = point_cnt + i_next_right; 155 } 156 157 if(p[i_next_left].y >= p[i_prev_left].y) { 158 if(p[i_next_left].y != p[i_prev_left].y && 159 p[i_next_left].x != p[i_prev_left].x) { 160 lv_draw_mask_line_points_init(mp_next, p[i_prev_left].x, p[i_prev_left].y, 161 p[i_next_left].x, p[i_next_left].y, 162 LV_DRAW_MASK_LINE_SIDE_RIGHT); 163 lv_draw_mask_add(mp_next, mp); 164 mp_next++; 165 } 166 mask_cnt++; 167 i_prev_left = i_next_left; 168 } 169 170 if(mask_cnt == point_cnt) break; 171 172 if(p[i_next_right].y >= p[i_prev_right].y) { 173 if(p[i_next_right].y != p[i_prev_right].y && 174 p[i_next_right].x != p[i_prev_right].x) { 175 176 lv_draw_mask_line_points_init(mp_next, p[i_prev_right].x, p[i_prev_right].y, 177 p[i_next_right].x, p[i_next_right].y, 178 LV_DRAW_MASK_LINE_SIDE_LEFT); 179 lv_draw_mask_add(mp_next, mp); 180 mp_next++; 181 } 182 mask_cnt++; 183 i_prev_right = i_next_right; 184 } 185 186 } while(mask_cnt < point_cnt); 187 188 lv_draw_rect(draw_ctx, draw_dsc, &poly_coords); 189 190 lv_draw_mask_remove_custom(mp); 191 192 lv_mem_buf_release(mp); 193 lv_mem_buf_release(p); 194 195 draw_ctx->clip_area = clip_area_ori; 196 #else 197 LV_UNUSED(points); 198 LV_UNUSED(point_cnt); 199 LV_UNUSED(draw_ctx); 200 LV_UNUSED(draw_dsc); 201 LV_LOG_WARN("Can't draw polygon with LV_DRAW_COMPLEX == 0"); 202 #endif /*LV_DRAW_COMPLEX*/ 203 } 204 205 /********************** 206 * STATIC FUNCTIONS 207 **********************/