evas: add support for interpolating Efl_VG_Node tree.
authorCedric BAIL <cedric@osg.samsung.com>
Tue, 16 Jun 2015 14:28:19 +0000 (16:28 +0200)
committerCedric BAIL <cedric@osg.samsung.com>
Fri, 21 Aug 2015 14:40:31 +0000 (16:40 +0200)
13 files changed:
src/lib/evas/canvas/efl_vg_base.eo
src/lib/evas/canvas/efl_vg_container.eo
src/lib/evas/canvas/efl_vg_gradient.eo
src/lib/evas/canvas/efl_vg_gradient_linear.eo
src/lib/evas/canvas/efl_vg_gradient_radial.eo
src/lib/evas/canvas/efl_vg_shape.eo
src/lib/evas/canvas/evas_vg_container.c
src/lib/evas/canvas/evas_vg_gradient.c
src/lib/evas/canvas/evas_vg_gradient_linear.c
src/lib/evas/canvas/evas_vg_gradient_radial.c
src/lib/evas/canvas/evas_vg_node.c
src/lib/evas/canvas/evas_vg_private.h
src/lib/evas/canvas/evas_vg_shape.c

index 1567f5a..7ddfce5 100644 (file)
@@ -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;
index 19a7b30..b3a6ec4 100644 (file)
@@ -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;
    }
 }
index de78039..959da5b 100644 (file)
@@ -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;
    }
 }
index 4aaddd4..aecfe4e 100644 (file)
@@ -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;
    }
index 62eb086..bd99848 100644 (file)
@@ -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;
    }
index 45d0d30..e2d5c27 100644 (file)
@@ -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;
    }
index e311260..683f5ce 100644 (file)
@@ -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)
 {
index 245b6fe..495a493 100644 (file)
@@ -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)
 {
index 9a54f7a..609dc7a 100644 (file)
@@ -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)
 {
index 8af5e7d..52ed957 100644 (file)
@@ -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)
 {
index b54b7ba..0f73808 100644 (file)
@@ -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)
 {
index cc5222f..8ee62b6 100644 (file)
@@ -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)
 {
index d736718..d17268d 100644 (file)
@@ -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)
 {