evas vg: fix broken morphing(interpolation)

efl_gfx_path itself took care of efl_gfx_shape data but its heirarchy was
conceptually wrong. Even efl_gfx_shape is mixing the efl_gfx_path...

Damend design...

Some of derived classes of efl_gfx_path (i.e. Vg.Node and Vg.Container) are
none of the Path acutally. They are just mixing Path's interpolation interface.

So, Here patch changes VG.Node to stop calling the super's interpolate method
and Vg.Shape to call both super -gfx_shape and vg_node- interpolate method.

@fix T6996
This commit is contained in:
Hermet Park 2018-06-14 19:51:13 +09:00
parent a5f0e2ecdf
commit a7e4c67039
5 changed files with 123 additions and 157 deletions

View File

@ -281,83 +281,49 @@ interpolatei(int from, int to, double pos_map)
return (from * (1.0 - pos_map)) + (to * pos_map);
}
typedef struct _Efl_Gfx_Property Efl_Gfx_Property;
struct _Efl_Gfx_Property
{
double scale;
double w;
double centered;
Efl_Gfx_Cap c;
Efl_Gfx_Join j;
const Efl_Gfx_Dash *dash;
unsigned int dash_length;
int r, g, b, a;
int fr, fg, fb, fa;
};
static inline void
_efl_gfx_property_get(const Eo *obj, Efl_Gfx_Property *property)
{
property->scale = efl_gfx_shape_stroke_scale_get(obj);
efl_gfx_shape_stroke_color_get(obj, &property->r, &property->g, &property->b, &property->a);
efl_gfx_color_get(obj, &property->fr, &property->fg, &property->fb, &property->fa);
property->w = efl_gfx_shape_stroke_width_get(obj);
property->centered = efl_gfx_shape_stroke_location_get(obj);
efl_gfx_shape_stroke_dash_get(obj, &property->dash, &property->dash_length);
property->c = efl_gfx_shape_stroke_cap_get(obj);
property->j = efl_gfx_shape_stroke_join_get(obj);
}
static void _path_interpolation(Eo *obj, Efl_Gfx_Path_Data *pd, char *from, char *to, double pos);
static void _efl_gfx_path_reset(Eo *obj, Efl_Gfx_Path_Data *pd);
EOLIAN static Eina_Bool
_efl_gfx_path_interpolate(Eo *obj, Efl_Gfx_Path_Data *pd,
const Eo *from, const Eo *to, double pos_map)
const Eo *from, const Eo *to, double pos_map)
{
Efl_Gfx_Path_Change_Event ev = { EFL_GFX_CHANGE_FLAG_PATH };
Efl_Gfx_Path_Data *from_pd, *to_pd;
Efl_Gfx_Path_Command *cmds;
Efl_Gfx_Property property_from, property_to;
Efl_Gfx_Dash *dash = NULL;
double interv; //interpolated value
double *pts;
unsigned int i, j;
if (!efl_isa(from, EFL_GFX_PATH_MIXIN) || !efl_isa(to, EFL_GFX_PATH_MIXIN))
return EINA_FALSE;
from_pd = efl_data_scope_get(from, EFL_GFX_PATH_MIXIN);
to_pd = efl_data_scope_get(to, EFL_GFX_PATH_MIXIN);
if (!efl_isa(from, EFL_GFX_PATH_MIXIN) || !efl_isa(to, EFL_GFX_PATH_MIXIN))
return EINA_FALSE;
//just in case
if (pd == from_pd || pd == to_pd) return EINA_FALSE;
_efl_gfx_property_get(from, &property_from);
_efl_gfx_property_get(to, &property_to);
if (property_from.dash_length != property_to.dash_length) return EINA_FALSE;
if (from_pd->path_data && to_pd->path_data)
{
_efl_gfx_path_reset(obj, pd);
_path_interpolation(obj, pd, from_pd->path_data, to_pd->path_data, pos_map);
_path_interpolation(obj, pd,
from_pd->path_data, to_pd->path_data, pos_map);
}
else
{
if (!_efl_gfx_path_equal_commands_internal(from_pd, to_pd))
return EINA_FALSE;
cmds = realloc(pd->commands,
sizeof (Efl_Gfx_Path_Command) * from_pd->commands_count);
if (!cmds && from_pd->commands_count) return EINA_FALSE;
sizeof(Efl_Gfx_Path_Command) * from_pd->commands_count);
if (!cmds && (from_pd->commands_count > 0)) return EINA_FALSE;
pd->commands = cmds;
pts = realloc(pd->points,
sizeof (double) * from_pd->points_count);
if (!pts && from_pd->points_count) return EINA_FALSE;
sizeof(double) * from_pd->points_count);
if (!pts && (from_pd->points_count > 0)) return EINA_FALSE;
pd->points = pts;
if (cmds)
@ -369,12 +335,12 @@ _efl_gfx_path_interpolate(Eo *obj, Efl_Gfx_Path_Data *pd,
{
double *to_pts = to_pd->points;
double *from_pts = from_pd->points;
int i, j;
for (i = 0; cmds[i] != EFL_GFX_PATH_COMMAND_TYPE_END; i++)
for (j = 0; j < _efl_gfx_path_command_length(cmds[i]); j++)
{
*pts = interpolate(*from_pts, *to_pts, pos_map);
pts++;
from_pts++;
to_pts++;
@ -385,51 +351,23 @@ _efl_gfx_path_interpolate(Eo *obj, Efl_Gfx_Path_Data *pd,
pd->points_count = from_pd->points_count;
pd->commands_count = from_pd->commands_count;
pd->current.x = interpolate(from_pd->current.x,
to_pd->current.x,
pos_map);
pd->current.y = interpolate(from_pd->current.y,
to_pd->current.y,
pos_map);
pd->current_ctrl.x = interpolate(from_pd->current_ctrl.x,
to_pd->current_ctrl.x,
pos_map);
pd->current_ctrl.y = interpolate(from_pd->current_ctrl.y,
to_pd->current_ctrl.y,
pos_map);
interv = interpolate(from_pd->current.x, to_pd->current.x, pos_map);
pd->current.x = interv;
interv = interpolate(from_pd->current.y, to_pd->current.y, pos_map);
pd->current.y = interv;
interv = interpolate(from_pd->current_ctrl.x, to_pd->current_ctrl.x,
pos_map);
pd->current_ctrl.x = interv;
interv = interpolate(from_pd->current_ctrl.y, to_pd->current_ctrl.y,
pos_map);
pd->current_ctrl.y = interv;
}
if (property_to.dash_length)
{
dash = malloc(sizeof (Efl_Gfx_Dash) * property_to.dash_length);
if (!dash) return EINA_FALSE;
for (i = 0; i < property_to.dash_length; i++)
{
dash[i].length = interpolate(property_from.dash[i].length,
property_to.dash[i].length, pos_map);
dash[i].gap = interpolate(property_from.dash[i].gap,
property_to.dash[i].gap, pos_map);
}
}
efl_gfx_shape_stroke_scale_set(obj, interpolate(property_from.scale, property_to.scale, pos_map));
efl_gfx_shape_stroke_color_set(obj, interpolatei(property_from.r, property_to.r, pos_map),
interpolatei(property_from.g, property_to.g, pos_map),
interpolatei(property_from.b, property_to.b, pos_map),
interpolatei(property_from.a, property_to.a, pos_map));
efl_gfx_color_set(obj, interpolatei(property_from.fr, property_to.fr, pos_map),
interpolatei(property_from.fg, property_to.fg, pos_map),
interpolatei(property_from.fb, property_to.fb, pos_map),
interpolatei(property_from.fa, property_to.fa, pos_map));
efl_gfx_shape_stroke_width_set(obj, interpolate(property_from.w, property_to.w, pos_map));
efl_gfx_shape_stroke_location_set(obj, interpolate(property_from.centered, property_to.centered, pos_map));
efl_gfx_shape_stroke_dash_set(obj, dash, property_to.dash_length);
efl_gfx_shape_stroke_cap_set(obj, pos_map < 0.5 ? property_from.c : property_to.c);
efl_gfx_shape_stroke_join_set(obj, pos_map < 0.5 ? property_from.j : property_to.j);
efl_event_callback_legacy_call(obj, EFL_GFX_PATH_EVENT_CHANGED, &ev);
efl_event_callback_legacy_call(obj, EFL_GFX_PATH_EVENT_CHANGED, &ev);
return EINA_TRUE;
}

View File

@ -62,23 +62,29 @@ _efl_gfx_property_get(const Eo *obj, Efl_Gfx_Property *property)
EOLIAN static Eina_Bool
_efl_gfx_shape_efl_gfx_path_interpolate(Eo *obj, Efl_Gfx_Shape_Data *pd,
const Eo *from, const Eo *to, double pos_map)
const Eo *from, const Eo *to,
double pos_map)
{
Efl_Gfx_Shape_Data *from_pd, *to_pd;
Efl_Gfx_Property property_from, property_to;
Efl_Gfx_Dash *dash = NULL;
double interv; //interpolated value
unsigned int i;
if (!efl_isa(from, EFL_GFX_SHAPE_MIXIN) || !efl_isa(to, EFL_GFX_SHAPE_MIXIN))
return EINA_FALSE;
from_pd = efl_data_scope_get(from, EFL_GFX_SHAPE_MIXIN);
to_pd = efl_data_scope_get(to, EFL_GFX_SHAPE_MIXIN);
if (!efl_isa(from, EFL_GFX_SHAPE_MIXIN) || !efl_isa(to, EFL_GFX_SHAPE_MIXIN))
return EINA_FALSE;
if ((pd == from_pd) || (pd == to_pd)) return EINA_FALSE;
_efl_gfx_property_get(from, &property_from);
_efl_gfx_property_get(to, &property_to);
if (property_from.dash_length != property_to.dash_length) return EINA_FALSE;
//Can be interpolated!
if (property_from.dash_length != property_to.dash_length)
return EINA_FALSE;
if (property_to.dash_length)
{
@ -94,35 +100,39 @@ _efl_gfx_shape_efl_gfx_path_interpolate(Eo *obj, Efl_Gfx_Shape_Data *pd,
}
}
efl_gfx_shape_stroke_scale_set(obj, interpolate(property_from.scale,
property_to.scale, pos_map));
interv = interpolate(property_from.scale, property_to.scale, pos_map);
efl_gfx_shape_stroke_scale_set(obj, interv);
efl_gfx_shape_stroke_color_set(obj,
interpolatei(property_from.r,
property_to.r, pos_map),
interpolatei(property_from.g,
property_to.g, pos_map),
interpolatei(property_from.b,
property_to.b, pos_map),
interpolatei(property_from.a,
property_to.a, pos_map));
interpolatei(property_from.r, property_to.r,
pos_map),
interpolatei(property_from.g, property_to.g,
pos_map),
interpolatei(property_from.b, property_to.b,
pos_map),
interpolatei(property_from.a, property_to.a,
pos_map));
//Color is not a part of Path. Is it correct?...
efl_gfx_color_set(obj,
interpolatei(property_from.fr, property_to.fr, pos_map),
interpolatei(property_from.fg, property_to.fg, pos_map),
interpolatei(property_from.fb, property_to.fb, pos_map),
interpolatei(property_from.fa, property_to.fa, pos_map));
efl_gfx_shape_stroke_width_set(obj, interpolate(property_from.w,
property_to.w, pos_map));
efl_gfx_shape_stroke_location_set(obj, interpolate(property_from.centered,
property_to.centered,
pos_map));
interv = interpolate(property_from.w, property_to.w, pos_map);
efl_gfx_shape_stroke_width_set(obj, interv);
interv = interpolate(property_from.centered, property_to.centered, pos_map);
efl_gfx_shape_stroke_location_set(obj, interv);
efl_gfx_shape_stroke_dash_set(obj, dash, property_to.dash_length);
efl_gfx_shape_stroke_cap_set(obj, (pos_map < 0.5) ?
property_from.c : property_to.c);
efl_gfx_shape_stroke_join_set(obj, (pos_map < 0.5) ?
property_from.j : property_to.j);
return efl_gfx_path_interpolate(efl_super(obj, MY_CLASS), from, to, pos_map);
return efl_gfx_path_interpolate(efl_cast(obj, EFL_GFX_PATH_MIXIN),
from, to, pos_map);
}
EOLIAN static void

