forked from enlightenment/efl
evas vector: support json loader for rlottie integration.
Summary: Introduce a new evas json loader to support lottie animation. This json loader uses rlottie library which is a new github open project. These days most ui frameworks (windowpws, skia, qt, xamarin, react, nativescript) supports lottie, the rlottie was designed to support lottie as a standalone library and compatible with efl as well. To enable this,please install rlottie library then remove json disabler in meson_options.txt For more information, See lottie/rlottie project and its a introdcution article: https://airbnb.io/lottie/#/ https://github.com/samsung/rlottie https://hermet.pe.kr/143 Co-authored-by: JunsuChoi <jsuya.choi@samsung.com> {D8941} {D8944} Reviewers: #committers, jsuya, bu5hm4n Subscribers: bu5hm4n, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8940
This commit is contained in:
parent
1c02b7740d
commit
23af6ec640
|
@ -201,8 +201,8 @@ option('evas-modules',
|
|||
option('evas-loaders-disabler',
|
||||
type : 'array',
|
||||
description : 'add names here to disable the loaders',
|
||||
choices : ['gst', 'pdf', 'ps', 'raw', 'svg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm'],
|
||||
value : ['webp']
|
||||
choices : ['gst', 'pdf', 'ps', 'raw', 'svg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm', 'json'],
|
||||
value : ['webp', 'json']
|
||||
)
|
||||
|
||||
option('ecore-imf-loaders-disabler',
|
||||
|
|
|
@ -185,6 +185,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(engine, wayland_egl);
|
|||
#if !EVAS_MODULE_NO_VG_LOADERS
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, eet);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, svg);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(vg_loader, json);
|
||||
#endif
|
||||
|
||||
#if !EVAS_MODULE_NO_IMAGE_LOADERS
|
||||
|
@ -274,6 +275,9 @@ static const struct {
|
|||
#ifdef EVAS_STATIC_BUILD_VG_EET
|
||||
EVAS_EINA_STATIC_MODULE_USE(vg_loader, eet),
|
||||
#endif
|
||||
#ifdef EVAS_STATIC_BUILD_VG_JSON
|
||||
EVAS_EINA_STATIC_MODULE_USE(vg_loader, json),
|
||||
#endif
|
||||
#endif
|
||||
#if !EVAS_MODULE_NO_IMAGE_LOADERS
|
||||
#ifdef EVAS_STATIC_BUILD_BMP
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
png = dependency('libpng')
|
||||
tiff = dependency('libtiff-4')
|
||||
giflib = cc.find_library('gif')
|
||||
|
||||
json = dependency('rlottie', required: get_option('evas-loaders-disabler').contains('json') == false)
|
||||
webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false)
|
||||
|
||||
#there are a few modules that should NEVER be build as a module but rather be build as static lib and linked in later
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#include <rlottie_capi.h>
|
||||
#include "vg_common.h"
|
||||
|
||||
#ifdef ERR
|
||||
# undef ERR
|
||||
#endif
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_evas_vg_loader_json_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef INF
|
||||
# undef INF
|
||||
#endif
|
||||
#define INF(...) EINA_LOG_DOM_INFO(_evas_vg_loader_json_log_dom, __VA_ARGS__)
|
||||
|
||||
static int _evas_vg_loader_json_log_dom = -1;
|
||||
|
||||
static Eina_Bool
|
||||
evas_vg_load_file_close_json(Vg_File_Data *vfd)
|
||||
{
|
||||
if (!vfd) return EINA_FALSE;
|
||||
|
||||
Lottie_Animation *lot_anim = (Lottie_Animation *) vfd->loader_data;
|
||||
lottie_animation_destroy(lot_anim);
|
||||
if (vfd->anim_data) free(vfd->anim_data);
|
||||
if (vfd->root) efl_unref(vfd->root);
|
||||
free(vfd);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
evas_vg_load_file_data_json(Vg_File_Data *vfd)
|
||||
{
|
||||
return vg_common_json_create_vg_node(vfd);
|
||||
}
|
||||
|
||||
static Vg_File_Data*
|
||||
evas_vg_load_file_open_json(Eina_File *file,
|
||||
const char *key,
|
||||
int *error EINA_UNUSED)
|
||||
{
|
||||
Vg_File_Data *vfd = calloc(1, sizeof(Vg_File_Data));
|
||||
if (!vfd) return NULL;
|
||||
|
||||
Lottie_Animation *lot_anim = NULL;
|
||||
|
||||
const char *data = (const char*) eina_file_map_all(file, EINA_FILE_SEQUENTIAL);
|
||||
if (!data) goto err;
|
||||
//@TODO pass corrct external_resource path.
|
||||
lot_anim = lottie_animation_from_data(data, key ? key:eina_file_filename_get(file), " ");
|
||||
eina_file_map_free(file, (void *) data);
|
||||
|
||||
if (!lot_anim)
|
||||
{
|
||||
ERR("Failed lottie_animation_from_file");
|
||||
goto err;
|
||||
}
|
||||
|
||||
unsigned int frame_cnt = lottie_animation_get_totalframe(lot_anim);
|
||||
|
||||
//Support animation
|
||||
if (frame_cnt > 1)
|
||||
{
|
||||
vfd->anim_data = calloc(1, sizeof(Vg_File_Anim_Data));
|
||||
if (!vfd->anim_data) goto err;
|
||||
vfd->anim_data->duration = lottie_animation_get_duration(lot_anim);
|
||||
vfd->anim_data->frame_cnt = frame_cnt;
|
||||
}
|
||||
|
||||
//default size
|
||||
size_t w, h;
|
||||
lottie_animation_get_size(lot_anim, &w, &h);
|
||||
vfd->w = (int) w;
|
||||
vfd->h = (int) h;
|
||||
|
||||
vfd->loader_data = (void *) lot_anim;
|
||||
vfd->no_share = EINA_TRUE;
|
||||
|
||||
return vfd;
|
||||
|
||||
err:
|
||||
if (vfd)
|
||||
{
|
||||
if (vfd->anim_data) free(vfd->anim_data);
|
||||
free(vfd);
|
||||
}
|
||||
if (lot_anim) lottie_animation_destroy(lot_anim);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Evas_Vg_Load_Func evas_vg_load_json_func =
|
||||
{
|
||||
evas_vg_load_file_open_json,
|
||||
evas_vg_load_file_close_json,
|
||||
evas_vg_load_file_data_json
|
||||
};
|
||||
|
||||
static int
|
||||
module_open(Evas_Module *em)
|
||||
{
|
||||
if (!em) return 0;
|
||||
em->functions = (void *)(&evas_vg_load_json_func);
|
||||
_evas_vg_loader_json_log_dom = eina_log_domain_register
|
||||
("vg-load-json", EVAS_DEFAULT_LOG_COLOR);
|
||||
if (_evas_vg_loader_json_log_dom < 0)
|
||||
{
|
||||
EINA_LOG_ERR("Can not create a module log domain.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
module_close(Evas_Module *em EINA_UNUSED)
|
||||
{
|
||||
if (_evas_vg_loader_json_log_dom >= 0)
|
||||
{
|
||||
eina_log_domain_unregister(_evas_vg_loader_json_log_dom);
|
||||
_evas_vg_loader_json_log_dom = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static Evas_Module_Api evas_modapi =
|
||||
{
|
||||
EVAS_MODULE_API_VERSION,
|
||||
"json",
|
||||
"none",
|
||||
{
|
||||
module_open,
|
||||
module_close
|
||||
}
|
||||
};
|
||||
|
||||
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_VG_LOADER, vg_loader, json);
|
||||
|
||||
#ifndef EVAS_STATIC_BUILD_VG_JSON
|
||||
EVAS_EINA_MODULE_DEFINE(vg_loader, json);
|
||||
#endif
|
||||
|
|
@ -1,13 +1,26 @@
|
|||
evas_vg_loaders_file = ['eet', 'svg']
|
||||
evas_vg_loaders_file = [
|
||||
['eet', [eet]],
|
||||
['json', [json]],
|
||||
['svg', []],
|
||||
]
|
||||
|
||||
foreach loader : evas_vg_loaders_file
|
||||
file = join_paths(loader, 'evas_vg_load_'+loader+'.c')
|
||||
static_library('vg_loader_'+loader, file,
|
||||
include_directories : config_dir,
|
||||
dependencies : evas_pre
|
||||
)
|
||||
evas_static_list += [declare_dependency(
|
||||
sources: file,
|
||||
)]
|
||||
config_h.set('EVAS_STATIC_BUILD_VG_'+loader.to_upper(), '1')
|
||||
foreach loader_inst : evas_vg_loaders_file
|
||||
loader = loader_inst[0]
|
||||
loader_deps = loader_inst[1]
|
||||
|
||||
if (get_option('evas-loaders-disabler').contains(loader) == false)
|
||||
file = join_paths(loader, 'evas_vg_load_'+loader+'.c')
|
||||
|
||||
static_library('vg_loader_'+loader, file,
|
||||
include_directories : config_dir,
|
||||
dependencies : [evas_pre] + loader_deps
|
||||
)
|
||||
|
||||
evas_static_list += [declare_dependency(
|
||||
sources: file,
|
||||
dependencies: loader_deps,
|
||||
)]
|
||||
|
||||
config_h.set('EVAS_STATIC_BUILD_VG_'+loader.to_upper(), '1')
|
||||
endif
|
||||
endforeach
|
||||
|
|
|
@ -5,6 +5,11 @@ vg_common_src = files([
|
|||
'vg_common.h',
|
||||
])
|
||||
|
||||
if get_option('evas-loaders-disabler').contains('json') == false
|
||||
config_h.set('BUILD_VG_LOADER_JSON', '1')
|
||||
vg_common_src += files('vg_common_json.c')
|
||||
endif
|
||||
|
||||
vg_common_inc_dir = include_directories('.')
|
||||
|
||||
vg_common = declare_dependency(
|
||||
|
|
|
@ -319,4 +319,10 @@ Vg_File_Data * vg_common_svg_create_vg_node(Svg_Node *node);
|
|||
Svg_Node *vg_common_svg_create_svg_node(Vg_File_Data *node);
|
||||
void vg_common_svg_node_free(Svg_Node *node);
|
||||
|
||||
|
||||
/******************************************************************************************
|
||||
* Lottie Compatible feature implementation
|
||||
******************************************************************************************/
|
||||
Eina_Bool vg_common_json_create_vg_node(Vg_File_Data *vfd);
|
||||
|
||||
#endif //EVAS_VG_COMMON_H_
|
||||
|
|
|
@ -0,0 +1,438 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "vg_common.h"
|
||||
#include <Evas.h>
|
||||
|
||||
#ifdef BUILD_VG_LOADER_JSON
|
||||
|
||||
#include <rlottie_capi.h>
|
||||
|
||||
//FIXME: This enum add temporarily to help understanding of additional code
|
||||
//related to masking in prepare_mask.
|
||||
//This needs to be formally declared through the eo class.
|
||||
typedef enum _EFL_CANVAS_VG_NODE_BLEND_TYPE
|
||||
{
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_NONE = 0,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT,
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE
|
||||
}EFL_CANVAS_VG_NODE_BLEND_TYPE;
|
||||
//
|
||||
|
||||
static char*
|
||||
_get_key_val(void *key)
|
||||
{
|
||||
static char buf[30];
|
||||
snprintf(buf, sizeof(buf), "%ld", (size_t) key);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
_construct_drawable_nodes(Efl_Canvas_Vg_Container *parent, const LOTLayerNode *layer, int depth EINA_UNUSED)
|
||||
{
|
||||
if (!parent) return;
|
||||
|
||||
for (unsigned int i = 0; i < layer->mNodeList.size; i++)
|
||||
{
|
||||
LOTNode *node = layer->mNodeList.ptr[i];
|
||||
if (!node) continue;
|
||||
|
||||
const float *data = node->mPath.ptPtr;
|
||||
if (!data) continue;
|
||||
|
||||
char *key = _get_key_val(node);
|
||||
Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key);
|
||||
if (!shape)
|
||||
{
|
||||
shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
|
||||
efl_key_data_set(parent, key, shape);
|
||||
}
|
||||
else
|
||||
efl_gfx_path_reset(shape);
|
||||
|
||||
efl_gfx_entity_visible_set(shape, EINA_TRUE);
|
||||
#if DEBUG
|
||||
for (int i = 0; i < depth; i++) printf(" ");
|
||||
printf("%s (%p)\n", efl_class_name_get(efl_class_get(shape)), shape);
|
||||
#endif
|
||||
//0: Path
|
||||
efl_gfx_path_reserve(shape, node->mPath.elmCount, node->mPath.ptCount);
|
||||
|
||||
for (int i = 0; i < node->mPath.elmCount; i++)
|
||||
{
|
||||
switch (node->mPath.elmPtr[i])
|
||||
{
|
||||
case 0:
|
||||
efl_gfx_path_append_move_to(shape, data[0], data[1]);
|
||||
data += 2;
|
||||
break;
|
||||
case 1:
|
||||
efl_gfx_path_append_line_to(shape, data[0], data[1]);
|
||||
data += 2;
|
||||
break;
|
||||
case 2:
|
||||
efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]);
|
||||
data += 6;
|
||||
break;
|
||||
case 3:
|
||||
efl_gfx_path_append_close(shape);
|
||||
break;
|
||||
default:
|
||||
ERR("No reserved path type = %d", node->mPath.elmPtr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//1: Stroke
|
||||
if (node->mStroke.enable)
|
||||
{
|
||||
//Stroke Width
|
||||
efl_gfx_shape_stroke_width_set(shape, node->mStroke.width);
|
||||
|
||||
//Stroke Cap
|
||||
Efl_Gfx_Cap cap;
|
||||
switch (node->mStroke.cap)
|
||||
{
|
||||
case CapFlat: cap = EFL_GFX_CAP_BUTT; break;
|
||||
case CapSquare: cap = EFL_GFX_CAP_SQUARE; break;
|
||||
case CapRound: cap = EFL_GFX_CAP_ROUND; break;
|
||||
default: cap = EFL_GFX_CAP_BUTT; break;
|
||||
}
|
||||
efl_gfx_shape_stroke_cap_set(shape, cap);
|
||||
|
||||
//Stroke Join
|
||||
Efl_Gfx_Join join;
|
||||
switch (node->mStroke.join)
|
||||
{
|
||||
case JoinMiter: join = EFL_GFX_JOIN_MITER; break;
|
||||
case JoinBevel: join = EFL_GFX_JOIN_BEVEL; break;
|
||||
case JoinRound: join = EFL_GFX_JOIN_ROUND; break;
|
||||
default: join = EFL_GFX_JOIN_MITER; break;
|
||||
}
|
||||
efl_gfx_shape_stroke_join_set(shape, join);
|
||||
|
||||
//Stroke Dash
|
||||
if (node->mStroke.dashArraySize > 0)
|
||||
{
|
||||
int size = (node->mStroke.dashArraySize / 2);
|
||||
Efl_Gfx_Dash *dash = malloc(sizeof(Efl_Gfx_Dash) * size);
|
||||
if (dash)
|
||||
{
|
||||
for (int i = 0; i <= size; i+=2)
|
||||
{
|
||||
dash[i].length = node->mStroke.dashArray[i];
|
||||
dash[i].gap = node->mStroke.dashArray[i + 1];
|
||||
}
|
||||
efl_gfx_shape_stroke_dash_set(shape, dash, size);
|
||||
free(dash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//2: Fill Method
|
||||
switch (node->mBrushType)
|
||||
{
|
||||
case BrushSolid:
|
||||
{
|
||||
float pa = ((float)node->mColor.a) / 255;
|
||||
int r = (int)(((float) node->mColor.r) * pa);
|
||||
int g = (int)(((float) node->mColor.g) * pa);
|
||||
int b = (int)(((float) node->mColor.b) * pa);
|
||||
int a = node->mColor.a;
|
||||
|
||||
if (node->mStroke.enable)
|
||||
efl_gfx_shape_stroke_color_set(shape, r, g, b, a);
|
||||
else
|
||||
efl_gfx_color_set(shape, r, g, b, a);
|
||||
}
|
||||
break;
|
||||
case BrushGradient:
|
||||
{
|
||||
Efl_Canvas_Vg_Gradient* grad = NULL;
|
||||
|
||||
if (node->mGradient.type == GradientLinear)
|
||||
{
|
||||
grad = efl_add(EFL_CANVAS_VG_GRADIENT_LINEAR_CLASS, parent);
|
||||
efl_gfx_gradient_linear_start_set(grad, node->mGradient.start.x, node->mGradient.start.y);
|
||||
efl_gfx_gradient_linear_end_set(grad, node->mGradient.end.x, node->mGradient.end.y);
|
||||
}
|
||||
else if (node->mGradient.type == GradientRadial)
|
||||
{
|
||||
grad = efl_add(EFL_CANVAS_VG_GRADIENT_RADIAL_CLASS, parent);
|
||||
efl_gfx_gradient_radial_center_set(grad, node->mGradient.center.x, node->mGradient.center.y);
|
||||
efl_gfx_gradient_radial_focal_set(grad, node->mGradient.focal.x, node->mGradient.focal.y);
|
||||
efl_gfx_gradient_radial_radius_set(grad, node->mGradient.cradius);
|
||||
}
|
||||
else
|
||||
ERR("No reserved gradient type = %d", node->mGradient.type);
|
||||
|
||||
if (grad)
|
||||
{
|
||||
//Gradient Stop
|
||||
Efl_Gfx_Gradient_Stop* stops = malloc(sizeof(Efl_Gfx_Gradient_Stop) * node->mGradient.stopCount);
|
||||
if (stops)
|
||||
{
|
||||
for (unsigned int i = 0; i < node->mGradient.stopCount; i++)
|
||||
{
|
||||
stops[i].offset = node->mGradient.stopPtr[i].pos;
|
||||
float pa = ((float)node->mGradient.stopPtr[i].a) / 255;
|
||||
stops[i].r = (int)(((float)node->mGradient.stopPtr[i].r) * pa);
|
||||
stops[i].g = (int)(((float)node->mGradient.stopPtr[i].g) * pa);
|
||||
stops[i].b = (int)(((float)node->mGradient.stopPtr[i].b) * pa);
|
||||
stops[i].a = node->mGradient.stopPtr[i].a;
|
||||
}
|
||||
efl_gfx_gradient_stop_set(grad, stops, node->mGradient.stopCount);
|
||||
free(stops);
|
||||
}
|
||||
if (node->mStroke.enable)
|
||||
efl_canvas_vg_shape_stroke_fill_set(shape, grad);
|
||||
else
|
||||
efl_canvas_vg_shape_fill_set(shape, grad);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERR("No reserved brush type = %d", node->mBrushType);
|
||||
}
|
||||
|
||||
//3: Fill Rule
|
||||
if (node->mFillRule == FillEvenOdd)
|
||||
efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_ODD_EVEN);
|
||||
else if (node->mFillRule == FillWinding)
|
||||
efl_gfx_shape_fill_rule_set(shape, EFL_GFX_FILL_RULE_WINDING);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_construct_mask_nodes(Efl_Canvas_Vg_Container *parent, LOTMask *mask, int depth EINA_UNUSED)
|
||||
{
|
||||
const float *data = mask->mPath.ptPtr;
|
||||
if (!data) return;
|
||||
|
||||
char *key = _get_key_val(mask);
|
||||
Efl_Canvas_Vg_Shape *shape = efl_key_data_get(parent, key);
|
||||
if (!shape)
|
||||
{
|
||||
shape = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
|
||||
efl_key_data_set(parent, key, shape);
|
||||
}
|
||||
else
|
||||
efl_gfx_path_reset(shape);
|
||||
|
||||
efl_gfx_entity_visible_set(shape, EINA_TRUE);
|
||||
|
||||
efl_gfx_path_reserve(shape, mask->mPath.elmCount, mask->mPath.ptCount);
|
||||
|
||||
for (int i = 0; i < mask->mPath.elmCount; i++)
|
||||
{
|
||||
switch (mask->mPath.elmPtr[i])
|
||||
{
|
||||
case 0:
|
||||
efl_gfx_path_append_move_to(shape, data[0], data[1]);
|
||||
data += 2;
|
||||
break;
|
||||
case 1:
|
||||
efl_gfx_path_append_line_to(shape, data[0], data[1]);
|
||||
data += 2;
|
||||
break;
|
||||
case 2:
|
||||
efl_gfx_path_append_cubic_to(shape, data[0], data[1], data[2], data[3], data[4], data[5]);
|
||||
data += 6;
|
||||
break;
|
||||
case 3:
|
||||
efl_gfx_path_append_close(shape);
|
||||
break;
|
||||
default:
|
||||
ERR("No reserved path type = %d", mask->mPath.elmPtr[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//White color and alpha setting
|
||||
float pa = ((float)mask->mAlpha) / 255;
|
||||
int r = (int) (255.0f * pa);
|
||||
int g = (int) (255.0f * pa);
|
||||
int b = (int) (255.0f * pa);
|
||||
int a = mask->mAlpha;
|
||||
efl_gfx_color_set(shape, r, g, b, a);
|
||||
}
|
||||
|
||||
static void
|
||||
_construct_masks(Efl_Canvas_Vg_Container *mtarget, LOTMask *masks, unsigned int mask_cnt, int depth)
|
||||
{
|
||||
char *key = NULL;
|
||||
|
||||
Efl_Canvas_Vg_Container *msource = NULL;
|
||||
|
||||
key = _get_key_val(mtarget);
|
||||
msource = efl_key_data_get(mtarget, key);
|
||||
if (!msource)
|
||||
{
|
||||
msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget);
|
||||
efl_key_data_set(mtarget, key, msource);
|
||||
}
|
||||
|
||||
//FIXME : EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA option is temporary
|
||||
//Currently matte alpha implemtnes is same the mask intersect impletment.
|
||||
//It has been implemented as a multiplication calculation.
|
||||
efl_canvas_vg_node_mask_set(mtarget, msource, EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA);
|
||||
|
||||
mtarget = msource;
|
||||
|
||||
//Make mask layers
|
||||
for (unsigned int i = 0; i < mask_cnt; i++)
|
||||
{
|
||||
LOTMask *mask = &masks[i];;
|
||||
key = _get_key_val(mask);
|
||||
msource = efl_key_data_get(mtarget, key);
|
||||
|
||||
if (!msource)
|
||||
{
|
||||
msource = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, mtarget);
|
||||
efl_key_data_set(mtarget, key, msource);
|
||||
}
|
||||
_construct_mask_nodes(msource, mask, depth + 1);
|
||||
|
||||
EFL_CANVAS_VG_NODE_BLEND_TYPE mask_mode;
|
||||
switch (mask->mMode)
|
||||
{
|
||||
case MaskSubstract:
|
||||
mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_SUBSTRACT;
|
||||
break;
|
||||
case MaskIntersect:
|
||||
mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_INTERSECT;
|
||||
break;
|
||||
case MaskDifference:
|
||||
mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_DIFFERENCE;
|
||||
break;
|
||||
case MaskAdd:
|
||||
default:
|
||||
mask_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_MASK_ADD;
|
||||
break;
|
||||
}
|
||||
efl_canvas_vg_node_mask_set(mtarget, msource, mask_mode);
|
||||
mtarget = msource;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_update_vg_tree(Efl_Canvas_Vg_Container *root, const LOTLayerNode *layer, int depth EINA_UNUSED)
|
||||
{
|
||||
if (!layer->mVisible)
|
||||
{
|
||||
efl_gfx_entity_visible_set(root, EINA_FALSE);
|
||||
return;
|
||||
}
|
||||
efl_gfx_entity_visible_set(root, EINA_TRUE);
|
||||
|
||||
Efl_Canvas_Vg_Container *ptree = NULL;
|
||||
|
||||
//Note: We assume that if matte is valid, next layer must be a matte source.
|
||||
int matte_mode = 0;
|
||||
Efl_Canvas_Vg_Container *mtarget = NULL;
|
||||
LOTLayerNode *mlayer = NULL;
|
||||
|
||||
//Is this layer a container layer?
|
||||
for (unsigned int i = 0; i < layer->mLayerList.size; i++)
|
||||
{
|
||||
LOTLayerNode *clayer = layer->mLayerList.ptr[i];
|
||||
|
||||
//Source Layer
|
||||
char *key = _get_key_val(clayer);
|
||||
Efl_Canvas_Vg_Container *ctree = efl_key_data_get(root, key);
|
||||
if (!ctree)
|
||||
{
|
||||
ctree = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, root);
|
||||
efl_key_data_set(root, key, ctree);
|
||||
}
|
||||
#if DEBUG
|
||||
for (int i = 0; i < depth; i++) printf(" ");
|
||||
printf("%s (%p) matte:%d => %p\n", efl_class_name_get(efl_class_get(ctree)), ctree, matte_mode, ptree);
|
||||
#endif
|
||||
_update_vg_tree(ctree, clayer, depth+1);
|
||||
|
||||
if (matte_mode != 0)
|
||||
{
|
||||
efl_canvas_vg_node_mask_set(ptree, ctree, matte_mode);
|
||||
mtarget = ctree;
|
||||
}
|
||||
matte_mode = (int) clayer->mMatte;
|
||||
|
||||
if (clayer->mMaskList.size > 0)
|
||||
{
|
||||
mlayer = clayer;
|
||||
if (!mtarget) mtarget = ctree;
|
||||
}
|
||||
|
||||
ptree = ctree;
|
||||
|
||||
//Remap Matte Mode
|
||||
switch (matte_mode)
|
||||
{
|
||||
case MatteNone:
|
||||
matte_mode = 0;
|
||||
break;
|
||||
case MatteAlpha:
|
||||
matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA;
|
||||
break;
|
||||
case MatteAlphaInv:
|
||||
matte_mode = EFL_CANVAS_VG_NODE_BLEND_TYPE_ALPHA_INV;
|
||||
break;
|
||||
case MatteLuma:
|
||||
matte_mode = 0;
|
||||
ERR("TODO: MatteLuma");
|
||||
break;
|
||||
case MatteLumaInv:
|
||||
matte_mode = 0;
|
||||
ERR("TODO: MatteLumaInv");
|
||||
break;
|
||||
default:
|
||||
matte_mode = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Construct drawable nodes.
|
||||
if (layer->mNodeList.size > 0)
|
||||
_construct_drawable_nodes(root, layer, depth);
|
||||
|
||||
//Construct node that have mask.
|
||||
if (mlayer)
|
||||
_construct_masks(mtarget, mlayer->mMaskList.ptr, mlayer->mMaskList.size, depth);
|
||||
}
|
||||
#endif
|
||||
|
||||
Eina_Bool
|
||||
vg_common_json_create_vg_node(Vg_File_Data *vfd)
|
||||
{
|
||||
#ifdef BUILD_VG_LOADER_JSON
|
||||
Lottie_Animation *lot_anim = (Lottie_Animation *) vfd->loader_data;
|
||||
if (!lot_anim) return EINA_FALSE;
|
||||
|
||||
unsigned int frame_num = (vfd->anim_data) ? vfd->anim_data->frame_num : 0;
|
||||
const LOTLayerNode *tree =
|
||||
lottie_animation_render_tree(lot_anim, frame_num,
|
||||
vfd->view_box.w, vfd->view_box.h);
|
||||
#if DEBUG
|
||||
printf("%s (%p)\n", efl_class_name_get(efl_class_get(vfd->root)), vfd->root);
|
||||
#endif
|
||||
|
||||
//Root node
|
||||
Efl_Canvas_Vg_Container *root = vfd->root;
|
||||
if (!root)
|
||||
{
|
||||
root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
|
||||
if (!root) return EINA_FALSE;
|
||||
efl_key_data_set(root, _get_key_val((void *) tree), tree);
|
||||
vfd->root = root;
|
||||
}
|
||||
|
||||
_update_vg_tree(root, tree, 1);
|
||||
#else
|
||||
return EINA_FALSE;
|
||||
#endif
|
||||
return EINA_TRUE;
|
||||
}
|
Loading…
Reference in New Issue