9 #include "ecore_private.h"
12 struct _Ecore_Animator
21 Ecore_Timeline_Cb run_func;
24 Eina_Bool delete_me : 1;
25 Eina_Bool suspended : 1;
29 static Eina_Bool _ecore_animator_run(void *data);
30 static Eina_Bool _ecore_animator(void *data);
32 static int animators_delete_me = 0;
33 static Ecore_Animator *animators = NULL;
34 static double animators_frametime = 1.0 / 30.0;
36 static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
37 static Ecore_Timer *timer = NULL;
38 static int ticking = 0;
39 static Ecore_Cb begin_tick_cb = NULL;
40 static const void *begin_tick_data = NULL;
41 static Ecore_Cb end_tick_cb = NULL;
42 static const void *end_tick_data = NULL;
51 case ECORE_ANIMATOR_SOURCE_TIMER:
54 double t_loop = ecore_loop_time_get();
56 double d = -fmod(t_loop - sync_0, animators_frametime);
58 timer = ecore_timer_loop_add(animators_frametime,
59 _ecore_animator, NULL);
60 ecore_timer_delay(timer, d);
63 case ECORE_ANIMATOR_SOURCE_CUSTOM:
64 if (begin_tick_cb) begin_tick_cb((void *)begin_tick_data);
78 case ECORE_ANIMATOR_SOURCE_TIMER:
81 ecore_timer_del(timer);
85 case ECORE_ANIMATOR_SOURCE_CUSTOM:
86 if (end_tick_cb) end_tick_cb((void *)end_tick_data);
96 Ecore_Animator *animator;
98 EINA_INLIST_FOREACH(animators, animator)
100 if (!animator->delete_me && !animator->suspended)
102 if (!animator->func(animator->data))
104 animator->delete_me = EINA_TRUE;
105 animators_delete_me++;
109 if (animators_delete_me)
112 for (l = animators; l;)
115 l = (Ecore_Animator *) EINA_INLIST_GET(l)->next;
116 if (animator->delete_me)
118 animators = (Ecore_Animator *)
119 eina_inlist_remove(EINA_INLIST_GET(animators),
120 EINA_INLIST_GET(animator));
121 ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
123 animators_delete_me--;
124 if (animators_delete_me == 0) break;
131 return ECORE_CALLBACK_CANCEL;
133 return ECORE_CALLBACK_RENEW;
137 * @addtogroup Ecore_Group Ecore - Main Loop and Job Functions.
143 * @addtogroup Ecore_Animator_Group Ecore Animator functions
149 * Add a animator to tick off at every animaton tick during main loop execution.
150 * @param func The function to call when it ticks off
151 * @param data The data to pass to the function
152 * @return A handle to the new animator
154 * This function adds a animator and returns its handle on success and NULL on
155 * failure. The function @p func will be called every N seconds where N is the
156 * frametime interval set by ecore_animator_frametime_set(). The function will
157 * be passed the @p data pointer as its parameter.
159 * When the animator @p func is called, it must return a value of either 1 or 0.
160 * If it returns 1 (or ECORE_CALLBACK_RENEW), it will be called again at the
161 * next tick, or if it returns 0 (or ECORE_CALLBACK_CANCEL) it will be deleted
162 * automatically making any references/handles for it invalid.
164 EAPI Ecore_Animator *
165 ecore_animator_add(Ecore_Task_Cb func, const void *data)
167 Ecore_Animator *animator;
169 if (!func) return NULL;
170 animator = calloc(1, sizeof(Ecore_Animator));
171 if (!animator) return NULL;
172 ECORE_MAGIC_SET(animator, ECORE_MAGIC_ANIMATOR);
173 animator->func = func;
174 animator->data = (void *)data;
175 animators = (Ecore_Animator *)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
181 * Add a animator that runs for a limited time
182 * @param runtime The time to run in seconds
183 * @param func The function to call when it ticks off
184 * @param data The data to pass to the function
185 * @return A handle to the new animator
187 * This function is just like ecore_animator_add() except the animator only
188 * runs for a limited time specified in seconds by @p runtime. Once the runtime
189 * the animator has elapsed (animator finished) it will automatically be
190 * deleted. The callback function @p func can return ECORE_CALLBACK_RENEW to
191 * keep the animator running or ECORE_CALLBACK_CANCEL ro stop it and have
192 * it be deleted automatically at any time.
194 * The @p func will ALSO be passed a position parameter that will be in value
195 * from 0.0 to 1.0 to indicate where along the timeline (0.0 start, 1.0 end)
196 * the animator run is at. If the callback wishes not to have a linear
197 * transition it can "map" this value to one of several curves and mappings
198 * via ecore_animator_pos_map().
202 EAPI Ecore_Animator *
203 ecore_animator_timeline_add(double runtime, Ecore_Timeline_Cb func, const void *data)
205 Ecore_Animator *animator;
207 if (runtime <= 0.0) runtime = 0.0;
208 animator = ecore_animator_add(_ecore_animator_run, NULL);
209 animator->data = animator;
210 animator->run_func = func;
211 animator->run_data = (void *)data;
212 animator->start = ecore_loop_time_get();
213 animator->run = runtime;
218 _pos_map_sin(double in)
220 return eina_f32p32_double_to(eina_f32p32_sin(eina_f32p32_double_from(in)));
224 _pos_map_cos(double in)
226 return eina_f32p32_double_to(eina_f32p32_cos(eina_f32p32_double_from(in)));
230 _pos_map_accel_factor(double pos, double v1)
232 int i, fact = (int)v1;
233 double p, o1 = pos, o2 = pos, v;
234 p = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0));
236 for (i = 0; i < fact; i++)
241 v = v1 - (double)fact;
242 pos = (v * o2) + ((1.0 - v) * o1);
247 _pos_map_pow(double pos, double divis, int p)
251 for (i = 0; i < p; i++) v *= pos;
252 return ((pos * divis) * (1.0 - v)) + (pos * v);
256 _pos_map_spring(double pos, int bounces, double decfac)
258 int segnum, segpos, b1, b2;
259 double len, decay, decpos, p2;
260 if (bounces < 0) bounces = 0;
261 p2 = _pos_map_pow(pos, 0.5, 3);
262 len = (M_PI / 2.0) + ((double)bounces * M_PI);
263 segnum = (bounces * 2) + 1;
264 segpos = 2 * (((int)(p2 * segnum) + 1) / 2);
268 decpos = (double)b1 / (double)b2;
269 decay = _pos_map_accel_factor(1.0 - decpos, decfac);
270 return _pos_map_sin((M_PI / 2.0) + (p2 * len)) * decay;
274 * Maps an input position from 0.0 to 1.0 along a timeline to another position
276 * Takes an input position (0.0 to 1.0) and maps to a new position (normally
277 * between 0.0 and 1.0, but it may go above/below 0.0 or 1.0 to show that it
278 * has "overshot" the mark) using some interpolation (mapping) algorithm.
280 * You might normally use this like:
282 * double pos; // input position in a timeline from 0.0 to 1.0
283 * double out; // output position after mapping
284 * int x1, y1, x2, y2; // x1 & y1 are start position, x2 & y2 are end position
285 * int x, y; // x & y are the calculated position
287 * out = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
288 * x = (x1 * out) + (x2 * (1.0 - out));
289 * y = (y1 * out) + (y2 * (1.0 - out));
290 * move_my_object_to(myobject, x, y);
293 * @param pos The input position to map
294 * @param map The mapping to use
295 * @param v1 A parameter use by the mapping (pass 0.0 if not used)
296 * @param v2 A parameter use by the mapping (pass 0.0 if not used)
297 * @return The mapped value
302 ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2)
304 if (pos > 1.0) pos = 1.0;
305 else if (pos < 0.0) pos = 0.0;
308 case ECORE_POS_MAP_LINEAR:
310 case ECORE_POS_MAP_ACCELERATE:
311 pos = 1.0 - _pos_map_sin((M_PI / 2.0) + ((pos * M_PI) / 2.0));
313 case ECORE_POS_MAP_DECELERATE:
314 pos = _pos_map_sin((pos * M_PI) / 2.0);
316 case ECORE_POS_MAP_SINUSOIDAL:
317 pos = (1.0 - _pos_map_cos(pos * M_PI)) / 2.0;
319 case ECORE_POS_MAP_ACCELERATE_FACTOR:
320 pos = _pos_map_accel_factor(pos, v1);
322 case ECORE_POS_MAP_DECELERATE_FACTOR:
323 pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v1);
325 case ECORE_POS_MAP_SINUSOIDAL_FACTOR:
326 if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v1) / 2.0;
327 else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v1) / 2.0);
329 case ECORE_POS_MAP_DIVISOR_INTERP:
330 pos = _pos_map_pow(pos, v1, (int)v2);
332 case ECORE_POS_MAP_BOUNCE:
333 pos = _pos_map_spring(pos, (int)v2, v1);
334 if (pos < 0.0) pos = -pos;
337 case ECORE_POS_MAP_SPRING:
338 pos = 1.0 - _pos_map_spring(pos, (int)v2, v1);
348 * Delete the specified animator from the animator list.
349 * @param animator The animator to delete
350 * @return The data pointer set for the animator on add
352 * Delete the specified @p aqnimator from the set of animators that are executed
353 * during main loop execution. This function returns the data parameter that
354 * was being passed to the callback on success, or NULL on failure. After this
355 * call returns the specified animator object @p animator is invalid and should not
356 * be used again. It will not get called again after deletion.
359 ecore_animator_del(Ecore_Animator *animator)
361 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
363 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
364 "ecore_animator_del");
367 if (animator->delete_me) return animator->data;
368 animator->delete_me = EINA_TRUE;
369 animators_delete_me++;
370 if (animator->run_func) return animator->run_data;
371 return animator->data;
375 * Set the animator call interval in seconds.
376 * @param frametime The time in seconds in between animator ticks.
378 * This function sets the time interval (in seconds) between animator ticks.
381 ecore_animator_frametime_set(double frametime)
383 if (frametime < 0.0) frametime = 0.0;
384 if (animators_frametime == frametime) return;
385 animators_frametime = frametime;
387 if (animators) _begin_tick();
391 * Get the animator call interval in seconds.
392 * @return The time in second in between animator ticks.
394 * this function retrieves the time between animator ticks, in seconds.
397 ecore_animator_frametime_get(void)
399 return animators_frametime;
403 * Suspend the specified animator.
404 * @param animator The animator to delete
406 * The specified @p animator will be temporarly removed from the set of animators
407 * that are executed during main loop execution.
410 ecore_animator_freeze(Ecore_Animator *animator)
412 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
414 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
415 "ecore_animator_del");
418 if (animator->delete_me) return;
419 animator->suspended = EINA_TRUE;
423 * Restore execution of the specified animator.
424 * @param animator The animator to delete
426 * The specified @p animator will be put back in the set of animators
427 * that are executed during main loop execution.
430 ecore_animator_thaw(Ecore_Animator *animator)
432 if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
434 ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
435 "ecore_animator_del");
438 if (animator->delete_me) return;
439 animator->suspended = EINA_FALSE;
443 * Set the source of animator ticks for the mainloop
445 * @param source The source of animator ticks to use
447 * This sets the source of animator ticks. When an animator is active the
448 * mainloop will "tick" over frame by frame calling all animators that are
449 * registered until none are. The mainloop will tick at a given rate based
450 * on the animator source. The default source is the system clock timer
451 * source - ECORE_ANIMATOR_SOURCE_TIMER. This source uses the system clock
452 * to tick over every N seconds (specified by ecore_animator_frametime_set(),
453 * with the default being 1/30th of a second unless set otherwise). You can
454 * set a custom tick source by setting the source to
455 * ECORE_ANIMATOR_SOURCE_CUSTOM and then drive it yourself based on some input
456 * tick source (like another application via ipc, some vertical blanking
457 * interrupt etc.) using ecore_animator_custom_source_tick_begin_callback_set()
458 * and ecore_animator_custom_source_tick_end_callback_set() to set the
459 * functions that will be called to start and stop the ticking source, which
460 * when it gets a "tick" should call ecore_animator_custom_tick() to make
461 * the animator "tick" over 1 frame.
464 ecore_animator_source_set(Ecore_Animator_Source source)
468 if (animators) _begin_tick();
472 * Get the animator source currently set
473 * @return The current animator source
475 * This gets the current animator source. See ecore_animator_source_set() for
478 EAPI Ecore_Animator_Source
479 ecore_animator_source_get(void)
485 * Set the function that begins a custom animator tick source
487 * @param func The function to call when ticking is to begin
488 * @param data The data passed to the tick begin function as its parameter
490 * The Ecore Animator infrastructure handles tracking if animators are needed
491 * or not and which ones need to be called and when, but when the tick source
492 * is custom, you have to provide a tick source by calling
493 * ecore_animator_custom_tick() to indicate a frame tick happened. In order
494 * to allow the source of ticks to be dynamically enabled or disabled as
495 * needed, the @p func when set is called to enable the tick source to
496 * produce tick events that call ecore_animator_custom_tick(). If @p func
497 * is NULL then no function is called to begin custom ticking.
500 ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, const void *data)
502 begin_tick_cb = func;
503 begin_tick_data = data;
505 if (animators) _begin_tick();
509 * Set the function that ends a custom animator tick source
510 * @param func The function to call when ticking is to end
511 * @param data The data passed to the tick end function as its parameter
513 * This function is a matching pair to the function set by
514 * ecore_animator_custom_source_tick_begin_callback_set() and is called
515 * when ticking is to stop. If @p func is NULL then no function will be
516 * called to stop ticking. For more information please see
517 * ecore_animator_custom_source_tick_begin_callback_set().
520 ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data)
523 end_tick_data = data;
525 if (animators) _begin_tick();
529 * Trigger a custom animator tick
531 * When animator source is set to ECORE_ANIMATOR_SOURCE_CUSTOM, then calling
532 * this function triggers a run of all animators currently registered with
533 * Ecore as this indicates a "frame tick" happened. This will do nothing
534 * if the animator source (set by ecore_animator_source_set() ) is not set
535 * to ECORE_ANIMATOR_SOURCE_CUSTOM.
538 ecore_animator_custom_tick(void)
540 if (src == ECORE_ANIMATOR_SOURCE_CUSTOM) _do_tick();
544 _ecore_animator_shutdown(void)
549 Ecore_Animator *animator;
551 animator = animators;
552 animators = (Ecore_Animator *) eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators));
553 ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
559 _ecore_animator_run(void *data)
561 Ecore_Animator *animator = data;
565 t = ecore_loop_time_get();
566 if (animator->run > 0.0)
568 pos = (t - animator->start) / animator->run;
569 if (pos > 1.0) pos = 1.0;
570 else if (pos < 0.0) pos = 0.0;
572 run_ret = animator->run_func(animator->run_data, pos);
573 if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE;
578 _ecore_animator(void *data __UNUSED__)