View File

@ -125,27 +125,25 @@ _efl_canvas_vg_container_children_get(Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Contain
}
static Eina_Bool
_efl_canvas_vg_container_efl_gfx_path_interpolate(Eo *obj,
Efl_Canvas_Vg_Container_Data *pd,
const Efl_VG *from, const Efl_VG *to,
double pos_map)
_efl_canvas_vg_container_efl_gfx_path_interpolate(Eo *obj, Efl_Canvas_Vg_Container_Data *pd, const Efl_VG *from, const Efl_VG *to, double pos_map)
{
Eina_Iterator *from_it, *to_it;
Eina_List *l;
Eina_Bool r, res = EINA_TRUE;
Eo *from_child, *to_child, *child;
//1. check if both the object are containers
if (!(efl_isa(from, EFL_CANVAS_VG_CONTAINER_CLASS) &&
efl_isa(to, EFL_CANVAS_VG_CONTAINER_CLASS)))
//Check if both objects have same type
if (!(efl_isa(from, MY_CLASS) && efl_isa(to, MY_CLASS)))
return EINA_FALSE;
r = efl_gfx_path_interpolate(efl_super(obj, EFL_CANVAS_VG_CONTAINER_CLASS), from, to, pos_map);
//Interpolates this nodes
r = efl_gfx_path_interpolate(efl_super(obj, MY_CLASS), from, to, pos_map);
if (!r) return EINA_FALSE;
from_it = efl_canvas_vg_container_children_get((Efl_VG *)from);
to_it = efl_canvas_vg_container_children_get((Efl_VG *)to);
//Interpolates children
EINA_LIST_FOREACH (pd->children, l, child)
{
res &= eina_iterator_next(from_it, (void **)&from_child);
@ -156,10 +154,10 @@ _efl_canvas_vg_container_efl_gfx_path_interpolate(Eo *obj,
r = EINA_FALSE;
break;
}
r &= efl_gfx_path_interpolate(child, from_child, to_child, pos_map);
if (!r)
break;
r = efl_gfx_path_interpolate(child, from_child, to_child, pos_map);
if (!r) break;
}
eina_iterator_free(from_it);
eina_iterator_free(to_it);

View File

@ -621,30 +621,33 @@ _efl_canvas_vg_node_interpolation_get(Efl_Canvas_Vg_Node_Data *pd)
static inline void
_efl_canvas_vg_node_interpolate_point(Eina_Point_3D *d,
const Eina_Point_3D *a, const Eina_Point_3D *b,
double pos_map, double from_map)
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;
}
/* Warning! Node itself doesn't have any path. Don't call super class(Path)'s */
static Eina_Bool
_efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj,
Efl_Canvas_Vg_Node_Data *pd, const Efl_VG *from, const Efl_VG *to,
double pos_map)
_efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj, Efl_Canvas_Vg_Node_Data *pd, const Efl_VG *from, const Efl_VG *to, double pos_map)
{
Efl_Canvas_Vg_Node_Data *fromd, *tod;
double from_map;
Eina_Bool r = EINA_TRUE;
fromd = efl_data_scope_get(from, EFL_CANVAS_VG_NODE_CLASS);
tod = efl_data_scope_get(to, EFL_CANVAS_VG_NODE_CLASS);
//Check if both objects have same type
if (!(efl_isa(from, MY_CLASS) && efl_isa(to, MY_CLASS)))
return EINA_FALSE;
fromd = efl_data_scope_get(from, MY_CLASS);
tod = efl_data_scope_get(to, MY_CLASS);
from_map = 1.0 - pos_map;
efl_unref(pd->renderer);
pd->renderer = NULL;
//Interpolates Node Transform Matrix
if (fromd->m || tod->m)
{
if (!pd->m) pd->m = malloc(sizeof (Eina_Matrix3));
@ -656,6 +659,7 @@ _efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj,
fi = _efl_canvas_vg_node_interpolation_get(fromd);
if (!fi) fi = &interpolation_identity;
ti = _efl_canvas_vg_node_interpolation_get(tod);
if (!ti) ti = &interpolation_identity;
@ -672,10 +676,14 @@ _efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj,
&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;
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,
@ -683,13 +691,16 @@ _efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj,
&result.translation,
&result.scale,
&result.skew);
eina_matrix4_matrix3_to(pd->m, &m);
}
}
//Position
pd->x = fromd->x * from_map + tod->x * pos_map;
pd->y = fromd->y * from_map + tod->y * pos_map;
//Color
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;
@ -697,15 +708,17 @@ _efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj,
pd->visibility = pos_map >= 0.5 ? tod->visibility : fromd->visibility;
//Interpolates Mask
if (fromd->mask && tod->mask && pd->mask)
{
r &= efl_gfx_path_interpolate(pd->mask, fromd->mask, tod->mask, pos_map);
if (!efl_gfx_path_interpolate(pd->mask,
fromd->mask, tod->mask, pos_map))
return EINA_FALSE;
}
_efl_canvas_vg_node_changed(obj);
if (!r) return EINA_FALSE;
return efl_gfx_path_interpolate(efl_super(obj, MY_CLASS), from, to, pos_map);
return EINA_TRUE;
}
EOLIAN static Efl_VG *

