From ec3b1a7b90314a13a9a4bed944e10f82183edcd5 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 20 Jan 2009 17:57:30 +0000 Subject: [PATCH] [animation] Implement new easing functions Instead of using our own homegrown alpha functions, we should use the easing functions also shared by other animation frameworks, like jQuery and Tween, in the interests of code portability. The easing functions have been defined by Robert Penner and are divided into three categories: In Out InOut Each category has a particular curve: Quadratic Cubic Quartic Quintic Sinusoidal Exponential Circular In addition, there are "physical" curves: Elastic Back (overshooting cubic) Bounce (exponentially decaying parabolic) Finally, the Linear curve is also provided as a reference. The functions are private, and are meant to be used only through their logical id as provided by the AnimationMode enumeration. The tests should be updated as well to match the new easing functions. --- clutter/clutter-alpha.c | 561 +++++++++++++++++++++++++++-- clutter/clutter-types.h | 134 +++++-- tests/interactive/test-animation.c | 2 +- tests/interactive/test-easing.c | 101 ++++-- 4 files changed, 703 insertions(+), 95 deletions(-) diff --git a/clutter/clutter-alpha.c b/clutter/clutter-alpha.c index eeef07d0c..615af0e1c 100644 --- a/clutter/clutter-alpha.c +++ b/clutter/clutter-alpha.c @@ -315,6 +315,37 @@ clutter_alpha_get_alpha (ClutterAlpha *alpha) return retval; } +/* + * clutter_alpha_set_closure_internal: + * @alpha: a #ClutterAlpha + * @closure: a #GClosure + * + * Sets the @closure for @alpha. This function does not + * set the #ClutterAlpha:mode property and does not emit + * the #GObject::notify signal for it. + */ +static inline void +clutter_alpha_set_closure_internal (ClutterAlpha *alpha, + GClosure *closure) +{ + ClutterAlphaPrivate *priv = alpha->priv; + + if (priv->closure) + g_closure_unref (priv->closure); + + /* need to take ownership of the closure before sinking it */ + priv->closure = g_closure_ref (closure); + g_closure_sink (closure); + + /* set the marshaller */ + if (G_CLOSURE_NEEDS_MARSHAL (closure)) + { + GClosureMarshal marshal = clutter_marshal_DOUBLE__VOID; + + g_closure_set_marshal (closure, marshal); + } +} + /** * clutter_alpha_set_closure: * @alpha: A #ClutterAlpha @@ -336,18 +367,7 @@ clutter_alpha_set_closure (ClutterAlpha *alpha, priv = alpha->priv; - if (priv->closure) - g_closure_unref (priv->closure); - - priv->closure = g_closure_ref (closure); - g_closure_sink (closure); - - if (G_CLOSURE_NEEDS_MARSHAL (closure)) - { - GClosureMarshal marshal = clutter_marshal_DOUBLE__VOID; - - g_closure_set_marshal (closure, marshal); - } + clutter_alpha_set_closure_internal (alpha, closure); priv->mode = CLUTTER_CUSTOM_MODE; g_object_notify (G_OBJECT (alpha), "mode"); @@ -374,13 +394,19 @@ clutter_alpha_set_func (ClutterAlpha *alpha, gpointer data, GDestroyNotify destroy) { + ClutterAlphaPrivate *priv; GClosure *closure; g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (func != NULL); - + + priv = alpha->priv; + closure = g_cclosure_new (G_CALLBACK (func), data, (GClosureNotify) destroy); - clutter_alpha_set_closure (alpha, closure); + clutter_alpha_set_closure_internal (alpha, closure); + + priv->mode = CLUTTER_CUSTOM_MODE; + g_object_notify (G_OBJECT (alpha), "mode"); } /** @@ -548,6 +574,418 @@ clutter_alpha_get_mode (ClutterAlpha *alpha) return alpha->priv->mode; } +static gdouble +clutter_linear (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + + return clutter_timeline_get_progress (timeline); +} + +static gdouble +clutter_ease_in_quad (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble progress = clutter_timeline_get_progress (timeline); + + return progress * progress; +} + +static gdouble +clutter_ease_out_quad (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return -1.0 * (t /= d) * (t - 2); +} + +static gdouble +clutter_ease_in_out_quad (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if ((t /= d / 2) < 1) + return 0.5 * t * t; + + return -0.5 * ((--t) * (t - 2) - 1); +} + +static gdouble +clutter_ease_in_cubic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t /= d) * t * t; +} + +static gdouble +clutter_ease_out_cubic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t = t / d - 1) * t * t + 1; +} + +static gdouble +clutter_ease_in_out_cubic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if ((t /= d / 2) < 1) + return 0.5 * t * t * t; + + return 0.5 * ((t -= 2) * t * t + 2); +} + +static gdouble +clutter_ease_in_quart (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t /= d) * t * t * t; +} + +static gdouble +clutter_ease_out_quart (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return -0.5 * ((t = t / d - 1) * t * t * t - 1); +} + +static gdouble +clutter_ease_in_out_quart (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if ((t /= d / 2) < 1) + return 0.5 * t * t * t * t; + + return -0.5 * ((t -= 2) * t * t * t - 2); +} + +static gdouble +clutter_ease_in_quint (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) + { + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t /= d) * t * t * t * t; +} + +static gdouble +clutter_ease_out_quint (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t = t / d - 1) * t * t * t * t + 1; +} + +static gdouble +clutter_ease_in_out_quint (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if ((t /= d / 2) < 1) + return 0.5 * t * t * t * t * t; + + return 0.5 * ((t -= 2) * t * t * t * t + 2); +} + +static gdouble +clutter_ease_in_sine (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return -1.0 * cos (t / d * G_PI_2) + 1.0; +} + +static gdouble +clutter_ease_out_sine (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return sin (t / d * G_PI_2); +} + +static gdouble +clutter_ease_in_out_sine (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return -0.5 * (cos (G_PI * t / d) - 1); +} + +static gdouble +clutter_ease_in_expo (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t == 0) ? 0.0 : pow (2, 10 * (t / d - 1)); +} + +static gdouble +clutter_ease_out_expo (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t == d) ? 1.0 : -pow (2, -10 * t / d) + 1; +} + +static gdouble +clutter_ease_in_out_expo (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if (t == 0) + return 0.0; + + if (t == d) + return 1.0; + + if ((t /= d / 2) < 1) + return 0.5 * pow (2, 10 * (t - 1)); + + return 0.5 * (-pow (2, -10 * --t) + 2); +} + +static gdouble +clutter_ease_in_circ (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return -1.0 * (sqrt (1 - (t /= d) * t) - 1); +} + +static gdouble +clutter_ease_out_circ (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return sqrt (1 - (t = t / d - 1) * t); +} + +static gdouble +clutter_ease_in_out_circ (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if ((t /= d / 2) < 1) + return -0.5 * (sqrt (1 - t * t) - 1); + + return 0.5 * (sqrt (1 - (t -= 2) * t) + 1); +} + +static gdouble +clutter_ease_in_elastic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble p = d * .3; + gdouble s = p / 4; + + if ((t /= d) == 1) + return 1.0; + + return -(pow (2, 10 * (t -= 1)) * sin ((t * d - s) * (2 * G_PI) / p)); +} + +static gdouble +clutter_ease_out_elastic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble p = d * .3; + gdouble s = p / 4; + + if ((t /= d) == 1) + return 1.0; + + return pow (2, -10 * t) * sin ((t * d - s) * (2 * G_PI) / p) + 1.0; +} + +static gdouble +clutter_ease_in_out_elastic (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble p = d * (.3 * 1.5); + gdouble s = p / 4; + + if ((t /= d / 2) == 2) + return 1.0; + + if (t < 1) + return -.5 * (pow (2, 10 * (t -= 1)) * sin ((t * d - s) * (2 * G_PI) / p)); + else + { + return pow (2, -10 * (t -= 1)) + * sin ((t * d - s) * (2 * G_PI) / p) + * .5 + 1.0; + } +} + +static gdouble +clutter_ease_in_back (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t /= d) * t * ((1.70158 + 1) * t - 1.70158); +} + +static gdouble +clutter_ease_out_back (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return (t = t / d - 1) * t * ((1.70158 + 1) * t + 1.70158) + 1; +} + +static gdouble +clutter_ease_in_out_back (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + gdouble s = 1.70158; + + if ((t /= d / 2) < 1) + return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); + + return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); +} + +static gdouble +ease_out_bounce_internal (gdouble t, + gdouble d) +{ + if ((t /= d) < (1 / 2.75)) + return 7.5625 * t * t; + else if (t < (2 / 2.75)) + return 7.5625 * (t -= (1.5 / 2.75)) * t + .75; + else if (t < (2.5 / 2.75)) + return 7.5625 * (t -= (2.25 / 2.75)) * t + .9375; + else + return 7.5625 * (t -= (2.625 / 2.75)) * t + .984375; +} + +static gdouble +ease_in_bounce_internal (gdouble t, + gdouble d) +{ + return 1.0 - ease_out_bounce_internal (d - t, d); +} + +static gdouble +clutter_ease_in_bounce (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return ease_in_bounce_internal (t, d); +} + +static gdouble +clutter_ease_out_bounce (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + return ease_out_bounce_internal (t, d); +} + +static gdouble +clutter_ease_in_out_bounce (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = alpha->priv->timeline; + gdouble t = clutter_timeline_get_current_frame (timeline); + gdouble d = clutter_timeline_get_n_frames (timeline); + + if (t < d / 2) + return ease_in_bounce_internal (t * 2, d) * 0.5; + else + return ease_out_bounce_internal (t * 2 - d, d) * 0.5 + 1.0 * 0.5; +} + /* static enum/function mapping table for the animation modes * we provide internally * @@ -557,7 +995,41 @@ static const struct { gulong mode; ClutterAlphaFunc func; } animation_modes[] = { - { CLUTTER_CUSTOM_MODE, NULL }, + { CLUTTER_CUSTOM_MODE, NULL }, + + { CLUTTER_LINEAR, clutter_linear }, + { CLUTTER_EASE_IN_QUAD, clutter_ease_in_quad }, + { CLUTTER_EASE_OUT_QUAD, clutter_ease_out_quad }, + { CLUTTER_EASE_IN_OUT_QUAD, clutter_ease_in_out_quad }, + { CLUTTER_EASE_IN_CUBIC, clutter_ease_in_cubic }, + { CLUTTER_EASE_OUT_CUBIC, clutter_ease_out_cubic }, + { CLUTTER_EASE_IN_OUT_CUBIC, clutter_ease_in_out_cubic }, + { CLUTTER_EASE_IN_QUART, clutter_ease_in_quart }, + { CLUTTER_EASE_OUT_QUART, clutter_ease_out_quart }, + { CLUTTER_EASE_IN_OUT_QUART, clutter_ease_in_out_quart }, + { CLUTTER_EASE_IN_QUINT, clutter_ease_in_quint }, + { CLUTTER_EASE_OUT_QUINT, clutter_ease_out_quint }, + { CLUTTER_EASE_IN_OUT_QUINT, clutter_ease_in_out_quint }, + { CLUTTER_EASE_IN_SINE, clutter_ease_in_sine }, + { CLUTTER_EASE_OUT_SINE, clutter_ease_out_sine }, + { CLUTTER_EASE_IN_OUT_SINE, clutter_ease_in_out_sine }, + { CLUTTER_EASE_IN_EXPO, clutter_ease_in_expo }, + { CLUTTER_EASE_OUT_EXPO, clutter_ease_out_expo }, + { CLUTTER_EASE_IN_OUT_EXPO, clutter_ease_in_out_expo }, + { CLUTTER_EASE_IN_CIRC, clutter_ease_in_circ }, + { CLUTTER_EASE_OUT_CIRC, clutter_ease_out_circ }, + { CLUTTER_EASE_IN_OUT_CIRC, clutter_ease_in_out_circ }, + { CLUTTER_EASE_IN_ELASTIC, clutter_ease_in_elastic }, + { CLUTTER_EASE_OUT_ELASTIC, clutter_ease_out_elastic }, + { CLUTTER_EASE_IN_OUT_ELASTIC, clutter_ease_in_out_elastic }, + { CLUTTER_EASE_IN_BACK, clutter_ease_in_back }, + { CLUTTER_EASE_OUT_BACK, clutter_ease_out_back }, + { CLUTTER_EASE_IN_OUT_BACK, clutter_ease_in_out_back }, + { CLUTTER_EASE_IN_BOUNCE, clutter_ease_in_bounce }, + { CLUTTER_EASE_OUT_BOUNCE, clutter_ease_out_bounce }, + { CLUTTER_EASE_IN_OUT_BOUNCE, clutter_ease_in_out_bounce }, + + { CLUTTER_ANIMATION_LAST, NULL }, }; typedef struct _AlphaData { @@ -593,15 +1065,24 @@ clutter_alpha_set_mode (ClutterAlpha *alpha, priv = alpha->priv; - if (mode < CLUTTER_ANIMATION_LAST) + if (mode == CLUTTER_CUSTOM_MODE) { + priv->mode = mode; + } + else if (mode < CLUTTER_ANIMATION_LAST) + { + GClosure *closure; + /* sanity check to avoid getting an out of sync * enum/function mapping */ g_assert (animation_modes[mode].mode == mode); + g_assert (animation_modes[mode].func != NULL); - if (G_LIKELY (animation_modes[mode].func != NULL)) - clutter_alpha_set_func (alpha, animation_modes[mode].func, NULL, NULL); + closure = g_cclosure_new (G_CALLBACK (animation_modes[mode].func), + NULL, + NULL); + clutter_alpha_set_closure_internal (alpha, closure); priv->mode = mode; } @@ -631,9 +1112,14 @@ clutter_alpha_set_mode (ClutterAlpha *alpha, if (alpha_data->closure_set) clutter_alpha_set_closure (alpha, alpha_data->closure); else - clutter_alpha_set_func (alpha, alpha_data->func, - alpha_data->data, - NULL); + { + GClosure *closure; + + closure = g_cclosure_new (G_CALLBACK (alpha_data->func), + alpha_data->data, + NULL); + clutter_alpha_set_closure_internal (alpha, closure); + } priv->mode = mode; } @@ -643,6 +1129,17 @@ clutter_alpha_set_mode (ClutterAlpha *alpha, g_object_notify (G_OBJECT (alpha), "mode"); } +static gulong +register_alpha_internal (AlphaData *alpha_data) +{ + if (G_UNLIKELY (clutter_alphas == NULL)) + clutter_alphas = g_ptr_array_new (); + + g_ptr_array_add (clutter_alphas, alpha_data); + + return clutter_alphas->len + CLUTTER_ANIMATION_LAST; +} + /** * clutter_alpha_register_func: * @func: a #ClutterAlphaFunc @@ -670,12 +1167,7 @@ clutter_alpha_register_func (ClutterAlphaFunc func, alpha_data->func = func; alpha_data->data = data; - if (G_UNLIKELY (clutter_alphas == NULL)) - clutter_alphas = g_ptr_array_new (); - - g_ptr_array_add (clutter_alphas, alpha_data); - - return clutter_alphas->len + CLUTTER_ANIMATION_LAST; + return register_alpha_internal (alpha_data); } /** @@ -696,18 +1188,13 @@ clutter_alpha_register_func (ClutterAlphaFunc func, gulong clutter_alpha_register_closure (GClosure *closure) { - AlphaData *data; + AlphaData *alpha_data; g_return_val_if_fail (closure != NULL, 0); - data = g_slice_new (AlphaData); - data->closure_set = TRUE; - data->closure = closure; + alpha_data = g_slice_new (AlphaData); + alpha_data->closure_set = TRUE; + alpha_data->closure = closure; - if (G_UNLIKELY (clutter_alphas == NULL)) - clutter_alphas = g_ptr_array_new (); - - g_ptr_array_add (clutter_alphas, data); - - return clutter_alphas->len + CLUTTER_ANIMATION_LAST; + return register_alpha_internal (alpha_data); } diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h index 2e1856905..968a7a589 100644 --- a/clutter/clutter-types.h +++ b/clutter/clutter-types.h @@ -189,39 +189,127 @@ typedef enum { /** * ClutterAnimationMode: * @CLUTTER_CUSTOM_MODE: custom progress function - * @CLUTTER_LINEAR: linear progress - * @CLUTTER_SINE_IN: sine-in progress - * @CLUTTER_SINE_OUT: sine-out progress - * @CLUTTER_SINE_IN_OUT: sine-in-out progress - * @CLUTTER_EASE_IN: ease-in progress - * @CLUTTER_EASE_OUT: ease-out progress - * @CLUTTER_EASE_IN_OUT: ease-in-out progress - * @CLUTTER_EXPO_IN: exponential in progress - * @CLUTTER_EXPO_OUT: exponential out progress - * @CLUTTER_EXPO_IN_OUT: exponential in-out progress - * @CLUTTER_SMOOTH_IN_OUT: smoothstep in-out progress - * @CLUTTER_ANIMATION_LAST: last animation mode + * @CLUTTER_LINEAR: linear tweening + * @CLUTTER_EASE_IN_QUAD: quadratic tweening + * @CLUTTER_EASE_OUT_QUAD: quadratic tweening, inverse of + * %CLUTTER_EASE_IN_QUAD + * @CLUTTER_EASE_IN_OUT_QUAD: quadratic tweening, combininig + * %CLUTTER_EASE_IN_QUAD and %CLUTTER_EASE_OUT_QUAD + * @CLUTTER_EASE_IN_CUBIC: cubic tweening + * @CLUTTER_EASE_OUT_CUBIC: cubic tweening, invers of + * %CLUTTER_EASE_IN_CUBIC + * @CLUTTER_EASE_IN_OUT_CUBIC: cubic tweening, combining + * %CLUTTER_EASE_IN_CUBIC and %CLUTTER_EASE_OUT_CUBIC + * @CLUTTER_EASE_IN_QUART: quartic tweening + * @CLUTTER_EASE_OUT_QUART: quartic tweening, inverse of + * %CLUTTER_EASE_IN_QUART + * @CLUTTER_EASE_IN_OUT_QUART: quartic tweening, combining + * %CLUTTER_EASE_IN_QUART and %CLUTTER_EASE_OUT_QUART + * @CLUTTER_EASE_IN_QUINT: quintic tweening + * @CLUTTER_EASE_OUT_QUINT: quintic tweening, inverse of + * %CLUTTER_EASE_IN_QUINT + * @CLUTTER_EASE_IN_OUT_QUINT: fifth power tweening, combining + * %CLUTTER_EASE_IN_QUINT and %CLUTTER_EASE_OUT_QUINT + * @CLUTTER_EASE_IN_SINE: sinusoidal tweening + * @CLUTTER_EASE_OUT_SINE: sinusoidal tweening, inverse of + * %CLUTTER_EASE_IN_SINE + * @CLUTTER_EASE_IN_OUT_SINE: sine wave tweening, combining + * %CLUTTER_EASE_IN_SINE and %CLUTTER_EASE_OUT_SINE + * @CLUTTER_EASE_IN_EXPO: exponential tweening + * @CLUTTER_EASE_OUT_EXPO: exponential tweening, inverse of + * %CLUTTER_EASE_IN_EXPO + * @CLUTTER_EASE_IN_OUT_EXPO: exponential tweening, combining + * %CLUTTER_EASE_IN_EXPO and %CLUTTER_EASE_OUT_EXPO + * @CLUTTER_EASE_IN_CIRC: circular tweening + * @CLUTTER_EASE_OUT_CIRC: circular tweening, inverse of + * %CLUTTER_EASE_IN_CIRC + * @CLUTTER_EASE_IN_OUT_CIRC: circular tweening, combining + * %CLUTTER_EASE_IN_CIRC and %CLUTTER_EASE_OUT_CIRC + * @CLUTTER_EASE_IN_ELASTIC: elastic tweening, with offshoot on start + * @CLUTTER_EASE_OUT_ELASTIC: elastic tweening, with offshoot on end + * @CLUTTER_EASE_IN_OUT_ELASTIC: elastic tweening with offshoot on both ends + * @CLUTTER_EASE_IN_BACK: overshooting cubic tweening, with + * backtracking on start + * @CLUTTER_EASE_OUT_BACK: overshooting cubic tweening, with + * backtracking on end + * @CLUTTER_EASE_IN_OUT_BACK: overshooting cubic tweening, with + * backtracking on both ends + * @CLUTTER_EASE_IN_BOUNCE: exponentially decaying parabolic (bounce) + * tweening, with bounce on start + * @CLUTTER_EASE_OUT_BOUNCE: exponentially decaying parabolic (bounce) + * tweening, with bounce on end + * @CLUTTER_EASE_IN_OUT_BOUNCE: exponentially decaying parabolic (bounce) + * tweening, with bounce on both ends + * @CLUTTER_ANIMATION_LAST: last animation mode, used as a guard for + * registered global alpha functions * * The animation modes used by #ClutterAlpha and #ClutterAnimation. This - * enumeration can be expanded in later versions of Clutter. + * enumeration can be expanded in later versions of Clutter. See the + * #ClutterAlpha documentation for a graph of all the animation modes. + * + * Every global alpha function registered using clutter_alpha_register_func() + * or clutter_alpha_register_closure() will have a logical id greater than + * %CLUTTER_ANIMATION_LAST. * * Since: 1.0 */ typedef enum { CLUTTER_CUSTOM_MODE = 0, + /* linear */ CLUTTER_LINEAR, - CLUTTER_SINE_IN, - CLUTTER_SINE_OUT, - CLUTTER_SINE_IN_OUT, - CLUTTER_EASE_IN, - CLUTTER_EASE_OUT, - CLUTTER_EASE_IN_OUT, - CLUTTER_EXPO_IN, - CLUTTER_EXPO_OUT, - CLUTTER_EXPO_IN_OUT, - CLUTTER_SMOOTH_IN_OUT, + /* quadratic */ + CLUTTER_EASE_IN_QUAD, + CLUTTER_EASE_OUT_QUAD, + CLUTTER_EASE_IN_OUT_QUAD, + + /* cubic */ + CLUTTER_EASE_IN_CUBIC, + CLUTTER_EASE_OUT_CUBIC, + CLUTTER_EASE_IN_OUT_CUBIC, + + /* quartic */ + CLUTTER_EASE_IN_QUART, + CLUTTER_EASE_OUT_QUART, + CLUTTER_EASE_IN_OUT_QUART, + + /* quintic */ + CLUTTER_EASE_IN_QUINT, + CLUTTER_EASE_OUT_QUINT, + CLUTTER_EASE_IN_OUT_QUINT, + + /* sinusoidal */ + CLUTTER_EASE_IN_SINE, + CLUTTER_EASE_OUT_SINE, + CLUTTER_EASE_IN_OUT_SINE, + + /* exponential */ + CLUTTER_EASE_IN_EXPO, + CLUTTER_EASE_OUT_EXPO, + CLUTTER_EASE_IN_OUT_EXPO, + + /* circular */ + CLUTTER_EASE_IN_CIRC, + CLUTTER_EASE_OUT_CIRC, + CLUTTER_EASE_IN_OUT_CIRC, + + /* elastic */ + CLUTTER_EASE_IN_ELASTIC, + CLUTTER_EASE_OUT_ELASTIC, + CLUTTER_EASE_IN_OUT_ELASTIC, + + /* overshooting cubic */ + CLUTTER_EASE_IN_BACK, + CLUTTER_EASE_OUT_BACK, + CLUTTER_EASE_IN_OUT_BACK, + + /* exponentially decaying parabolic */ + CLUTTER_EASE_IN_BOUNCE, + CLUTTER_EASE_OUT_BOUNCE, + CLUTTER_EASE_IN_OUT_BOUNCE, + + /* guard, before registered alpha functions */ CLUTTER_ANIMATION_LAST } ClutterAnimationMode; diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c index ee0ff7337..54cf0fe89 100644 --- a/tests/interactive/test-animation.c +++ b/tests/interactive/test-animation.c @@ -64,7 +64,7 @@ on_button_press (ClutterActor *actor, vertex.y = CLUTTER_UNITS_FROM_FLOAT ((float) new_height / 2); animation = - clutter_actor_animate (actor, CLUTTER_EASE_IN, 2000, + clutter_actor_animate (actor, CLUTTER_EASE_IN_EXPO, 2000, "x", new_x, "y", new_y, "width", new_width, diff --git a/tests/interactive/test-easing.c b/tests/interactive/test-easing.c index 22048ad4e..d625d6cac 100644 --- a/tests/interactive/test-easing.c +++ b/tests/interactive/test-easing.c @@ -7,16 +7,36 @@ const struct { ClutterAnimationMode mode; } easing_modes[] = { { "linear", CLUTTER_LINEAR }, - { "sine-in", CLUTTER_SINE_IN }, - { "sine-out", CLUTTER_SINE_OUT }, - { "sine-in-out", CLUTTER_SINE_IN_OUT }, - { "ease-in", CLUTTER_EASE_IN }, - { "ease-out", CLUTTER_EASE_OUT }, - { "ease-in-out", CLUTTER_EASE_IN_OUT }, - { "expo-in", CLUTTER_EXPO_IN }, - { "expo-out", CLUTTER_EXPO_OUT }, - { "expo-in-out", CLUTTER_EXPO_IN_OUT }, - { "smooth-in-out", CLUTTER_SMOOTH_IN_OUT } + { "easeInQuad", CLUTTER_EASE_IN_QUAD }, + { "easeOutQuad", CLUTTER_EASE_OUT_QUAD }, + { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD }, + { "easeInCubic", CLUTTER_EASE_IN_CUBIC }, + { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC }, + { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC }, + { "easeInQuart", CLUTTER_EASE_IN_QUART }, + { "easeOutQuart", CLUTTER_EASE_OUT_QUART }, + { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART }, + { "easeInQuint", CLUTTER_EASE_IN_QUINT }, + { "easeOutQuint", CLUTTER_EASE_OUT_QUINT }, + { "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT }, + { "easeInSine", CLUTTER_EASE_IN_SINE }, + { "easeOutSine", CLUTTER_EASE_OUT_SINE }, + { "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE }, + { "easeInExpo", CLUTTER_EASE_IN_EXPO }, + { "easeOutExpo", CLUTTER_EASE_OUT_EXPO }, + { "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO }, + { "easeInCirc", CLUTTER_EASE_IN_CIRC }, + { "easeOutCirc", CLUTTER_EASE_OUT_CIRC }, + { "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC }, + { "easeInElastic", CLUTTER_EASE_IN_ELASTIC }, + { "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC }, + { "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC }, + { "easeInBack", CLUTTER_EASE_IN_BACK }, + { "easeOutBack", CLUTTER_EASE_OUT_BACK }, + { "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK }, + { "easeInBounce", CLUTTER_EASE_IN_BOUNCE }, + { "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE }, + { "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE }, }; static const gint n_easing_modes = G_N_ELEMENTS (easing_modes); @@ -30,36 +50,48 @@ on_button_press (ClutterActor *actor, ClutterButtonEvent *event, ClutterActor *rectangle) { - ClutterAnimation *animation; - ClutterAnimationMode cur_mode; - gchar *text; - guint stage_width, stage_height; - guint label_width, label_height; + if (event->button == 3) + { + gchar *text; + guint stage_width, stage_height; + guint label_width, label_height; - text = g_strdup_printf ("Easing mode: %s (%d of %d)\n", - easing_modes[current_mode].name, - current_mode + 1, - n_easing_modes); + current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 + : 0; - clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text); - g_free (text); + text = g_strdup_printf ("Easing mode: %s (%d of %d)\n" + "Right click to change the easing mode", + easing_modes[current_mode].name, + current_mode + 1, + n_easing_modes); - clutter_actor_get_size (main_stage, &stage_width, &stage_height); - clutter_actor_get_size (easing_mode_label, &label_width, &label_height); + clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text); + g_free (text); - clutter_actor_set_position (easing_mode_label, - stage_width - label_width - 10, - stage_height - label_height - 10); + clutter_actor_get_size (main_stage, + &stage_width, + &stage_height); + clutter_actor_get_size (easing_mode_label, + &label_width, + &label_height); - cur_mode = easing_modes[current_mode].mode; + clutter_actor_set_position (easing_mode_label, + stage_width - label_width - 10, + stage_height - label_height - 10); + } + else if (event->button == 1) + { + ClutterAnimation *animation; + ClutterAnimationMode cur_mode; - animation = - clutter_actor_animate (rectangle, cur_mode, 2000, - "x", event->x, - "y", event->y, - NULL); + cur_mode = easing_modes[current_mode].mode; - current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 : 0; + animation = + clutter_actor_animate (rectangle, cur_mode, 2000, + "x", event->x, + "y", event->y, + NULL); + } return TRUE; } @@ -92,7 +124,8 @@ test_easing_main (int argc, char *argv[]) "button-press-event", G_CALLBACK (on_button_press), rect); - text = g_strdup_printf ("Easing mode: %s (%d of %d)\n", + text = g_strdup_printf ("Easing mode: %s (%d of %d)\n" + "Right click to change the easing mode", easing_modes[current_mode].name, current_mode + 1, n_easing_modes);