9 #include "ecore_private.h"
11 struct _Ecore_Animator
20 Ecore_Timeline_Cb run_func;
23 Eina_Bool delete_me : 1;
24 Eina_Bool suspended : 1;
25 Eina_Bool just_added : 1;
28 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Animator);
30 static Eina_Bool _ecore_animator_run(void *data);
31 static Eina_Bool _ecore_animator(void *data);
33 static int animators_delete_me = 0;
34 static Ecore_Animator *animators = NULL;
35 static double animators_frametime = 1.0 / 30.0;
37 static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
38 static Ecore_Timer *timer = NULL;
39 static int ticking = 0;
40 static Ecore_Cb begin_tick_cb = NULL;
41 static const void *begin_tick_data = NULL;
42 static Ecore_Cb end_tick_cb = NULL;
43 static const void *end_tick_data = NULL;
52 case ECORE_ANIMATOR_SOURCE_TIMER:
55 double t_loop = ecore_loop_time_get();
57 double d = -fmod(t_loop - sync_0, animators_frametime);
59 timer = _ecore_timer_loop_add(animators_frametime,
60 _ecore_animator, NULL);
61 _ecore_timer_delay(timer, d);
65 case ECORE_ANIMATOR_SOURCE_CUSTOM:
66 if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data);
82 _ecore_timer_del(timer);
86 if ((src == ECORE_ANIMATOR_SOURCE_CUSTOM) && end_tick_cb)
87 end_tick_cb((void *)end_tick_data);
93 Ecore_Animator *animator;
95 EINA_INLIST_FOREACH(animators, animator)
97 animator->just_added = EINA_FALSE;
99 EINA_INLIST_FOREACH(animators, animator)
101 if ((!animator->delete_me) &&
102 (!animator->suspended) &&
103 (!animator->just_added))
105 if (!_ecore_call_task_cb(animator->func, animator->data))
107 animator->delete_me = EINA_TRUE;
108 animators_delete_me++;
111 else animator->just_added = EINA_FALSE;
113 if (animators_delete_me)
116 for (l = animators; l; )
119 l = (Ecore_Animator *)EINA_INLIST_GET(l)->next;
120 if (animator->delete_me)
122 animators = (Ecore_Animator *)
123 eina_inlist_remove(EINA_INLIST_GET(animators),
124 EINA_INLIST_GET(animator));
125 ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
126 ecore_animator_mp_free(animator);
127 animators_delete_me--;
128 if (animators_delete_me == 0) break;
135 return ECORE_CALLBACK_CANCEL;
137 return ECORE_CALLBACK_RENEW;
140 static Ecore_Animator *
141 _ecore_animator_add(Ecore_Task_Cb func,
144 Ecore_Animator *animator = NULL;
146 if (!func) return animator;
147 animator = ecore_animator_calloc(1);
148 if (!animator) return animator;
149 ECORE_MAGIC_SET(animator, ECORE_MAGIC_ANIMATOR);
150 animator->func = func;
151 animator->data = (void *)data;
152 animator->just_added = EINA_TRUE;
153 animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
158 EAPI Ecore_Animator *
159 ecore_animator_add(Ecore_Task_Cb func,
162 Ecore_Animator *animator;
164 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
166 animator = _ecore_animator_add(func, data);
172 EAPI Ecore_Animator *
173 ecore_animator_timeline_add(double runtime,
174 Ecore_Timeline_Cb func,
177 Ecore_Animator *animator;
179 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
181 if (runtime <= 0.0) runtime = 0.0;
182 animator = _ecore_animator_add(_ecore_animator_run, NULL);
183 animator->data = animator;
184 animator->run_func = func;
185 animator->run_data = (void *)data;
186 animator->start = ecore_loop_time_get();
187 animator->run = runtime;
193 _pos_map_sin(double in)
195 return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in)));
200 _pos_map_cos(double in)
202 return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in)));
207 _pos_map_accel_factor(double pos,
210 int i, fact = (int)v1;
211 double p, o1 = pos, o2, v;
212 p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0));
214 for (i = 0; i < fact; i++)
219 v = v1 - (double)fact;
220 pos = (v * o2) + ((1.0 - v) * o1);
225 _pos_map_pow(double pos,
231 for (i = 0; i < p; i++) v *= pos;
232 return ((pos * divis) * (1.0 - v)) + (pos * v);
236 _pos_map_spring(double pos,
240 int segnum, segpos, b1, b2;
241 double len, decay, decpos, p2;
242 if (bounces < 0) bounces = 0;
243 p2 = _pos_map_pow(pos, 0.5, 3);
244 len = (M_PI / 2.0) + ((double)bounces * M_PI);
245 segnum = (bounces * 2) + 1;
246 segpos = 2 * (((int)(p2 * segnum) + 1) / 2);
250 decpos = (double)b1 / (double)b2;
251 decay = _pos_map_accel_factor(1.0 - decpos, decfac);
252 return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay;
256 _cubic_bezier_a (double a1, double a2)
258 return 1.0 - 3.0 * a2 + 3.0 * a1;
262 _cubic_bezier_b (double a1, double a2)
264 return 3.0 * a2 - 6.0 * a1;
268 _cubic_bezier_c(double a1)
274 _cubic_bezier_calc(double t,
278 return ((_cubic_bezier_a(a1, a2) * t +
279 _cubic_bezier_b(a1, a2)) * t +
280 _cubic_bezier_c(a1)) * t;
284 _cubic_bezier_slope_get(double t,
288 return 3.0 * _cubic_bezier_a(a1, a2) * t * t +
289 2.0 * _cubic_bezier_b(a1, a2) * t +
294 _cubic_bezier_t_get(double a,
298 #define APPROXIMATE_RANGE(val) \
299 ((((val) < 0.01) && ((val) > -0.01)) ? EINA_TRUE : EINA_FALSE)
301 const int LIMIT = 100;
302 double current_slope;
307 for (int i = 0; i < LIMIT; i++)
309 current_slope = _cubic_bezier_slope_get(guess_t, x1, x2);
310 if (current_slope == 0.0) return guess_t;
311 current_x = _cubic_bezier_calc(guess_t, x1, x2) - a;
312 change = current_x / current_slope;
314 if (APPROXIMATE_RANGE(change)) break;
320 _pos_map_cubic_bezier(double pos,
326 if (x1 == y1 && x2 == y2) return pos;
327 return _cubic_bezier_calc(_cubic_bezier_t_get(pos, x1, x2), y1, y2);
330 #define DBL_TO(Fp) eina_f32p32_double_to(Fp)
331 #define DBL_FROM(D) eina_f32p32_double_from(D)
332 #define INT_FROM(I) eina_f32p32_int_from(I)
333 #define SIN(Fp) eina_f32p32_sin(Fp)
334 #define COS(Fp) eina_f32p32_cos(Fp)
335 #define ADD(A, B) eina_f32p32_add(A, B)
336 #define SUB(A, B) eina_f32p32_sub(A, B)
337 #define MUL(A, B) eina_f32p32_mul(A, B)
340 ecore_animator_pos_map_n(double pos,
345 double v0 = 0, v1 = 0, v2 = 0, v3 = 0;
347 /* purely functional - locking not required */
348 if (pos >= 1.0) return 1.0;
353 case ECORE_POS_MAP_LINEAR:
356 case ECORE_POS_MAP_ACCELERATE:
357 /* pos = 1 - sin(Pi / 2 + pos * Pi / 2); */
358 pos = DBL_TO(SUB(INT_FROM(1), SIN(ADD((EINA_F32P32_PI >> 1), MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))))));
361 case ECORE_POS_MAP_DECELERATE:
362 /* pos = sin(pos * Pi / 2); */
363 pos = DBL_TO(SIN(MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))));
366 case ECORE_POS_MAP_SINUSOIDAL:
367 /* pos = (1 - cos(pos * Pi)) / 2 */
368 pos = DBL_TO((SUB(INT_FROM(1), COS(MUL(DBL_FROM(pos), EINA_F32P32_PI)))) >> 1);
371 case ECORE_POS_MAP_ACCELERATE_FACTOR:
372 if (v_size > 0) v0 = v[0];
373 pos = _pos_map_accel_factor(pos, v0);
376 case ECORE_POS_MAP_DECELERATE_FACTOR:
377 if (v_size > 0) v0 = v[0];
378 pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v0);
381 case ECORE_POS_MAP_SINUSOIDAL_FACTOR:
382 if (v_size > 0) v0 = v[0];
383 if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v0) / 2.0;
384 else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v0) / 2.0);
387 case ECORE_POS_MAP_DIVISOR_INTERP:
388 if (v_size > 0) v0 = v[0];
389 if (v_size > 1) v1 = v[1];
390 pos = _pos_map_pow(pos, v0, (int)v1);
393 case ECORE_POS_MAP_BOUNCE:
394 if (v_size > 0) v0 = v[0];
395 if (v_size > 1) v1 = v[1];
396 pos = _pos_map_spring(pos, (int)v1, v0);
397 if (pos < 0.0) pos = -pos;
401 case ECORE_POS_MAP_SPRING:
402 if (v_size > 0) v0 = v[0];
403 if (v_size > 1) v1 = v[1];
404 pos = 1.0 - _pos_map_spring(pos, (int)v1, v0);
407 case ECORE_POS_MAP_CUBIC_BEZIER:
408 if (v_size > 0) v0 = v[0];
409 if (v_size > 1) v1 = v[1];
410 if (v_size > 2) v2 = v[2];
411 if (v_size > 3) v3 = v[3];
412 pos = _pos_map_cubic_bezier(pos, v0, v1, v2, v3);
423 ecore_animator_pos_map(double pos,
432 return ecore_animator_pos_map_n(pos, map, 2, v);
436 ecore_animator_del(Ecore_Animator *animator)
439 if (!animator) return NULL;
441 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
443 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
445 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
446 "ecore_animator_del");
449 if (animator->delete_me)
451 data = animator->data;
454 animator->delete_me = EINA_TRUE;
455 animators_delete_me++;
456 if (animator->run_func)
457 data = animator->run_data;
459 data = animator->data;
466 ecore_animator_frametime_set(double frametime)
468 EINA_MAIN_LOOP_CHECK_RETURN;
470 if (frametime < 0.0) frametime = 0.0;
471 if (animators_frametime == frametime) goto unlock;
472 animators_frametime = frametime;
474 if (animators) _begin_tick();
480 ecore_animator_frametime_get(void)
482 EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
483 return animators_frametime;
487 ecore_animator_freeze(Ecore_Animator *animator)
489 EINA_MAIN_LOOP_CHECK_RETURN;
491 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
493 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
494 "ecore_animator_del");
497 if (animator->delete_me) goto unlock;
498 animator->suspended = EINA_TRUE;
504 ecore_animator_thaw(Ecore_Animator *animator)
506 EINA_MAIN_LOOP_CHECK_RETURN;
508 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
510 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
511 "ecore_animator_del");
514 if (animator->delete_me) goto unlock;
515 animator->suspended = EINA_FALSE;
521 ecore_animator_source_set(Ecore_Animator_Source source)
523 EINA_MAIN_LOOP_CHECK_RETURN;
527 if (animators) _begin_tick();
531 EAPI Ecore_Animator_Source
532 ecore_animator_source_get(void)
534 EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
539 ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func,
542 EINA_MAIN_LOOP_CHECK_RETURN;
545 begin_tick_cb = func;
546 begin_tick_data = data;
547 if (animators) _begin_tick();
552 ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func,
555 EINA_MAIN_LOOP_CHECK_RETURN;
559 end_tick_data = data;
560 if (animators) _begin_tick();
565 ecore_animator_custom_tick(void)
567 EINA_MAIN_LOOP_CHECK_RETURN;
569 if (src == ECORE_ANIMATOR_SOURCE_CUSTOM) _do_tick();
574 _ecore_animator_shutdown(void)
579 Ecore_Animator *animator;
581 animator = animators;
582 animators = (Ecore_Animator *)eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators));
583 ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
584 ecore_animator_mp_free(animator);
589 _ecore_animator_run(void *data)
591 Ecore_Animator *animator = data;
595 t = ecore_loop_time_get();
596 if (animator->run > 0.0)
598 pos = (t - animator->start) / animator->run;
599 if (pos > 1.0) pos = 1.0;
603 run_ret = animator->run_func(animator->run_data, pos);
604 if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE;
609 _ecore_animator(void *data __UNUSED__)