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