tizen 2.3.1 release
[framework/uifw/ecore.git] / src / lib / ecore / ecore_anim.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <math.h>
7
8 #include "Ecore.h"
9 #include "ecore_private.h"
10
11 struct _Ecore_Animator
12 {
13    EINA_INLIST;
14                      ECORE_MAGIC;
15
16    Ecore_Task_Cb     func;
17    void             *data;
18
19    double            start, run;
20    Ecore_Timeline_Cb run_func;
21    void             *run_data;
22
23    Eina_Bool         delete_me : 1;
24    Eina_Bool         suspended : 1;
25    Eina_Bool         just_added : 1;
26 };
27
28 GENERIC_ALLOC_SIZE_DECLARE(Ecore_Animator);
29
30 static Eina_Bool _ecore_animator_run(void *data);
31 static Eina_Bool _ecore_animator(void *data);
32
33 static int animators_delete_me = 0;
34 static Ecore_Animator *animators = NULL;
35 static double animators_frametime = 1.0 / 30.0;
36
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;
44
45 static void
46 _begin_tick(void)
47 {
48    if (ticking) return;
49    ticking = 1;
50    switch (src)
51      {
52       case ECORE_ANIMATOR_SOURCE_TIMER:
53         if (!timer)
54           {
55              double t_loop = ecore_loop_time_get();
56              double sync_0 = 0.0;
57              double d = -fmod(t_loop - sync_0, animators_frametime);
58
59              timer = _ecore_timer_loop_add(animators_frametime,
60                                            _ecore_animator, NULL);
61              _ecore_timer_delay(timer, d);
62           }
63         break;
64
65       case ECORE_ANIMATOR_SOURCE_CUSTOM:
66         if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data);
67         break;
68
69       default:
70         break;
71      }
72 }
73
74 static void
75 _end_tick(void)
76 {
77    if (!ticking) return;
78    ticking = 0;
79
80    if (timer)
81      {
82         _ecore_timer_del(timer);
83         timer = NULL;
84      }
85
86    if ((src == ECORE_ANIMATOR_SOURCE_CUSTOM) && end_tick_cb)
87      end_tick_cb((void *)end_tick_data);
88 }
89
90 static Eina_Bool
91 _do_tick(void)
92 {
93    Ecore_Animator *animator;
94
95    EINA_INLIST_FOREACH(animators, animator)
96      {
97         animator->just_added = EINA_FALSE;
98      }
99    EINA_INLIST_FOREACH(animators, animator)
100      {
101         if ((!animator->delete_me) && 
102             (!animator->suspended) && 
103             (!animator->just_added))
104           {
105              if (!_ecore_call_task_cb(animator->func, animator->data))
106                {
107                   animator->delete_me = EINA_TRUE;
108                   animators_delete_me++;
109                }
110           }
111         else animator->just_added = EINA_FALSE;
112      }
113    if (animators_delete_me)
114      {
115         Ecore_Animator *l;
116         for (l = animators; l; )
117           {
118              animator = l;
119              l = (Ecore_Animator *)EINA_INLIST_GET(l)->next;
120              if (animator->delete_me)
121                {
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;
129                }
130           }
131      }
132    if (!animators)
133      {
134         _end_tick();
135         return ECORE_CALLBACK_CANCEL;
136      }
137    return ECORE_CALLBACK_RENEW;
138 }
139
140 static Ecore_Animator *
141 _ecore_animator_add(Ecore_Task_Cb func,
142                     const void   *data)
143 {
144    Ecore_Animator *animator = NULL;
145
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));
154    _begin_tick();
155    return animator;
156 }
157
158 EAPI Ecore_Animator *
159 ecore_animator_add(Ecore_Task_Cb func,
160                    const void   *data)
161 {
162    Ecore_Animator *animator;
163
164    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
165    _ecore_lock();
166    animator = _ecore_animator_add(func, data);
167    _ecore_unlock();
168
169    return animator;
170 }
171
172 EAPI Ecore_Animator *
173 ecore_animator_timeline_add(double            runtime,
174                             Ecore_Timeline_Cb func,
175                             const void       *data)
176 {
177    Ecore_Animator *animator;
178
179    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
180    _ecore_lock();
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;
188    _ecore_unlock();
189    return animator;
190 }
191
192 static double
193 _pos_map_sin(double in)
194 {
195    return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in)));
196 }
197
198 #if 0
199 static double
200 _pos_map_cos(double in)
201 {
202    return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in)));
203 }
204 #endif
205
206 static double
207 _pos_map_accel_factor(double pos,
208                       double v1)
209 {
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));
213    o2 = p;
214    for (i = 0; i < fact; i++)
215      {
216         o1 = o2;
217         o2 = o2 * p;
218      }
219    v = v1 - (double)fact;
220    pos = (v * o2) + ((1.0 - v) * o1);
221    return pos;
222 }
223
224 static double
225 _pos_map_pow(double pos,
226              double divis,
227              int    p)
228 {
229    double v = 1.0;
230    int i;
231    for (i = 0; i < p; i++) v *= pos;
232    return ((pos * divis) * (1.0 - v)) + (pos * v);
233 }
234
235 static double
236 _pos_map_spring(double pos,
237                 int    bounces,
238                 double decfac)
239 {
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);
247    b1 = segpos;
248    b2 = segnum + 1;
249    if (b1 < 0) b1 = 0;
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;
253 }
254
255 static double
256 _cubic_bezier_a (double a1, double a2)
257 {
258     return 1.0 - 3.0 * a2 + 3.0 * a1;
259 }
260
261 static double
262 _cubic_bezier_b (double a1, double a2)
263 {
264     return 3.0 * a2 - 6.0 * a1;
265 }
266
267 static double
268 _cubic_bezier_c(double a1)
269 {
270     return 3.0 * a1;
271 }
272
273 static double
274 _cubic_bezier_calc(double t,
275                    double a1,
276                    double a2)
277 {
278     return ((_cubic_bezier_a(a1, a2) * t +
279              _cubic_bezier_b(a1, a2)) * t +
280             _cubic_bezier_c(a1)) * t;
281 }
282
283 static double
284 _cubic_bezier_slope_get(double t,
285                         double a1,
286                         double a2)
287 {
288     return 3.0 * _cubic_bezier_a(a1, a2) * t * t +
289            2.0 * _cubic_bezier_b(a1, a2) * t +
290            _cubic_bezier_c(a1);
291 }
292
293 static double
294 _cubic_bezier_t_get(double a,
295                         double x1,
296                         double x2)
297 {
298 #define APPROXIMATE_RANGE(val) \
299   ((((val) < 0.01) && ((val) > -0.01)) ? EINA_TRUE : EINA_FALSE)
300
301     const int LIMIT = 100;
302     double current_slope;
303     double change;
304     double current_x;
305     double guess_t = a;
306
307     for (int i = 0; i < LIMIT; i++)
308       {
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;
313          guess_t -= change;
314          if (APPROXIMATE_RANGE(change)) break;
315       }
316     return guess_t;
317 }
318
319 static double
320 _pos_map_cubic_bezier(double pos,
321                       double x1,
322                       double y1,
323                       double x2,
324                       double y2)
325 {
326     if (x1 == y1 && x2 == y2) return pos;
327     return _cubic_bezier_calc(_cubic_bezier_t_get(pos, x1, x2), y1, y2);
328 }
329
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)
338
339 EAPI double
340 ecore_animator_pos_map_n(double        pos,
341                          Ecore_Pos_Map map,
342                          int v_size,
343                          double v[])
344 {
345     double v0 = 0, v1 = 0, v2 = 0, v3 = 0;
346
347    /* purely functional - locking not required */
348     if (pos >= 1.0) return 1.0;
349     else if (pos <= 0.0)
350       return 0.0;
351     switch (map)
352       {
353        case ECORE_POS_MAP_LINEAR:
354          return pos;
355
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))))));
359          return pos;
360
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))));
364          return pos;
365
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);
369          return pos;
370
371        case ECORE_POS_MAP_ACCELERATE_FACTOR:
372          if (v_size > 0) v0 = v[0];
373          pos = _pos_map_accel_factor(pos, v0);
374          return pos;
375
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);
379          return pos;
380
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);
385          return pos;
386
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);
391          return pos;
392
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;
398          pos = 1.0 - pos;
399          return pos;
400
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);
405          return pos;
406
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);
413          return pos;
414
415        default:
416          return pos;
417       }
418
419     return pos;
420 }
421
422 EAPI double
423 ecore_animator_pos_map(double        pos,
424                        Ecore_Pos_Map map,
425                        double        v1,
426                        double        v2)
427 {
428     double v[2];
429
430     v[0] = v1;
431     v[1] = v2;
432     return ecore_animator_pos_map_n(pos, map, 2, v);
433 }
434
435 EAPI void *
436 ecore_animator_del(Ecore_Animator *animator)
437 {
438    void *data = NULL;
439    if (!animator) return NULL;
440
441    EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
442    _ecore_lock();
443    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
444      {
445         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
446                          "ecore_animator_del");
447         goto unlock;
448      }
449    if (animator->delete_me)
450      {
451         data = animator->data;
452         goto unlock;
453      }
454    animator->delete_me = EINA_TRUE;
455    animators_delete_me++;
456    if (animator->run_func)
457      data = animator->run_data;
458    else
459      data = animator->data;
460 unlock:
461    _ecore_unlock();
462    return data;
463 }
464
465 EAPI void
466 ecore_animator_frametime_set(double frametime)
467 {
468    EINA_MAIN_LOOP_CHECK_RETURN;
469    _ecore_lock();
470    if (frametime < 0.0) frametime = 0.0;
471    if (animators_frametime == frametime) goto unlock;
472    animators_frametime = frametime;
473    _end_tick();
474    if (animators) _begin_tick();
475 unlock:
476    _ecore_unlock();
477 }
478
479 EAPI double
480 ecore_animator_frametime_get(void)
481 {
482    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
483    return animators_frametime;
484 }
485
486 EAPI void
487 ecore_animator_freeze(Ecore_Animator *animator)
488 {
489    EINA_MAIN_LOOP_CHECK_RETURN;
490    _ecore_lock();
491    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
492      {
493         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
494                          "ecore_animator_del");
495         goto unlock;
496      }
497    if (animator->delete_me) goto unlock;
498    animator->suspended = EINA_TRUE;
499 unlock:
500    _ecore_unlock();
501 }
502
503 EAPI void
504 ecore_animator_thaw(Ecore_Animator *animator)
505 {
506    EINA_MAIN_LOOP_CHECK_RETURN;
507    _ecore_lock();
508    if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
509      {
510         ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
511                          "ecore_animator_del");
512         goto unlock;
513      }
514    if (animator->delete_me) goto unlock;
515    animator->suspended = EINA_FALSE;
516 unlock:
517    _ecore_unlock();
518 }
519
520 EAPI void
521 ecore_animator_source_set(Ecore_Animator_Source source)
522 {
523    EINA_MAIN_LOOP_CHECK_RETURN;
524    _ecore_lock();
525    _end_tick();
526    src = source;
527    if (animators) _begin_tick();
528    _ecore_unlock();
529 }
530
531 EAPI Ecore_Animator_Source
532 ecore_animator_source_get(void)
533 {
534    EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
535    return src;
536 }
537
538 EAPI void
539 ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb    func,
540                                                      const void *data)
541 {
542    EINA_MAIN_LOOP_CHECK_RETURN;
543    _ecore_lock();
544    _end_tick();
545    begin_tick_cb = func;
546    begin_tick_data = data;
547    if (animators) _begin_tick();
548    _ecore_unlock();
549 }
550
551 EAPI void
552 ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb    func,
553                                                    const void *data)
554 {
555    EINA_MAIN_LOOP_CHECK_RETURN;
556    _ecore_lock();
557    _end_tick();
558    end_tick_cb = func;
559    end_tick_data = data;
560    if (animators) _begin_tick();
561    _ecore_unlock();
562 }
563
564 EAPI void
565 ecore_animator_custom_tick(void)
566 {
567    EINA_MAIN_LOOP_CHECK_RETURN;
568    _ecore_lock();
569    if (src == ECORE_ANIMATOR_SOURCE_CUSTOM) _do_tick();
570    _ecore_unlock();
571 }
572
573 void
574 _ecore_animator_shutdown(void)
575 {
576    _end_tick();
577    while (animators)
578      {
579         Ecore_Animator *animator;
580
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);
585      }
586 }
587
588 static Eina_Bool
589 _ecore_animator_run(void *data)
590 {
591    Ecore_Animator *animator = data;
592    double pos = 0.0, t;
593    Eina_Bool run_ret;
594
595    t = ecore_loop_time_get();
596    if (animator->run > 0.0)
597      {
598         pos = (t - animator->start) / animator->run;
599         if (pos > 1.0) pos = 1.0;
600         else if (pos < 0.0)
601           pos = 0.0;
602      }
603    run_ret = animator->run_func(animator->run_data, pos);
604    if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE;
605    return run_ret;
606 }
607
608 static Eina_Bool
609 _ecore_animator(void *data __UNUSED__)
610 {
611    Eina_Bool r;
612    _ecore_lock();
613    r = _do_tick();
614    _ecore_unlock();
615    return r;
616 }
617