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_rlottie.c (8984B)

      1 /**
      2  * @file lv_rlottie.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_rlottie.h"
     10 #if LV_USE_RLOTTIE
     11 
     12 #include <rlottie_capi.h>
     13 
     14 /*********************
     15 *      DEFINES
     16 *********************/
     17 #define MY_CLASS &lv_rlottie_class
     18 #define LV_ARGB32   32
     19 
     20 /**********************
     21 *      TYPEDEFS
     22 **********************/
     23 #define LV_ARGB32   32
     24 
     25 /**********************
     26  *  STATIC PROTOTYPES
     27  **********************/
     28 static void lv_rlottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     29 static void lv_rlottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     30 static void next_frame_task_cb(lv_timer_t * t);
     31 
     32 /**********************
     33  *  STATIC VARIABLES
     34  **********************/
     35 const lv_obj_class_t lv_rlottie_class = {
     36     .constructor_cb = lv_rlottie_constructor,
     37     .destructor_cb = lv_rlottie_destructor,
     38     .instance_size = sizeof(lv_rlottie_t),
     39     .base_class = &lv_img_class
     40 };
     41 
     42 static lv_coord_t create_width;
     43 static lv_coord_t create_height;
     44 static const char * rlottie_desc_create;
     45 static const char * path_create;
     46 
     47 /**********************
     48  *      MACROS
     49  **********************/
     50 
     51 /**********************
     52  *   GLOBAL FUNCTIONS
     53  **********************/
     54 
     55 lv_obj_t * lv_rlottie_create_from_file(lv_obj_t * parent, lv_coord_t width, lv_coord_t height, const char * path)
     56 {
     57 
     58     create_width = width;
     59     create_height = height;
     60     path_create = path;
     61     rlottie_desc_create = NULL;
     62 
     63     LV_LOG_INFO("begin");
     64     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     65     lv_obj_class_init_obj(obj);
     66 
     67     return obj;
     68 
     69 }
     70 
     71 lv_obj_t * lv_rlottie_create_from_raw(lv_obj_t * parent, lv_coord_t width, lv_coord_t height, const char * rlottie_desc)
     72 {
     73 
     74     create_width = width;
     75     create_height = height;
     76     rlottie_desc_create = rlottie_desc;
     77     path_create = NULL;
     78 
     79     LV_LOG_INFO("begin");
     80     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
     81     lv_obj_class_init_obj(obj);
     82 
     83     return obj;
     84 }
     85 
     86 void lv_rlottie_set_play_mode(lv_obj_t * obj, const lv_rlottie_ctrl_t ctrl)
     87 {
     88     lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
     89     rlottie->play_ctrl = ctrl;
     90 
     91     if(rlottie->task && (rlottie->dest_frame != rlottie->current_frame ||
     92                          (rlottie->play_ctrl & LV_RLOTTIE_CTRL_PAUSE) == LV_RLOTTIE_CTRL_PLAY)) {
     93         lv_timer_resume(rlottie->task);
     94     }
     95 }
     96 
     97 void lv_rlottie_set_current_frame(lv_obj_t * obj, const size_t goto_frame)
     98 {
     99     lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
    100     rlottie->current_frame = goto_frame < rlottie->total_frames ? goto_frame : rlottie->total_frames - 1;
    101 }
    102 
    103 /**********************
    104  *   STATIC FUNCTIONS
    105  **********************/
    106 
    107 static void lv_rlottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    108 {
    109     LV_UNUSED(class_p);
    110     lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
    111 
    112     if(rlottie_desc_create) {
    113         rlottie->animation = lottie_animation_from_data(rlottie_desc_create, rlottie_desc_create, "");
    114     }
    115     else if(path_create) {
    116         rlottie->animation = lottie_animation_from_file(path_create);
    117     }
    118     if(rlottie->animation == NULL) {
    119         LV_LOG_WARN("The aniamtion can't be opened");
    120         return;
    121     }
    122 
    123     rlottie->total_frames = lottie_animation_get_totalframe(rlottie->animation);
    124     rlottie->framerate = (size_t)lottie_animation_get_framerate(rlottie->animation);
    125     rlottie->current_frame = 0;
    126 
    127     rlottie->scanline_width = create_width * LV_ARGB32 / 8;
    128 
    129     size_t allocaled_buf_size = (create_width * create_height * LV_ARGB32 / 8);
    130     rlottie->allocated_buf = lv_mem_alloc(allocaled_buf_size);
    131     if(rlottie->allocated_buf != NULL) {
    132         rlottie->allocated_buffer_size = allocaled_buf_size;
    133         memset(rlottie->allocated_buf, 0, allocaled_buf_size);
    134     }
    135 
    136     rlottie->imgdsc.header.always_zero = 0;
    137     rlottie->imgdsc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
    138     rlottie->imgdsc.header.h = create_height;
    139     rlottie->imgdsc.header.w = create_width;
    140     rlottie->imgdsc.data = (void *)rlottie->allocated_buf;
    141     rlottie->imgdsc.data_size = allocaled_buf_size;
    142 
    143     lv_img_set_src(obj, &rlottie->imgdsc);
    144 
    145     rlottie->play_ctrl = LV_RLOTTIE_CTRL_FORWARD | LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_LOOP;
    146     rlottie->dest_frame = rlottie->total_frames; /* invalid destination frame so it's possible to pause on frame 0 */
    147 
    148     rlottie->task = lv_timer_create(next_frame_task_cb, 1000 / rlottie->framerate, obj);
    149 
    150     lv_obj_update_layout(obj);
    151 }
    152 
    153 
    154 static void lv_rlottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    155 {
    156     LV_UNUSED(class_p);
    157     lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
    158 
    159     if(rlottie->animation) {
    160         lottie_animation_destroy(rlottie->animation);
    161         rlottie->animation = 0;
    162         rlottie->current_frame = 0;
    163         rlottie->framerate = 0;
    164         rlottie->scanline_width = 0;
    165         rlottie->total_frames = 0;
    166     }
    167 
    168     if(rlottie->task) {
    169         lv_timer_del(rlottie->task);
    170         rlottie->task = NULL;
    171         rlottie->play_ctrl = LV_RLOTTIE_CTRL_FORWARD;
    172         rlottie->dest_frame = 0;
    173     }
    174 
    175     lv_img_cache_invalidate_src(&rlottie->imgdsc);
    176     if(rlottie->allocated_buf) {
    177         lv_mem_free(rlottie->allocated_buf);
    178         rlottie->allocated_buf = NULL;
    179         rlottie->allocated_buffer_size = 0;
    180     }
    181 
    182 }
    183 
    184 #if LV_COLOR_DEPTH == 16
    185 static void convert_to_rgba5658(uint32_t * pix, const size_t width, const size_t height)
    186 {
    187     /* rlottie draws in ARGB32 format, but LVGL only deal with RGB565 format with (optional 8 bit alpha channel)
    188        so convert in place here the received buffer to LVGL format. */
    189     uint8_t * dest = (uint8_t *)pix;
    190     uint32_t * src = pix;
    191     for(size_t y = 0; y < height; y++) {
    192         /* Convert a 4 bytes per pixel in format ARGB to R5G6B5A8 format
    193             naive way:
    194                         r = ((c & 0xFF0000) >> 19)
    195                         g = ((c & 0xFF00) >> 10)
    196                         b = ((c & 0xFF) >> 3)
    197                         rgb565 = (r << 11) | (g << 5) | b
    198                         a = c >> 24;
    199             That's 3 mask, 6 bitshift and 2 or operations
    200 
    201             A bit better:
    202                         r = ((c & 0xF80000) >> 8)
    203                         g = ((c & 0xFC00) >> 5)
    204                         b = ((c & 0xFF) >> 3)
    205                         rgb565 = r | g | b
    206                         a = c >> 24;
    207             That's 3 mask, 3 bitshifts and 2 or operations */
    208         for(size_t x = 0; x < width; x++) {
    209             uint32_t in = src[x];
    210 #if LV_COLOR_16_SWAP == 0
    211             uint16_t r = (uint16_t)(((in & 0xF80000) >> 8) | ((in & 0xFC00) >> 5) | ((in & 0xFF) >> 3));
    212 #else
    213             /* We want: rrrr rrrr GGGg gggg bbbb bbbb => gggb bbbb rrrr rGGG */
    214             uint16_t r = (uint16_t)(((in & 0xF80000) >> 16) | ((in & 0xFC00) >> 13) | ((in & 0x1C00) << 3) | ((in & 0xF8) << 5));
    215 #endif
    216 
    217             lv_memcpy(dest, &r, sizeof(r));
    218             dest[sizeof(r)] = (uint8_t)(in >> 24);
    219             dest += LV_IMG_PX_SIZE_ALPHA_BYTE;
    220         }
    221         src += width;
    222     }
    223 }
    224 #endif
    225 
    226 static void next_frame_task_cb(lv_timer_t * t)
    227 {
    228     lv_obj_t * obj = t->user_data;
    229     lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
    230 
    231     if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_PAUSE) == LV_RLOTTIE_CTRL_PAUSE) {
    232         if(rlottie->current_frame == rlottie->dest_frame) {
    233             /* Pause the timer too when it has run once to avoid CPU consumption */
    234             lv_timer_pause(t);
    235             return;
    236         }
    237         rlottie->dest_frame = rlottie->current_frame;
    238     }
    239     else {
    240         if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_BACKWARD) == LV_RLOTTIE_CTRL_BACKWARD) {
    241             if(rlottie->current_frame > 0)
    242                 --rlottie->current_frame;
    243             else { /* Looping ? */
    244                 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_LOOP) == LV_RLOTTIE_CTRL_LOOP)
    245                     rlottie->current_frame = rlottie->total_frames - 1;
    246                 else {
    247                     lv_event_send(obj, LV_EVENT_READY, NULL);
    248                     lv_timer_pause(t);
    249                     return;
    250                 }
    251             }
    252         }
    253         else {
    254             if(rlottie->current_frame < rlottie->total_frames)
    255                 ++rlottie->current_frame;
    256             else { /* Looping ? */
    257                 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_LOOP) == LV_RLOTTIE_CTRL_LOOP)
    258                     rlottie->current_frame = 0;
    259                 else {
    260                     lv_event_send(obj, LV_EVENT_READY, NULL);
    261                     lv_timer_pause(t);
    262                     return;
    263                 }
    264             }
    265         }
    266     }
    267 
    268     lottie_animation_render(
    269         rlottie->animation,
    270         rlottie->current_frame,
    271         rlottie->allocated_buf,
    272         rlottie->imgdsc.header.w,
    273         rlottie->imgdsc.header.h,
    274         rlottie->scanline_width
    275     );
    276 
    277 #if LV_COLOR_DEPTH == 16
    278     convert_to_rgba5658(rlottie->allocated_buf, rlottie->imgdsc.header.w, rlottie->imgdsc.header.h);
    279 #endif
    280 
    281     lv_obj_invalidate(obj);
    282 }
    283 
    284 #endif /*LV_USE_RLOTTIE*/