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