1 /**
2 * @file lv_rlottie.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../lvgl.h"
10 #if LV_USE_RLOTTIE
11
12 #include "lv_rlottie_private.h"
13 #include "../../core/lv_obj_class_private.h"
14 #include <rlottie_capi.h>
15 #include <string.h>
16
17 /*********************
18 * DEFINES
19 *********************/
20 #define MY_CLASS (&lv_rlottie_class)
21 #define LV_ARGB32 32
22
23 /**********************
24 * TYPEDEFS
25 **********************/
26 #define LV_ARGB32 32
27
28 /**********************
29 * STATIC PROTOTYPES
30 **********************/
31 static void lv_rlottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
32 static void lv_rlottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
33 static void next_frame_task_cb(lv_timer_t * t);
34
35 /**********************
36 * STATIC VARIABLES
37 **********************/
38
39 const lv_obj_class_t lv_rlottie_class = {
40 .constructor_cb = lv_rlottie_constructor,
41 .destructor_cb = lv_rlottie_destructor,
42 .instance_size = sizeof(lv_rlottie_t),
43 .base_class = &lv_image_class,
44 .name = "rlottie",
45 };
46
47 typedef struct {
48 int32_t width;
49 int32_t height;
50 const char * rlottie_desc;
51 const char * path;
52 } lv_rlottie_create_info_t;
53
54 /*Only used in lv_obj_class_create_obj, no affect multiple instances*/
55 static lv_rlottie_create_info_t create_info;
56
57 /**********************
58 * MACROS
59 **********************/
60
61 /**********************
62 * GLOBAL FUNCTIONS
63 **********************/
64
lv_rlottie_create_from_file(lv_obj_t * parent,int32_t width,int32_t height,const char * path)65 lv_obj_t * lv_rlottie_create_from_file(lv_obj_t * parent, int32_t width, int32_t height, const char * path)
66 {
67 create_info.width = width;
68 create_info.height = height;
69 create_info.path = path;
70 create_info.rlottie_desc = NULL;
71
72 LV_LOG_INFO("begin");
73 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
74 lv_obj_class_init_obj(obj);
75
76 return obj;
77 }
78
lv_rlottie_create_from_raw(lv_obj_t * parent,int32_t width,int32_t height,const char * rlottie_desc)79 lv_obj_t * lv_rlottie_create_from_raw(lv_obj_t * parent, int32_t width, int32_t height, const char * rlottie_desc)
80 {
81 create_info.width = width;
82 create_info.height = height;
83 create_info.rlottie_desc = rlottie_desc;
84 create_info.path = NULL;
85
86 LV_LOG_INFO("begin");
87 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
88 lv_obj_class_init_obj(obj);
89
90 return obj;
91 }
92
lv_rlottie_set_play_mode(lv_obj_t * obj,const lv_rlottie_ctrl_t ctrl)93 void lv_rlottie_set_play_mode(lv_obj_t * obj, const lv_rlottie_ctrl_t ctrl)
94 {
95 lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
96 rlottie->play_ctrl = ctrl;
97
98 if(rlottie->task && (rlottie->dest_frame != rlottie->current_frame ||
99 (rlottie->play_ctrl & LV_RLOTTIE_CTRL_PAUSE) == LV_RLOTTIE_CTRL_PLAY)) {
100 lv_timer_resume(rlottie->task);
101 }
102 }
103
lv_rlottie_set_current_frame(lv_obj_t * obj,const size_t goto_frame)104 void lv_rlottie_set_current_frame(lv_obj_t * obj, const size_t goto_frame)
105 {
106 lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
107 rlottie->current_frame = goto_frame < rlottie->total_frames ? goto_frame : rlottie->total_frames - 1;
108 }
109
110 /**********************
111 * STATIC FUNCTIONS
112 **********************/
113
lv_rlottie_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)114 static void lv_rlottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
115 {
116 LV_UNUSED(class_p);
117 lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
118
119 if(create_info.rlottie_desc) {
120 rlottie->animation = lottie_animation_from_data(create_info.rlottie_desc, create_info.rlottie_desc, "");
121 }
122 else if(create_info.path) {
123 rlottie->animation = lottie_animation_from_file(create_info.path);
124 }
125 if(rlottie->animation == NULL) {
126 LV_LOG_WARN("The animation can't be opened");
127 return;
128 }
129
130 rlottie->total_frames = lottie_animation_get_totalframe(rlottie->animation);
131 rlottie->framerate = (size_t)lottie_animation_get_framerate(rlottie->animation);
132 rlottie->current_frame = 0;
133
134 rlottie->scanline_width = create_info.width * LV_ARGB32 / 8;
135
136 size_t allocated_buf_size = (create_info.width * create_info.height * LV_ARGB32 / 8);
137 rlottie->allocated_buf = lv_malloc(allocated_buf_size);
138 if(rlottie->allocated_buf != NULL) {
139 rlottie->allocated_buffer_size = allocated_buf_size;
140 memset(rlottie->allocated_buf, 0, allocated_buf_size);
141 }
142
143 rlottie->imgdsc.header.cf = LV_COLOR_FORMAT_ARGB8888;
144 rlottie->imgdsc.header.h = create_info.height;
145 rlottie->imgdsc.header.w = create_info.width;
146 rlottie->imgdsc.data = (void *)rlottie->allocated_buf;
147 rlottie->imgdsc.data_size = allocated_buf_size;
148
149 lv_image_set_src(obj, &rlottie->imgdsc);
150
151 rlottie->play_ctrl = LV_RLOTTIE_CTRL_FORWARD | LV_RLOTTIE_CTRL_PLAY | LV_RLOTTIE_CTRL_LOOP;
152 rlottie->dest_frame = rlottie->total_frames; /* invalid destination frame so it's possible to pause on frame 0 */
153
154 rlottie->task = lv_timer_create(next_frame_task_cb, 1000 / rlottie->framerate, obj);
155
156 lv_obj_update_layout(obj);
157 }
158
lv_rlottie_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)159 static void lv_rlottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
160 {
161 LV_UNUSED(class_p);
162 lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
163
164 if(rlottie->animation) {
165 lottie_animation_destroy(rlottie->animation);
166 rlottie->animation = 0;
167 rlottie->current_frame = 0;
168 rlottie->framerate = 0;
169 rlottie->scanline_width = 0;
170 rlottie->total_frames = 0;
171 }
172
173 if(rlottie->task) {
174 lv_timer_delete(rlottie->task);
175 rlottie->task = NULL;
176 rlottie->play_ctrl = LV_RLOTTIE_CTRL_FORWARD;
177 rlottie->dest_frame = 0;
178 }
179
180 lv_image_cache_drop(&rlottie->imgdsc);
181
182 if(rlottie->allocated_buf) {
183 lv_free(rlottie->allocated_buf);
184 rlottie->allocated_buf = NULL;
185 rlottie->allocated_buffer_size = 0;
186 }
187
188 }
189
next_frame_task_cb(lv_timer_t * t)190 static void next_frame_task_cb(lv_timer_t * t)
191 {
192 lv_obj_t * obj = lv_timer_get_user_data(t);
193 lv_rlottie_t * rlottie = (lv_rlottie_t *) obj;
194
195 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_PAUSE) == LV_RLOTTIE_CTRL_PAUSE) {
196 if(rlottie->current_frame == rlottie->dest_frame) {
197 /* Pause the timer too when it has run once to avoid CPU consumption */
198 lv_timer_pause(t);
199 return;
200 }
201 rlottie->dest_frame = rlottie->current_frame;
202 }
203 else {
204 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_BACKWARD) == LV_RLOTTIE_CTRL_BACKWARD) {
205 if(rlottie->current_frame > 0)
206 --rlottie->current_frame;
207 else { /* Looping ? */
208 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_LOOP) == LV_RLOTTIE_CTRL_LOOP)
209 rlottie->current_frame = rlottie->total_frames - 1;
210 else {
211 lv_obj_send_event(obj, LV_EVENT_READY, NULL);
212 lv_timer_pause(t);
213 return;
214 }
215 }
216 }
217 else {
218 if(rlottie->current_frame < rlottie->total_frames)
219 ++rlottie->current_frame;
220 else { /* Looping ? */
221 if((rlottie->play_ctrl & LV_RLOTTIE_CTRL_LOOP) == LV_RLOTTIE_CTRL_LOOP)
222 rlottie->current_frame = 0;
223 else {
224 lv_obj_send_event(obj, LV_EVENT_READY, NULL);
225 lv_timer_pause(t);
226 return;
227 }
228 }
229 }
230 }
231
232 lottie_animation_render(
233 rlottie->animation,
234 rlottie->current_frame,
235 rlottie->allocated_buf,
236 rlottie->imgdsc.header.w,
237 rlottie->imgdsc.header.h,
238 rlottie->scanline_width
239 );
240
241 lv_obj_invalidate(obj);
242 }
243
244 #endif /*LV_USE_RLOTTIE*/
245