[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.
This commit is contained in:
Emmanuele Bassi 2009-01-20 17:57:30 +00:00
parent 7d7372af43
commit ec3b1a7b90
4 changed files with 703 additions and 95 deletions

View File

@ -315,6 +315,37 @@ clutter_alpha_get_alpha (ClutterAlpha *alpha)
return retval; 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: * clutter_alpha_set_closure:
* @alpha: A #ClutterAlpha * @alpha: A #ClutterAlpha
@ -336,18 +367,7 @@ clutter_alpha_set_closure (ClutterAlpha *alpha,
priv = alpha->priv; priv = alpha->priv;
if (priv->closure) clutter_alpha_set_closure_internal (alpha, 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);
}
priv->mode = CLUTTER_CUSTOM_MODE; priv->mode = CLUTTER_CUSTOM_MODE;
g_object_notify (G_OBJECT (alpha), "mode"); g_object_notify (G_OBJECT (alpha), "mode");
@ -374,13 +394,19 @@ clutter_alpha_set_func (ClutterAlpha *alpha,
gpointer data, gpointer data,
GDestroyNotify destroy) GDestroyNotify destroy)
{ {
ClutterAlphaPrivate *priv;
GClosure *closure; GClosure *closure;
g_return_if_fail (CLUTTER_IS_ALPHA (alpha)); g_return_if_fail (CLUTTER_IS_ALPHA (alpha));
g_return_if_fail (func != NULL); g_return_if_fail (func != NULL);
priv = alpha->priv;
closure = g_cclosure_new (G_CALLBACK (func), data, (GClosureNotify) destroy); 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; 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 /* static enum/function mapping table for the animation modes
* we provide internally * we provide internally
* *
@ -558,6 +996,40 @@ static const struct {
ClutterAlphaFunc func; ClutterAlphaFunc func;
} animation_modes[] = { } 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 { typedef struct _AlphaData {
@ -593,15 +1065,24 @@ clutter_alpha_set_mode (ClutterAlpha *alpha,
priv = alpha->priv; 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 /* sanity check to avoid getting an out of sync
* enum/function mapping * enum/function mapping
*/ */
g_assert (animation_modes[mode].mode == mode); g_assert (animation_modes[mode].mode == mode);
g_assert (animation_modes[mode].func != NULL);
if (G_LIKELY (animation_modes[mode].func != NULL)) closure = g_cclosure_new (G_CALLBACK (animation_modes[mode].func),
clutter_alpha_set_func (alpha, animation_modes[mode].func, NULL, NULL); NULL,
NULL);
clutter_alpha_set_closure_internal (alpha, closure);
priv->mode = mode; priv->mode = mode;
} }
@ -631,9 +1112,14 @@ clutter_alpha_set_mode (ClutterAlpha *alpha,
if (alpha_data->closure_set) if (alpha_data->closure_set)
clutter_alpha_set_closure (alpha, alpha_data->closure); clutter_alpha_set_closure (alpha, alpha_data->closure);
else else
clutter_alpha_set_func (alpha, alpha_data->func, {
GClosure *closure;
closure = g_cclosure_new (G_CALLBACK (alpha_data->func),
alpha_data->data, alpha_data->data,
NULL); NULL);
clutter_alpha_set_closure_internal (alpha, closure);
}
priv->mode = mode; priv->mode = mode;
} }
@ -643,6 +1129,17 @@ clutter_alpha_set_mode (ClutterAlpha *alpha,
g_object_notify (G_OBJECT (alpha), "mode"); 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: * clutter_alpha_register_func:
* @func: a #ClutterAlphaFunc * @func: a #ClutterAlphaFunc
@ -670,12 +1167,7 @@ clutter_alpha_register_func (ClutterAlphaFunc func,
alpha_data->func = func; alpha_data->func = func;
alpha_data->data = data; alpha_data->data = data;
if (G_UNLIKELY (clutter_alphas == NULL)) return register_alpha_internal (alpha_data);
clutter_alphas = g_ptr_array_new ();
g_ptr_array_add (clutter_alphas, alpha_data);
return clutter_alphas->len + CLUTTER_ANIMATION_LAST;
} }
/** /**
@ -696,18 +1188,13 @@ clutter_alpha_register_func (ClutterAlphaFunc func,
gulong gulong
clutter_alpha_register_closure (GClosure *closure) clutter_alpha_register_closure (GClosure *closure)
{ {
AlphaData *data; AlphaData *alpha_data;
g_return_val_if_fail (closure != NULL, 0); g_return_val_if_fail (closure != NULL, 0);
data = g_slice_new (AlphaData); alpha_data = g_slice_new (AlphaData);
data->closure_set = TRUE; alpha_data->closure_set = TRUE;
data->closure = closure; alpha_data->closure = closure;
if (G_UNLIKELY (clutter_alphas == NULL)) return register_alpha_internal (alpha_data);
clutter_alphas = g_ptr_array_new ();
g_ptr_array_add (clutter_alphas, data);
return clutter_alphas->len + CLUTTER_ANIMATION_LAST;
} }

View File

@ -189,39 +189,127 @@ typedef enum {
/** /**
* ClutterAnimationMode: * ClutterAnimationMode:
* @CLUTTER_CUSTOM_MODE: custom progress function * @CLUTTER_CUSTOM_MODE: custom progress function
* @CLUTTER_LINEAR: linear progress * @CLUTTER_LINEAR: linear tweening
* @CLUTTER_SINE_IN: sine-in progress * @CLUTTER_EASE_IN_QUAD: quadratic tweening
* @CLUTTER_SINE_OUT: sine-out progress * @CLUTTER_EASE_OUT_QUAD: quadratic tweening, inverse of
* @CLUTTER_SINE_IN_OUT: sine-in-out progress * %CLUTTER_EASE_IN_QUAD
* @CLUTTER_EASE_IN: ease-in progress * @CLUTTER_EASE_IN_OUT_QUAD: quadratic tweening, combininig
* @CLUTTER_EASE_OUT: ease-out progress * %CLUTTER_EASE_IN_QUAD and %CLUTTER_EASE_OUT_QUAD
* @CLUTTER_EASE_IN_OUT: ease-in-out progress * @CLUTTER_EASE_IN_CUBIC: cubic tweening
* @CLUTTER_EXPO_IN: exponential in progress * @CLUTTER_EASE_OUT_CUBIC: cubic tweening, invers of
* @CLUTTER_EXPO_OUT: exponential out progress * %CLUTTER_EASE_IN_CUBIC
* @CLUTTER_EXPO_IN_OUT: exponential in-out progress * @CLUTTER_EASE_IN_OUT_CUBIC: cubic tweening, combining
* @CLUTTER_SMOOTH_IN_OUT: smoothstep in-out progress * %CLUTTER_EASE_IN_CUBIC and %CLUTTER_EASE_OUT_CUBIC
* @CLUTTER_ANIMATION_LAST: last animation mode * @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 * 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 * Since: 1.0
*/ */
typedef enum { typedef enum {
CLUTTER_CUSTOM_MODE = 0, CLUTTER_CUSTOM_MODE = 0,
/* linear */
CLUTTER_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 CLUTTER_ANIMATION_LAST
} ClutterAnimationMode; } ClutterAnimationMode;

