diff --git a/legacy/ecore/ChangeLog b/legacy/ecore/ChangeLog index 08f241df33..2619f37b60 100644 --- a/legacy/ecore/ChangeLog +++ b/legacy/ecore/ChangeLog @@ -140,3 +140,12 @@ 2011-04-19 Mike Blumenkrantz * +ecore_exe_data_set + +2011-04-20 Carsten Haitzler (The Rasterman) + + * Added ecore animator run, where animator runs for a + specified time (in seconds) and then stops, but it also passes + the position in the timeline (as a 0.0 to 1.0 value) to the + callback which it can then use the new pos map call to map to + some ease in/out, bounce, spring or whatever position. + diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index 1a7e9abc64..62e80e166d 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -146,6 +146,21 @@ extern "C" { ECORE_POLLER_CORE = 0 /**< The core poller interval */ }; typedef enum _Ecore_Poller_Type Ecore_Poller_Type; + + enum _Ecore_Pos_Map /* Position mappings */ + { + ECORE_POS_MAP_LINEAR, /**< Linear 0.0 -> 1.0 */ + ECORE_POS_MAP_ACCELERATE, /**< Start slow then speed up */ + ECORE_POS_MAP_DECELERATE, /**< Start fast then slow down */ + ECORE_POS_MAP_SINUSOIDAL, /**< Start slow, speed up then slow down at end */ + ECORE_POS_MAP_ACCELERATE_FACTOR, /**< Start slow then speed up, v1 being a power factor, 0.0 being linear, 1.0 being normal accelerate, 2.0 being much more pronounced accelerate (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_DECELERATE_FACTOR, /**< Start fast then slow down, v1 being a power factor, 0.0 being linear, 1.0 being normal decelerate, 2.0 being much more pronounced decelerate (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_SINUSOIDAL_FACTOR, /**< Start slow, speed up then slow down at end, v1 being a power factor, 0.0 being linear, 1.0 being normal sinusoidal, 2.0 being much more pronounced sinusoidal (squared), 3.0 being cubed, etc. */ + ECORE_POS_MAP_DIVISOR_INTERP, /**< Start at gradient * v1, interpolated via power of v2 curve */ + ECORE_POS_MAP_BOUNCE, /**< Start at 0.0 then "drop" like a ball bouncing to the ground at 1.0, and bounce v2 times, with decay factor of v1 */ + ECORE_POS_MAP_SPRING /**< Start at 0.0 then "wobble" like a sping rest position 1.0, and wobble v2 times, with decay factor of v1 */ + }; + typedef enum _Ecore_Pos_Map Ecore_Pos_Map; typedef struct _Ecore_Exe Ecore_Exe; /**< A handle for spawned processes */ typedef struct _Ecore_Timer Ecore_Timer; /**< A handle for timers */ @@ -218,9 +233,14 @@ extern "C" { typedef void (*Ecore_Thread_Notify_Cb) (void *data, Ecore_Thread *thread, void *msg_data); /** * @typedef Ecore_Task_Cb Ecore_Task_Cb - * A callback run for a task (timer, idler, poller, animater, etc) + * A callback run for a task (timer, idler, poller, animator, etc) */ typedef Eina_Bool (*Ecore_Task_Cb) (void *data); + /** + * @typedef Ecore_Timeline_Cb Ecore_Timeline_Cb + * A callback run for a task (animators with runtimes) + */ + typedef Eina_Bool (*Ecore_Timeline_Cb) (void *data, double pos); /** * @typedef Ecore_Cb Ecore_Cb * A generic callback called as a hook when a certain point in execution is reached. @@ -555,12 +575,14 @@ extern "C" { */ EAPI Ecore_Animator *ecore_animator_add(Ecore_Task_Cb func, const void *data); + EAPI Ecore_Animator *ecore_animator_run_add(double runtime, Ecore_Timeline_Cb func, const void *data); EAPI void *ecore_animator_del(Ecore_Animator *animator); EAPI void ecore_animator_freeze(Ecore_Animator *animator); EAPI void ecore_animator_thaw(Ecore_Animator *animator); EAPI void ecore_animator_frametime_set(double frametime); EAPI double ecore_animator_frametime_get(void); - + EAPI double ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2); + /** * @} */ diff --git a/legacy/ecore/src/lib/ecore/ecore_anim.c b/legacy/ecore/src/lib/ecore/ecore_anim.c index c86026c486..87fa52a7e1 100644 --- a/legacy/ecore/src/lib/ecore/ecore_anim.c +++ b/legacy/ecore/src/lib/ecore/ecore_anim.c @@ -16,12 +16,17 @@ struct _Ecore_Animator Ecore_Task_Cb func; void *data; + + double start, run; + Ecore_Timeline_Cb run_func; + void *run_data; Eina_Bool delete_me : 1; Eina_Bool suspended : 1; }; +static Eina_Bool _ecore_animator_run(void *data); static Eina_Bool _ecore_animator(void *data); static Ecore_Timer *timer = NULL; @@ -81,10 +86,165 @@ ecore_animator_add(Ecore_Task_Cb func, const void *data) return animator; } +/** + * Add a animator that runs for a limited time + * @param runtime The time to run in seconds + * @param func The function to call when it ticks off + * @param data The data to pass to the function + * @return A handle to the new animator + * + * This function is just like ecore_animator_add() except the animator only + * runs for a limited time specified in seconds by @p runtime. Once the runtime + * the animator has elapsed (animator finished) it will automatically be + * deleted. The callback function @p func can return ECORE_CALLBACK_RENEW to + * keep the animator running or ECORE_CALLBACK_CANCEL ro stop it and have + * it be deleted automatically at any time. + * + * The @p func will ALSO be passed a position parameter that will be in value + * from 0.0 to 1.0 to indicate where along the timeline (0.0 start, 1.0 end) + * the animator run is at. If the callback wishes not to have a linear + * transition it can "map" this value to one of several curves and mappings + * via ecore_animator_pos_map(). + * + * @since 1.1.0 + */ +EAPI Ecore_Animator * +ecore_animator_run_add(double runtime, Ecore_Timeline_Cb func, const void *data) +{ + Ecore_Animator *animator; + + if (runtime <= 0.0) runtime = 0.0; + animator = ecore_animator_add(_ecore_animator_run, NULL); + animator->data = animator; + animator->run_func = func; + animator->run_data = (void *)data; + animator->start = ecore_loop_time_get(); + animator->run = runtime; + return animator; +} + +static double +_pos_map_accel_factor(double pos, double v1) +{ + int i, fact = (int)v1; + double p, o1 = pos, o2 = pos, v; + p = 1.0 - sin((M_PI / 2.0) + ((pos * M_PI) / 2.0)); + o2 = p; + for (i = 0; i < fact; i++) + { + o1 = o2; + o2 = o2 * p; + } + v = v1 - (double)fact; + pos = (v * o2) + ((1.0 - v) * o1); + return pos; +} + +static double +_pos_map_pow(double pos, double divis, int p) +{ + double v = 1.0; + int i; + for (i = 0; i < p; i++) v *= pos; + return ((pos * divis) * (1.0 - v)) + (pos * v); +} + +static double +_pos_map_spring(double pos, int bounces, double decfac) +{ + int segnum, segpos, b1, b2; + double len, decay, decpos, p2; + if (bounces < 0) bounces = 0; + p2 = _pos_map_pow(pos, 0.5, 3); + len = (M_PI / 2.0) + ((double)bounces * M_PI); + segnum = (bounces * 2) + 1; + segpos = 2 * (((int)(p2 * segnum) + 1) / 2); + b1 = segpos; + b2 = segnum + 1; + if (b1 < 0) b1 = 0; + decpos = (double)b1 / (double)b2; + decay = _pos_map_accel_factor(1.0 - decpos, decfac); + return sin((M_PI / 2.0) + (p2 * len)) * decay; +} + +/** + * Maps an input position from 0.0 to 1.0 along a timeline to another position + * + * Takes an input position (0.0 to 1.0) and maps to a new position (normally + * between 0.0 and 1.0, but it may go above/below 0.0 or 1.0 to show that it + * has "overshot" the mark) using some interpolation (mapping) algorithm. + * + * You might normally use this like: + * @code + * double pos; // input position in a timeline from 0.0 to 1.0 + * double out; // output position after mapping + * int x1, y1, x2, y2; // x1 & y1 are start position, x2 & y2 are end position + * int x, y; // x & y are the calculated position + * + * out = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7); + * x = (x1 * out) + (x2 * (1.0 - out)); + * y = (y1 * out) + (y2 * (1.0 - out)); + * move_my_object_to(myobject, x, y); + * @endcode + * + * @param pos The input position to map + * @param map The mapping to use + * @param v1 A parameter use by the mapping (pass 0.0 if not used) + * @param v2 A parameter use by the mapping (pass 0.0 if not used) + * @return The mapped value + * + * @since 1.1.0 + */ +EAPI double +ecore_animator_pos_map(double pos, Ecore_Pos_Map map, double v1, double v2) +{ + if (pos > 1.0) pos = 1.0; + else if (pos < 0.0) pos = 0.0; + switch (map) + { + case ECORE_POS_MAP_LINEAR: + return pos; + case ECORE_POS_MAP_ACCELERATE: + pos = 1.0 - sin((M_PI / 2.0) + ((pos * M_PI) / 2.0)); + return pos; + case ECORE_POS_MAP_DECELERATE: + pos = sin((pos * M_PI) / 2.0); + return pos; + case ECORE_POS_MAP_SINUSOIDAL: + pos = (1.0 - cos(pos * M_PI)) / 2.0; + return pos; + case ECORE_POS_MAP_ACCELERATE_FACTOR: + pos = _pos_map_accel_factor(pos, v1); + return pos; + case ECORE_POS_MAP_DECELERATE_FACTOR: + pos = 1.0 - _pos_map_accel_factor(1.0 - pos, v1); + return pos; + case ECORE_POS_MAP_SINUSOIDAL_FACTOR: + if (pos < 0.5) pos = _pos_map_accel_factor(pos * 2.0, v1) / 2.0; + else pos = 1.0 - (_pos_map_accel_factor((1.0 - pos) * 2.0, v1) / 2.0); + return pos; + case ECORE_POS_MAP_DIVISOR_INTERP: + pos = _pos_map_pow(pos, v1, (int)v2); + return pos; + case ECORE_POS_MAP_BOUNCE: + pos = _pos_map_spring(pos, (int)v2, v1); + if (pos < 0.0) pos = -pos; + pos = 1.0 - pos; + return pos; + case ECORE_POS_MAP_SPRING: + pos = 1.0 - _pos_map_spring(pos, (int)v2, v1); + return pos; + default: + return pos; + } + return pos; + v2 = 0.0; +} + /** * Delete the specified animator from the animator list. * @param animator The animator to delete - * @return The data pointer set for the animator + * @return The data pointer set for the animator on add * * Delete the specified @p aqnimator from the set of animators that are executed * during main loop execution. This function returns the data parameter that @@ -104,6 +264,7 @@ ecore_animator_del(Ecore_Animator *animator) if (animator->delete_me) return animator->data; animator->delete_me = EINA_TRUE; animators_delete_me++; + if (animator->run_func) return animator->run_data; return animator->data; } @@ -199,6 +360,25 @@ _ecore_animator_shutdown(void) } } +static Eina_Bool +_ecore_animator_run(void *data) +{ + Ecore_Animator *animator = data; + double pos = 0.0, t; + Eina_Bool run_ret; + + t = ecore_loop_time_get(); + if (animator->run > 0.0) + { + pos = (t - animator->start) / animator->run; + if (pos > 1.0) pos = 1.0; + else if (pos < 0.0) pos = 0.0; + } + run_ret = animator->run_func(animator->run_data, pos); + if (t >= (animator->start + animator->run)) run_ret = EINA_FALSE; + return run_ret; +} + static Eina_Bool _ecore_animator(void *data __UNUSED__) {