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_sdl_arc.c (8305B)
1 /** 2 * @file lv_draw_sdl_arc.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "../../lv_conf_internal.h" 10 11 #if LV_USE_GPU_SDL 12 13 #include "lv_draw_sdl.h" 14 #include "lv_draw_sdl_utils.h" 15 #include "lv_draw_sdl_texture_cache.h" 16 #include "lv_draw_sdl_composite.h" 17 18 /********************* 19 * DEFINES 20 *********************/ 21 22 /********************** 23 * TYPEDEFS 24 **********************/ 25 26 /********************** 27 * STATIC PROTOTYPES 28 **********************/ 29 30 /********************** 31 * STATIC VARIABLES 32 **********************/ 33 34 /********************** 35 * MACROS 36 **********************/ 37 38 static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count, 39 const int16_t * caps); 40 41 static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center, 42 lv_area_t * out); 43 44 /********************** 45 * GLOBAL FUNCTIONS 46 **********************/ 47 void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, 48 uint16_t radius, uint16_t start_angle, uint16_t end_angle) 49 { 50 lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx; 51 52 lv_area_t area_out; 53 area_out.x1 = center->x - radius; 54 area_out.y1 = center->y - radius; 55 area_out.x2 = center->x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/ 56 area_out.y2 = center->y + radius - 1; 57 58 lv_area_t draw_area; 59 if(!_lv_area_intersect(&draw_area, &area_out, draw_ctx->clip_area)) { 60 return; 61 } 62 63 lv_area_t area_in; 64 lv_area_copy(&area_in, &area_out); 65 area_in.x1 += dsc->width; 66 area_in.y1 += dsc->width; 67 area_in.x2 -= dsc->width; 68 area_in.y2 -= dsc->width; 69 70 71 while(start_angle >= 360) start_angle -= 360; 72 while(end_angle >= 360) end_angle -= 360; 73 74 int16_t mask_ids[3] = {LV_MASK_ID_INV, LV_MASK_ID_INV, LV_MASK_ID_INV}, mask_ids_count = 1; 75 int16_t cap_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV}; 76 77 lv_draw_mask_radius_param_t mask_out_param; 78 lv_draw_mask_radius_init(&mask_out_param, &area_out, LV_RADIUS_CIRCLE, false); 79 mask_ids[0] = lv_draw_mask_add(&mask_out_param, NULL); 80 81 lv_draw_mask_radius_param_t mask_in_param; 82 if(lv_area_get_width(&area_in) > 0 && lv_area_get_height(&area_in) > 0) { 83 lv_draw_mask_radius_init(&mask_in_param, &area_in, LV_RADIUS_CIRCLE, true); 84 mask_ids[1] = lv_draw_mask_add(&mask_in_param, NULL); 85 mask_ids_count++; 86 } 87 88 lv_draw_mask_angle_param_t mask_angle_param; 89 if((start_angle - end_angle) % 360) { 90 lv_draw_mask_angle_init(&mask_angle_param, center->x, center->y, start_angle, end_angle); 91 mask_ids[2] = lv_draw_mask_add(&mask_angle_param, NULL); 92 mask_ids_count++; 93 } 94 95 lv_draw_mask_radius_param_t cap_start_param, cap_end_param; 96 if(mask_ids_count == 3 && dsc->rounded) { 97 lv_area_t start_area, end_area; 98 get_cap_area((int16_t) start_angle, dsc->width, radius, center, &start_area); 99 get_cap_area((int16_t) end_angle, dsc->width, radius, center, &end_area); 100 lv_draw_mask_radius_init(&cap_start_param, &start_area, dsc->width / 2, false); 101 cap_ids[0] = lv_draw_mask_add(&cap_start_param, NULL); 102 lv_draw_mask_radius_init(&cap_end_param, &end_area, dsc->width / 2, false); 103 cap_ids[1] = lv_draw_mask_add(&cap_end_param, NULL); 104 } 105 106 lv_coord_t w = lv_area_get_width(&draw_area), h = lv_area_get_height(&draw_area); 107 SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, w, h); 108 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 109 dump_masks(texture, &draw_area, mask_ids, mask_ids_count, cap_ids[0] != LV_MASK_ID_INV ? cap_ids : NULL); 110 111 lv_draw_mask_remove_id(mask_ids[0]); 112 lv_draw_mask_free_param(&mask_out_param); 113 114 if(mask_ids_count > 1) { 115 lv_draw_mask_remove_id(mask_ids[1]); 116 lv_draw_mask_free_param(&mask_in_param); 117 } 118 119 if(mask_ids_count > 2) { 120 lv_draw_mask_remove_id(mask_ids[2]); 121 lv_draw_mask_free_param(&mask_angle_param); 122 } 123 124 if(cap_ids[0] != LV_MASK_ID_INV) { 125 lv_draw_mask_remove_id(cap_ids[0]); 126 lv_draw_mask_remove_id(cap_ids[1]); 127 lv_draw_mask_free_param(&cap_start_param); 128 lv_draw_mask_free_param(&cap_end_param); 129 } 130 131 SDL_Rect srcrect = {0, 0, w, h}, dstrect; 132 lv_area_to_sdl_rect(&draw_area, &dstrect); 133 SDL_Color color; 134 lv_color_to_sdl_color(&dsc->color, &color); 135 SDL_SetTextureColorMod(texture, color.r, color.g, color.b); 136 SDL_SetTextureAlphaMod(texture, dsc->opa); 137 SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect); 138 } 139 140 /********************** 141 * STATIC FUNCTIONS 142 **********************/ 143 144 static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count, 145 const int16_t * caps) 146 { 147 lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords); 148 SDL_assert(w > 0 && h > 0); 149 SDL_Rect rect = {0, 0, w, h}; 150 uint8_t * pixels; 151 int pitch; 152 if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return; 153 154 lv_opa_t * line_buf = lv_mem_buf_get(rect.w); 155 for(lv_coord_t y = 0; y < rect.h; y++) { 156 lv_memset_ff(line_buf, rect.w); 157 lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w; 158 lv_draw_mask_res_t res; 159 res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, ids, ids_count); 160 if(res == LV_DRAW_MASK_RES_TRANSP) { 161 lv_memset_00(&pixels[y * pitch], 4 * rect.w); 162 } 163 else if(res == LV_DRAW_MASK_RES_FULL_COVER) { 164 lv_memset_ff(&pixels[y * pitch], 4 * rect.w); 165 } 166 else { 167 for(int x = 0; x < rect.w; x++) { 168 uint8_t * pixel = &pixels[y * pitch + x * 4]; 169 *pixel = line_buf[x]; 170 pixel[1] = pixel[2] = pixel[3] = 0xFF; 171 } 172 } 173 if(caps) { 174 for(int i = 0; i < 2; i++) { 175 lv_memset_ff(line_buf, rect.w); 176 res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, &caps[i], 1); 177 if(res == LV_DRAW_MASK_RES_TRANSP) { 178 /* Ignore */ 179 } 180 else if(res == LV_DRAW_MASK_RES_FULL_COVER) { 181 lv_memset_ff(&pixels[y * pitch], 4 * rect.w); 182 } 183 else { 184 for(int x = 0; x < rect.w; x++) { 185 uint8_t * pixel = &pixels[y * pitch + x * 4]; 186 uint16_t old_opa = line_buf[x] + *pixel; 187 *pixel = LV_MIN(old_opa, 0xFF); 188 pixel[1] = pixel[2] = pixel[3] = 0xFF; 189 } 190 } 191 } 192 } 193 } 194 lv_mem_buf_release(line_buf); 195 SDL_UnlockTexture(texture); 196 } 197 198 static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, const lv_point_t * center, 199 lv_area_t * out) 200 { 201 const uint8_t ps = 8; 202 const uint8_t pa = 127; 203 204 int32_t thick_half = thickness / 2; 205 uint8_t thick_corr = (thickness & 0x01) ? 0 : 1; 206 207 int32_t cir_x; 208 int32_t cir_y; 209 210 cir_x = ((radius - thick_half) * lv_trigo_sin((int16_t)(90 - angle))) >> (LV_TRIGO_SHIFT - ps); 211 cir_y = ((radius - thick_half) * lv_trigo_sin(angle)) >> (LV_TRIGO_SHIFT - ps); 212 213 /*Actually the center of the pixel need to be calculated so apply 1/2 px offset*/ 214 if(cir_x > 0) { 215 cir_x = (cir_x - pa) >> ps; 216 out->x1 = cir_x - thick_half + thick_corr; 217 out->x2 = cir_x + thick_half; 218 } 219 else { 220 cir_x = (cir_x + pa) >> ps; 221 out->x1 = cir_x - thick_half; 222 out->x2 = cir_x + thick_half - thick_corr; 223 } 224 225 if(cir_y > 0) { 226 cir_y = (cir_y - pa) >> ps; 227 out->y1 = cir_y - thick_half + thick_corr; 228 out->y2 = cir_y + thick_half; 229 } 230 else { 231 cir_y = (cir_y + pa) >> ps; 232 out->y1 = cir_y - thick_half; 233 out->y2 = cir_y + thick_half - thick_corr; 234 } 235 lv_area_move(out, center->x, center->y); 236 } 237 238 #endif /*LV_USE_GPU_SDL*/