cedric pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=7cb92ff35d3e49c53368b6fe4ade1d2a732018fc
commit 7cb92ff35d3e49c53368b6fe4ade1d2a732018fc Author: Cedric BAIL <[email protected]> Date: Tue Jun 16 16:28:19 2015 +0200 evas: add support for interpolating Efl_VG_Node tree. --- src/lib/evas/canvas/efl_vg_base.eo | 8 ++ src/lib/evas/canvas/efl_vg_container.eo | 1 + src/lib/evas/canvas/efl_vg_gradient.eo | 1 + src/lib/evas/canvas/efl_vg_gradient_linear.eo | 1 + src/lib/evas/canvas/efl_vg_gradient_radial.eo | 1 + src/lib/evas/canvas/efl_vg_shape.eo | 1 + src/lib/evas/canvas/evas_vg_container.c | 38 ++++++ src/lib/evas/canvas/evas_vg_gradient.c | 43 ++++++ src/lib/evas/canvas/evas_vg_gradient_linear.c | 31 +++++ src/lib/evas/canvas/evas_vg_gradient_radial.c | 32 +++++ src/lib/evas/canvas/evas_vg_node.c | 184 ++++++++++++++++++++++++++ src/lib/evas/canvas/evas_vg_private.h | 12 ++ src/lib/evas/canvas/evas_vg_shape.c | 34 +++++ 13 files changed, 387 insertions(+) diff --git a/src/lib/evas/canvas/efl_vg_base.eo b/src/lib/evas/canvas/efl_vg_base.eo index 1567f5a..7ddfce5 100644 --- a/src/lib/evas/canvas/efl_vg_base.eo +++ b/src/lib/evas/canvas/efl_vg_base.eo @@ -88,6 +88,14 @@ abstract Efl.VG.Base (Eo.Base, Efl.Gfx.Base, Efl.Gfx.Stack) @out r: Eina.Rectangle; [[bounding box to be returned.]] } } + interpolate { + return: bool; + params { + @in from: const(Efl.VG.Base)*; + @in to: const(Efl.VG.Base)*; + @in pos_map: double; + } + } } implements { Eo.Base.parent.set; diff --git a/src/lib/evas/canvas/efl_vg_container.eo b/src/lib/evas/canvas/efl_vg_container.eo index 19a7b30..b3a6ec4 100644 --- a/src/lib/evas/canvas/efl_vg_container.eo +++ b/src/lib/evas/canvas/efl_vg_container.eo @@ -16,5 +16,6 @@ class Efl.VG.Container (Efl.VG.Base) Eo.Base.constructor; Eo.Base.destructor; Efl.VG.Base.bounds_get; + Efl.VG.Base.interpolate; } } diff --git a/src/lib/evas/canvas/efl_vg_gradient.eo b/src/lib/evas/canvas/efl_vg_gradient.eo index de78039..959da5b 100644 --- a/src/lib/evas/canvas/efl_vg_gradient.eo +++ b/src/lib/evas/canvas/efl_vg_gradient.eo @@ -6,5 +6,6 @@ abstract Efl.VG.Gradient (Efl.VG.Base, Efl.Gfx.Gradient.Base) Efl.Gfx.Gradient.Base.stop.get; Efl.Gfx.Gradient.Base.spread.set; Efl.Gfx.Gradient.Base.spread.get; + Efl.VG.Base.interpolate; } } diff --git a/src/lib/evas/canvas/efl_vg_gradient_linear.eo b/src/lib/evas/canvas/efl_vg_gradient_linear.eo index 4aaddd4..aecfe4e 100644 --- a/src/lib/evas/canvas/efl_vg_gradient_linear.eo +++ b/src/lib/evas/canvas/efl_vg_gradient_linear.eo @@ -7,6 +7,7 @@ class Efl.VG.Gradient_Linear (Efl.VG.Gradient, Efl.Gfx.Gradient.Linear) Efl.Gfx.Gradient.Linear.end.set; Efl.Gfx.Gradient.Linear.end.get; Efl.VG.Base.bounds_get; + Efl.VG.Base.interpolate; Eo.Base.constructor; Eo.Base.destructor; } diff --git a/src/lib/evas/canvas/efl_vg_gradient_radial.eo b/src/lib/evas/canvas/efl_vg_gradient_radial.eo index 62eb086..bd99848 100644 --- a/src/lib/evas/canvas/efl_vg_gradient_radial.eo +++ b/src/lib/evas/canvas/efl_vg_gradient_radial.eo @@ -9,6 +9,7 @@ class Efl.VG.Gradient_Radial (Efl.VG.Gradient, Efl.Gfx.Gradient.Radial) Efl.Gfx.Gradient.Radial.focal.set; Efl.Gfx.Gradient.Radial.focal.get; Efl.VG.Base.bounds_get; + Efl.VG.Base.interpolate; Eo.Base.constructor; Eo.Base.destructor; } diff --git a/src/lib/evas/canvas/efl_vg_shape.eo b/src/lib/evas/canvas/efl_vg_shape.eo index 45d0d30..e2d5c27 100644 --- a/src/lib/evas/canvas/efl_vg_shape.eo +++ b/src/lib/evas/canvas/efl_vg_shape.eo @@ -41,6 +41,7 @@ class Efl.VG.Shape (Efl.VG.Base, Efl.Gfx.Shape) Efl.Gfx.Base.color_part.set; Efl.Gfx.Base.color_part.get; Efl.VG.Base.bounds_get; + Efl.VG.Base.interpolate; Eo.Base.constructor; Eo.Base.destructor; } diff --git a/src/lib/evas/canvas/evas_vg_container.c b/src/lib/evas/canvas/evas_vg_container.c index e311260..683f5ce 100644 --- a/src/lib/evas/canvas/evas_vg_container.c +++ b/src/lib/evas/canvas/evas_vg_container.c @@ -97,6 +97,44 @@ _efl_vg_container_children_get(Eo *obj EINA_UNUSED, Efl_VG_Container_Data *pd) return eina_list_iterator_new(pd->children); } +static Eina_Bool +_efl_vg_container_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Container_Data *pd, + const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Container_Data *fd; + Efl_VG_Container_Data *td; + Eina_Iterator *it; + Eina_Hash_Tuple *tuple; + Eina_Bool r; + + eo_do_super(obj, EFL_VG_CONTAINER_CLASS, r = efl_vg_interpolate(from, to, pos_map)); + + if (!r) return EINA_FALSE; + + fd = eo_data_scope_get(from, EFL_VG_CONTAINER_CLASS); + td = eo_data_scope_get(to, EFL_VG_CONTAINER_CLASS); + + it = eina_hash_iterator_tuple_new(pd->names); + EINA_ITERATOR_FOREACH(it, tuple) + { + Eo *fromc, *toc; + Eo *cc = tuple->data; + + fromc = eina_hash_find(fd->names, tuple->key); + toc = eina_hash_find(td->names, tuple->key); + + if (!toc || !fromc) continue ; + if (eo_class_get(toc) != eo_class_get(fromc)) continue ; + + eo_do(cc, r &= efl_vg_interpolate(fromc, toc, pos_map)); + } + eina_iterator_free(it); + + return r; +} + EAPI Efl_VG* evas_vg_container_add(Efl_VG *parent) { diff --git a/src/lib/evas/canvas/evas_vg_gradient.c b/src/lib/evas/canvas/evas_vg_gradient.c index 245b6fe..495a493 100644 --- a/src/lib/evas/canvas/evas_vg_gradient.c +++ b/src/lib/evas/canvas/evas_vg_gradient.c @@ -51,6 +51,49 @@ _efl_vg_gradient_efl_gfx_gradient_base_spread_get(Eo *obj EINA_UNUSED, return pd->s; } +static Eina_Bool +_efl_vg_gradient_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Gradient_Data *pd, + const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Gradient_Data *fromd, *tod; + Efl_Gfx_Gradient_Stop *colors; + unsigned int i; + double from_map; + Eina_Bool r; + + eo_do_super(obj, EFL_VG_GRADIENT_CLASS, r = efl_vg_interpolate(from, to, pos_map)); + + fromd = eo_data_scope_get(from, EFL_VG_GRADIENT_CLASS); + tod = eo_data_scope_get(to, EFL_VG_GRADIENT_CLASS); + from_map = 1.0 - pos_map; + + if (!r) return EINA_FALSE; + if (fromd->colors_count != tod->colors_count) return EINA_FALSE; + + colors = realloc(pd->colors, sizeof (Efl_Gfx_Gradient_Stop) * tod->colors_count); + if (!colors) return EINA_FALSE; + + pd->colors = colors; + +#define INTP(Pd, From, To, I, Member, From_Map, Pos_Map) \ + Pd->colors[I].Member = From->colors[I].Member * From_Map + To->colors[I].Member * Pos_Map + + for (i = 0; i < fromd->colors_count; i++) + { + INTP(pd, fromd, tod, i, offset, from_map, pos_map); + INTP(pd, fromd, tod, i, r, from_map, pos_map); + INTP(pd, fromd, tod, i, g, from_map, pos_map); + INTP(pd, fromd, tod, i, b, from_map, pos_map); + INTP(pd, fromd, tod, i, a, from_map, pos_map); + } + +#undef INTP + + return EINA_TRUE; +} + EAPI void evas_vg_gradient_stop_set(Eo *obj, const Efl_Gfx_Gradient_Stop *colors, unsigned int length) { diff --git a/src/lib/evas/canvas/evas_vg_gradient_linear.c b/src/lib/evas/canvas/evas_vg_gradient_linear.c index 9a54f7a..609dc7a 100644 --- a/src/lib/evas/canvas/evas_vg_gradient_linear.c +++ b/src/lib/evas/canvas/evas_vg_gradient_linear.c @@ -120,6 +120,37 @@ _efl_vg_gradient_linear_efl_vg_base_bounds_get(Eo *obj, Efl_VG_Gradient_Linear_D pd->end.x - pd->start.x, pd->end.y - pd->start.x); } +static Eina_Bool +_efl_vg_gradient_linear_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Gradient_Linear_Data *pd, + const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Gradient_Linear_Data *fromd, *tod; + double from_map; + Eina_Bool r; + + eo_do_super(obj, EFL_VG_GRADIENT_LINEAR_CLASS, r = efl_vg_interpolate(from, to, pos_map)); + + if (!r) return EINA_FALSE; + + fromd = eo_data_scope_get(from, EFL_VG_GRADIENT_LINEAR_CLASS); + tod = eo_data_scope_get(to, EFL_VG_GRADIENT_LINEAR_CLASS); + from_map = 1.0 - pos_map; + +#define INTP(Pd, From, To, Member, From_Map, Pos_Map) \ + Pd->Member = From->Member * From_Map + To->Member * Pos_Map + + INTP(pd, fromd, tod, start.x, from_map, pos_map); + INTP(pd, fromd, tod, start.y, from_map, pos_map); + INTP(pd, fromd, tod, end.x, from_map, pos_map); + INTP(pd, fromd, tod, end.y, from_map, pos_map); + +#undef INTP + + return EINA_TRUE; +} + EAPI void evas_vg_gradient_linear_start_set(Eo *obj, double x, double y) { diff --git a/src/lib/evas/canvas/evas_vg_gradient_radial.c b/src/lib/evas/canvas/evas_vg_gradient_radial.c index 8af5e7d..52ed957 100644 --- a/src/lib/evas/canvas/evas_vg_gradient_radial.c +++ b/src/lib/evas/canvas/evas_vg_gradient_radial.c @@ -138,6 +138,38 @@ _efl_vg_gradient_radial_efl_vg_base_bounds_get(Eo *obj, Efl_VG_Gradient_Radial_D pd->radius * 2, pd->radius * 2); } +static Eina_Bool +_efl_vg_gradient_radial_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Gradient_Radial_Data *pd, + const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Gradient_Radial_Data *fromd, *tod; + double from_map; + Eina_Bool r; + + eo_do_super(obj, EFL_VG_GRADIENT_RADIAL_CLASS, r = efl_vg_interpolate(from, to, pos_map)); + + if (!r) return EINA_FALSE; + + fromd = eo_data_scope_get(from, EFL_VG_GRADIENT_RADIAL_CLASS); + tod = eo_data_scope_get(to, EFL_VG_GRADIENT_RADIAL_CLASS); + from_map = 1.0 - pos_map; + +#define INTP(Pd, From, To, Member, From_Map, Pos_Map) \ + Pd->Member = From->Member * From_Map + To->Member * Pos_Map + + INTP(pd, fromd, tod, focal.x, from_map, pos_map); + INTP(pd, fromd, tod, focal.y, from_map, pos_map); + INTP(pd, fromd, tod, center.x, from_map, pos_map); + INTP(pd, fromd, tod, center.y, from_map, pos_map); + INTP(pd, fromd, tod, radius, from_map, pos_map); + +#undef INTP + + return EINA_TRUE; +} + EAPI void evas_vg_gradient_radial_center_set(Eo *obj, double x, double y) { diff --git a/src/lib/evas/canvas/evas_vg_node.c b/src/lib/evas/canvas/evas_vg_node.c index b54b7ba..0f73808 100644 --- a/src/lib/evas/canvas/evas_vg_node.c +++ b/src/lib/evas/canvas/evas_vg_node.c @@ -9,6 +9,14 @@ #define MY_CLASS EFL_VG_BASE_CLASS +static const Efl_VG_Interpolation interpolation_identity = { + { 0, 0, 0, 1 }, + { 0, 0, 0, 1 }, + { 0, 0, 0 }, + { 1, 1, 1 }, + { 0, 0, 0 } +}; + static Eina_Bool _efl_vg_base_property_changed(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info) { @@ -28,6 +36,12 @@ _efl_vg_base_transformation_set(Eo *obj, Efl_VG_Base_Data *pd, const Eina_Matrix3 *m) { + if (pd->intp) + { + free(pd->intp); + pd->intp = NULL; + } + if (m) { if (!pd->m) @@ -272,6 +286,11 @@ _efl_vg_base_eo_base_destructor(Eo *obj, Efl_VG_Base_Data *pd) eo_del(pd->renderer); pd->renderer = NULL; } + if (pd->intp) + { + free(pd->intp); + pd->intp = NULL; + } eo_do_super(obj, MY_CLASS, eo_destructor()); } @@ -597,6 +616,171 @@ _efl_vg_base_efl_gfx_stack_above_get(Eo *obj, Efl_VG_Base_Data *pd EINA_UNUSED) return above; } +static Efl_VG_Interpolation * +_efl_vg_interpolation_get(Efl_VG_Base_Data *pd) +{ + Eina_Matrix4 m; + + if (!pd->m) return NULL; + if (pd->intp) return pd->intp; + + pd->intp = calloc(1, sizeof (Efl_VG_Interpolation)); + if (!pd->intp) return NULL; + + eina_matrix3_matrix4_to(&m, pd->m); + + if (eina_matrix4_quaternion_to(&pd->intp->rotation, + &pd->intp->perspective, + &pd->intp->translation, + &pd->intp->scale, + &pd->intp->skew, + &m)) + return pd->intp; + + free(pd->intp); + pd->intp = NULL; + + return NULL; +} + +static inline void +_efl_vg_interpolate_point(Eina_Point_3D *d, + const Eina_Point_3D *a, const Eina_Point_3D *b, + double pos_map, double from_map) +{ + d->x = a->x * from_map + b->x * pos_map; + d->y = a->y * from_map + b->y * pos_map; + d->z = a->z * from_map + b->z * pos_map; +} + +static Eina_Bool +_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Base_Data *pd, const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Base_Data *fromd, *tod; + double from_map; + Eina_Bool r = EINA_TRUE; + + fromd = eo_data_scope_get(from, EFL_VG_BASE_CLASS); + tod = eo_data_scope_get(to, EFL_VG_BASE_CLASS); + from_map = 1.0 - pos_map; + + eo_del(pd->renderer); + pd->renderer = NULL; + + if (fromd->m || tod->m) + { + if (!pd->m) pd->m = malloc(sizeof (Eina_Matrix3)); + if (pd->m) + { + const Efl_VG_Interpolation *fi, *ti; + Efl_VG_Interpolation result; + Eina_Matrix4 m; + + fi = _efl_vg_interpolation_get(fromd); + if (!fi) fi = &interpolation_identity; + ti = _efl_vg_interpolation_get(tod); + if (!ti) ti = &interpolation_identity; + + eina_quaternion_slerp(&result.rotation, + &fi->rotation, &ti->rotation, + pos_map); + _efl_vg_interpolate_point(&result.translation, + &fi->translation, &ti->translation, + pos_map, from_map); + _efl_vg_interpolate_point(&result.scale, + &fi->scale, &ti->scale, + pos_map, from_map); + _efl_vg_interpolate_point(&result.skew, + &fi->skew, &ti->skew, + pos_map, from_map); + + result.perspective.x = fi->perspective.x * from_map + ti->perspective.x * pos_map; + result.perspective.y = fi->perspective.y * from_map + ti->perspective.y * pos_map; + result.perspective.z = fi->perspective.z * from_map + ti->perspective.z * pos_map; + result.perspective.w = fi->perspective.w * from_map + ti->perspective.w * pos_map; + + eina_quaternion_matrix4_to(&m, + &result.rotation, + &result.perspective, + &result.translation, + &result.scale, + &result.skew); + eina_matrix4_matrix3_to(pd->m, &m); + } + } + + pd->x = fromd->x * from_map + tod->x * pos_map; + pd->y = fromd->y * from_map + tod->y * pos_map; + + pd->r = fromd->r * from_map + tod->r * pos_map; + pd->g = fromd->g * from_map + tod->g * pos_map; + pd->b = fromd->b * from_map + tod->b * pos_map; + pd->a = fromd->a * from_map + tod->a * pos_map; + + pd->visibility = pos_map >= 0.5 ? tod->visibility : fromd->visibility; + + if (fromd->mask && tod->mask && pd->mask) + { + eo_do(pd->mask, + r &= efl_vg_interpolate(fromd->mask, tod->mask, pos_map)); + } + + _efl_vg_base_changed(obj); + + return r; +} + +static void +_efl_vg_base_dup(Eo *obj, Efl_VG_Base_Data *pd, const Efl_VG_Base *from) +{ + Efl_VG_Container_Data *cd = NULL; + Efl_VG_Base_Data *fromd; + Eo *parent = NULL; + + fromd = eo_data_scope_get(from, EFL_VG_BASE_CLASS); + pd->name = eina_stringshare_ref(fromd->name); + + _efl_vg_base_parent_checked_get(obj, &parent, &cd); + if (cd) _efl_vg_base_name_insert(obj, pd, cd); + + if (pd->intp) + { + free(pd->intp); + pd->intp = NULL; + } + + if (fromd->m) + { + pd->m = pd->m ? pd->m : malloc(sizeof (Eina_Matrix3)) ; + if (pd->m) memcpy(pd->m, fromd->m, sizeof (Eina_Matrix3)); + } + else + { + free(pd->m); + } + + // We may come from an already duped/initialized node, clean it first + _efl_vg_clean_object(&pd->mask); + if (fromd->mask) + { + pd->mask = eo_add(eo_class_get(fromd->mask), + obj, + efl_vg_dup(pd->mask)); + } + + pd->x = fromd->x; + pd->y = fromd->y; + pd->r = fromd->r; + pd->g = fromd->g; + pd->b = fromd->b; + pd->a = fromd->a; + pd->visibility = fromd->visibility; + + _efl_vg_base_changed(obj); +} + EAPI Eina_Bool evas_vg_node_visible_get(Eo *obj) { diff --git a/src/lib/evas/canvas/evas_vg_private.h b/src/lib/evas/canvas/evas_vg_private.h index cc5222f..8ee62b6 100644 --- a/src/lib/evas/canvas/evas_vg_private.h +++ b/src/lib/evas/canvas/evas_vg_private.h @@ -6,12 +6,15 @@ typedef struct _Efl_VG_Base_Data Efl_VG_Base_Data; typedef struct _Efl_VG_Container_Data Efl_VG_Container_Data; typedef struct _Efl_VG_Gradient_Data Efl_VG_Gradient_Data; +typedef struct _Efl_VG_Interpolation Efl_VG_Interpolation; struct _Efl_VG_Base_Data { const char *name; Eina_Matrix3 *m; + Efl_VG_Interpolation *intp; + Efl_VG *mask; Ector_Renderer *renderer; @@ -41,6 +44,15 @@ struct _Efl_VG_Gradient_Data Efl_Gfx_Gradient_Spread s; }; +struct _Efl_VG_Interpolation +{ + Eina_Quaternion rotation; + Eina_Quaternion perspective; + Eina_Point_3D translation; + Eina_Point_3D scale; + Eina_Point_3D skew; +}; + static inline Efl_VG_Base_Data * _evas_vg_render_pre(Efl_VG *child, Ector_Surface *s, Eina_Matrix3 *m) { diff --git a/src/lib/evas/canvas/evas_vg_shape.c b/src/lib/evas/canvas/evas_vg_shape.c index d736718..d17268d 100644 --- a/src/lib/evas/canvas/evas_vg_shape.c +++ b/src/lib/evas/canvas/evas_vg_shape.c @@ -341,6 +341,40 @@ _efl_vg_shape_eo_base_destructor(Eo *obj, Efl_VG_Shape_Data *pd EINA_UNUSED) eo_do_super(obj, MY_CLASS, eo_destructor()); } +static Eina_Bool +_efl_vg_shape_efl_vg_base_interpolate(Eo *obj, + Efl_VG_Shape_Data *pd, + const Efl_VG_Base *from, const Efl_VG_Base *to, + double pos_map) +{ + Efl_VG_Shape_Data *fromd, *tod; + Eina_Bool r; + + fromd = eo_data_scope_get(from, EFL_VG_SHAPE_CLASS); + tod = eo_data_scope_get(to, EFL_VG_SHAPE_CLASS); + + eo_do_super(obj, MY_CLASS, r = efl_vg_interpolate(from, to, pos_map)); + + eo_do(obj, r &= efl_gfx_shape_interpolate(from, to, pos_map)); + + if (fromd->fill && tod->fill && pd->fill) + { + eo_do(pd->fill, r &= efl_vg_interpolate(fromd->fill, tod->fill, pos_map)); + } + if (fromd->stroke.fill && tod->stroke.fill && pd->stroke.fill) + { + eo_do(pd->stroke.fill, + r &= efl_vg_interpolate(fromd->stroke.fill, tod->stroke.fill, pos_map)); + } + if (fromd->stroke.marker && tod->stroke.marker && pd->stroke.marker) + { + eo_do(pd->stroke.marker, + r &= efl_vg_interpolate(fromd->stroke.marker, tod->stroke.marker, pos_map)); + } + + return r; +} + EAPI double evas_vg_shape_stroke_scale_get(Eo *obj) { --