View File

@ -64,7 +64,7 @@ on_button_press (ClutterActor *actor,
vertex.y = CLUTTER_UNITS_FROM_FLOAT ((float) new_height / 2); vertex.y = CLUTTER_UNITS_FROM_FLOAT ((float) new_height / 2);
animation = animation =
clutter_actor_animate (actor, CLUTTER_EASE_IN, 2000, clutter_actor_animate (actor, CLUTTER_EASE_IN_EXPO, 2000,
"x", new_x, "x", new_x,
"y", new_y, "y", new_y,
"width", new_width, "width", new_width,

View File

@ -7,16 +7,36 @@ const struct {
ClutterAnimationMode mode; ClutterAnimationMode mode;
} easing_modes[] = { } easing_modes[] = {
{ "linear", CLUTTER_LINEAR }, { "linear", CLUTTER_LINEAR },
{ "sine-in", CLUTTER_SINE_IN }, { "easeInQuad", CLUTTER_EASE_IN_QUAD },
{ "sine-out", CLUTTER_SINE_OUT }, { "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
{ "sine-in-out", CLUTTER_SINE_IN_OUT }, { "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
{ "ease-in", CLUTTER_EASE_IN }, { "easeInCubic", CLUTTER_EASE_IN_CUBIC },
{ "ease-out", CLUTTER_EASE_OUT }, { "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
{ "ease-in-out", CLUTTER_EASE_IN_OUT }, { "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
{ "expo-in", CLUTTER_EXPO_IN }, { "easeInQuart", CLUTTER_EASE_IN_QUART },
{ "expo-out", CLUTTER_EXPO_OUT }, { "easeOutQuart", CLUTTER_EASE_OUT_QUART },
{ "expo-in-out", CLUTTER_EXPO_IN_OUT }, { "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
{ "smooth-in-out", CLUTTER_SMOOTH_IN_OUT } { "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); static const gint n_easing_modes = G_N_ELEMENTS (easing_modes);
@ -30,13 +50,17 @@ on_button_press (ClutterActor *actor,
ClutterButtonEvent *event, ClutterButtonEvent *event,
ClutterActor *rectangle) ClutterActor *rectangle)
{ {
ClutterAnimation *animation; if (event->button == 3)
ClutterAnimationMode cur_mode; {
gchar *text; gchar *text;
guint stage_width, stage_height; guint stage_width, stage_height;
guint label_width, label_height; guint label_width, label_height;
text = g_strdup_printf ("Easing mode: %s (%d of %d)\n", current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1
: 0;
text = g_strdup_printf ("Easing mode: %s (%d of %d)\n"
"Right click to change the easing mode",
easing_modes[current_mode].name, easing_modes[current_mode].name,
current_mode + 1, current_mode + 1,
n_easing_modes); n_easing_modes);
@ -44,12 +68,21 @@ on_button_press (ClutterActor *actor,
clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text); clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text);
g_free (text); g_free (text);
clutter_actor_get_size (main_stage, &stage_width, &stage_height); clutter_actor_get_size (main_stage,
clutter_actor_get_size (easing_mode_label, &label_width, &label_height); &stage_width,
&stage_height);
clutter_actor_get_size (easing_mode_label,
&label_width,
&label_height);
clutter_actor_set_position (easing_mode_label, clutter_actor_set_position (easing_mode_label,
stage_width - label_width - 10, stage_width - label_width - 10,
stage_height - label_height - 10); stage_height - label_height - 10);
}
else if (event->button == 1)
{
ClutterAnimation *animation;
ClutterAnimationMode cur_mode;
cur_mode = easing_modes[current_mode].mode; cur_mode = easing_modes[current_mode].mode;
@ -58,8 +91,7 @@ on_button_press (ClutterActor *actor,
"x", event->x, "x", event->x,
"y", event->y, "y", event->y,
NULL); NULL);
}
current_mode = (current_mode + 1 < n_easing_modes) ? current_mode + 1 : 0;
return TRUE; return TRUE;
} }
@ -92,7 +124,8 @@ test_easing_main (int argc, char *argv[])
"button-press-event", G_CALLBACK (on_button_press), "button-press-event", G_CALLBACK (on_button_press),
rect); 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, easing_modes[current_mode].name,
current_mode + 1, current_mode + 1,
n_easing_modes); n_easing_modes);