1 /**
2 * @file lv_lottie.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_lottie_private.h"
10 #include "../../lv_conf_internal.h"
11 #if LV_USE_LOTTIE
12
13 #if LV_USE_THORVG_EXTERNAL
14 #include <thorvg_capi.h>
15 #else
16 #include "../../libs/thorvg/thorvg_capi.h"
17 #endif
18
19 #include "../../misc/lv_timer.h"
20 #include "../../core/lv_obj_class_private.h"
21 #include "../../misc/cache/lv_image_cache.h"
22
23 /*********************
24 * DEFINES
25 *********************/
26 #define MY_CLASS (&lv_lottie_class)
27
28 /**********************
29 * TYPEDEFS
30 **********************/
31
32 /**********************
33 * STATIC PROTOTYPES
34 **********************/
35 static void lv_lottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
36 static void lv_lottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
37 static void anim_exec_cb(void * var, int32_t v);
38 static void lottie_update(lv_lottie_t * lottie, int32_t v);
39
40 /**********************
41 * STATIC VARIABLES
42 **********************/
43 const lv_obj_class_t lv_lottie_class = {
44 .constructor_cb = lv_lottie_constructor,
45 .destructor_cb = lv_lottie_destructor,
46 .width_def = LV_DPI_DEF,
47 .height_def = LV_DPI_DEF,
48 .instance_size = sizeof(lv_lottie_t),
49 .base_class = &lv_canvas_class,
50 .name = "lottie",
51 };
52
53 /**********************
54 * GLOBAL VARIABLES
55 **********************/
56
57 /**********************
58 * MACROS
59 **********************/
60
61 /**********************
62 * GLOBAL FUNCTIONS
63 **********************/
64
lv_lottie_create(lv_obj_t * parent)65 lv_obj_t * lv_lottie_create(lv_obj_t * parent)
66 {
67 LV_LOG_INFO("begin");
68 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
69 lv_obj_class_init_obj(obj);
70 return obj;
71 }
72
lv_lottie_set_buffer(lv_obj_t * obj,int32_t w,int32_t h,void * buf)73 void lv_lottie_set_buffer(lv_obj_t * obj, int32_t w, int32_t h, void * buf)
74 {
75 lv_lottie_t * lottie = (lv_lottie_t *)obj;
76 int32_t stride = lv_draw_buf_width_to_stride(w, LV_COLOR_FORMAT_ARGB8888);
77 buf = lv_draw_buf_align(buf, LV_COLOR_FORMAT_ARGB8888);
78
79 tvg_swcanvas_set_target(lottie->tvg_canvas, buf, stride / 4, w, h, TVG_COLORSPACE_ARGB8888);
80 tvg_canvas_push(lottie->tvg_canvas, lottie->tvg_paint);
81 lv_canvas_set_buffer(obj, buf, w, h, LV_COLOR_FORMAT_ARGB8888);
82 tvg_picture_set_size(lottie->tvg_paint, w, h);
83
84 /* Rendered output images are premultiplied */
85 lv_draw_buf_t * draw_buf = lv_canvas_get_draw_buf(obj);
86 lv_draw_buf_set_flag(draw_buf, LV_IMAGE_FLAGS_PREMULTIPLIED);
87
88 /*Force updating when the buffer changes*/
89 float f_current;
90 tvg_animation_get_frame(lottie->tvg_anim, &f_current);
91 anim_exec_cb(obj, (int32_t) f_current);
92 }
93
lv_lottie_set_draw_buf(lv_obj_t * obj,lv_draw_buf_t * draw_buf)94 void lv_lottie_set_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
95 {
96 if(draw_buf->header.cf != LV_COLOR_FORMAT_ARGB8888) {
97 LV_LOG_WARN("The draw buf needs to have ARGB8888 color format");
98 return;
99 }
100
101 lv_lottie_t * lottie = (lv_lottie_t *)obj;
102 tvg_swcanvas_set_target(lottie->tvg_canvas, (void *)draw_buf->data, draw_buf->header.stride / 4,
103 draw_buf->header.w, draw_buf->header.h, TVG_COLORSPACE_ARGB8888);
104 tvg_canvas_push(lottie->tvg_canvas, lottie->tvg_paint);
105 lv_canvas_set_draw_buf(obj, draw_buf);
106 tvg_picture_set_size(lottie->tvg_paint, draw_buf->header.w, draw_buf->header.h);
107
108 /* Rendered output images are premultiplied */
109 lv_draw_buf_set_flag(draw_buf, LV_IMAGE_FLAGS_PREMULTIPLIED);
110
111 /*Force updating when the buffer changes*/
112 float f_current;
113 tvg_animation_get_frame(lottie->tvg_anim, &f_current);
114 anim_exec_cb(obj, (int32_t) f_current);
115 }
116
lv_lottie_set_src_data(lv_obj_t * obj,const void * src,size_t src_size)117 void lv_lottie_set_src_data(lv_obj_t * obj, const void * src, size_t src_size)
118 {
119 lv_lottie_t * lottie = (lv_lottie_t *)obj;
120 tvg_picture_load_data(lottie->tvg_paint, src, src_size, "lottie", true);
121 lv_draw_buf_t * canvas_draw_buf = lv_canvas_get_draw_buf(obj);
122 if(canvas_draw_buf) {
123 tvg_picture_set_size(lottie->tvg_paint, canvas_draw_buf->header.w, canvas_draw_buf->header.h);
124 }
125
126 float f_total;
127 tvg_animation_get_total_frame(lottie->tvg_anim, &f_total);
128 lv_anim_set_duration(lottie->anim, (int32_t)f_total * 1000 / 60); /*60 FPS*/
129 lottie->anim->act_time = 0;
130 lottie->anim->end_value = (int32_t)f_total;
131 lottie->anim->reverse_play_in_progress = false;
132 lottie_update(lottie, 0); /*Render immediately*/
133 }
134
lv_lottie_set_src_file(lv_obj_t * obj,const char * src)135 void lv_lottie_set_src_file(lv_obj_t * obj, const char * src)
136 {
137 lv_lottie_t * lottie = (lv_lottie_t *)obj;
138 tvg_picture_load(lottie->tvg_paint, src);
139 lv_draw_buf_t * canvas_draw_buf = lv_canvas_get_draw_buf(obj);
140 if(canvas_draw_buf) {
141 tvg_picture_set_size(lottie->tvg_paint, canvas_draw_buf->header.w, canvas_draw_buf->header.h);
142 }
143
144 float f_total;
145 tvg_animation_get_total_frame(lottie->tvg_anim, &f_total);
146 lv_anim_set_duration(lottie->anim, (int32_t)f_total * 1000 / 60); /*60 FPS*/
147 lottie->anim->act_time = 0;
148 lottie->anim->end_value = (int32_t)f_total;
149 lottie->anim->reverse_play_in_progress = false;
150 lottie_update(lottie, 0); /*Render immediately*/
151 }
152
153
lv_lottie_get_anim(lv_obj_t * obj)154 lv_anim_t * lv_lottie_get_anim(lv_obj_t * obj)
155 {
156 LV_ASSERT_OBJ(obj, MY_CLASS);
157 lv_lottie_t * lottie = (lv_lottie_t *)obj;
158 return lottie->anim;
159 }
160
161 /**********************
162 * STATIC FUNCTIONS
163 **********************/
164
lv_lottie_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)165 static void lv_lottie_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
166 {
167 LV_UNUSED(class_p);
168 LV_TRACE_OBJ_CREATE("begin");
169
170 lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
171
172 lv_lottie_t * lottie = (lv_lottie_t *)obj;
173 lottie->tvg_anim = tvg_animation_new();
174
175 lottie->tvg_paint = tvg_animation_get_picture(lottie->tvg_anim);
176
177 lottie->tvg_canvas = tvg_swcanvas_create();
178
179 lv_anim_t a;
180 lv_anim_init(&a);
181 lv_anim_set_exec_cb(&a, anim_exec_cb);
182 lv_anim_set_var(&a, obj);
183 lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
184 lottie->anim = lv_anim_start(&a);
185
186 LV_TRACE_OBJ_CREATE("finished");
187 }
188
lv_lottie_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)189 static void lv_lottie_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
190 {
191 LV_UNUSED(class_p);
192 lv_lottie_t * lottie = (lv_lottie_t *)obj;
193
194 tvg_animation_del(lottie->tvg_anim);
195 tvg_canvas_destroy(lottie->tvg_canvas);
196 }
197
anim_exec_cb(void * var,int32_t v)198 static void anim_exec_cb(void * var, int32_t v)
199 {
200 lv_lottie_t * lottie = var;
201
202 /*Do not render not visible animations.*/
203 if(lv_obj_is_visible(var)) {
204 lottie_update(lottie, v);
205 if(lottie->anim) {
206 lottie->last_rendered_time = lottie->anim->act_time;
207 }
208 }
209 else {
210 /*Artificially keep the animation on the last rendered frame's time
211 *To avoid a jump when the widget becomes visible*/
212 if(lottie->anim) {
213 lottie->anim->act_time = lottie->last_rendered_time;
214 }
215 }
216 }
217
lottie_update(lv_lottie_t * lottie,int32_t v)218 static void lottie_update(lv_lottie_t * lottie, int32_t v)
219 {
220 lv_obj_t * obj = (lv_obj_t *) lottie;
221
222 lv_draw_buf_t * draw_buf = lv_canvas_get_draw_buf(obj);
223 if(draw_buf) {
224 lv_draw_buf_clear(draw_buf, NULL);
225
226 /*Drop old cached image*/
227 lv_image_cache_drop(lv_image_get_src(obj));
228 }
229
230 tvg_animation_set_frame(lottie->tvg_anim, v);
231 tvg_canvas_update(lottie->tvg_canvas);
232 tvg_canvas_draw(lottie->tvg_canvas);
233 tvg_canvas_sync(lottie->tvg_canvas);
234
235 lv_obj_invalidate(obj);
236 }
237
238 #endif /*LV_USE_LOTTIE*/
239