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