View File

@ -145,30 +145,37 @@ _efl_canvas_vg_shape_efl_object_destructor(Eo *obj, Efl_Canvas_Vg_Shape_Data *pd
static Eina_Bool
_efl_canvas_vg_shape_efl_gfx_path_interpolate(Eo *obj,
Efl_Canvas_Vg_Shape_Data *pd,
const Efl_Canvas_Vg_Node *from, const Efl_Canvas_Vg_Node *to,
double pos_map)
Efl_Canvas_Vg_Shape_Data *pd,
const Efl_Canvas_Vg_Node *from,
const Efl_Canvas_Vg_Node *to,
double pos_map)
{
Efl_Canvas_Vg_Shape_Data *fromd, *tod;
Eina_Bool r;
Eina_Bool r = EINA_TRUE;
fromd = efl_data_scope_get(from, EFL_CANVAS_VG_SHAPE_CLASS);
tod = efl_data_scope_get(to, EFL_CANVAS_VG_SHAPE_CLASS);
//Check if both objects have same type
if (!(efl_isa(from, MY_CLASS) && efl_isa(to, MY_CLASS)))
return EINA_FALSE;
r = efl_gfx_path_interpolate(efl_super(obj, MY_CLASS), from, to, pos_map);
//Is this the best way?
r &= efl_gfx_path_interpolate(efl_cast(obj, EFL_CANVAS_VG_NODE_CLASS),
from, to, pos_map);
r &= efl_gfx_path_interpolate(efl_super(obj, MY_CLASS), from, to, pos_map);
fromd = efl_data_scope_get(from, MY_CLASS);
tod = efl_data_scope_get(to, MY_CLASS);
//Fill
if (fromd->fill && tod->fill && pd->fill)
{
r &= efl_gfx_path_interpolate(pd->fill, fromd->fill, tod->fill, pos_map);
}
r &= efl_gfx_path_interpolate(pd->fill, fromd->fill, tod->fill, pos_map);
//Stroke Fill
if (fromd->stroke.fill && tod->stroke.fill && pd->stroke.fill)
{
r &= efl_gfx_path_interpolate(pd->stroke.fill, fromd->stroke.fill, tod->stroke.fill, pos_map);
}
r &= efl_gfx_path_interpolate(pd->stroke.fill, fromd->stroke.fill, tod->stroke.fill, pos_map);
//Stroke Marker
if (fromd->stroke.marker && tod->stroke.marker && pd->stroke.marker)
{
r &= efl_gfx_path_interpolate(pd->stroke.marker, fromd->stroke.marker, tod->stroke.marker, pos_map);
}
r &= efl_gfx_path_interpolate(pd->stroke.marker, fromd->stroke.marker, tod->stroke.marker, pos_map);
return r;
}