From 7d7372af43ec23d5c89c55ba57600a47bcd07471 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 20 Jan 2009 16:42:49 +0000 Subject: [PATCH 1/4] [animation] Move the alpha value to floating point The current Alpha value is an unsigned integer that can be used implicitly as a fixed point value. This makes writing an alpha function overshooting below and above the current range basically impossible without complicating an already complex code, and creating weird corner cases. For this reason, the Alpha value should be defined as a floating point normalized value, spanning a range between 0.0 and 1.0; in order to allow overshooting, the valid range is extended one unit below and one unit above, thus making it -1.0 .. 2.0. This commit updates the various users of the ClutterAlpha API and the tests cases. This commit also removes all the current alpha functions exposed in the public API. --- clutter/clutter-alpha.c | 967 ++----------------------- clutter/clutter-alpha.h | 74 +- clutter/clutter-animation.c | 9 +- clutter/clutter-behaviour-depth.c | 6 +- clutter/clutter-behaviour-ellipse.c | 4 +- clutter/clutter-behaviour-opacity.c | 5 +- clutter/clutter-behaviour-path.c | 7 +- clutter/clutter-behaviour-rotate.c | 4 +- clutter/clutter-behaviour-scale.c | 6 +- clutter/clutter-behaviour.c | 8 +- clutter/clutter-behaviour.h | 2 +- clutter/clutter-interval.c | 2 - clutter/clutter-marshal.list | 1 + clutter/clutter-script.c | 24 +- tests/interactive/test-actors.c | 13 +- tests/interactive/test-layout.c | 2 +- tests/interactive/test-paint-wrapper.c | 12 +- tests/interactive/test-scale.c | 11 +- 18 files changed, 107 insertions(+), 1050 deletions(-) diff --git a/clutter/clutter-alpha.c b/clutter/clutter-alpha.c index 78b79a275..eeef07d0c 100644 --- a/clutter/clutter-alpha.c +++ b/clutter/clutter-alpha.c @@ -8,7 +8,8 @@ * Emmanuele Bassi * Tomas Frydrych * - * Copyright (C) 2006, 2007 OpenedHand + * Copyright (C) 2006, 2007, 2008 OpenedHand + * Copyright (C) 2009 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,8 +32,8 @@ * @short_description: A class for calculating an alpha value as a function * of time. * - * #ClutterAlpha is a class for calculating an integer value between - * 0 and %CLUTTER_ALPHA_MAX_ALPHA as a function of time. + * #ClutterAlpha is a class for calculating an floating point value + * dependent only on the position of a #ClutterTimeline. * * A #ClutterAlpha binds a #ClutterTimeline to a progress function which * translates the time T into an adimensional factor alpha. The factor can @@ -42,7 +43,8 @@ * You should provide a #ClutterTimeline and bind it to the #ClutterAlpha * instance using clutter_alpha_set_timeline(). You should also set an * "animation mode", either by using the #ClutterAnimatioMode values that - * Clutter itself provides or by registering custom functions. + * Clutter itself provides or by registering custom functions using + * clutter_alpha_register_func(). * * Instead of a #ClutterAnimationMode you may provide a function returning * the alpha value depending on the progress of the timeline, using @@ -54,12 +56,8 @@ * pause, stop or resume the #ClutterAlpha from calling the alpha function by * using the appropriate functions of the #ClutterTimeline object. * - * #ClutterAlpha is used to "drive" a #ClutterBehaviour instance. - * - *
- * Graphic representation of some alpha functions - * - *
+ * #ClutterAlpha is used to "drive" a #ClutterBehaviour instance, and it + * is internally used by the #ClutterAnimation API. * * Since: 0.2 */ @@ -85,7 +83,7 @@ struct _ClutterAlphaPrivate ClutterTimeline *timeline; guint timeline_new_frame_id; - guint32 alpha; + gdouble alpha; GClosure *closure; @@ -160,7 +158,7 @@ clutter_alpha_get_property (GObject *object, break; case PROP_ALPHA: - g_value_set_uint (value, priv->alpha); + g_value_set_double (value, priv->alpha); break; case PROP_MODE: @@ -199,6 +197,7 @@ static void clutter_alpha_class_init (ClutterAlphaClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *pspec; object_class->set_property = clutter_alpha_set_property; object_class->get_property = clutter_alpha_get_property; @@ -214,29 +213,30 @@ clutter_alpha_class_init (ClutterAlphaClass *klass) * * Since: 0.2 */ - g_object_class_install_property (object_class, - PROP_TIMELINE, - g_param_spec_object ("timeline", - "Timeline", - "Timeline", - CLUTTER_TYPE_TIMELINE, - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_object ("timeline", + "Timeline", + "Timeline used by the alpha", + CLUTTER_TYPE_TIMELINE, + CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_TIMELINE, pspec); + /** * ClutterAlpha:alpha: * - * The alpha value as computed by the alpha function. + * The alpha value as computed by the alpha function. The linear + * interval is 0.0 to 1.0, but the Alpha allows overshooting by + * one unit in each direction, so the valid interval is -1.0 to 2.0. * * Since: 0.2 */ - g_object_class_install_property (object_class, - PROP_ALPHA, - g_param_spec_uint ("alpha", - "Alpha value", - "Alpha value", - 0, - CLUTTER_ALPHA_MAX_ALPHA, - 0, - CLUTTER_PARAM_READABLE)); + pspec = g_param_spec_double ("alpha", + "Alpha value", + "Alpha value", + -1.0, 2.0, + 0.0, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_ALPHA, pspec); + /** * ClutterAlpha:mode: * @@ -250,15 +250,13 @@ clutter_alpha_class_init (ClutterAlphaClass *klass) * * Since: 1.0 */ - g_object_class_install_property (object_class, - PROP_MODE, - g_param_spec_ulong ("mode", - "Mode", - "Progress mode", - 0, G_MAXULONG, - CLUTTER_CUSTOM_MODE, - G_PARAM_CONSTRUCT | - CLUTTER_PARAM_READWRITE)); + pspec = g_param_spec_ulong ("mode", + "Mode", + "Progress mode", + 0, G_MAXULONG, + CLUTTER_CUSTOM_MODE, + G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MODE, pspec); } static void @@ -269,6 +267,7 @@ clutter_alpha_init (ClutterAlpha *self) ClutterAlphaPrivate); self->priv->mode = CLUTTER_CUSTOM_MODE; + self->priv->alpha = 0.0; } /** @@ -281,11 +280,11 @@ clutter_alpha_init (ClutterAlpha *self) * * Since: 0.2 */ -guint32 +gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha) { ClutterAlphaPrivate *priv; - guint32 retval = 0; + gdouble retval = 0; g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), 0); @@ -298,18 +297,14 @@ clutter_alpha_get_alpha (ClutterAlpha *alpha) g_object_ref (alpha); - g_value_init (&result_value, G_TYPE_UINT); + g_value_init (&result_value, G_TYPE_DOUBLE); g_value_init (¶ms, CLUTTER_TYPE_ALPHA); g_value_set_object (¶ms, alpha); - g_closure_invoke (priv->closure, - &result_value, - 1, - ¶ms, - NULL); + g_closure_invoke (priv->closure, &result_value, 1, ¶ms, NULL); - retval = g_value_get_uint (&result_value); + retval = g_value_get_double (&result_value); g_value_unset (&result_value); g_value_unset (¶ms); @@ -349,7 +344,7 @@ clutter_alpha_set_closure (ClutterAlpha *alpha, if (G_CLOSURE_NEEDS_MARSHAL (closure)) { - GClosureMarshal marshal = clutter_marshal_UINT__VOID; + GClosureMarshal marshal = clutter_marshal_DOUBLE__VOID; g_closure_set_marshal (closure, marshal); } @@ -563,18 +558,6 @@ static const struct { ClutterAlphaFunc func; } animation_modes[] = { { CLUTTER_CUSTOM_MODE, NULL }, - { CLUTTER_LINEAR, clutter_ramp_inc_func }, - { CLUTTER_SINE_IN, clutter_sine_in_func }, - { CLUTTER_SINE_OUT, clutter_sine_out_func }, - { CLUTTER_SINE_IN_OUT, clutter_sine_in_out_func }, - { CLUTTER_EASE_IN, clutter_ease_in_func }, - { CLUTTER_EASE_OUT, clutter_ease_out_func }, - { CLUTTER_EASE_IN_OUT, clutter_ease_in_out_func }, - { CLUTTER_EXPO_IN, clutter_exp_in_func }, - { CLUTTER_EXPO_OUT, clutter_exp_out_func }, - { CLUTTER_EXPO_IN_OUT, clutter_exp_in_out_func }, - { CLUTTER_SMOOTH_IN_OUT, clutter_smoothstep_inc_func }, - { CLUTTER_ANIMATION_LAST, NULL }, }; typedef struct _AlphaData { @@ -728,867 +711,3 @@ clutter_alpha_register_closure (GClosure *closure) return clutter_alphas->len + CLUTTER_ANIMATION_LAST; } - -/** - * clutter_ramp_inc_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a monotonic increasing ramp. You - * can use this function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.2 - */ -guint32 -clutter_ramp_inc_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - return (current_frame_num * CLUTTER_ALPHA_MAX_ALPHA) / n_frames; -} - -/** - * CLUTTER_ALPHA_RAMP_DEC: - * - * Convenience symbol for clutter_ramp_dec_func(). - * - * Since: 0.2 - */ - -/** - * clutter_ramp_dec_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a monotonic decreasing ramp. You - * can use this function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.2 - */ -guint32 -clutter_ramp_dec_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - return (n_frames - current_frame_num) - * CLUTTER_ALPHA_MAX_ALPHA - / n_frames; -} - -/** - * CLUTTER_ALPHA_RAMP: - * - * Convenience symbol for clutter_ramp_func(). - * - * Since: 0.2 - */ - -/** - * clutter_ramp_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a full ramp function (increase for - * half the time, decrease for the remaining half). You can use this - * function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.2 - */ -guint32 -clutter_ramp_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - if (current_frame_num > (n_frames / 2)) - { - return (n_frames - current_frame_num) - * CLUTTER_ALPHA_MAX_ALPHA - / (n_frames / 2); - } - else - { - return current_frame_num - * CLUTTER_ALPHA_MAX_ALPHA - / (n_frames / 2); - } -} - -static guint32 -sincx1024_func (ClutterAlpha *alpha, - ClutterAngle angle, - ClutterFixed offset) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = angle * current_frame_num / n_frames; - - x -= (512 * 512 / angle); - - sine = ((cogl_angle_sin (x) + offset) / 2) - * CLUTTER_ALPHA_MAX_ALPHA; - - sine = sine >> COGL_FIXED_Q; - - return sine; -} - -#if 0 -/* - * The following two functions are left in place for reference - * purposes. - */ -static guint32 -sincx_func (ClutterAlpha *alpha, - ClutterFixed angle, - ClutterFixed offset) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - ClutterFixed x, sine; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = angle * current_frame_num / n_frames; - x = COGL_FIXED_FAST_MUL (x, COGL_FIXED_PI) - - COGL_FIXED_FAST_DIV (COGL_FIXED_PI, angle); - - sine = (cogl_fixed_sin (x) + offset) / 2; - - CLUTTER_NOTE (ALPHA, "sine: %2f\n", COGL_FIXED_TO_DOUBLE (sine)); - - return COGL_FIXED_TO_INT (sine * CLUTTER_ALPHA_MAX_ALPHA); -} - -/* NB: angle is not in radians but in muliples of PI, i.e., 2.0 - * represents full circle. - */ -static guint32 -sinc_func (ClutterAlpha *alpha, - float angle, - float offset) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - gdouble x, sine; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - /* FIXME: fixed point, and fixed point sine() */ - - x = (gdouble) (current_frame_num * angle * G_PI) / n_frames ; - sine = (sin (x - (G_PI / angle)) + offset) * 0.5f; - - CLUTTER_NOTE (ALPHA, "sine: %2f\n",sine); - - return COGL_FLOAT_TO_INT ((sine * (gdouble) CLUTTER_ALPHA_MAX_ALPHA)); -} -#endif - -/** - * CLUTTER_ALPHA_SINE: - * - * Convenience symbol for clutter_sine_func(). - * - * Since: 0.2 - */ - -/** - * clutter_sine_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a sine wave. You can use this - * function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.2 - */ -guint32 -clutter_sine_func (ClutterAlpha *alpha, - gpointer dummy) -{ -#if 0 - return sinc_func (alpha, 2.0, 1.0); -#else - /* 2.0 above represents full circle */ - return sincx1024_func (alpha, 1024, COGL_FIXED_1); -#endif -} - -/** - * CLUTTER_ALPHA_SINE_INC: - * - * Convenience symbol for clutter_sine_inc_func(). - * - * Since: 0.2 - */ - -/** - * clutter_sine_inc_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a sine wave over interval [0, pi / 2]. - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.2 - */ -guint32 -clutter_sine_inc_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline * timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = 256 * frame / n_frames; - - sine = cogl_angle_sin (x) * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * CLUTTER_ALPHA_SINE_DEC: - * - * Convenience symbol for clutter_sine_dec_func(). - * - * Since: 0.2 - */ - -/** - * clutter_sine_dec_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a sine wave over interval [pi / 2, pi]. - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.4 - */ -guint32 -clutter_sine_dec_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline * timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = 256 * frame / n_frames + 256; - - sine = cogl_angle_sin (x) * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * CLUTTER_ALPHA_SINE_HALF: - * - * Convenience symbol for clutter_sine_half_func(). - * - * Since: 0.4 - */ - -/** - * clutter_sine_half_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a sine wave over interval [0, pi]. - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.4 - */ -guint32 -clutter_sine_half_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = 512 * frame / n_frames; - - sine = cogl_angle_sin (x) * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * clutter_sine_in_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for (sin(x) + 1) over the - * interval [-pi/2, 0]. - * - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_sine_in_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - /* XXX- if we use 768 we overflow */ - x = 256 * frame / n_frames + 767; - - sine = (cogl_angle_sin (x) + 1) * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * clutter_sine_in_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for sin(x) over the interval [0, pi/2]. - * - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_sine_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = 256 * frame / n_frames; - - sine = cogl_angle_sin (x) * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * clutter_sine_in_out_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for (sin(x) + 1) / 2 over the - * interval [-pi/2, pi/2]. - * - * You can use this function as the alpha function for - * clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_sine_in_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint frame; - gint n_frames; - ClutterAngle x; - ClutterFixed sine; - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = -256 * frame / n_frames + 256; - - sine = (cogl_angle_sin (x) + 1) / 2 * CLUTTER_ALPHA_MAX_ALPHA; - - return ((guint32) sine) >> COGL_FIXED_Q; -} - -/** - * CLUTTER_ALPHA_SQUARE: - * - * Convenience symbol for clutter_square_func(). - * - * Since: 0.4 - * - * Deprecated: 1.0: Use clutter_square_func() instead - */ - -/** - * clutter_square_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a square wave. You can use this - * function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value - * - * Since: 0.4 - */ -guint32 -clutter_square_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint current_frame_num, n_frames; - - timeline = clutter_alpha_get_timeline (alpha); - - current_frame_num = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - return (current_frame_num > (n_frames / 2)) ? CLUTTER_ALPHA_MAX_ALPHA - : 0; -} - -/** - * CLUTTER_ALPHA_SMOOTHSTEP_INC: - * - * Convenience symbol for clutter_smoothstep_inc_func(). - * - * Since: 0.4 - */ - -/** - * clutter_smoothstep_inc_func: - * @alpha: a #ClutterAlpha - * @dummy: unused - * - * Convenience alpha function for a smoothstep curve. You can use this - * function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value - * - * Since: 0.4 - */ -guint32 -clutter_smoothstep_inc_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gint frame; - gint n_frames; - guint32 r; - guint32 x; - - /* - * The smoothstep function uses f(x) = -2x^3 + 3x^2 where x is from <0,1>, - * and precission is critical -- we use 8.24 fixed format for this operation. - * The earlier operations involve division, which we cannot do in 8.24 for - * numbers in <0,1> we use ClutterFixed. - */ - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - /* - * Convert x to 8.24 for next step. - */ - x = COGL_FIXED_FAST_DIV (frame, n_frames) << 8; - - /* - * f(x) = -2x^3 + 3x^2 - * - * Convert result to ClutterFixed to avoid overflow in next step. - */ - r = ((x >> 12) * (x >> 12) * 3 - (x >> 15) * (x >> 16) * (x >> 16)) >> 8; - - return COGL_FIXED_TO_INT (r * CLUTTER_ALPHA_MAX_ALPHA); -} - -/** - * CLUTTER_ALPHA_SMOOTHSTEP_DEC: - * - * Convenience symbol for clutter_smoothstep_dec_func(). - * - * Since: 0.4 - */ - -/** - * clutter_smoothstep_dec_func: - * @alpha: a #ClutterAlpha - * @dummy: unused - * - * Convenience alpha function for a downward smoothstep curve. You can use - * this function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value - * - * Since: 0.4 - */ -guint32 -clutter_smoothstep_dec_func (ClutterAlpha *alpha, - gpointer dummy) -{ - return CLUTTER_ALPHA_MAX_ALPHA - clutter_smoothstep_inc_func (alpha, dummy); -} - -/** - * CLUTTER_ALPHA_EXP_INC: - * - * Convenience symbol for clutter_exp_inc_func() - * - * Since: 0.4 - */ - -/** - * clutter_exp_inc_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a 2^x curve. You can use this function as the - * alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.4 - */ -guint32 -clutter_exp_inc_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline * timeline; - gint frame; - gint n_frames; - ClutterFixed x; - ClutterFixed x_alpha_max = 0x100000; - guint32 result; - - /* - * Choose x_alpha_max such that - * - * (2^x_alpha_max) - 1 == CLUTTER_ALPHA_MAX_ALPHA - */ -#if CLUTTER_ALPHA_MAX_ALPHA != 0xffff -#error Adjust x_alpha_max to match CLUTTER_ALPHA_MAX_ALPHA -#endif - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = x_alpha_max * frame / n_frames; - - result = CLAMP (cogl_fixed_pow2 (x) - 1, 0, CLUTTER_ALPHA_MAX_ALPHA); - - return result; -} - -/** - * CLUTTER_ALPHA_EXP_DEC: - * - * Convenience symbold for clutter_exp_dec_func(). - * - * Since: 0.4 - */ - -/** - * clutter_exp_dec_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a decreasing 2^x curve. You can use this - * function as the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 0.4 - */ -guint32 -clutter_exp_dec_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline * timeline; - gint frame; - gint n_frames; - ClutterFixed x; - ClutterFixed x_alpha_max = 0x100000; - guint32 result; - - /* - * Choose x_alpha_max such that - * - * (2^x_alpha_max) - 1 == CLUTTER_ALPHA_MAX_ALPHA - */ -#if CLUTTER_ALPHA_MAX_ALPHA != 0xffff -#error Adjust x_alpha_max to match CLUTTER_ALPHA_MAX_ALPHA -#endif - - timeline = clutter_alpha_get_timeline (alpha); - frame = clutter_timeline_get_current_frame (timeline); - n_frames = clutter_timeline_get_n_frames (timeline); - - x = (x_alpha_max * (n_frames - frame)) / n_frames; - - result = CLAMP (cogl_fixed_pow2 (x) - 1, 0, CLUTTER_ALPHA_MAX_ALPHA); - - return result; -} - -static inline gdouble -clutter_cubic_bezier (ClutterAlpha *alpha, - gdouble x_1, - gdouble y_1, - gdouble x_2, - gdouble y_2) -{ - ClutterTimeline *timeline; - gdouble t, b_t, res; - - /* the cubic bezier has a parametric form of: - * - * B(t) = (1 - t)^3 * P_0 - * + 3t * (1 - t)^2 * P_1 - * + 3t^2 * (1 - t) * P_2 - * + t^3 * P_3 (with t included in [0, 1]) - * - * the P_0 and P_3 points are set to (0, 0) and (1, 1) respectively, - * and the curve never passes through P_1 and P_2 - with these two - * points merely acting as control points for the curve starting - * from P_0 and ending at P_3. - * - * since the starting point is (0, 0) we can simplify the previous - * parametric form to: - * - * B(t) = 3t * (1 - t)^2 * P_1 - * + 3t^2 * (1 - t) * P_2 - * + t^3 * P_3 (with t included in [0, 1]) - * - * and, similarly, since the final point is (1, 1) we can simplify - * it further to: - * - * B(t) = 3t * (1 - t)^2 * P_1 - * + 3t^2 * (1 - t) * P_2 - * + t^3 (with t included in [0, 1]) - * - * since an alpha function has only a time parameter and we have two - * coordinates for each point, we pass the time as the first - * coordinate for the point and then we solve the cubic beziér curve - * for the second coordinate at the same point. - */ - - timeline = clutter_alpha_get_timeline (alpha); - t = clutter_timeline_get_progress (timeline); - - b_t = 3 * t * pow (1 - t, 2) * x_1 - + 3 * pow (t, 2) * (1 - t) * x_2 - + pow (t, 3); - - res = 3 * b_t * pow (1 - b_t, 2) * y_1 - + 3 * pow (b_t, 2) * (1 - b_t) * y_2 - + pow (b_t, 3); - - return res; -} - -/** - * clutter_ease_in_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a cubic Beziér curve with control - * points at (0.42, 0) and (1, 0). You can use this function as the - * alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_ease_in_func (ClutterAlpha *alpha, - gpointer dummy) -{ - gdouble res; - - res = clutter_cubic_bezier (alpha, 0.42, 0, 1, 0); - - return CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); -} - -/** - * clutter_ease_out_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a cubic Beziér curve with control - * points at (0, 0) and (0.58, 1). You can use this function as the - * alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_ease_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - gdouble res; - - res = clutter_cubic_bezier (alpha, 0, 0, 0.58, 1); - - return CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); -} - -/** - * clutter_ease_in_out_func: - * @alpha: a #ClutterAlpha - * @dummy: unused argument - * - * Convenience alpha function for a cubic Beziér curve with control - * points at (0.42, 0) and (0.58, 1). You can use this function as - * the alpha function for clutter_alpha_set_func(). - * - * Return value: an alpha value. - * - * Since: 1.0 - */ -guint32 -clutter_ease_in_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - gdouble res; - - res = clutter_cubic_bezier (alpha, 0.42, 0, 0.58, 1); - - return CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); -} - -guint32 -clutter_exp_in_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gdouble progress, res; - - timeline = clutter_alpha_get_timeline (alpha); - progress = clutter_timeline_get_progress (timeline); - - res = pow (2, 10 * (progress - 1)); - res = CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); - - return res; -} - -guint32 -clutter_exp_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gdouble progress, res; - - timeline = clutter_alpha_get_timeline (alpha); - progress = clutter_timeline_get_progress (timeline); - - res = -pow (2, (-10 * progress)) + 1; - res = CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); - - return res; -} - -guint32 -clutter_exp_in_out_func (ClutterAlpha *alpha, - gpointer dummy) -{ - ClutterTimeline *timeline; - gdouble progress, res; - - timeline = clutter_alpha_get_timeline (alpha); - progress = clutter_timeline_get_progress (timeline); - - if (progress < 0.5) - res = 0.5 * pow (2, (10 * (progress - 1))); - else - res = 0.5 * -pow (2, (-10 * progress)) + 1; - - res = CLAMP (res * CLUTTER_ALPHA_MAX_ALPHA, 0, CLUTTER_ALPHA_MAX_ALPHA); - - return res; -} diff --git a/clutter/clutter-alpha.h b/clutter/clutter-alpha.h index 8872f7a9e..5f64d1d7d 100644 --- a/clutter/clutter-alpha.h +++ b/clutter/clutter-alpha.h @@ -8,7 +8,8 @@ * Emmanuele Bassi * Tomas Frydrych * - * Copyright (C) 2006, 2007 OpenedHand + * Copyright (C) 2006, 2007, 2008 OpenedHand + * Copyright (C) 2009 Intel Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -52,15 +53,14 @@ typedef struct _ClutterAlphaPrivate ClutterAlphaPrivate; * @alpha: a #ClutterAlpha * @user_data: user data passed to the function * - * A function of time, which returns a value between 0 and - * %CLUTTER_ALPHA_MAX_ALPHA. + * A function returning a value depending on the position of + * the #ClutterTimeline bound to @alpha. * - * Return value: an unsigned integer value, between 0 and - * %CLUTTER_ALPHA_MAX_ALPHA. + * Return value: a floating point value * * Since: 0.2 */ -typedef guint32 (*ClutterAlphaFunc) (ClutterAlpha *alpha, +typedef gdouble (*ClutterAlphaFunc) (ClutterAlpha *alpha, gpointer user_data); /** @@ -76,6 +76,7 @@ struct _ClutterAlpha { /*< private >*/ GInitiallyUnowned parent; + ClutterAlphaPrivate *priv; }; @@ -98,15 +99,6 @@ struct _ClutterAlphaClass void (*_clutter_alpha_5) (void); }; -/** - * CLUTTER_ALPHA_MAX_ALPHA: - * - * Maximum value returned by #ClutterAlphaFunc - * - * Since: 0.2 - */ -#define CLUTTER_ALPHA_MAX_ALPHA (0xffff) - GType clutter_alpha_get_type (void) G_GNUC_CONST; ClutterAlpha * clutter_alpha_new (void); @@ -117,7 +109,7 @@ ClutterAlpha * clutter_alpha_new_with_func (ClutterTimeline *timeline, gpointer data, GDestroyNotify destroy); -guint32 clutter_alpha_get_alpha (ClutterAlpha *alpha); +gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha); void clutter_alpha_set_func (ClutterAlpha *alpha, ClutterAlphaFunc func, gpointer data, @@ -135,56 +127,6 @@ gulong clutter_alpha_register_func (ClutterAlphaFunc func, gpointer data); gulong clutter_alpha_register_closure (GClosure *closure); -/* convenience functions */ -guint32 clutter_ramp_inc_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_ramp_dec_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_ramp_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_sine_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_inc_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_dec_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_half_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_in_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_out_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_sine_in_out_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_square_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_smoothstep_inc_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_smoothstep_dec_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_exp_inc_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_exp_dec_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_ease_in_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_ease_out_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_ease_in_out_func (ClutterAlpha *alpha, - gpointer dummy); - -guint32 clutter_exp_in_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_exp_out_func (ClutterAlpha *alpha, - gpointer dummy); -guint32 clutter_exp_in_out_func (ClutterAlpha *alpha, - gpointer dummy); - G_END_DECLS #endif /* __CLUTTER_ALPHA_H__ */ diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c index 5994ff38e..900c5fba3 100644 --- a/clutter/clutter-animation.c +++ b/clutter/clutter-animation.c @@ -664,7 +664,7 @@ on_alpha_notify (GObject *gobject, { ClutterAnimationPrivate *priv = animation->priv; GList *properties, *p; - guint32 alpha_value; + gdouble alpha_value; gboolean is_animatable = FALSE; ClutterAnimatable *animatable = NULL; @@ -683,7 +683,6 @@ on_alpha_notify (GObject *gobject, { const gchar *p_name = p->data; ClutterInterval *interval; - gdouble factor; GValue value = { 0, }; interval = g_hash_table_lookup (priv->properties, p_name); @@ -691,8 +690,6 @@ on_alpha_notify (GObject *gobject, g_value_init (&value, clutter_interval_get_value_type (interval)); - factor = (gdouble) alpha_value / CLUTTER_ALPHA_MAX_ALPHA; - if (is_animatable) { const GValue *initial, *final; @@ -704,7 +701,7 @@ on_alpha_notify (GObject *gobject, clutter_animatable_animate_property (animatable, animation, p_name, initial, final, - factor, + alpha_value, &value); g_object_set_property (priv->object, p_name, &value); @@ -713,7 +710,7 @@ on_alpha_notify (GObject *gobject, { CLUTTER_NOTE (ANIMATION, "Standard property `%s'", p_name); - if (clutter_interval_compute_value (interval, factor, &value)) + if (clutter_interval_compute_value (interval, alpha_value, &value)) g_object_set_property (priv->object, p_name, &value); } diff --git a/clutter/clutter-behaviour-depth.c b/clutter/clutter-behaviour-depth.c index 90fc456af..3aee44712 100644 --- a/clutter/clutter-behaviour-depth.c +++ b/clutter/clutter-behaviour-depth.c @@ -74,7 +74,7 @@ alpha_notify_foreach (ClutterBehaviour *behaviour, static void clutter_behaviour_depth_alpha_notify (ClutterBehaviour *behaviour, - guint32 alpha_value) + gdouble alpha_value) { ClutterFixed factor; ClutterBehaviourDepthPrivate *priv; @@ -83,11 +83,11 @@ clutter_behaviour_depth_alpha_notify (ClutterBehaviour *behaviour, priv = CLUTTER_BEHAVIOUR_DEPTH (behaviour)->priv; /* Need to create factor as to avoid borking signedness */ - factor = COGL_FIXED_FROM_INT (alpha_value) / CLUTTER_ALPHA_MAX_ALPHA; + factor = COGL_FIXED_FROM_FLOAT (alpha_value); depth = priv->depth_start + COGL_FIXED_TO_INT (factor * (priv->depth_end - priv->depth_start)); - CLUTTER_NOTE (BEHAVIOUR, "alpha: %d, depth: %d", alpha_value, depth); + CLUTTER_NOTE (BEHAVIOUR, "alpha: %.4f, depth: %d", alpha_value, depth); clutter_behaviour_actors_foreach (behaviour, alpha_notify_foreach, diff --git a/clutter/clutter-behaviour-ellipse.c b/clutter/clutter-behaviour-ellipse.c index a5d4bff35..4b97355e6 100644 --- a/clutter/clutter-behaviour-ellipse.c +++ b/clutter/clutter-behaviour-ellipse.c @@ -205,7 +205,7 @@ clamp_angle (ClutterAngle a) static void clutter_behaviour_ellipse_alpha_notify (ClutterBehaviour *behave, - guint32 alpha) + gdouble alpha) { ClutterBehaviourEllipse *self = CLUTTER_BEHAVIOUR_ELLIPSE (behave); ClutterBehaviourEllipsePrivate *priv = self->priv; @@ -225,7 +225,7 @@ clutter_behaviour_ellipse_alpha_notify (ClutterBehaviour *behave, end -= 1024; } - angle = (end - start) * alpha / CLUTTER_ALPHA_MAX_ALPHA + start; + angle = (end - start) * alpha + start; clutter_behaviour_ellipse_advance (self, angle, &knot); diff --git a/clutter/clutter-behaviour-opacity.c b/clutter/clutter-behaviour-opacity.c index f31099442..0ad25c22b 100644 --- a/clutter/clutter-behaviour-opacity.c +++ b/clutter/clutter-behaviour-opacity.c @@ -87,7 +87,7 @@ alpha_notify_foreach (ClutterBehaviour *behaviour, static void clutter_behaviour_alpha_notify (ClutterBehaviour *behave, - guint32 alpha_value) + gdouble alpha_value) { ClutterBehaviourOpacityPrivate *priv; guint8 opacity; @@ -96,10 +96,9 @@ clutter_behaviour_alpha_notify (ClutterBehaviour *behave, opacity = alpha_value * (priv->opacity_end - priv->opacity_start) - / CLUTTER_ALPHA_MAX_ALPHA + priv->opacity_start; - CLUTTER_NOTE (BEHAVIOUR, "alpha: %u, opacity: %u", + CLUTTER_NOTE (BEHAVIOUR, "alpha: %.4f, opacity: %u", alpha_value, opacity); diff --git a/clutter/clutter-behaviour-path.c b/clutter/clutter-behaviour-path.c index 7594fdbfb..eea1733b7 100644 --- a/clutter/clutter-behaviour-path.c +++ b/clutter/clutter-behaviour-path.c @@ -123,7 +123,7 @@ actor_apply_knot_foreach (ClutterBehaviour *behaviour, static void clutter_behaviour_path_alpha_notify (ClutterBehaviour *behave, - guint32 alpha_value) + gdouble alpha_value) { ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (behave); ClutterBehaviourPathPrivate *priv = pathb->priv; @@ -131,10 +131,7 @@ clutter_behaviour_path_alpha_notify (ClutterBehaviour *behave, guint knot_num; if (priv->path) - knot_num = clutter_path_get_position (priv->path, - alpha_value - / (gdouble) CLUTTER_ALPHA_MAX_ALPHA, - &position); + knot_num = clutter_path_get_position (priv->path, alpha_value, &position); else { memset (&position, 0, sizeof (position)); diff --git a/clutter/clutter-behaviour-rotate.c b/clutter/clutter-behaviour-rotate.c index 3e13c6dab..6864ca963 100644 --- a/clutter/clutter-behaviour-rotate.c +++ b/clutter/clutter-behaviour-rotate.c @@ -117,7 +117,7 @@ ClutterFixed clamp_angle (ClutterFixed a) static void clutter_behaviour_rotate_alpha_notify (ClutterBehaviour *behaviour, - guint32 alpha_value) + gdouble alpha_value) { ClutterFixed factor, angle, start, end; ClutterBehaviourRotate *rotate_behaviour; @@ -126,7 +126,7 @@ clutter_behaviour_rotate_alpha_notify (ClutterBehaviour *behaviour, rotate_behaviour = CLUTTER_BEHAVIOUR_ROTATE (behaviour); priv = rotate_behaviour->priv; - factor = COGL_FIXED_FROM_INT (alpha_value) / CLUTTER_ALPHA_MAX_ALPHA; + factor = COGL_FIXED_FROM_FLOAT (alpha_value); angle = 0; start = priv->angle_start; diff --git a/clutter/clutter-behaviour-scale.c b/clutter/clutter-behaviour-scale.c index f358a71f0..babb44ae7 100644 --- a/clutter/clutter-behaviour-scale.c +++ b/clutter/clutter-behaviour-scale.c @@ -90,7 +90,7 @@ scale_frame_foreach (ClutterBehaviour *behaviour, static void clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, - guint32 alpha_value) + gdouble alpha_value) { ClutterBehaviourScalePrivate *priv; ClutterFixed scale_x, scale_y; @@ -101,7 +101,7 @@ clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, /* Fix the start/end values, avoids potential rounding errors on large * values. */ - if (alpha_value == CLUTTER_ALPHA_MAX_ALPHA) + if (alpha_value == 1.0) { scale_x = priv->x_scale_end; scale_y = priv->y_scale_end; @@ -115,7 +115,7 @@ clutter_behaviour_scale_alpha_notify (ClutterBehaviour *behave, { ClutterFixed factor; - factor = COGL_FIXED_FROM_INT (alpha_value) / CLUTTER_ALPHA_MAX_ALPHA; + factor = COGL_FIXED_FROM_FLOAT (alpha_value); scale_x = COGL_FIXED_FAST_MUL (factor, (priv->x_scale_end - priv->x_scale_start)); diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c index 006be1bda..f4bdf546f 100644 --- a/clutter/clutter-behaviour.c +++ b/clutter/clutter-behaviour.c @@ -240,7 +240,7 @@ clutter_behaviour_get_property (GObject *object, static void clutter_behaviour_alpha_notify_unimplemented (ClutterBehaviour *behaviour, - guint32 alpha_value) + gdouble alpha_value) { g_warning ("ClutterBehaviourClass::alpha_notify not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (behaviour))); @@ -533,11 +533,9 @@ notify_cb (GObject *object, if (klass->alpha_notify) { - guint32 alpha_value; + gdouble alpha_value = clutter_alpha_get_alpha (behave->priv->alpha); - alpha_value = clutter_alpha_get_alpha (behave->priv->alpha); - - CLUTTER_NOTE (BEHAVIOUR, "calling %s::alpha_notify (%p, %d)", + CLUTTER_NOTE (BEHAVIOUR, "calling %s::alpha_notify (%p, %.4f)", g_type_name (G_TYPE_FROM_CLASS (klass)), behave, alpha_value); diff --git a/clutter/clutter-behaviour.h b/clutter/clutter-behaviour.h index c190961e5..74ac9134c 100644 --- a/clutter/clutter-behaviour.h +++ b/clutter/clutter-behaviour.h @@ -113,7 +113,7 @@ struct _ClutterBehaviourClass /*< public >*/ /* vfunc, not signal */ void (*alpha_notify) (ClutterBehaviour *behave, - guint32 alpha_value); + gdouble alpha_value); /* signals */ void (*applied) (ClutterBehaviour *behave, diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c index efdf58dff..35f38189d 100644 --- a/clutter/clutter-interval.c +++ b/clutter/clutter-interval.c @@ -891,8 +891,6 @@ clutter_interval_compute_value (ClutterInterval *interval, g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE); g_return_val_if_fail (value != NULL, FALSE); - factor = CLAMP (factor, 0.0, 1.0); - return CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval, factor, value); diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index 613d84a9e..d68ce4b27 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -1,5 +1,6 @@ BOOLEAN:BOXED BOOLEAN:STRING,UINT,ENUM +DOUBLE:VOID UINT:VOID VOID:BOXED VOID:INT diff --git a/clutter/clutter-script.c b/clutter/clutter-script.c index d4b23754e..8b357de70 100644 --- a/clutter/clutter-script.c +++ b/clutter/clutter-script.c @@ -528,30 +528,8 @@ static const struct ClutterAlphaFunc symbol; } clutter_alphas[] = { #define ALPHA_FUNC(func,nick) { #func, nick, func } - ALPHA_FUNC (clutter_ramp_inc_func, "ramp-inc"), - ALPHA_FUNC (clutter_ramp_dec_func, "ramp-dec"), - ALPHA_FUNC (clutter_ramp_func, "ramp"), - ALPHA_FUNC (clutter_sine_inc_func, "sine-inc"), - ALPHA_FUNC (clutter_sine_dec_func, "sine-dec"), - ALPHA_FUNC (clutter_sine_half_func, "sine-half"), - ALPHA_FUNC (clutter_sine_in_func, "sine-in"), - ALPHA_FUNC (clutter_sine_out_func, "sine-out"), - ALPHA_FUNC (clutter_sine_in_out_func, "sine-in-out"), - ALPHA_FUNC (clutter_sine_func, "sine"), - ALPHA_FUNC (clutter_square_func, "square"), - ALPHA_FUNC (clutter_smoothstep_inc_func, "smoothstep-inc"), - ALPHA_FUNC (clutter_smoothstep_dec_func, "smoothstep-dec"), - ALPHA_FUNC (clutter_exp_inc_func, "exp-inc"), - ALPHA_FUNC (clutter_exp_dec_func, "exp-dec"), - ALPHA_FUNC (clutter_ramp_inc_func, "linear"), - ALPHA_FUNC (clutter_ease_in_func, "ease-in"), - ALPHA_FUNC (clutter_ease_out_func, "ease-out"), - ALPHA_FUNC (clutter_ease_in_out_func, "ease-in-out"), - ALPHA_FUNC (clutter_exp_in_func, "exp-in"), - ALPHA_FUNC (clutter_exp_out_func, "exp-out"), - ALPHA_FUNC (clutter_exp_in_out_func, "exp-in-out"), - ALPHA_FUNC (clutter_smoothstep_inc_func, "smooth-in-out") #undef ALPHA_FUNC + { NULL, NULL, NULL } }; static const gint n_clutter_alphas = G_N_ELEMENTS (clutter_alphas); diff --git a/tests/interactive/test-actors.c b/tests/interactive/test-actors.c index ded1e1a24..819adfaae 100644 --- a/tests/interactive/test-actors.c +++ b/tests/interactive/test-actors.c @@ -123,6 +123,16 @@ frame_cb (ClutterTimeline *timeline, } } +static gdouble +my_sine_wave (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); + gdouble progress = clutter_timeline_get_progress (timeline); + + return sin (progress * G_PI); +} + G_MODULE_EXPORT int test_actors_main (int argc, char *argv[]) { @@ -168,8 +178,7 @@ test_actors_main (int argc, char *argv[]) g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ - alpha = clutter_alpha_new_with_func (timeline, clutter_sine_func, - NULL, NULL); + alpha = clutter_alpha_new_with_func (timeline, my_sine_wave, NULL, NULL); scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, diff --git a/tests/interactive/test-layout.c b/tests/interactive/test-layout.c index f446779cc..4b70260a8 100644 --- a/tests/interactive/test-layout.c +++ b/tests/interactive/test-layout.c @@ -765,7 +765,7 @@ test_layout_main (int argc, char *argv[]) G_CALLBACK (relayout_on_frame), NULL); - alpha = clutter_alpha_new_full (main_timeline, CLUTTER_SINE_IN_OUT); + alpha = clutter_alpha_new_full (main_timeline, CLUTTER_LINEAR); behaviour = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 2.0, 2.0); box = my_thing_new (10, 10); diff --git a/tests/interactive/test-paint-wrapper.c b/tests/interactive/test-paint-wrapper.c index 5bc60f018..79f4b4c01 100644 --- a/tests/interactive/test-paint-wrapper.c +++ b/tests/interactive/test-paint-wrapper.c @@ -160,6 +160,16 @@ hand_post_paint (ClutterActor *actor, oh->paint_guards[actor_num] = FALSE; } +static gdouble +my_sine_wave (ClutterAlpha *alpha, + gpointer dummy G_GNUC_UNUSED) +{ + ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); + gdouble progress = clutter_timeline_get_progress (timeline); + + return sin (progress * G_PI); +} + G_MODULE_EXPORT int test_paint_wrapper_main (int argc, char *argv[]) { @@ -205,7 +215,7 @@ test_paint_wrapper_main (int argc, char *argv[]) g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), oh); /* Set up some behaviours to handle scaling */ - alpha = clutter_alpha_new_full (timeline, CLUTTER_SINE_IN_OUT); + alpha = clutter_alpha_new_with_func (timeline, my_sine_wave, NULL, NULL); scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, diff --git a/tests/interactive/test-scale.c b/tests/interactive/test-scale.c index 0a466cb5d..7a2d86fdf 100644 --- a/tests/interactive/test-scale.c +++ b/tests/interactive/test-scale.c @@ -36,6 +36,15 @@ set_next_gravity (ClutterActor *actor) gindex = 0; } +static gdouble +my_ramp_func (ClutterAlpha *alpha, + gpointer unused) +{ + ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha); + + return clutter_timeline_get_progress (timeline); +} + G_MODULE_EXPORT int test_scale_main (int argc, char *argv[]) { @@ -79,7 +88,7 @@ test_scale_main (int argc, char *argv[]) timeline = clutter_timeline_new_for_duration (750); alpha = clutter_alpha_new_with_func (timeline, - clutter_ramp_func, + my_ramp_func, NULL, NULL); behave = clutter_behaviour_scale_new (alpha, From ec3b1a7b90314a13a9a4bed944e10f82183edcd5 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 20 Jan 2009 17:57:30 +0000 Subject: [PATCH 2/4] [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); From 268abcd7865bb6ae10d40a92dd2eb1de79df3de8 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 20 Jan 2009 18:13:36 +0000 Subject: [PATCH 3/4] [docs] Update the easing modes documentation The ClutterAlpha API reference page should also list the easing modes Clutter provides by default, by showing the curves used by each entry in the AnimationMode enumeration. We can also remove the incomplete graph showing the old alpha functions. --- clutter/clutter-alpha.c | 5 + doc/reference/clutter/Makefile.am | 5 +- doc/reference/clutter/alpha-func.png | Bin 30651 -> 0 bytes doc/reference/clutter/clutter-sections.txt | 34 +- doc/reference/clutter/easing-modes.png | Bin 0 -> 51834 bytes doc/reference/clutter/easing-modes.svg | 920 +++++++++++++++++++++ 6 files changed, 934 insertions(+), 30 deletions(-) delete mode 100644 doc/reference/clutter/alpha-func.png create mode 100644 doc/reference/clutter/easing-modes.png create mode 100644 doc/reference/clutter/easing-modes.svg diff --git a/clutter/clutter-alpha.c b/clutter/clutter-alpha.c index 615af0e1c..4fab3426a 100644 --- a/clutter/clutter-alpha.c +++ b/clutter/clutter-alpha.c @@ -59,6 +59,11 @@ * #ClutterAlpha is used to "drive" a #ClutterBehaviour instance, and it * is internally used by the #ClutterAnimation API. * + *
+ * Easing modes provided by Clutter + * + *
+ * * Since: 0.2 */ diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am index d03a283d0..e396ad68d 100644 --- a/doc/reference/clutter/Makefile.am +++ b/doc/reference/clutter/Makefile.am @@ -91,7 +91,7 @@ EXTRA_HFILES=\ # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png HTML_IMAGES=\ actor-box.png \ - alpha-func.png \ + easing-modes.png \ event-flow.png \ path-alpha-func.png @@ -132,6 +132,7 @@ include $(top_srcdir)/gtk-doc.make EXTRA_DIST += \ version.xml.in \ actor-box.png \ - alpha-func.png \ + easing-modes.png \ + easing-modes.svg \ event-flow.png \ path-alpha-func.png diff --git a/doc/reference/clutter/alpha-func.png b/doc/reference/clutter/alpha-func.png deleted file mode 100644 index 292d493259ab5099312ee475719074a8c3061cb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30651 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

