1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <math.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11
12 #if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H)
13 # define HAVE_EPOLL 1
14 # include <sys/epoll.h>
15 # include <sys/timerfd.h>
16 #endif
17
18 #ifdef _WIN32
19
20 # include <winsock2.h>
21 # include <evil_private.h> /* pipe */
22
23 # define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0)
24 # define pipe_read(fd, buffer, size) recv((fd), (char *)(buffer), size, 0)
25 # define pipe_close(fd) closesocket(fd)
26 # define PIPE_FD_ERROR SOCKET_ERROR
27
28 #else
29
30 # include <sys/select.h>
31 # include <fcntl.h>
32
33 # define pipe_write(fd, buffer, size) write((fd), buffer, size)
34 # define pipe_read(fd, buffer, size) read((fd), buffer, size)
35 # define pipe_close(fd) close(fd)
36 # define PIPE_FD_ERROR -1
37
38 #endif /* ! _WIN32 */
39
40 #ifdef HAVE_PRCTL
41 # include <sys/prctl.h>
42 #endif
43
44 #include "Ecore.h"
45 #include "ecore_private.h"
46
47 static int _ecore_anim_log_dom = -1;
48 static Eina_Bool _ee_animators_setup = EINA_FALSE;
49
50 #ifdef ERR
51 # undef ERR
52 #endif
53 #define ERR(...) EINA_LOG_DOM_ERR(_ecore_anim_log_dom, __VA_ARGS__)
54
55 #ifdef DBG
56 # undef DBG
57 #endif
58 #define DBG(...) EINA_LOG_DOM_DBG(_ecore_anim_log_dom, __VA_ARGS__)
59
60 #ifdef INF
61 # undef INF
62 #endif
63 #define INF(...) EINA_LOG_DOM_INFO(_ecore_anim_log_dom, __VA_ARGS__)
64
65 #ifdef WRN
66 # undef WRN
67 #endif
68 #define WRN(...) EINA_LOG_DOM_WARN(_ecore_anim_log_dom, __VA_ARGS__)
69
70 #ifdef CRI
71 # undef CRI
72 #endif
73 #define CRI(...) EINA_LOG_DOM_CRIT(_ecore_anim_log_dom, __VA_ARGS__)
74
75 static void _do_tick(void);
76 static Eina_Bool _ecore_animator_run(void *data);
77
78 static int animators_delete_me = 0;
79 static Ecore_Animator *animators = NULL;
80 static volatile double animators_frametime = 1.0 / 60.0;
81 static unsigned int animators_suspended = 0;
82
83 static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
84 static int ticking = 0;
85 static Ecore_Cb begin_tick_cb = NULL;
86 static const void *begin_tick_data = NULL;
87 static Ecore_Cb end_tick_cb = NULL;
88 static const void *end_tick_data = NULL;
89 static Eina_Bool animator_ran = EINA_FALSE;
90
91 static volatile int timer_fd_read = -1;
92 static volatile int timer_fd_write = -1;
93 static Ecore_Thread *timer_thread = NULL;
94 static volatile int timer_event_is_busy = 0;
95 static Eina_Spinlock tick_queue_lock;
96 static int tick_queue_count = 0;
97 static Eina_Bool tick_skip = EINA_FALSE;
98
99 #ifndef _WIN32
100 extern volatile int exit_signal_received;
101 #endif
102
103 static Ecore_Evas_Object_Animator_Interface _anim_iface;
104
105 static void
_tick_send(signed char val)106 _tick_send(signed char val)
107 {
108 DBG("_tick_send(%i)", val);
109 if (pipe_write(timer_fd_write, &val, 1) != 1)
110 {
111 ERR("Cannot write to animator control fd");
112 }
113 }
114
115 static void
_timer_send_time(double t,Ecore_Thread * thread)116 _timer_send_time(double t, Ecore_Thread *thread)
117 {
118 double *tim = malloc(sizeof(*tim));
119 if (tim)
120 {
121 *tim = t;
122 DBG(" ... send %1.8f", t);
123 eina_spinlock_take(&tick_queue_lock);
124 tick_queue_count++;
125 eina_spinlock_release(&tick_queue_lock);
126 ecore_thread_feedback(thread, tim);
127 }
128 }
129
130 static void
_timer_tick_core(void * data EINA_UNUSED,Ecore_Thread * thread)131 _timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
132 {
133 #ifdef HAVE_EPOLL
134 int pollfd = -1, timerfd = -1;
135 struct epoll_event pollev = { 0 };
136 struct epoll_event pollincoming[2];
137 uint64_t timerfdbuf;
138 int i;
139 unsigned int t_ft;
140 double pframetime = -1.0;
141 struct itimerspec tspec_new;
142 struct itimerspec tspec_old;
143 #endif
144 fd_set rfds, wfds, exfds;
145 struct timeval tv;
146 Eina_Bool data_control;
147 Eina_Bool data_timeout;
148 unsigned int t;
149 signed char tick = 0;
150 double t0, d, ft;
151 int ret;
152
153 eina_thread_name_set(eina_thread_self(), "Eanimator-timer");
154 #ifdef HAVE_PRCTL
155 prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
156 #endif
157
158 #ifdef HAVE_EPOLL
159 pollfd = epoll_create(1);
160 if (pollfd >= 0) eina_file_close_on_exec(pollfd, EINA_TRUE);
161
162 #if defined(TFD_NONBLOCK) && defined(TFD_CLOEXEC)
163 timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
164 #endif
165 if (timerfd < 0)
166 {
167 timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
168 if (timerfd >= 0) eina_file_close_on_exec(timerfd, EINA_TRUE);
169 }
170 if ((timerfd < 0) && (pollfd >= 0))
171 {
172 close(pollfd);
173 pollfd = -1;
174 }
175
176 #define INPUT_TIMER_CONTROL (&(pollincoming[0]))
177 #define INPUT_TIMER_TIMERFD (&(pollincoming[1]))
178
179 if (pollfd >= 0)
180 {
181 pollev.data.ptr = INPUT_TIMER_CONTROL;
182 pollev.events = EPOLLIN;
183 if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timer_fd_read, &pollev) != 0)
184 {
185 close(timerfd);
186 timerfd = -1;
187 close(pollfd);
188 pollfd = -1;
189 }
190 if (pollfd >= 0)
191 {
192 pollev.data.ptr = INPUT_TIMER_TIMERFD;
193 pollev.events = EPOLLIN;
194 if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timerfd, &pollev) != 0)
195 {
196 close(timerfd);
197 timerfd = -1;
198 close(pollfd);
199 pollfd = -1;
200 }
201 }
202 }
203
204 if (pollfd >= 0)
205 {
206 while (!ecore_thread_check(thread))
207 {
208 data_control = EINA_FALSE;
209 data_timeout = EINA_FALSE;
210 ft = animators_frametime;
211
212 DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
213
214 t0 = ecore_time_get();
215 d = fmod(t0, ft);
216 if (tick)
217 {
218 if (!EINA_DBL_EQ(pframetime, ft))
219 {
220 t = (ft - d) * 1000000000.0;
221 t_ft = ft * 1000000000.0;
222 tspec_new.it_value.tv_sec = t / 1000000000;
223 tspec_new.it_value.tv_nsec = t % 1000000000;
224 tspec_new.it_interval.tv_sec = t_ft / 1000000000;
225 tspec_new.it_interval.tv_nsec = t_ft % 1000000000;
226 timerfd_settime(timerfd, 0, &tspec_new, &tspec_old);
227 pframetime = ft;
228 }
229 DBG("sleep...");
230 ret = epoll_wait(pollfd, pollincoming, 2, -1);
231 }
232 else
233 {
234 tspec_new.it_value.tv_sec = 0;
235 tspec_new.it_value.tv_nsec = 0;
236 tspec_new.it_interval.tv_sec = 0;
237 tspec_new.it_interval.tv_nsec = 0;
238 pframetime = -1.0;
239 timerfd_settime(timerfd, 0, &tspec_new, &tspec_old);
240 DBG("wait...");
241 ret = epoll_wait(pollfd, pollincoming, 2, -1);
242 }
243
244 for (i = 0; i < ret; i++)
245 {
246 if (pollincoming[i].events & EPOLLIN)
247 {
248 if (pollincoming[i].data.ptr == INPUT_TIMER_TIMERFD)
249 {
250 if (read(timerfd, &timerfdbuf, sizeof(timerfdbuf)) == -1)
251 {
252 ERR("Cannot read from timer descriptor. %m.");
253 }
254 data_timeout = EINA_TRUE;
255 }
256 else if (pollincoming[i].data.ptr == INPUT_TIMER_CONTROL)
257 data_control = EINA_TRUE;
258 }
259 }
260 if (data_control)
261 {
262 if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
263 {
264 ERR("Cannot read from animator control fd");
265 }
266 DBG("tick = %i", tick);
267 if (tick == -1) goto done;
268 }
269 else if (data_timeout)
270 {
271 if (tick) _timer_send_time(t0 - d + ft, thread);
272 }
273 }
274 }
275 else
276 #endif
277 {
278 while (!ecore_thread_check(thread))
279 {
280 data_control = EINA_FALSE;
281 data_timeout = EINA_FALSE;
282 ft = animators_frametime;
283
284 DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
285 FD_ZERO(&rfds);
286 FD_ZERO(&wfds);
287 FD_ZERO(&exfds);
288 FD_SET(timer_fd_read, &rfds);
289
290 t0 = ecore_time_get();
291 d = fmod(t0, ft);
292 if (tick)
293 {
294 DBG("sleep...");
295 t = (animators_frametime - d) * 1000000.0;
296 tv.tv_sec = t / 1000000;
297 tv.tv_usec = t % 1000000;
298 ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, &tv);
299 }
300 else
301 {
302 DBG("wait...");
303 ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL);
304 }
305 if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds)))
306 data_control = EINA_TRUE;
307 else if (ret == 0)
308 data_timeout = EINA_TRUE;
309 if (data_control)
310 {
311 if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
312 {
313 ERR("Cannot read from animator control fd");
314 }
315 DBG("tick = %i", tick);
316 if (tick == -1) goto done;
317 }
318 else if (data_timeout)
319 {
320 if (tick) _timer_send_time(t0 - d + ft, thread);
321 }
322 }
323 }
324 done:
325 #ifdef HAVE_EPOLL
326 if (pollfd >= 0)
327 {
328 close(pollfd);
329 pollfd = -1;
330 }
331 if (timerfd >= 0)
332 {
333 close(timerfd);
334 timerfd = -1;
335 }
336 #endif
337 pipe_close(timer_fd_read);
338 timer_fd_read = -1;
339 pipe_close(timer_fd_write);
340 timer_fd_write = -1;
341 }
342
343 static void
_timer_tick_notify(void * data EINA_UNUSED,Ecore_Thread * thread EINA_UNUSED,void * msg)344 _timer_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg)
345 {
346 int tick_queued;
347
348 eina_spinlock_take(&tick_queue_lock);
349 tick_queued = tick_queue_count;
350 tick_queue_count--;
351 eina_spinlock_release(&tick_queue_lock);
352 DBG("notify.... %3.3f %i", *((double *)msg), timer_event_is_busy);
353 if (timer_event_is_busy)
354 {
355 double *t = msg;
356 static double pt = 0.0;
357
358 DBG("VSYNC %1.8f = delt %1.8f", *t, *t - pt);
359 if ((!tick_skip) || (tick_queued == 1))
360 {
361 ecore_loop_time_set(*t);
362 #ifndef _WIN32
363 if (!exit_signal_received)
364 #endif
365 _do_tick();
366 _ecore_animator_flush();
367 }
368 pt = *t;
369 }
370 free(msg);
371 }
372
373 static void
_timer_tick_finished(void * data EINA_UNUSED,Ecore_Thread * thread EINA_UNUSED)374 _timer_tick_finished(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED)
375 {
376 eina_spinlock_free(&tick_queue_lock);
377 timer_thread = NULL;
378 tick_queue_count = 0;
379 if (timer_fd_read >= 0)
380 {
381 pipe_close(timer_fd_read);
382 timer_fd_read = -1;
383 }
384 if (timer_fd_write >= 0)
385 {
386 pipe_close(timer_fd_write);
387 timer_fd_write = -1;
388 }
389 }
390
391 static void
_timer_tick_begin(void)392 _timer_tick_begin(void)
393 {
394 if (timer_fd_read < 0)
395 {
396 int fds[2];
397
398 if (pipe(fds) != 0) return;
399 eina_file_close_on_exec(fds[0], EINA_TRUE);
400 eina_file_close_on_exec(fds[1], EINA_TRUE);
401 timer_fd_read = fds[0];
402 timer_fd_write = fds[1];
403 if (getenv("ECORE_ANIMATOR_SKIP")) tick_skip = EINA_TRUE;
404 tick_queue_count = 0;
405 eina_spinlock_new(&tick_queue_lock);
406 timer_thread = ecore_thread_feedback_run(_timer_tick_core,
407 _timer_tick_notify,
408 _timer_tick_finished,
409 _timer_tick_finished,
410 NULL, EINA_TRUE);
411 }
412 timer_event_is_busy = 1;
413 _tick_send(1);
414 }
415
416 static void
_timer_tick_end(void)417 _timer_tick_end(void)
418 {
419 if (timer_fd_read < 0) return;
420 timer_event_is_busy = 0;
421 _tick_send(0);
422 }
423
424 static void
_timer_tick_quit(void)425 _timer_tick_quit(void)
426 {
427 if (timer_fd_read < 0) return;
428 _tick_send(-1);
429 if (timer_thread) ecore_thread_wait(timer_thread, 0.5);
430 }
431
432 static Eina_Bool
_have_animators(void)433 _have_animators(void)
434 {
435 if ((animators) &&
436 (animators_suspended < eina_inlist_count(EINA_INLIST_GET(animators)))
437 )
438 return EINA_TRUE;
439 return EINA_FALSE;
440 }
441
442 static void
_begin_tick(void)443 _begin_tick(void)
444 {
445 if (ticking) return;
446 eina_evlog(">animator", NULL, 0.0, NULL);
447 ticking = 1;
448 switch (src)
449 {
450 case ECORE_ANIMATOR_SOURCE_TIMER:
451 DBG("General animator registered with timer source.");
452 _timer_tick_begin();
453 break;
454
455 case ECORE_ANIMATOR_SOURCE_CUSTOM:
456 DBG("General animator registered with custom source.");
457 if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data);
458 break;
459
460 default:
461 break;
462 }
463 }
464
465 static void
_end_tick(void)466 _end_tick(void)
467 {
468 if (!ticking) return;
469 eina_evlog("<animator", NULL, 0.0, NULL);
470 ticking = 0;
471
472 DBG("General animator unregistered.");
473
474 _timer_tick_end();
475
476 if ((src == ECORE_ANIMATOR_SOURCE_CUSTOM) && end_tick_cb)
477 end_tick_cb((void *)end_tick_data);
478 }
479
480 static void
_do_tick(void)481 _do_tick(void)
482 {
483 Ecore_Animator *animator;
484 Eina_Inlist *tmp;
485
486 DBG("General animator tick.");
487 EINA_INLIST_FOREACH(animators, animator)
488 {
489 animator->just_added = EINA_FALSE;
490 }
491 if (animators) eina_evlog("!FRAME", NULL, ecore_loop_time_get(), NULL);
492 EINA_INLIST_FOREACH_SAFE(animators, tmp, animator)
493 {
494 if ((!animator->delete_me) &&
495 (!animator->suspended) &&
496 (!animator->just_added))
497 {
498 animator_ran = EINA_TRUE;
499 eina_evlog("+animator", animator, 0.0, NULL);
500 if (!_ecore_call_task_cb(animator->func, animator->data))
501 {
502 animator->delete_me = EINA_TRUE;
503 animators_delete_me++;
504 }
505 eina_evlog("-animator", animator, 0.0, NULL);
506 }
507 else animator->just_added = EINA_FALSE;
508 }
509 }
510
511 static Ecore_Animator *
_ecore_animator_add(Ecore_Task_Cb func,const void * data)512 _ecore_animator_add(Ecore_Task_Cb func,
513 const void *data)
514 {
515 Ecore_Animator *animator;
516
517 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
518
519 if (!func)
520 {
521 ERR("callback function must be set up for an Ecore_Animator object.");
522 return NULL;
523 }
524
525 animator = calloc(1, sizeof (Ecore_Animator));
526 if (!animator) return NULL;
527
528 animator->func = func;
529 animator->data = (void *)data;
530 animator->just_added = EINA_TRUE;
531 animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
532 _begin_tick();
533
534 return animator;
535 }
536
537 EAPI Ecore_Animator *
ecore_animator_add(Ecore_Task_Cb func,const void * data)538 ecore_animator_add(Ecore_Task_Cb func,
539 const void *data)
540 {
541 return _ecore_animator_add(func, data);
542 }
543
544 EAPI Ecore_Animator *
ecore_animator_timeline_add(double runtime,Ecore_Timeline_Cb func,const void * data)545 ecore_animator_timeline_add(double runtime,
546 Ecore_Timeline_Cb func,
547 const void *data)
548 {
549 Ecore_Animator *animator;
550
551 if (runtime <= 0.0) runtime = 0.0;
552
553 animator = _ecore_animator_add(_ecore_animator_run, NULL);
554 if (!animator)
555 return NULL;
556
557 animator->data = animator;
558 animator->run_func = func;
559 animator->run_data = (void *)data;
560 animator->start = ecore_loop_time_get();
561 animator->run = runtime;
562
563 return animator;
564 }
565
566 static double
_pos_map_sin(double in)567 _pos_map_sin(double in)
568 {
569 return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in)));
570 }
571
572 #if 0
573 static double
574 _pos_map_cos(double in)
575 {
576 return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in)));
577 }
578 #endif
579
580 static double
_pos_map_accel_factor(double pos,double v1)581 _pos_map_accel_factor(double pos,
582 double v1)
583 {
584 int i, fact = (int)v1;
585 double p, o1 = pos, o2, v;
586 p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0));
587 o2 = p;
588 for (i = 0; i < fact; i++)
589 {
590 o1 = o2;
591 o2 = o2 * p;
592 }
593 v = v1 - (double)fact;
594 pos = (v * o2) + ((1.0 - v) * o1);
595 return pos;
596 }
597
598 static double
_pos_map_pow(double pos,double divis,int p)599 _pos_map_pow(double pos,
600 double divis,
601 int p)
602 {
603 double v = 1.0;
604 int i;
605 for (i = 0; i < p; i++) v *= pos;
606 return ((pos * divis) * (1.0 - v)) + (pos * v);
607 }
608
609 static double
_pos_map_spring(double pos,int bounces,double decfac)610 _pos_map_spring(double pos,
611 int bounces,
612 double decfac)
613 {
614 int segnum, segpos, b1, b2;
615 double len, decay, decpos, p2;
616 if (bounces < 0) bounces = 0;
617 p2 = _pos_map_pow(pos, 0.5, 3);
618 len = (M_PI / 2.0) + ((double)bounces * M_PI);
619 segnum = (bounces * 2) + 1;
620 segpos = 2 * (((int)(p2 * segnum) + 1) / 2);
621 b1 = segpos;
622 b2 = segnum + 1;
623 if (b1 < 0) b1 = 0;
624 decpos = (double)b1 / (double)b2;
625 decay = _pos_map_accel_factor(1.0 - decpos, decfac);
626 return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay;
627 }
628
629 static inline double
cuberoot(double v)630 cuberoot(double v)
631 {
632 if (v < 0.0)
633 return -pow(-v, 1. / 3.);
634 else
635 return pow(v, 1. / 3.);
636 }
637
638 static double
_bezier_t_get(double _x,double _x1,double _x2)639 _bezier_t_get(double _x, double _x1, double _x2)
640 {
641 if (_x < 0.0 || _x > 1.0) return _x;
642
643 // Cardano's algorithm
644 double\
645 pa = _x - 0.0,
646 pb = _x - _x1,
647 pc = _x - _x2,
648 pd = _x - 1.0;
649
650 double\
651 a = 3*pa-6*pb+3*pc,
652 b = -3*pa+3*pb,
653 c = pa,
654 d = -pa+3*pb-3*pc+pd;
655
656 a /= d;
657 b /= d;
658 c /= d;
659
660 double\
661 p = (3*b-a*a)/3.0,
662 p3 = p/3.0,
663 q = (2*a*a*a-9*a*b+27*c)/27.0,
664 q2 = q/2.0,
665 discriminant = q2*q2 + p3*p3*p3;
666
667 double u1, v1, root1, root2, root3;
668
669 if (discriminant < 0)
670 {
671 double\
672 mp3 = -p/3.0,
673 mp33 = mp3*mp3*mp3,
674 r = sqrt(mp33),
675 t = -q / (2*r),
676 cosphi = t<-1.0 ? -1.0 : t>1.0 ? 1.0 : t,
677 phi = acos(cosphi),
678 crtr = cuberoot(r),
679 t1 = 2*crtr;
680 root1 = t1 * cos(phi/3.0) - a/3.0;
681 root2 = t1 * cos((phi+2*M_PI)/3.0) - a/3.0;
682 root3 = t1 * cos((phi+4*M_PI)/3.0) - a/3.0;
683
684 if (root1 >= 0.0 && root1 <= 1.0) return root1;
685 if (root2 >= 0.0 && root2 <= 1.0) return root2;
686 if (root3 >= 0.0 && root3 <= 1.0) return root3;
687 }
688 else if (discriminant == 0)
689 {
690 u1 = q2 < 0 ? cuberoot(-q2) : -cuberoot(q2);
691 root1 = 2*u1 - a/3.0;
692 root2 = -u1 - a/3.0;
693
694 if (root1 >= 0.0 && root1 <= 1.0) return root1;
695 if (root2 >= 0.0 && root2 <= 1.0) return root2;
696 }
697 else
698 {
699 double sd = sqrt(discriminant);
700 u1 = cuberoot(sd - q2);
701 v1 = cuberoot(sd + q2);
702 root1 = u1 - v1 - a/3.0;
703
704 if (root1 >= 0.0 && root1 <= 1.0) return root1;
705 }
706
707 return _x;
708 }
709
710 static double
_bezier_calc(double t,double y1,double y2)711 _bezier_calc(double t, double y1, double y2)
712 {
713 double y0 = 0.0;
714 double y3 = 1.0;
715
716 double u = 1.0 - t;
717 double t2 = t*t;
718 double t3 = t*t*t;
719 double u2 = u*u;
720 double u3 = u*u*u;
721
722 return u3 * y0 +
723 3.0 * u2 * t * y1 +
724 3.0 * u * t2 * y2 +
725 t3 * y3;
726 }
727
728 static double
_pos_map_cubic_bezier(double pos,double x1,double y1,double x2,double y2)729 _pos_map_cubic_bezier(double pos,
730 double x1,
731 double y1,
732 double x2,
733 double y2)
734 {
735 if (EINA_DBL_EQ(x1, y1) &&
736 EINA_DBL_EQ(x2, y2))
737 return pos;
738 return _bezier_calc(_bezier_t_get(pos, x1, x2), y1, y2);
739 }
740
741 #define DBL_TO(Fp) eina_f32p32_double_to(Fp)
742 #define DBL_FROM(D) eina_f32p32_double_from(D)
743 #define INT_FROM(I) eina_f32p32_int_from(I)
744 #define SIN(Fp) eina_f32p32_sin(Fp)
745 #define COS(Fp) eina_f32p32_cos(Fp)
746 #define ADD(A, B) eina_f32p32_add(A, B)
747 #define SUB(A, B) eina_f32p32_sub(A, B)
748 #define MUL(A, B) eina_f32p32_mul(A, B)
749
750 EAPI double
ecore_animator_pos_map_n(double pos,Ecore_Pos_Map map,int v_size,double * v)751 ecore_animator_pos_map_n(double pos,
752 Ecore_Pos_Map map,
753 int v_size,
754 double *v)
755 {
756 double v0 = 0, v1 = 0, v2 = 0, v3 = 0;
757
758 /* purely functional - locking not required */
759 if (pos >= 1.0) return 1.0;
760 else if (pos <= 0.0)
761 return 0.0;
762 switch (map)
763 {
764 case ECORE_POS_MAP_LINEAR:
765 return pos;
766
767 case ECORE_POS_MAP_ACCELERATE:
768 /* pos = 1 - sin(Pi / 2 + pos * Pi / 2); */
769 pos = DBL_TO(SUB(INT_FROM(1), SIN(ADD((EINA_F32P32_PI >> 1), MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))))));
770 return pos;
771
772 case ECORE_POS_MAP_DECELERATE:
773 /* pos = sin(pos * Pi / 2); */
774 pos = DBL_TO(SIN(MUL(DBL_FROM(pos), (EINA_F32P32_PI >> 1))));
775 return pos;
776
777 case ECORE_POS_MAP_SINUSOIDAL:
778 /* pos = (1 - cos(pos * Pi)) / 2 */
779 pos = DBL_TO((SUB(INT_FROM(1), COS(MUL(DBL_FROM(pos), EINA_F32P32_PI)))) >> 1);
780 return pos;
781
782 case ECORE_POS_MAP_ACCELERATE_FACTOR:
783 if (v_size > 0) v0 = v[0];
784 pos = _pos_map_accel_factor(pos, v0);
785 return pos;
786
787 case ECORE_POS_MAP_DECELERATE_FACTOR:
788 if (v_size > 0) v0 = v[0];
789 pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v0);
790 return pos;
791
792 case ECORE_POS_MAP_SINUSOIDAL_FACTOR:
793 if (v_size > 0) v0 = v[0];
794 if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v0) / 2.0;
795 else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v0) / 2.0);
796 return pos;
797
798 case ECORE_POS_MAP_DIVISOR_INTERP:
799 if (v_size > 0) v0 = v[0];
800 if (v_size > 1) v1 = v[1];
801 pos = _pos_map_pow(pos, v0, (int)v1);
802 return pos;
803
804 case ECORE_POS_MAP_BOUNCE:
805 if (v_size > 0) v0 = v[0];
806 if (v_size > 1) v1 = v[1];
807 pos = _pos_map_spring(pos, (int)v1, v0);
808 if (pos < 0.0) pos = -pos;
809 pos = 1.0 - pos;
810 return pos;
811
812 case ECORE_POS_MAP_SPRING:
813 if (v_size > 0) v0 = v[0];
814 if (v_size > 1) v1 = v[1];
815 pos = 1.0 - _pos_map_spring(pos, (int)v1, v0);
816 return pos;
817
818 case ECORE_POS_MAP_CUBIC_BEZIER:
819 if (v_size > 0) v0 = v[0];
820 if (v_size > 1) v1 = v[1];
821 if (v_size > 2) v2 = v[2];
822 if (v_size > 3) v3 = v[3];
823 pos = _pos_map_cubic_bezier(pos, v0, v1, v2, v3);
824 return pos;
825
826 default:
827 return pos;
828 }
829
830 return pos;
831 }
832
833 EAPI double
ecore_animator_pos_map(double pos,Ecore_Pos_Map map,double v1,double v2)834 ecore_animator_pos_map(double pos,
835 Ecore_Pos_Map map,
836 double v1,
837 double v2)
838 {
839 double v[2];
840
841 v[0] = v1;
842 v[1] = v2;
843 return ecore_animator_pos_map_n(pos, map, 2, v);
844 }
845
846 EAPI void *
ecore_animator_del(Ecore_Animator * animator)847 ecore_animator_del(Ecore_Animator *animator)
848 {
849 void *data = NULL;
850
851 if (!animator) return NULL;
852 EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
853
854 if (animator->ee) return _anim_iface.del(animator);
855
856 if (animator->delete_me)
857 {
858 data = animator->data;
859 goto end;
860 }
861
862 animator->delete_me = EINA_TRUE;
863 animators_delete_me++;
864 if (animator->run_func)
865 data = animator->run_data;
866 else
867 data = animator->data;
868
869 end:
870 if (!in_main_loop) _ecore_animator_flush();
871 return data;
872 }
873
874 EAPI void
ecore_animator_frametime_set(double frametime)875 ecore_animator_frametime_set(double frametime)
876 {
877 EINA_MAIN_LOOP_CHECK_RETURN;
878 if (frametime < 0.0) frametime = 0.0;
879 if (EINA_DBL_EQ(animators_frametime, frametime)) return ;
880 animators_frametime = frametime;
881 _end_tick();
882 if (_have_animators()) _begin_tick();
883 }
884
885 EAPI double
ecore_animator_frametime_get(void)886 ecore_animator_frametime_get(void)
887 {
888 EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0);
889 return animators_frametime;
890 }
891
892 EAPI void
ecore_animator_freeze(Ecore_Animator * animator)893 ecore_animator_freeze(Ecore_Animator *animator)
894 {
895 EINA_MAIN_LOOP_CHECK_RETURN;
896 if (!animator) return;
897 if (animator->delete_me) return;
898 if (animator->suspended) return;
899
900 if (animator->ee)
901 {
902 _anim_iface.freeze(animator);
903 return;
904 }
905 animator->suspended = EINA_TRUE;
906 animators_suspended++;
907 if (!_have_animators()) _end_tick();
908 }
909
910 EAPI void
ecore_animator_thaw(Ecore_Animator * animator)911 ecore_animator_thaw(Ecore_Animator *animator)
912 {
913 EINA_MAIN_LOOP_CHECK_RETURN;
914 if (!animator) return;
915 if (animator->delete_me) return;
916 if (!animator->suspended) return;
917
918 if (animator->ee)
919 {
920 _anim_iface.thaw(animator);
921 return;
922 }
923 animator->suspended = EINA_FALSE;
924 animators_suspended--;
925 if (_have_animators()) _begin_tick();
926 }
927
928 EAPI void
ecore_animator_source_set(Ecore_Animator_Source source)929 ecore_animator_source_set(Ecore_Animator_Source source)
930 {
931 EINA_MAIN_LOOP_CHECK_RETURN;
932 _end_tick();
933 src = source;
934 DBG("New source set to %s.",
935 source == ECORE_ANIMATOR_SOURCE_TIMER ? "TIMER" :
936 source == ECORE_ANIMATOR_SOURCE_CUSTOM ? "CUSTOM" :
937 "UNKNOWN");
938 if (_have_animators()) _begin_tick();
939 }
940
941 EAPI Ecore_Animator_Source
ecore_animator_source_get(void)942 ecore_animator_source_get(void)
943 {
944 EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
945 return src;
946 }
947
948 EAPI void
ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func,const void * data)949 ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func,
950 const void *data)
951 {
952 EINA_MAIN_LOOP_CHECK_RETURN;
953 _end_tick();
954 begin_tick_cb = func;
955 begin_tick_data = data;
956 if (_have_animators()) _begin_tick();
957 }
958
959 EAPI void
ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func,const void * data)960 ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func,
961 const void *data)
962 {
963 EINA_MAIN_LOOP_CHECK_RETURN;
964 _end_tick();
965 end_tick_cb = func;
966 end_tick_data = data;
967 if (_have_animators()) _begin_tick();
968 }
969
970 EAPI void
ecore_animator_custom_tick(void)971 ecore_animator_custom_tick(void)
972 {
973 EINA_MAIN_LOOP_CHECK_RETURN;
974 if (src != ECORE_ANIMATOR_SOURCE_CUSTOM) return;
975 #ifndef _WIN32
976 if (!exit_signal_received)
977 #endif
978 _do_tick();
979 _ecore_animator_flush();
980 }
981
982 void
_ecore_animator_shutdown(void)983 _ecore_animator_shutdown(void)
984 {
985 Ecore_Animator *animator;
986
987 _timer_tick_quit();
988 _end_tick();
989
990 EINA_INLIST_FREE(animators, animator)
991 {
992 if (animator->suspended) animators_suspended--;
993 if (animator->delete_me) animators_delete_me--;
994
995 animators = (Ecore_Animator *) eina_inlist_remove
996 (EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
997 free(animator);
998 }
999
1000 eina_log_domain_unregister(_ecore_anim_log_dom);
1001 _ecore_anim_log_dom = -1;
1002 }
1003
1004 void
_ecore_animator_run_reset(void)1005 _ecore_animator_run_reset(void)
1006 {
1007 animator_ran = EINA_FALSE;
1008 }
1009
1010 Eina_Bool
_ecore_animator_run_get(void)1011 _ecore_animator_run_get(void)
1012 {
1013 return animator_ran;
1014 }
1015
1016 static Eina_Bool
_ecore_animator_run(void * data)1017 _ecore_animator_run(void *data)
1018 {
1019 Ecore_Animator *animator = data;
1020 double pos = 0.0, t;
1021 Eina_Bool run_ret;
1022
1023 t = ecore_loop_time_get();
1024 if (animator->run > 0.0)
1025 {
1026 pos = (t - animator->start) / animator->run;
1027 if (pos > 1.0) pos = 1.0;
1028 else if (pos < 0.0)
1029 pos = 0.0;
1030 }
1031 run_ret = animator->run_func(animator->run_data, pos);
1032 if (eina_dbl_exact(pos, 1.0)) run_ret = EINA_FALSE;
1033 return run_ret;
1034 }
1035
1036 Eina_Bool
_ecore_animator_flush(void)1037 _ecore_animator_flush(void)
1038 {
1039 Ecore_Animator *animator;
1040
1041 if (animators_delete_me)
1042 {
1043 Ecore_Animator *l;
1044 for (l = animators; l; )
1045 {
1046 animator = l;
1047 l = (Ecore_Animator *)EINA_INLIST_GET(l)->next;
1048 if (animator->delete_me)
1049 {
1050 if (animator->suspended) animators_suspended--;
1051 animators = (Ecore_Animator *)
1052 eina_inlist_remove(EINA_INLIST_GET(animators),
1053 EINA_INLIST_GET(animator));
1054
1055 free(animator);
1056
1057 animators_delete_me--;
1058 if (animators_delete_me == 0) break;
1059 }
1060 }
1061 }
1062 if (!_have_animators())
1063 {
1064 _end_tick();
1065 return EINA_FALSE;
1066 }
1067 return EINA_TRUE;
1068 }
1069
1070 void
_ecore_animator_init(void)1071 _ecore_animator_init(void)
1072 {
1073 _ecore_anim_log_dom = eina_log_domain_register("ecore_animator", ECORE_DEFAULT_LOG_COLOR);
1074 if (_ecore_anim_log_dom < 0)
1075 {
1076 EINA_LOG_ERR("Ecore was unable to create a log domain.");
1077 }
1078 }
1079
1080 void
ecore_evas_object_animator_init(Ecore_Evas_Object_Animator_Interface * iface)1081 ecore_evas_object_animator_init(Ecore_Evas_Object_Animator_Interface *iface)
1082 {
1083 _anim_iface = *iface;
1084 _ee_animators_setup = EINA_TRUE;
1085 }
1086
1087 Ecore_Animator *
ecore_evas_animator_timeline_add(void * evo,double runtime,Ecore_Timeline_Cb func,const void * data)1088 ecore_evas_animator_timeline_add(void *evo, double runtime, Ecore_Timeline_Cb func, const void *data)
1089 {
1090 Ecore_Animator *anim = NULL;
1091
1092 if (_ee_animators_setup)
1093 anim = _anim_iface.timeline_add(evo, runtime, func, data);
1094
1095 if (anim) return anim;
1096
1097 return ecore_animator_timeline_add(runtime, func, data);
1098 }
1099
1100 Ecore_Animator *
ecore_evas_animator_add(void * evo,Ecore_Task_Cb func,const void * data)1101 ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data)
1102 {
1103 Ecore_Animator *anim = NULL;
1104
1105 if (_ee_animators_setup)
1106 anim = _anim_iface.add(evo, func, data);
1107
1108 if (anim) return anim;
1109
1110 return ecore_animator_add(func, data);
1111 }
1112