efl_canvas_animation: fix numerical error on map effect calculation

Previously, for a single canvas animation, map effect was applied in
animator callback without resetting previously applied map effect.
This increased numerical error because each time map effect factors
(e.g. scale, degree) should be calculated based on the current map
coordinates.

To resolve this numerical error, now the previously applied map effect
is reset before applying the current map effect in animator callback.
This commit is contained in:
Jaehyun Cho 2019-06-04 18:52:14 +09:00
parent 28adabd214
commit 9eb0b28cc7
5 changed files with 29 additions and 76 deletions

View File

@ -107,6 +107,10 @@ _animator_cb(void *data)
pd->progress = (double)(pd->is_direction_forward);
}
/* The previously applied map effect should be reset before applying the
* current map effect. Otherwise, the incrementally added map effects
* increase numerical error. */
efl_gfx_mapping_reset(efl_animation_player_target_get(eo_obj));
efl_animation_apply(anim, pd->progress, efl_animation_player_target_get(eo_obj));
Efl_Canvas_Animation_Player_Event_Running event_running;
@ -207,11 +211,14 @@ _efl_canvas_animation_player_efl_player_stop(Eo *eo_obj,
Efl_Canvas_Animation_Player_Data *pd)
{
EFL_ANIMATION_PLAYER_ANIMATION_GET(eo_obj, anim);
//Reset the state of the target to the initial state
efl_gfx_mapping_reset(efl_animation_player_target_get(eo_obj));
Eina_Bool play = efl_player_play_get(eo_obj);
if (play)
{
efl_player_play_set(eo_obj, EINA_FALSE);
//Reset the state of the target to the initial state
if ((efl_animation_final_state_keep_get(anim)) &&
(efl_animation_repeat_mode_get(anim) != EFL_CANVAS_ANIMATION_REPEAT_MODE_REVERSE) &&
(!(efl_animation_repeat_count_get(anim) & 1)))
@ -223,14 +230,12 @@ _efl_canvas_animation_player_efl_player_stop(Eo *eo_obj,
else
{
pd->progress = 0.0;
efl_gfx_mapping_reset(efl_animation_player_target_get(eo_obj));
}
efl_event_callback_call(eo_obj, EFL_ANIMATION_PLAYER_EVENT_ENDED, NULL);
}
else
{
pd->progress = 0.0;
efl_gfx_mapping_reset(efl_animation_player_target_get(eo_obj));
}
if (pd->auto_del) efl_del(eo_obj);
@ -303,6 +308,11 @@ _efl_canvas_animation_player_efl_player_pos_set(Eo *eo_obj,
EFL_ANIMATION_PLAYER_ANIMATION_GET(eo_obj, anim);
double length = efl_animation_duration_get(anim);
pd->progress = sec / length;
/* The previously applied map effect should be reset before applying the
* current map effect. Otherwise, the incrementally added map effects
* increase numerical error. */
efl_gfx_mapping_reset(efl_animation_player_target_get(eo_obj));
efl_animation_apply(anim, pd->progress, efl_animation_player_target_get(eo_obj));
}

View File

@ -21,7 +21,7 @@ typedef struct _Efl_Canvas_Animation_Data
Efl_Canvas_Animation_Data *pd = efl_data_scope_get(o, EFL_CANVAS_ANIMATION_CLASS)
#define GET_STATUS(from, to, progress) \
((from) + (((to) - (from)) * (progress)))
((from * (1.0 - progress)) + (to * progress))
#define FINAL_STATE_IS_REVERSE(anim) \
((efl_animation_repeat_mode_get(anim) == EFL_CANVAS_ANIMATION_REPEAT_MODE_REVERSE) && \

View File

@ -2,19 +2,6 @@
#define MY_CLASS EFL_CANVAS_ANIMATION_ROTATE_CLASS
static double
_rotation_get(Eo *target)
{
double x1, x2, y1, y2;
double theta;
efl_gfx_mapping_coord_absolute_get(target, 0, &x1, &y1, NULL);
efl_gfx_mapping_coord_absolute_get(target, 1, &x2, &y2, NULL);
theta = atan((y2 - y1) / (x2 - x1));
return theta * 180 / M_PI;
}
EOLIAN static void
_efl_canvas_animation_rotate_rotate_set(Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Animation_Rotate_Data *pd,
@ -115,26 +102,24 @@ _efl_canvas_animation_rotate_efl_canvas_animation_animation_apply(Eo *eo_obj,
Efl_Canvas_Object *target)
{
double new_degree;
double prev_degree;
progress = efl_animation_apply(efl_super(eo_obj, MY_CLASS), progress, target);
if (!target) return progress;
prev_degree = _rotation_get(target);
new_degree = GET_STATUS(pd->from.degree, pd->to.degree, progress);
if (pd->use_rel_pivot)
{
efl_gfx_mapping_rotate(target,
new_degree - prev_degree,
(pd->rel_pivot.obj) ? pd->rel_pivot.obj : target,
pd->rel_pivot.cx, pd->rel_pivot.cy);
new_degree,
(pd->rel_pivot.obj) ? pd->rel_pivot.obj : target,
pd->rel_pivot.cx, pd->rel_pivot.cy);
}
else
{
efl_gfx_mapping_rotate_absolute(target,
new_degree - prev_degree,
pd->abs_pivot.cx, pd->abs_pivot.cy);
new_degree,
pd->abs_pivot.cx, pd->abs_pivot.cy);
}
return progress;

View File

@ -2,27 +2,6 @@
#define MY_CLASS EFL_CANVAS_ANIMATION_SCALE_CLASS
static Efl_Canvas_Animation_Scale_Property
_scale_get(Eo *target)
{
double x1, x2, x3, y1, y2, y3, w, h;
Efl_Canvas_Animation_Scale_Property scale;
Eina_Rect geometry;
geometry = efl_gfx_entity_geometry_get(target);
efl_gfx_mapping_coord_absolute_get(target, 0, &x1, &y1, NULL);
efl_gfx_mapping_coord_absolute_get(target, 1, &x2, &y2, NULL);
efl_gfx_mapping_coord_absolute_get(target, 2, &x3, &y3, NULL);
w = sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
h = sqrt(((x3 - x2) * (x3 - x2)) + ((y3 - y2) * (y3 - y2)));
scale.scale_x = w / geometry.w;
scale.scale_y = h / geometry.h;
return scale;
}
EOLIAN static void
_efl_canvas_animation_scale_scale_set(Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Animation_Scale_Data *pd,
@ -149,30 +128,26 @@ _efl_canvas_animation_scale_efl_canvas_animation_animation_apply(Eo *eo_obj,
double progress,
Efl_Canvas_Object *target)
{
Efl_Canvas_Animation_Scale_Property prev_scale;
Efl_Canvas_Animation_Scale_Property new_scale;
progress = efl_animation_apply(efl_super(eo_obj, MY_CLASS), progress, target);
if (!target) return progress;
prev_scale = _scale_get(target);
new_scale.scale_x = GET_STATUS(pd->from.scale_x, pd->to.scale_x, progress);
new_scale.scale_y = GET_STATUS(pd->from.scale_y, pd->to.scale_y, progress);
if (pd->use_rel_pivot)
{
efl_gfx_mapping_zoom(target,
new_scale.scale_x / prev_scale.scale_x,
new_scale.scale_y / prev_scale.scale_y,
(pd->rel_pivot.obj) ? pd->rel_pivot.obj : target,
pd->rel_pivot.cx, pd->rel_pivot.cy);
new_scale.scale_x, new_scale.scale_y,
(pd->rel_pivot.obj) ? pd->rel_pivot.obj : target,
pd->rel_pivot.cx, pd->rel_pivot.cy);
}
else
{
efl_gfx_mapping_zoom_absolute(target,
new_scale.scale_x / prev_scale.scale_x,
new_scale.scale_y / prev_scale.scale_y,
pd->abs_pivot.cx, pd->abs_pivot.cy);
new_scale.scale_x, new_scale.scale_y,
pd->abs_pivot.cx, pd->abs_pivot.cy);
}
return progress;

View File

@ -8,23 +8,6 @@ typedef struct __Translate_Property_Double
double y;
} _Translate_Property_Double;
static _Translate_Property_Double
_translation_get(Eo *target)
{
double x1, x2, y1, y2;
_Translate_Property_Double translate;
Eina_Rect geometry;
geometry = efl_gfx_entity_geometry_get(target);
efl_gfx_mapping_coord_absolute_get(target, 0, &x1, &y1, NULL);
efl_gfx_mapping_coord_absolute_get(target, 2, &x2, &y2, NULL);
translate.x = ((x1 + x2) / 2.0) - (geometry.x + (geometry.w / 2.0));
translate.y = ((y1 + y2) / 2.0) - (geometry.y + (geometry.h / 2.0));
return translate;
}
EOLIAN static void
_efl_canvas_animation_translate_translate_set(Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Animation_Translate_Data *pd,
@ -115,13 +98,12 @@ _efl_canvas_animation_translate_efl_canvas_animation_animation_apply(Eo *eo_obj,
double progress,
Efl_Canvas_Object *target)
{
_Translate_Property_Double prev;
_Translate_Property_Double new;
Eina_Rect geometry;
progress = efl_animation_apply(efl_super(eo_obj, MY_CLASS), progress, target);
if (!target) return progress;
prev = _translation_get(target);
if (pd->use_rel_move)
{
new.x = GET_STATUS(pd->from.move_x, pd->to.move_x, progress);
@ -129,11 +111,12 @@ _efl_canvas_animation_translate_efl_canvas_animation_animation_apply(Eo *eo_obj,
}
else
{
new.x = GET_STATUS(pd->from.x, pd->to.x, progress);
new.y = GET_STATUS(pd->from.y, pd->to.y, progress);
geometry = efl_gfx_entity_geometry_get(target);
new.x = GET_STATUS(pd->from.x, pd->to.x, progress) - geometry.x;
new.y = GET_STATUS(pd->from.y, pd->to.y, progress) - geometry.y;
}
efl_gfx_mapping_translate(target, new.x - prev.x, new.y - prev.y, 0.0);
efl_gfx_mapping_translate(target, new.x, new.y, 0.0);
return progress;
}