^K2>_Q!5rw%T>HJp}&s2x~*0Z*Og=fnL5IjNK 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 diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index dfc898d0e..7cbb297a9 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -100,46 +100,24 @@ clutter_behaviour_get_type ClutterAlpha ClutterAlpha ClutterAlphaClass +ClutterAlphaFunc clutter_alpha_new clutter_alpha_new_full clutter_alpha_new_with_func -clutter_alpha_get_alpha -CLUTTER_ALPHA_MAX_ALPHA -ClutterAlphaFunc -clutter_alpha_set_func -clutter_alpha_set_closure clutter_alpha_set_timeline clutter_alpha_get_timeline clutter_alpha_set_mode clutter_alpha_get_mode +clutter_alpha_get_alpha + + +clutter_alpha_set_func +clutter_alpha_set_closure clutter_alpha_register_closure clutter_alpha_register_func - -clutter_ramp_inc_func -clutter_ramp_dec_func -clutter_ramp_func -clutter_sine_func -clutter_sine_inc_func -clutter_sine_dec_func -clutter_sine_half_func -clutter_sine_in_func -clutter_sine_out_func -clutter_sine_in_out_func -clutter_square_func -clutter_smoothstep_inc_func -clutter_smoothstep_dec_func -clutter_exp_inc_func -clutter_exp_dec_func -clutter_exp_in_func -clutter_exp_out_func -clutter_exp_in_out_func -clutter_ease_in_func -clutter_ease_out_func -clutter_ease_in_out_func - CLUTTER_ALPHA CLUTTER_IS_ALPHA diff --git a/doc/reference/clutter/easing-modes.png b/doc/reference/clutter/easing-modes.png new file mode 100644 index 0000000000000000000000000000000000000000..c1cbe1460e69a280682eb256be7eaff86808e13e GIT binary patch literal 51834 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 CZlALLr zUCmzj!c^Ua57>~tZy;bv*WVCCW#pG`}RK^mh0$oi77>=3gy8+-x2x^RD8 zYpl$-2^Z2io(wpG;V<)Bib?**S?Ib&qJviIh1FNCGa*#QdYH<|A~h@i>R~Wts z-}+aMY(dTnDjIZbsR+t?>4rRvK3AykQr|DaC6L8=YFj<)QHz?(W#l4Oo}}x9ElABB ztJA@oPF()<3fLsVgqNA)XV|tBR*<1bM;Zr7@&=)o18o$n{U2rak&EgX(dY}ekY|A_ z1X@G-Q|Po{WT$KfH^K&=Esj?LGyU0&4F`FK8K5RJT2!}o=VytcoaNP@VFGrFh+*lvm(1LP~4T0bp2%fmON(BKP4(>O*2| zD-!FerT~VTb*zSzKY{(}#O?u|V-6>*PMHMe@Le$yMbn?N^%@F#nE}6TtMgyMhT#SP zEYrC}dEr@z)g;Kje6pe1?DfVO@$P#oN?SOv8bi9`CN($*2IS?XO2Z4``d2l?$T>d#jqm`**LT~0NF z0~XU1hK;q{<@Gx-Dv&bT@qD?d2|cG0y%uVBUMtY3n+S5OSa7dc51_l|dy(#pf#A&#*LnPGz+cnSzTt6@13qI^hE8p3u~L>%wfGXXDUx2`pzJZ3A?_LzyKTjeZf(N4EV1O@swTSm5aNP-Or)>oYjP+eP6e1LRHOt4qqklmq3cw zS2>F*>4Lt-mn$OpkzMb-uxmrI13w+8@#*KTbidMRBXFZQ))@Z3`^OW^S8=aw*|wY7 zd9`G8z|Q+~`}vjqvfB&=?i%ETougA?e%8PI;bMp6saSobBDVuYiT`N}gT}pN~(c%7;GHGt_iGLx(ekzs|PVtW8hI zAdT2_V~U(Hrx!AIe)oE9Ns8mEGx{m>51)c_d}iNKB#r;kkE>Ig^tQwah_uw+vg_0ir!Dh3ED5qY2F{#z!=3w{vK|zSv*aFCL zQOUw_d5*f8>PU4L1*Y=ll=ZCQy!Y*S$)0_rfcuTIm3yboY|+IV0=vC08gkfRjt=Z> z3h{2a_4no?cML0vBaG=M7N)+Wr%Kn6=Y^4b!ngG)KfDyM!(1P!^Q>4n*xd?a08+VG z?s*wk*#_%fZQfx3{njo`Iji0o8K%agDpr|$+%M^OFWKDci|Gj2TX5~!Y_4D?cUmKT z-A5Z+)gzN}8pHY}u3HCpJ^tN*)8LYkpjx&qzOk?PR2oiHj&>l=R$x-no(tW+3gEnL=@eP$Ezs1(_Tle6PqyGHdf zYD50ET9pyH>^tRKA-E|!I`w{$UY4z&R8;0G8#d)6&!t#m#2ou)kiHEsR#;oLNEWZ` zB}@-3sF+=_@-OVPPiKXgT~y&PTZ8s{-T~#P0znFhu&wu^X4o3}+`2uiZJIl{kjSUr zZF`#|slANvq|YW5#E#Kj1oihneKT_?8Q)%-$?999ZMN&n3Jc(d_+QF{J3I2E>;mC_ zQAT$RZ&JjzFBLZLo__D?47w5SY5ct6l>U^GZOok|TGHJvDgo7pELOItF9L-8J1ZjM zsueHVo*H6K2S!l~1TH-TcyB&sBPZz{xo9J@l>pDTTHlri+s3<9%~%vpx=urCeTR5~ z08RQsJmsas=aLX48M$P-Me!P5MR6cdptE4SKd|y>d(t`cnjUVEmH`>O(DfNg-`PUf zE^f(ial3jaQcQu%%zDvi>AUz3#?+dUqAIV`#?3Fi+)qtePWA22$c>q=Yri$YuD*`c zD45Orr8{+Uz=ryF!-K}!xwS~D7l)}`VWZb)edXa7&nK~?HaBt?A}2JHkW<1HAYE93 z6l^Ce3aoDGBF+_&Z=Q-?wa~~~Exhs^Bh`YE>696d86c%|5iZ2vzkbd5r*Iu@0T-HCU)^yuj>55{(!Csv+EVo#71uq9(Yaf(B zboB#+r2NY&Ug@0Tq?5!~bDWNjyKDmW*>p)tNP`^l7i#x84{@hhi#l^{y0E^4R(^%N zZO4LDV-?@29N874nVx*{_D`D4t7|tdq&Txwl{`H1OXkfAN+nKBdsPjCLJ<@TS)~;R zg1Q5PXoSzi8$r9bbp+9BHk|`TCqgLYlK@fr6UpR@(HWR)tbnOxgp*-+W0;^X?$Vak+L$th;^QTD(yx&1!V)-D9CqVd?^48jNREoJv{&G{gk zx&-GF;2f36_tA$3M7i%I(7ePS5#u=x!w%h)_`7dh=A1RE8%a%XPcK@-3U}>1?94-r zAc&}E9mFOJA&O|-K^CF?3(5&S9c8w*L{%TNx!Jkwu-xY4VV0z$4H4@8rPXP~FzLYT zS4dLQuvv@2N&6E!WJk5PeG5tlfg&QLE4h@yNCz%MXR~b@Kf|%e+JNA+a|7yNl&%P_ zF9cHB>Ip${Wfk61@*N_+$fY2n>RtW^GiqXcIj4?8V*cVYmYcwj(&`_eN6j1+`4(1y z??qPf9CJpBYmk1O8hAHvX5%^+f{fSe3RL0ki?nqd7t9|f-6^><7C#@`kYlh#u$#Ce7}yZ`jfer?+Dt3X|rKP)EL|SeOj|2Mt)vyk+So^ zg-X3Stg9Jzifc#9Lm|~7jY7O-TEWYVShhCY_iyTb$G>gIu9OPow73KC1c0%th?#vz4bZKGg(V zk*4`moh9ACM3i%-$C*j-B}%)&H`S70>0wmW54LvS!Ole+RPSmRt?XSPv5*P^(g_Bd zsk)@nm2IP*rq_l@r4uG~X*2as>f7ch0r3WXmz#+9}D*l&N(#gi=o z$+lFBbkM2dLEFeG4DrDw$!|g{=n)H~}nq*A1K!mt4 z-HE|xXS5YFp*hg(`$9^~s$L={K3mhV>#GotkEDHt=OrXE`-h~PKD}NKE4Nmkp3)2I z;J-yx8P#X-pO^my+Wc2<2C)|X|Ef-GHEI`8#;7rndpT}q(ardW0^0x==YOz<%t5gk zQ~4hS=Koqt{m?)c(F00N}nivI1V=b#Qsli-CrKxv7!p*1gAI z8EFj3w?$_qs}b~HL?6-%`=W$7Jsn0j5~IHUCJ{LM`yExZKV<7edSC0-z5TE(0DvRV zQ@VP6H1e8t@3LtB%2^aAXziqcE0a+5AYJN_if^z9yRv^;ir^VFS3UuqiM|Tw0)NzX zf+tZ99LVcPAmivN@;@b7z(yf9X4vuHKZzRGIig>Le2d-Hy^eDZD1@T>&G3LvNsh5Q z4sw1`!!tDfv}V_MFHCExv%)#gHKX0bPD?{U=;zj;@1VmA4uChLOybRvph#ig*Gm1f zZ~DEX?Ll+0dvNL4SW?W%aBZ+#!vOFbvD@15vAFG!>rR;~?k$r!e3*_c^f};1>>C30 zyI>CxHv>a%`ec*cyd@``3#AtNwTZhxqwoHGRd-0Ji2F?}g1HEvT4T|mIU}lQxO+u* z$T2_aJaIIfUZftnR1K5SmK#Num$Pdz`UniaFY4e)9_^ZTZ|vms`6aVHg+uftYRL=@ zxB!6JU9e2OvP;|N)LPUg5c;P0PfC9=1hOAn58D@@8CQvJ`Bw{n{d1(K?1mQpNCR5M z3-(F3wWdX^!=l;V-WOB%w|#sd{u^wq8mn`Vw6ME3TOU?c_V#9jGoaiKrEq1*S& zmmLP69U>EG@b2eI(tIBpmu&39W#v`7@h%KeDj^h5)S){oBtWT9syY;hsa_2>hYOb=zn&5 z3|Gm468KTj`L#rg4=uG^7)QZ?p;6;~M%mYI*zA(!joK}B*?WwhS+=J2{k$TjNDQs@J+Yc^^nfyR)Z!98FKoTQKu#apCbOas?`9a27ScCJbAM-3MQs z|Mf>{y@dzpgneX&BfS|i)(>echa!mw<+(P6N76{uiAe*ib3Y*7;hf2AKa{S!o5a(7 z3~n8dq+uh1NU@j97{iU>2d8Xsq$~cC0{pka{!;8>%_?z*{pyj`^#Tiej$Z4&&@Zrg z6u8Kb>6U2LrqQ9m<0)p^Byf)^;Bi7+dZH4+pN?Gjhg~6{P5k_syNgQ^(Jb4~!jE{# zn;iX@ZzOFhnQndsWRekBMx|@kK_hYxWxWPOY;+4RulCPw644+7*MafJohag# z*BvfH^M5ePDUy@;5KMzOHsWhNHR(Fbe_axx!moHyH?DIbc zk=sQrDi%v!@xmD=XN445BJaICD~WncKwcx9a4tn8+#R5vLv{_Ff)t@#%A3g2WnIt(Mc+}sEX@#_-@JnmhMD9(rgUXaM(GikU%n|}112kr_-I%k?f8Q8*GbpJZ(*lXOBeSS z)DTPjTInJ8S-16hW^e^}Z`g4QFW*lY+LUlu;}ok-{T#;hzyhEATcJ;zR1&`pzdd-v zkUK$D#d#=hbE@d4<8!w!Fj&I*O*=0xgKY2k1O%_bK(hoU`SO`%gtio>*()Bwy?V4K zQq;{|tt^C7?3|Zfb{U(n+eHzb>;mDhJNSO#m*dv}49OiWBl!8cmV8UQ}|4?a~tdfi_u<9K=A2Te+v z@HlleJVREn9rJ$J9Aw*va#NKF?wYCjT}ij+za++VVrC|eL`iY%{rge9r?6VNLZO}4 zozQ4@QYpW{19yM>61l0cWA-j$N@t~ZKEdb~l2nyOkC}*KONL6CI)`xswIWZUdft> z&dw!%ZoW3M*i$G!RBDpyc=J$Fs)&ntq50Xh{=ctWa{k-8E-l61@%C4&@&DY**g?-Y zGptojwY)J_6MT`JLKgACws-iN3-*?UzdzeN;GSx48lGT(kn8TDF;aKk18mDzN0KJ6 zP1YFVW0rThxI2!2izgY49X#X|D#lgFbr!kb_PAuiAwlD@kpAFjFXyhH78+zIpAs>3gjog7*$ zEwnZLVYRyc-jnN$%r4uf*NDoHlz$*jcmx{BmR2`&o#FpsPpEvmDpP2;uM;raY*pSr z#z>&;Vsfvf8%y6r)sH~~u&VwRJs(n40e(e^n#J$q zYo!8broQ%HI3ul9RD0}qmh=M$*|YnCXO6(;>VdfZqp#ieTXbEyFAyCnNnJSq< z=Q2K8eSXM>b+T&s%bh&K_J>9St>8mD!41YG(XswM(#f)BVXo-*ZD>P!gVu6yh8@Z4 zHJxWIPfTg<#f?o=IRKxkp^Wm$6!(eJBk;%+-TIsLu(?M6l;iTAh5=*Pr0#C@D%eQZ z{k1%jw`^}oT^tGl=hc+h_pvz(^P1?+YGLy}dI7Hw+Cc2mS?Qa$)3^Li#xXGj?vP)W;axsG}0zJ zYuK-xUW1yOUJ@!ufx8||9W3mHbC?T`K-!yhDB~XTNu2Jp6_1HhErLaier4pI59!zU z!`!*KX%M0bxui?G3REX$3wv^_;;X&j4fpPDj5oeJY2{hhN}8{hj}QG;t@dPl8-z9bq{c$bV-k>%OHN_F`dDaP`A$ z2ezTk2An17%32{Wxb0s5c9Z@;&7Ju_l;8jVZABv_((KOYa)%nLt+<6d#T4D9AW)>y`xW(aW1>#}L{agom)(>H6gtbV)dWgzeE;IYyL z4?{J%JI+9U*)=W{-v|0M^b{(E}Ey8Mu z#H{86Y+hp-%O|tu&QuQ7sz+!X-0zUErZT?vK-1|85Ev2iUKj=C7_W7_a0ANdDQdsR zU|fFLxaz}=nH(z1Z%T#mN!rC)%W@ph5CwI^#LRQ|g92}#Hz=u`b_N%gKLRQcQSX+J zvp>AMrGN0?LBna+z|A2?!d7F@@kE{YCv~@Z0~*gaSxqE~OE+2}^?5Obzhg*mX-Z?4 ztR6@O;7_T&4r@BJj)oIrn>hc;xWg;XpH&H=HfuAjz@J z23rJhtk-{`V}11QuF25RQBP5@Rb*f61)>2Ur3kLeqzA&U%oDu@yJqPTOvCi<$X7Y; zxz7rKJ{UO1kKXBa1uL#eA1O)V=%)v_=X@e!(|nIMp@zyGk}Y2CcQ$yXiJ|xGP^`zD zNf@)3*e%bS8Q1e|-;dqEW97u*iU0a{UW|HCgwfyc>?O_1nBb;=TwaFl8?5U2@}cNx zMj;m#vo35Q=}0JHp4I?wAohFU1-)7alV`(3OdtXN;_-9#RS3^J_4@|1HNLzrI*O%!xPI$OaZWYjA0Bko zG~m^9C;8p*bM9ORbs&!mWnKEo*~u!9;3TeHbte4>DSPg0;eN;B=ImRMbUivNk@GkE zsAE=_;yM$1-C<@yQp-q9 zzi@gp?xT#(6vziFGn#fbmSYLo{;vs#BsA>vI%wz=JURCw^M01kG?NzFv@1G>NeAJd z{;i4R{uOY~&IG4AsR!ujAEh816b$V99FKjbui2-DjkT+nX60xj*gDzRatmkB(Oym z7nTdxHLDt`wKLpMrN^0o=p|cu^i!2@KL&B-6V%J z&o%PoJkIL|yU6p)u@zI{ z?|(OcKi<<9&+F`ZKHJe;+MpT)eR_fk7mszNf`;P?9qsXK_z2#s@BCR0cE5E(nCNJ8 z@80Q?`d=L2Hbzv?pgfClxqKsMuH&TXZhIGH5B;Ar20p(?~H5Pj>?Y z{+&mF@^m}ubp(IUVD)Ro&wM+osfaobR^9p<9B`TE>6HFtTy1p)4bHb}V!J|+`p&-@ zH8WpcTx-Kl&?f9Ht7PaWWJi+1-ZjGC5b@jZ1!2F%oYgn~&30yk8n&B^ ziwdLl_2xBiM(nXw>MvQOORA@tcKC*ZL|ciXYoDw&s$OCR#8qB`oJv!_TLx~v`jRzb zb%(3*#ct9jd0*}E3ox$n32j%i3e;GNb9=qb7+=p! zWZnSwT<-I1jL)ZZ?Be{jP|3sIKe+5OkjF5u%qsG9vVfl*E?hK?ANBZn(s0HqW&_V_ zV)Znzs;E7InF#(j1jvHul>Vj5l@hn#3M;TGl>vN<%-um03+7U@LgF}ES?jqroiYP| zLRev`z)%4EkbzMDz*olpE~6YFew*`iMuv@|HRq%C|GyiKF@LkjUTh(Ok!q@`3Bfo8 z%y@rdpU7&VV~~Y(%*DgQ+Jr@yw(^E^%#1PHr?E{u_MFSYVnen;myP(}ml-=OIE7+m zr22aFo20enAWp9GLh5wURFjfTo&2Un&5Rs8SvMD7KsQ zsZ9n1aEeT`l_Wcaj=6wHEx^^nayUSmDGowyM5aL;17I@DIp&4aNw8FQvo$rwL3*Jj z>&%eY!et&I&DwSzA>05srxmk-s|BW?DuFpDcp+!0_lf{Vf0ZfO0TI55zaY15xG>1X z43xrqIe)nne&!0hw`w!NK{n7h!s7=QpAsGmdP8WDc^>DyfCq&}Yij66eUMp}>;Oc+ zL0vf9FNiXPLrl_p;u<%Eq$+ek$nh;5P(u9HjQ$o4HHWPdvC@2ZI!AO>mG2e0Q}5RkyXqW0H+c4Qt_`D=KL$ z{$)Jg#h%BjY3uWR#i3;dry;A>x~Nx>mKofGQy#$r97q}?pkxUOVEYOHmgJx>xmbt9 zX&c@55}5&2hHXQ^5GibkgAipAZ;13ZcLDoh&q(S*Smb2$e|Fl50~`tR^YmD#mLCH= zEI@?p^V&368GssLz7BDNm1m~tZ0>n7S`Wu@rJwB`6QA?q5T!C5fRi|ACvF?v(iHbH zbIKGb60lq@gquhKBarvI-8FF>P4!nhr=e}lMq+00ae5IW- zqGp}8HB!bwIY~g;mhiWNzzip#DFF{c zCdlFgq&6JTC;_8*SEI*m<&)H?;9}X_k>vLy!32Dc+eHH2ypeNCos}(QCRW7fPtVY2 zSHJx8Ij(*?rlI_R7lsr_V*bU*-Ts>)W-Ln-DePp6DGLQz9Jt0jIx`(r#DU=bhL>a^ z>*??L;USmZq&91z~%e2pIHT?Syz)ao;TLDPHR?)$I_4*#h! z|7yhL+&%qa7bP4-p%ky1f><@cRyz*IezFZ^5-dF`8e<2GPZ$40sg*!YwjkRJ(*3vC zeQK~DN*SjMXh}`cZaw|LY%RFizK% zrYS!T?H?BYja`Yfa2$NzL`LBkBda;2ukkWRQl5D%0@7KnY^z{G?Rd4a4St0rQ}Vu* zgYYBY^!+*P@gH5@-8PZ+x$#Vy2|63o>D*ibVPSn_{td~ct`v?op&#uq^AxhUbP}(? zafD|qULKcZO>)3GXI~1>*t4C7M$g{dc}QS7fujjtw~`3m8SOL7CJrIAb$OG>cqD5I zRX5_=-PIkJ*iluLWJfYbe%Fthv2I+g@bViQ>{p1*qr#u4W}ZCs)i?8Gj(peYz5s3Y zxRe5{VO#TNJA@XWr-Y1!b{eqtWG7>CTSQjmQxpgWkrb6VC5jQrX!+(=!f(ILk`Ras z7hm%yR(RAH7FWcTZiP-#7$@T1MRrCMWjncDz-K#=#{B0{HF|7q`V+ouMXRaNr!F4p z`wwW!zt`5CN&9EWa%0=v;YHEKD-(u_ctG*X!Dhcs{9&oBcz*easd)Z6F0B)0Tvyt` zz6j`${C0lw1TwP#)(J23WPR=6eZC){&^VwrUbHQXZvml+_JwjRE*i&o|Fu`Nav&}j z@DO+UE3zPp9$wincJWzNgWD>rc~a&|Q-^{C(Q3!Sft>ju4H3Ejwplh^52T-11 zq537O%y}V!n;;q#cp+Z6U82f>sIRFytgw&0mP#k5JTQCi%!LwI}i z5JN&`dw^v`42cOz?b~cd(IV}t|Dv|L{lP>o-(-AXWum8zb)KIvDs2wlf8syv=*+gbClsO+$?nG3Bh=HK=$~uhWZaYe^euj}y(7MqKnX!~5}~ zbYqdVf++qu1=@aIW3rLhe=%Lj`@=TB;#c0&2yN;fZH+OHibdP-bC{GU^ER6%zGQ(3 zDR!z=!?*os`i)T43N^pkGXJCJT(7^243SHow9@I6)(LGP6R+Tvj=sH7v}%|$GJ%h^ zHBYq=B8TfZw&kHI8yR*}rU&E|OM8M>#BK*0%{J2J4@{ez7t&zj2bxiHUWGb}OZQa8 zd}a$n!Az)3Wh^>?y^!M-8<|tv{bpil-r-Hw3KZhFwkX*jZ9Y+!R`XH_;d|TbG)8Z%vnenZwj{NdhI1u6hs^>W)u2(eifKPP-8V_z+G|;wwguVD_)%sY zm=Bvpmj}~;b;5K@`N;1?N(9M-BC67w>=hY9em?XUzrs6i(76nV_<=bE50qhEoc5_D zQVh0k-;691!aw5wG3D(??$#KwAhse7i zJ$tO|&@RQflb#9Bn$*1B&yD_6Q%@VZzW0i;xnBb|`CT*RlO4w!C?;%ogzo3#32C>A zqK-Z6o)48x?U^r+hB7b&I4NY8Rzr%bMu8HVMuYmA;=Tpz58Gv_m_!XH8fj;M5M;{84!O zJ^l&42WQ(QM%K*juS%cA7XP+OrEJ|~^e}DVW|y>__J3NskuCJc{m<{-h>AYc2^5J= z$RWbjM1skCv#~6-w&;7#0y?@9uNdl^anT+`@iXK86H*$&Xr0=Q;?*KKF48{IlA5;o1*I8`^Q$qTJlV3ZM!9c)!=7-s0OU-g>*spVp{-qRD@oxLO<` zHferxjJBU%VsW8Rz~&2zw3BJ8`K7pytm{cTvDquwE4{3jTC=AH28ha=Dva$*OZZ=_xDktV6_}*^KK{mw5qA&$``wP#)$yL!WPEIj}mI zQ?Xs*Y41BMbTt;N213qsKYKVp)1U2OJS_1&e(lKHcQHNlQsiK>Bdurx;7hkHJ6>~} z@=^d=OP__t+B{u+XM620Yh`tf_<$X#oakV#F^ z`OUANur)snM-N!u>=)!2xNo1P=5^Vmd@CJ&`xU7{f*QZlowA>rA$hgZ@SZq1Q9c)E zfFZj6wJv)Qers2n*7>0>$Q7c;$uP*n?>jax`H}2rQ<`a>ZrK^1vzBj;Glt!oMRHze z=AFeHtWiKk#cNp=qDGRcM6aO{J}&Xy!m$&i@7Bi|L_tp;GoIjq{-BoiVs0V5xIgZ} zs6ni7gjy19_t_;qcLTJ}cW=CM7v9A0yj`w+4XG{u~+Q>7@J5DD*zb1Tx2u z*DK!lOGxL|MVj|(0?PNuAE{WOU1 zdiiQddqZe@s&HOF8v01+cm(xm=@W&@fHX>t1W=7ie(y`SxNdd0gYMIjzY? zWK#L^F^aNI0~D$5McfYQpc#5K$UEKTSj%W!n*5QpM>->5YIaCr;~%n)7{SKuu^8i{ zWG=rL<*bI{VdXqn59V?wwUBX=K_Z2YiH=!yo~j%@vdGEEyxgNrrn!2?_07NVc@Po- zIeUG*^D^QRlK!-wWVi6j?+i`;jyj-AXl@R)8*C3@cl*@@+ia*c7N8h9#>x zAr{f*JekRQODI;CxlU?NL~E0w0%_adG>P2ef_Wb%B zAEeX-cMxtB3#y$h4{9+neNE{{4&zIP+B%H*Jc@F+RtE&Z{FSoiZfc=22G7p1L| z)O+peEA7JkHJHDpTR}&hhVBa}58TD4Vw&JO%B5yzXvGgVZe=@WT{1qxb5$%z7FC~( zGsEGy7e%Q#*={thx4GeY?u+%$rwd&k)sA%Vdx+e$~=ag zZednmg)WcQedx>8&iKAjzQNsq){Q4J%eI2N)N00A5$39`{aG?RGM>3+g{dX&xEnbv zrMF`JK`YngxkVLn86Ws07xhMN5_#NJ1%UP_K6SuudOi3J3`0i=dqkk3PbzPq8#AO4 zzm(0$YY6!W1smDg^NAy>-WF3iud?s49?6}@Ao>;YvM}k;7((11{~>3R(nwnPo#kZl z0PQ{P!SdOuxc&XFQy9wCapQe2%;PuS4qqcbTsOs!*{7ar{t$*YNn>D0B0F*#C(C5< zBvsyo^~NEYB@|Pbxtn+2cG*8NHV=b6iG#%4ETM*#PI7F)@5gc#MHMX=lfB%3E+LNO zM?7kS+m?FhJtVu@4oOvOQxhzsf(qATvD%HxSqgJn%st{^#N&T5$N85OC>hpWz~CCO z^w2~VP7*XGZA;!o-lYNm%S13A1o9X)y02|JI@_Q7EfOv;~(P{`_qgX)1H%C+`VQJi`zDm&(dB^eJU}g zw6crH7?L6JE^5tM72518p6_F(ikkrAC>57TlPy#I)U@A9v_|#%8^|z^4F$1H52+<7 zdLG{q+D?ibNh(-sBz>be%1@D|Mv3ezSV8|KFJqZ5(WsvW=w_M#44C;5UzCqTtO!M} zX(g^<%2FHCnk9s0o=ACU?@oCBJC!CdlE0o!3G#f&NI4gPiUjsKqSQBE-pRdbivJhI z$}%4D@>0t~NW69W;8V4Ll-RQtp`o(v06l0*dReu8A0oCPZAk2(@3n=qXS+z{SW3RE za5OBg`?x#dW%%*zWNxu!e%M*O*zdqZB2T=A^zFx{SsI<~H{(N6w1xxentIi$BT~(t zrTrbJ1CdTf+J`pmHymMW)WCdx+PUV0o7|QYFUHEv%Sn3x=ziau(UlE3@?f)nYrO-$ zLF1_=VZD5uqCyI6t}EQyr|rE>ER>dHEZW~$l5cmJD$jBh{NJQGa%Rte6X?ja|4k*c a_@7)~t*SD<69QnJTvo?zEvn7WCj1{4fjx!* literal 0 HcmV?d00001 diff --git a/doc/reference/clutter/easing-modes.svg b/doc/reference/clutter/easing-modes.svg new file mode 100644 index 000000000..34e0b34a3 --- /dev/null +++ b/doc/reference/clutter/easing-modes.svg @@ -0,0 +1,920 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ac1a0d568ed650f37fbce906eb82a969f0d41a77 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 20 Jan 2009 18:24:58 +0000 Subject: [PATCH 4/4] [script] Parse easing modes by name The easing modes for a ClutterAlpha can either be parsed by using the enumeration "nickname" (the shorthand form of the enumeration value) or by using the common naming policy used in other animation frameworks, like: easeInCubic easeOutElastic easeInOutBounce --- clutter/clutter-script.c | 108 +++++++++++++++++++++++--------- tests/interactive/test-script.c | 6 +- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/clutter/clutter-script.c b/clutter/clutter-script.c index 8b357de70..faeeede35 100644 --- a/clutter/clutter-script.c +++ b/clutter/clutter-script.c @@ -184,6 +184,7 @@ #include "clutter-script-private.h" #include "clutter-scriptable.h" +#include "clutter-enum-types.h" #include "clutter-private.h" #include "clutter-debug.h" @@ -517,41 +518,77 @@ construct_timeline (ClutterScript *script, return retval; } -/* ugh. if g_module_open() fails (*cough* python *cough*) we need a fallback - * for finding at least our own functions. keep the nick in sync with the - * ClutterAnimationMode enumeration +/* define the names of the animation modes to match the ones + * that developers might be more accustomed to */ static const struct { const gchar *name; - const gchar *short_name; - ClutterAlphaFunc symbol; -} clutter_alphas[] = { -#define ALPHA_FUNC(func,nick) { #func, nick, func } -#undef ALPHA_FUNC - { NULL, NULL, NULL } + ClutterAnimationMode mode; +} animation_modes[] = { + { "linear", CLUTTER_LINEAR }, + { "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_clutter_alphas = G_N_ELEMENTS (clutter_alphas); +static const gint n_animation_modes = G_N_ELEMENTS (animation_modes); + +static ClutterAnimationMode +resolve_animation_mode (const gchar *name) +{ + gint i, res = 0; + + for (i = 0; i < n_animation_modes; i++) + { + if (strcmp (animation_modes[i].name, name) == 0) + return animation_modes[i].mode; + } + + if (clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE, + name, &res)) + return res; + + g_warning ("Unable to find the animation mode '%s'", name); + + return CLUTTER_CUSTOM_MODE; +} static ClutterAlphaFunc resolve_alpha_func (const gchar *name) { static GModule *module = NULL; ClutterAlphaFunc func; - gint i; CLUTTER_NOTE (SCRIPT, "Looking up `%s' alpha function", name); - for (i = 0; i < n_clutter_alphas; i++) - if (strcmp (name, clutter_alphas[i].name) == 0 || - strcmp (name, clutter_alphas[i].short_name) == 0) - { - CLUTTER_NOTE (SCRIPT, "Found `%s' alpha function in the whitelist", - name); - return clutter_alphas[i].symbol; - } - if (G_UNLIKELY (!module)) module = g_module_open (NULL, G_MODULE_BIND_LAZY); @@ -573,6 +610,7 @@ clutter_script_parse_alpha (ClutterScript *script, JsonObject *object; ClutterTimeline *timeline = NULL; ClutterAlphaFunc alpha_func = NULL; + ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE; JsonNode *val; gboolean unref_timeline = FALSE; @@ -599,25 +637,39 @@ clutter_script_parse_alpha (ClutterScript *script, } } - val = json_object_get_member (object, "function"); + val = json_object_get_member (object, "mode"); if (val && json_node_get_string (val) != NULL) + mode = resolve_animation_mode (json_node_get_string (val)); + + if (mode == CLUTTER_CUSTOM_MODE) { - alpha_func = resolve_alpha_func (json_node_get_string (val)); - if (!alpha_func) + val = json_object_get_member (object, "function"); + if (val && json_node_get_string (val) != NULL) { - g_warning ("Unable to find the function `%s' in the " - "Clutter alpha functions or the symbols table", - json_node_get_string (val)); + alpha_func = resolve_alpha_func (json_node_get_string (val)); + if (!alpha_func) + { + g_warning ("Unable to find the function `%s' in the " + "Clutter alpha functions or the symbols table", + json_node_get_string (val)); + } } } - CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) and func:%p", + CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)", unref_timeline ? "implicit" : "explicit", timeline ? timeline : 0x0, + mode != CLUTTER_CUSTOM_MODE ? mode : 0, alpha_func ? alpha_func : 0x0); retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL); - clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL); + + if (mode != CLUTTER_CUSTOM_MODE) + clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode); + + if (alpha_func != NULL) + clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL); + clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline); if (unref_timeline) g_object_unref (timeline); diff --git a/tests/interactive/test-script.c b/tests/interactive/test-script.c index 5e6464d4d..664e87361 100644 --- a/tests/interactive/test-script.c +++ b/tests/interactive/test-script.c @@ -43,7 +43,7 @@ static const gchar *test_behaviour = " \"path\" : \"M 50 50 L 100 100\"," " \"alpha\" : {" " \"timeline\" : \"main-timeline\"," -" \"function\" : \"ramp\"" +" \"mode\" : \"linear\"" " }" " }," " {" @@ -54,7 +54,7 @@ static const gchar *test_behaviour = " \"axis\" : \"y-axis\"," " \"alpha\" : {" " \"timeline\" : \"main-timeline\"," -" \"function\" : \"sine\"" +" \"mode\" : \"ease-in-sine\"" " }" " }," " {" @@ -64,7 +64,7 @@ static const gchar *test_behaviour = " \"opacity-end\" : 0," " \"alpha\" : {" " \"timeline\" : \"main-timeline\"," -" \"function\" : \"ramp-inc\"" +" \"mode\" : \"easeOutCubic\"" " }" " }" "]";