2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #ifndef EFL_BETA_API_SUPPORT
23 #define EFL_BETA_API_SUPPORT
26 #ifndef EFL_EO_API_SUPPORT
27 #define EFL_EO_API_SUPPORT
34 #include <Ecore_Evas.h>
36 #include "rlottie_capi.h"
40 class RenderStrategy {
42 virtual ~RenderStrategy() {
43 evas_object_del(renderObject());
45 RenderStrategy(Evas_Object *obj):_renderObject(obj){}
46 virtual rlottie::Animation *player() {return nullptr;}
47 virtual void loadFromFile(const char *filePath) = 0;
48 virtual void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath) = 0;
49 virtual size_t totalFrame() = 0;
50 virtual double frameRate() = 0;
51 virtual size_t frameAtPos(double pos) = 0;
52 virtual double duration() = 0;
53 virtual void renderRequest(int frame) = 0;
54 virtual void renderFlush() {}
55 virtual void resize(int width, int height) = 0;
56 virtual void setPos(int x, int y) {evas_object_move(renderObject(), x, y);}
57 void show() {evas_object_show(_renderObject);}
58 void hide() {evas_object_hide(_renderObject);}
59 Evas_Object* renderObject() const {return _renderObject;}
61 Evas_Object *_renderObject;
64 class CppApiBase : public RenderStrategy {
66 CppApiBase(Evas_Object *renderObject): RenderStrategy(renderObject) {}
67 rlottie::Animation *player() {return mPlayer.get();}
68 void loadFromFile(const char *filePath)
70 mPlayer = rlottie::Animation::loadFromFile(filePath);
73 printf("load failed file %s\n", filePath);
77 void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath)
79 mPlayer = rlottie::Animation::loadFromData(jsonData, key, resourcePath);
81 printf("load failed from data\n");
86 return mPlayer->totalFrame();
90 return mPlayer->duration();
94 return mPlayer->frameRate();
97 size_t frameAtPos(double pos) {
98 return mPlayer->frameAtPos(pos);
101 std::unique_ptr<rlottie::Animation> mPlayer;
104 class RlottieRenderStrategyCBase : public RenderStrategy {
106 RlottieRenderStrategyCBase(Evas *evas):RenderStrategy(evas_object_image_filled_add(evas)) {
107 evas_object_image_colorspace_set(renderObject(), EVAS_COLORSPACE_ARGB8888);
108 evas_object_image_alpha_set(renderObject(), EINA_TRUE);
110 void resize(int width, int height) {
111 evas_object_resize(renderObject(), width, height);
112 evas_object_image_size_set(renderObject(), width, height);
116 class RlottieRenderStrategy : public CppApiBase {
118 RlottieRenderStrategy(Evas *evas):CppApiBase(evas_object_image_filled_add(evas)) {
119 evas_object_image_colorspace_set(renderObject(), EVAS_COLORSPACE_ARGB8888);
120 evas_object_image_alpha_set(renderObject(), EINA_TRUE);
122 void resize(int width, int height) {
123 evas_object_resize(renderObject(), width, height);
124 evas_object_image_size_set(renderObject(), width, height);
128 class RlottieRenderStrategy_CPP : public RlottieRenderStrategy {
130 RlottieRenderStrategy_CPP(Evas *evas):RlottieRenderStrategy(evas) {}
132 void renderRequest(int frame) {
134 Evas_Object *image = renderObject();
135 evas_object_image_size_get(image, &width, &height);
136 auto buffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
137 size_t bytesperline = evas_object_image_stride_get(image);
138 rlottie::Surface surface(buffer, width, height, bytesperline);
139 mPlayer->renderSync(frame, surface);
140 evas_object_image_data_set(image, surface.buffer());
141 evas_object_image_data_update_add(image, 0 , 0, surface.width(), surface.height());
145 class RlottieRenderStrategy_CPP_ASYNC : public RlottieRenderStrategy_CPP {
147 RlottieRenderStrategy_CPP_ASYNC(Evas *evas):RlottieRenderStrategy_CPP(evas) {}
148 ~RlottieRenderStrategy_CPP_ASYNC() {
149 if (mRenderTask.valid())
152 void renderRequest(int frame) {
153 if (mRenderTask.valid()) return;
156 Evas_Object *image = renderObject();
157 evas_object_image_size_get(image, &width, &height);
158 auto buffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
159 size_t bytesperline = evas_object_image_stride_get(image);
160 rlottie::Surface surface(buffer, width, height, bytesperline);
161 mRenderTask = mPlayer->render(frame, surface);
163 evas_object_image_data_update_add(renderObject(), 0 , 0, surface.width(), surface.height());
169 if (!mRenderTask.valid()) return;
171 auto surface = mRenderTask.get();
172 evas_object_image_data_set(renderObject(), surface.buffer());
173 evas_object_image_data_update_add(renderObject(), 0 , 0, surface.width(), surface.height());
177 std::future<rlottie::Surface> mRenderTask;
182 class RlottieRenderStrategy_C : public RlottieRenderStrategyCBase {
184 RlottieRenderStrategy_C(Evas *evas):RlottieRenderStrategyCBase(evas) {}
185 ~RlottieRenderStrategy_C() {
186 if (mPlayer) lottie_animation_destroy(mPlayer);
188 void loadFromFile(const char *filePath)
190 mPlayer = lottie_animation_from_file(filePath);
193 printf("load failed file %s\n", filePath);
197 void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath)
199 mPlayer = lottie_animation_from_data(jsonData.c_str(), key.c_str(), resourcePath.c_str());
201 printf("load failed from data\n");
205 size_t totalFrame() {
206 return lottie_animation_get_totalframe(mPlayer);
211 return lottie_animation_get_framerate(mPlayer);
214 size_t frameAtPos(double pos) {
215 return lottie_animation_get_frame_at_pos(mPlayer, pos);
219 return lottie_animation_get_duration(mPlayer);
222 void renderRequest(int frame) {
224 Evas_Object *image = renderObject();
225 evas_object_image_size_get(image, &width, &height);
226 auto buffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
227 size_t bytesperline = evas_object_image_stride_get(image);
228 lottie_animation_render_async(mPlayer, frame, buffer, width, height, bytesperline);
229 lottie_animation_render_flush(mPlayer);
230 evas_object_image_data_set(image, buffer);
231 evas_object_image_data_update_add(image, 0 , 0, width, height);
235 Lottie_Animation *mPlayer;
238 class RlottieRenderStrategy_C_ASYNC : public RlottieRenderStrategy_C {
240 RlottieRenderStrategy_C_ASYNC(Evas *evas):RlottieRenderStrategy_C(evas) {}
241 ~RlottieRenderStrategy_C_ASYNC() {
242 if (mDirty) lottie_animation_render_flush(mPlayer);
244 void renderRequest(int frame) {
247 Evas_Object *image = renderObject();
248 evas_object_image_size_get(image, &mWidth, &mHeight);
249 mBuffer = (uint32_t *)evas_object_image_data_get(image, EINA_TRUE);
250 size_t bytesperline = evas_object_image_stride_get(image);
251 lottie_animation_render_async(mPlayer, frame, mBuffer, mWidth, mHeight, bytesperline);
253 evas_object_image_data_update_add(renderObject(), 0 , 0, mWidth, mWidth);
258 lottie_animation_render_flush(mPlayer);
259 evas_object_image_data_set(renderObject(), mBuffer);
260 evas_object_image_data_update_add(renderObject(), 0 , 0, mWidth, mHeight);
270 enum class Strategy {
281 enum class RepeatMode {
285 LottieView(Evas *evas, Strategy s = Strategy::renderCppAsync);
287 rlottie::Animation *player(){return mRenderDelegate->player();}
288 Evas_Object *getImage();
289 void setSize(int w, int h);
290 void setPos(int x, int y);
291 void setFilePath(const char *filePath);
292 void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath="");
295 void loop(bool loop);
296 void setSpeed(float speed) { mSpeed = speed;}
297 void setRepeatCount(int count);
298 void setRepeatMode(LottieView::RepeatMode mode);
299 float getFrameRate() const { return mRenderDelegate->frameRate(); }
300 long getTotalFrame() const { return mRenderDelegate->totalFrame(); }
302 void seek(float pos);
309 void initializeBufferObject(Evas *evas);
310 void setMinProgress(float progress)
313 mMinProgress = progress;
315 void setMaxProgress(float progress)
318 mMaxprogress = progress;
321 float mapProgress(float progress) {
322 //clamp it to the segment
323 progress = (mMinProgress + (mMaxprogress - mMinProgress) * progress);
325 // currently playing and in reverse mode
326 if (mPalying && mReverse)
327 progress = mMaxprogress > mMinProgress ?
328 mMaxprogress - progress : mMinProgress - progress;
333 float duration() const {
334 // usually we run the animation for mPlayer->duration()
335 // but now run animation for segmented duration.
336 return mRenderDelegate->duration() * fabs(mMaxprogress - mMinProgress);
338 void createVgNode(LOTNode *node, Efl_VG *root);
339 void update(const std::vector<LOTNode *> &);
340 void updateTree(const LOTLayerNode *);
341 void update(const LOTLayerNode *, Efl_VG *parent);
345 LottieView::RepeatMode mRepeatMode;
346 size_t mCurFrame{UINT_MAX};
347 Ecore_Animator *mAnimator{nullptr};
354 //keep a segment of the animation default is [0, 1]
355 float mMinProgress{0};
356 float mMaxprogress{1};
357 std::unique_ptr<RenderStrategy> mRenderDelegate;
361 class EflVgRenderStrategy : public CppApiBase {
365 EflVgRenderStrategy(Evas *evas):CppApiBase(evas_object_vg_add(evas)) {}
367 void resize(int width, int height) {
370 evas_object_resize(renderObject(), width, height);
373 void renderRequest(int frame) {
374 const LOTLayerNode *root = mPlayer->renderTree(frame, mW, mH);
378 void updateTree(const LOTLayerNode * node)
380 Efl_VG *root = evas_vg_container_add(renderObject());
382 evas_object_vg_root_node_set(renderObject(), root);
385 void createVgNode(LOTNode *node, Efl_VG *root)
387 Efl_VG *shape = evas_vg_shape_add(root);
390 const float *data = node->mPath.ptPtr;
393 for (int i = 0; i < node->mPath.elmCount; i++) {
394 switch (node->mPath.elmPtr[i]) {
396 evas_vg_shape_append_move_to(shape, data[0], data[1]);
400 evas_vg_shape_append_line_to(shape, data[0], data[1]);
404 evas_vg_shape_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]);
408 evas_vg_shape_append_close(shape);
416 if (node->mStroke.enable) {
418 evas_vg_shape_stroke_width_set(shape, node->mStroke.width);
422 switch (node->mStroke.cap) {
423 case CapFlat: cap = EFL_GFX_CAP_BUTT; break;
424 case CapSquare: cap = EFL_GFX_CAP_SQUARE; break;
425 case CapRound: cap = EFL_GFX_CAP_ROUND; break;
426 default: cap = EFL_GFX_CAP_BUTT; break;
428 evas_vg_shape_stroke_cap_set(shape, cap);
432 switch (node->mStroke.join) {
433 case JoinMiter: join = EFL_GFX_JOIN_MITER; break;
434 case JoinBevel: join = EFL_GFX_JOIN_BEVEL; break;
435 case JoinRound: join = EFL_GFX_JOIN_ROUND; break;
436 default: join = EFL_GFX_JOIN_MITER; break;
438 evas_vg_shape_stroke_join_set(shape, join);
441 if (node->mStroke.dashArraySize > 0) {
442 int size = (node->mStroke.dashArraySize / 2);
443 Efl_Gfx_Dash *dash = static_cast<Efl_Gfx_Dash*>(malloc(sizeof(Efl_Gfx_Dash) * size));
445 for (int i = 0; i <= size; i+=2) {
446 dash[i].length = node->mStroke.dashArray[i];
447 dash[i].gap = node->mStroke.dashArray[i + 1];
449 evas_vg_shape_stroke_dash_set(shape, dash, size);
456 switch (node->mBrushType) {
458 float pa = ((float)node->mColor.a) / 255;
459 int r = (int)(((float) node->mColor.r) * pa);
460 int g = (int)(((float) node->mColor.g) * pa);
461 int b = (int)(((float) node->mColor.b) * pa);
462 int a = node->mColor.a;
463 if (node->mStroke.enable)
464 evas_vg_shape_stroke_color_set(shape, r, g, b, a);
466 evas_vg_node_color_set(shape, r, g, b, a);
469 case BrushGradient: {
471 if (node->mGradient.type == GradientLinear) {
472 grad = evas_vg_gradient_linear_add(root);
473 evas_vg_gradient_linear_start_set(grad, node->mGradient.start.x, node->mGradient.start.y);
474 evas_vg_gradient_linear_end_set(grad, node->mGradient.end.x, node->mGradient.end.y);
477 else if (node->mGradient.type == GradientRadial) {
478 grad = evas_vg_gradient_radial_add(root);
479 evas_vg_gradient_radial_center_set(grad, node->mGradient.center.x, node->mGradient.center.y);
480 evas_vg_gradient_radial_focal_set(grad, node->mGradient.focal.x, node->mGradient.focal.y);
481 evas_vg_gradient_radial_radius_set(grad, node->mGradient.cradius);
486 Efl_Gfx_Gradient_Stop* stops = static_cast<Efl_Gfx_Gradient_Stop*>(malloc(sizeof(Efl_Gfx_Gradient_Stop) * node->mGradient.stopCount));
488 for (unsigned int i = 0; i < node->mGradient.stopCount; i++) {
489 stops[i].offset = node->mGradient.stopPtr[i].pos;
490 float pa = ((float)node->mGradient.stopPtr[i].a) / 255;
491 stops[i].r = (int)(((float)node->mGradient.stopPtr[i].r) * pa);
492 stops[i].g = (int)(((float)node->mGradient.stopPtr[i].g) * pa);
493 stops[i].b = (int)(((float)node->mGradient.stopPtr[i].b) * pa);
494 stops[i].a = node->mGradient.stopPtr[i].a;
496 evas_vg_gradient_stop_set(grad, stops, node->mGradient.stopCount);
499 if (node->mStroke.enable)
500 evas_vg_shape_stroke_fill_set(shape, grad);
502 evas_vg_shape_fill_set(shape, grad);
511 // if (node->mFillRule == FillEvenOdd)
512 // efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_ODD_EVEN);
513 // else if (node->mFillRule == FillWinding)
514 // efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_WINDING);
517 void update(const std::vector<LOTNode *> &renderList)
519 Efl_VG *root = evas_vg_container_add(renderObject());
520 for(auto i : renderList) {
521 createVgNode(i, root);
523 evas_object_vg_root_node_set(renderObject(), root);
526 void update(const LOTLayerNode * node, Efl_VG *parent)
528 // if the layer is invisible return
529 if (!node->mVisible) return;
531 // check if this layer is a container layer
532 bool hasMatte = false;
533 if (node->mLayerList.size) {
534 for (unsigned int i = 0; i < node->mLayerList.size; i++) {
539 // if the layer has matte then
540 // the next layer has to be rendered using this layer
542 if (node->mLayerList.ptr[i]->mMatte != MatteNone) {
544 printf("Matte is not supported Yet\n");
547 update(node->mLayerList.ptr[i], parent);
551 // check if this layer has drawable
552 if (node->mNodeList.size) {
553 for (unsigned int i = 0; i < node->mNodeList.size; i++) {
554 createVgNode(node->mNodeList.ptr[i], parent);
560 #endif //LOTTIEVIEW_H