[clutter] timeline: Add cubic-bezier() progress functions



commit 12c75e9737152f91c440c935c0393f5ee9ef473f
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Jul 19 21:55:35 2012 -0400

    timeline: Add cubic-bezier() progress functions
    
    Another progress function from the CSS3 Transitions specification, using
    a parametrices cubic bezier curve between (0, 0) and (1, 1) with two
    control points.
    
    (sadly, no ASCII art can approximate a cubic bezier, so no graph)
    
    The cubic-bezier() progress function comes with a bunch of preset easing
    modes: ease, ease-in, ease-out, and ease-in-out, that we can map to
    enumeration values.

 clutter/clutter-easing.c   |   72 ++++++++++++++++++++++++++
 clutter/clutter-easing.h   |    7 +++
 clutter/clutter-enums.h    |   19 +++++++-
 clutter/clutter-timeline.c |  103 +++++++++++++++++++++++++++++++++++++
 clutter/clutter-timeline.h |  120 +++++++++++++++++++++++--------------------
 clutter/clutter.symbols    |    2 +
 6 files changed, 266 insertions(+), 57 deletions(-)
---
diff --git a/clutter/clutter-easing.c b/clutter/clutter-easing.c
index 5f3dae2..1ed6798 100644
--- a/clutter/clutter-easing.c
+++ b/clutter/clutter-easing.c
@@ -402,6 +402,71 @@ clutter_ease_steps_end (double t,
   return ease_steps_end ((t / d), n_steps);
 }
 
+static inline double
+x_for_t (double t,
+         double x_1,
+         double x_2)
+{
+  double omt = 1.0 - t;
+
+  return 3.0 * omt * omt * t * x_1
+       + 3.0 * omt * t * t * x_2
+       + t * t * t;
+}
+
+static inline double
+y_for_t (double t,
+         double y_1,
+         double y_2)
+{
+  double omt = 1.0 - t;
+
+  return 3.0 * omt * omt * t * y_1
+       + 3.0 * omt * t * t * y_2
+       + t * t * t;
+}
+
+static inline double
+t_for_x (double x,
+         double x_1,
+         double x_2)
+{
+  double min_t = 0, max_t = 1;
+  int i;
+
+  for (i = 0; i < 30; ++i)
+    {
+      double guess_t = (min_t + max_t) / 2.0;
+      double guess_x = x_for_t (guess_t, x_1, x_2);
+
+      if (x < guess_x)
+        max_t = guess_t;
+      else
+        min_t = guess_t;
+    }
+
+  return (min_t + max_t) / 2.0;
+}
+
+double
+clutter_ease_cubic_bezier (double t,
+                           double d,
+                           double x_1,
+                           double y_1,
+                           double x_2,
+                           double y_2)
+{
+  double p = t / d;
+
+  if (p == 0.0)
+    return 0.0;
+
+  if (p == 1.0)
+    return 1.0;
+
+  return y_for_t (t_for_x (p, x_1, x_2), y_1, y_2);
+}
+
 /*< private >
  * _clutter_animation_modes:
  *
@@ -446,10 +511,17 @@ static const struct {
   { CLUTTER_EASE_OUT_BOUNCE,     clutter_ease_out_bounce, "easeOutBounce" },
   { CLUTTER_EASE_IN_OUT_BOUNCE,  clutter_ease_in_out_bounce, "easeInOutBounce" },
 
+  /* the parametrized functions need a cast */
   { CLUTTER_STEPS,               (ClutterEasingFunc) clutter_ease_steps_end, "steps" },
   { CLUTTER_STEP_START,          (ClutterEasingFunc) clutter_ease_steps_start, "stepStart" },
   { CLUTTER_STEP_END,            (ClutterEasingFunc) clutter_ease_steps_end, "stepEnd" },
 
+  { CLUTTER_CUBIC_BEZIER,        (ClutterEasingFunc) clutter_ease_cubic_bezier, "cubicBezier" },
+  { CLUTTER_EASE,                (ClutterEasingFunc) clutter_ease_cubic_bezier, "ease" },
+  { CLUTTER_EASE_IN,             (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeIn" },
+  { CLUTTER_EASE_OUT,            (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeOut" },
+  { CLUTTER_EASE_IN_OUT,         (ClutterEasingFunc) clutter_ease_cubic_bezier, "easeInOut" },
+
   { CLUTTER_ANIMATION_LAST,      NULL, "sentinel" },
 };
 
diff --git a/clutter/clutter-easing.h b/clutter/clutter-easing.h
index ab9556b..f7e6dcc 100644
--- a/clutter/clutter-easing.h
+++ b/clutter/clutter-easing.h
@@ -129,6 +129,13 @@ G_GNUC_INTERNAL
 double  clutter_ease_steps_end          (double t,
                                          double d,
                                          int    steps);
+G_GNUC_INTERNAL
+double  clutter_ease_cubic_bezier       (double t,
+                                         double d,
+                                         double x_1,
+                                         double y_1,
+                                         double x_2,
+                                         double y_2);
 
 G_END_DECLS
 
diff --git a/clutter/clutter-enums.h b/clutter/clutter-enums.h
index 2df11a8..c59c3cf 100644
--- a/clutter/clutter-enums.h
+++ b/clutter/clutter-enums.h
@@ -165,7 +165,17 @@ typedef enum { /*< prefix=CLUTTER_REQUEST >*/
  * @CLUTTER_STEP_START: equivalent to %CLUTTER_STEPS with a number of steps
  *   equal to 1, and a step mode of %CLUTTER_STEP_MODE_START. (Since 1.12)
  * @CLUTTER_STEP_END: equivalent to %CLUTTER_STEPS with a number of steps
- *   equal to 1, and a step mode of %CLUTTER_STEP_MODE_END. (Since: 1.12)
+ *   equal to 1, and a step mode of %CLUTTER_STEP_MODE_END. (Since 1.12)
+ * @CLUTTER_CUBIC_BEZIER: cubic bezier between (0, 0) and (1, 1) with two
+ *   control points; see clutter_timeline_set_cubic_bezier_progress(). (Since 1.12)
+ * @CLUTTER_EASE: equivalent to %CLUTTER_CUBIC_BEZIER with control points
+ *   in (0.25, 0.1) and (0.25, 1.0). (Since 1.12)
+ * @CLUTTER_EASE_IN: equivalent to %CLUTTER_CUBIC_BEZIER with control points
+ *   in (0.42, 0) and (1.0, 1.0). (Since 1.12)
+ * @CLUTTER_EASE_OUT: equivalent to %CLUTTER_CUBIC_BEZIER with control points
+ *   in (0, 0) and (0.58, 1.0). (Since 1.12)
+ * @CLUTTER_EASE_IN_OUT: equivalent to %CLUTTER_CUBIC_BEZIER with control points
+ *   in (0.42, 0) and (0.58, 1.0). (Since 1.12)
  * @CLUTTER_ANIMATION_LAST: last animation mode, used as a guard for
  *   registered global alpha functions
  *
@@ -244,6 +254,13 @@ typedef enum {
   CLUTTER_STEP_START, /* steps(1, start) */
   CLUTTER_STEP_END, /* steps(1, end) */
 
+  /* cubic bezier (see css3-transitions) */
+  CLUTTER_CUBIC_BEZIER,
+  CLUTTER_EASE,
+  CLUTTER_EASE_IN,
+  CLUTTER_EASE_OUT,
+  CLUTTER_EASE_IN_OUT,
+
   /* guard, before registered alpha functions */
   CLUTTER_ANIMATION_LAST
 } ClutterAnimationMode;
diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c
index cdde665..135335e 100644
--- a/clutter/clutter-timeline.c
+++ b/clutter/clutter-timeline.c
@@ -150,9 +150,14 @@ struct _ClutterTimelinePrivate
   GDestroyNotify progress_notify;
   ClutterAnimationMode progress_mode;
 
+  /* step() parameters */
   gint n_steps;
   ClutterStepMode step_mode;
 
+  /* cubic-bezier() parameters */
+  ClutterPoint cb_1;
+  ClutterPoint cb_2;
+
   guint is_playing         : 1;
 
   /* If we've just started playing and haven't yet gotten
@@ -815,8 +820,14 @@ clutter_timeline_init (ClutterTimeline *self)
                                  ClutterTimelinePrivate);
 
   priv->progress_mode = CLUTTER_LINEAR;
+
+  /* default steps() parameters are 1, end */
   priv->n_steps = 1;
   priv->step_mode = CLUTTER_STEP_MODE_END;
+
+  /* default cubic-bezier() paramereters are (0, 0, 1, 1) */
+  clutter_point_init (&priv->cb_1, 0, 0);
+  clutter_point_init (&priv->cb_2, 1, 1);
 }
 
 struct CheckIfMarkerHitClosure
@@ -2148,6 +2159,27 @@ clutter_timeline_progress_func (ClutterTimeline *timeline,
     case CLUTTER_STEP_END:
       return clutter_ease_steps_end (elapsed, duration, 1);
 
+    case CLUTTER_CUBIC_BEZIER:
+      return clutter_ease_cubic_bezier (elapsed, duration,
+                                        priv->cb_1.x, priv->cb_1.y,
+                                        priv->cb_2.x, priv->cb_2.y);
+
+    case CLUTTER_EASE:
+      return clutter_ease_cubic_bezier (elapsed, duration,
+                                        0.25, 0.1, 0.25, 1.0);
+
+    case CLUTTER_EASE_IN:
+      return clutter_ease_cubic_bezier (elapsed, duration,
+                                        0.42, 0.0, 1.0, 1.0);
+
+    case CLUTTER_EASE_OUT:
+      return clutter_ease_cubic_bezier (elapsed, duration,
+                                        0.0, 0.0, 0.58, 1.0);
+
+    case CLUTTER_EASE_IN_OUT:
+      return clutter_ease_cubic_bezier (elapsed, duration,
+                                        0.42, 0.0, 0.58, 1.0);
+
     default:
       break;
     }
@@ -2339,3 +2371,74 @@ clutter_timeline_get_step_progress (ClutterTimeline *timeline,
 
   return TRUE;
 }
+
+/**
+ * clutter_timeline_set_cubic_bezier_progress:
+ * @timeline: a #ClutterTimeline
+ * @c_1: the first control point for the cubic bezier
+ * @c_2: the second control point for the cubic bezier
+ *
+ * Sets the #ClutterTimeline:progress-mode of @timeline
+ * to %CLUTTER_CUBIC_BEZIER, and sets the two control
+ * points for the cubic bezier.
+ *
+ * The cubic bezier curve is between (0, 0) and (1, 1). The X coordinate
+ * of the two control points must be in the [ 0, 1 ] range, while the
+ * Y coordinate of the two control points can exceed this range.
+ *
+ * Since: 1.12
+ */
+void
+clutter_timeline_set_cubic_bezier_progress (ClutterTimeline    *timeline,
+                                            const ClutterPoint *c_1,
+                                            const ClutterPoint *c_2)
+{
+  ClutterTimelinePrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+  g_return_if_fail (c_1 != NULL && c_2 != NULL);
+
+  priv = timeline->priv;
+
+  priv->cb_1 = *c_1;
+  priv->cb_2 = *c_2;
+  clutter_timeline_set_progress_mode (timeline, CLUTTER_CUBIC_BEZIER);
+}
+
+/**
+ * clutter_timeline_get_cubic_bezier_progress:
+ * @timeline: a #ClutterTimeline
+ * @c_1: (out caller-allocates): return location for the first control
+ *   point of the cubic bezier, or %NULL
+ * @c_2: (out caller-allocates): return location for the second control
+ *   point of the cubic bezier, or %NULL
+ *
+ * Retrieves the control points for the cubic bezier progress mode.
+ *
+ * Return value: %TRUE if the @timeline is using a cubic bezier progress
+ *   more, and %FALSE otherwise
+ *
+ * Since: 1.12
+ */
+gboolean
+clutter_timeline_get_cubic_bezier_progress (ClutterTimeline *timeline,
+                                            ClutterPoint    *c_1,
+                                            ClutterPoint    *c_2)
+{
+  g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE);
+
+  if (timeline->priv->progress_mode != CLUTTER_CUBIC_BEZIER ||
+      timeline->priv->progress_mode != CLUTTER_EASE ||
+      timeline->priv->progress_mode != CLUTTER_EASE_IN ||
+      timeline->priv->progress_mode != CLUTTER_EASE_OUT ||
+      timeline->priv->progress_mode != CLUTTER_EASE_IN_OUT)
+    return FALSE;
+
+  if (c_1 != NULL)
+    *c_1 = timeline->priv->cb_1;
+
+  if (c_2 != NULL)
+    *c_2 = timeline->priv->cb_2;
+
+  return TRUE;
+}
diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h
index e153613..a1a2dc6 100644
--- a/clutter/clutter-timeline.h
+++ b/clutter/clutter-timeline.h
@@ -117,72 +117,80 @@ struct _ClutterTimelineClass
 
 GType clutter_timeline_get_type (void) G_GNUC_CONST;
 
-ClutterTimeline *               clutter_timeline_new                    (guint                     msecs);
-
-guint                           clutter_timeline_get_duration           (ClutterTimeline          *timeline);
-void                            clutter_timeline_set_duration           (ClutterTimeline          *timeline,
-                                                                         guint                     msecs);
-ClutterTimelineDirection        clutter_timeline_get_direction          (ClutterTimeline          *timeline);
-void                            clutter_timeline_set_direction          (ClutterTimeline          *timeline,
-                                                                         ClutterTimelineDirection  direction);
-void                            clutter_timeline_start                  (ClutterTimeline          *timeline);
-void                            clutter_timeline_pause                  (ClutterTimeline          *timeline);
-void                            clutter_timeline_stop                   (ClutterTimeline          *timeline);
-void                            clutter_timeline_set_auto_reverse       (ClutterTimeline          *timeline,
-                                                                         gboolean                  reverse);
-gboolean                        clutter_timeline_get_auto_reverse       (ClutterTimeline          *timeline);
+ClutterTimeline *               clutter_timeline_new                            (guint                     msecs);
+
+guint                           clutter_timeline_get_duration                   (ClutterTimeline          *timeline);
+void                            clutter_timeline_set_duration                   (ClutterTimeline          *timeline,
+                                                                                 guint                     msecs);
+ClutterTimelineDirection        clutter_timeline_get_direction                  (ClutterTimeline          *timeline);
+void                            clutter_timeline_set_direction                  (ClutterTimeline          *timeline,
+                                                                                 ClutterTimelineDirection  direction);
+void                            clutter_timeline_start                          (ClutterTimeline          *timeline);
+void                            clutter_timeline_pause                          (ClutterTimeline          *timeline);
+void                            clutter_timeline_stop                           (ClutterTimeline          *timeline);
+void                            clutter_timeline_set_auto_reverse               (ClutterTimeline          *timeline,
+                                                                                 gboolean                  reverse);
+gboolean                        clutter_timeline_get_auto_reverse               (ClutterTimeline          *timeline);
 CLUTTER_AVAILABLE_IN_1_10
-void                            clutter_timeline_set_repeat_count       (ClutterTimeline          *timeline,
-                                                                         gint                      count);
+void                            clutter_timeline_set_repeat_count               (ClutterTimeline          *timeline,
+                                                                                 gint                      count);
 CLUTTER_AVAILABLE_IN_1_10
-gint                            clutter_timeline_get_repeat_count       (ClutterTimeline          *timeline);
-void                            clutter_timeline_rewind                 (ClutterTimeline          *timeline);
-void                            clutter_timeline_skip                   (ClutterTimeline          *timeline,
-                                                                         guint                     msecs);
-void                            clutter_timeline_advance                (ClutterTimeline          *timeline,
-                                                                         guint                     msecs);
-guint                           clutter_timeline_get_elapsed_time       (ClutterTimeline          *timeline);
-gdouble                         clutter_timeline_get_progress           (ClutterTimeline          *timeline);
-gboolean                        clutter_timeline_is_playing             (ClutterTimeline          *timeline);
-void                            clutter_timeline_set_delay              (ClutterTimeline          *timeline,
-                                                                         guint                     msecs);
-guint                           clutter_timeline_get_delay              (ClutterTimeline          *timeline);
-guint                           clutter_timeline_get_delta              (ClutterTimeline          *timeline);
-void                            clutter_timeline_add_marker_at_time     (ClutterTimeline          *timeline,
-                                                                         const gchar              *marker_name,
-                                                                         guint                     msecs);
-void                            clutter_timeline_remove_marker          (ClutterTimeline          *timeline,
-                                                                         const gchar              *marker_name);
-gchar **                        clutter_timeline_list_markers           (ClutterTimeline          *timeline,
-                                                                         gint                      msecs,
-                                                                         gsize                    *n_markers) G_GNUC_MALLOC;
-gboolean                        clutter_timeline_has_marker             (ClutterTimeline          *timeline,
-                                                                         const gchar              *marker_name);
-void                            clutter_timeline_advance_to_marker      (ClutterTimeline          *timeline,
-                                                                         const gchar              *marker_name);
+gint                            clutter_timeline_get_repeat_count               (ClutterTimeline          *timeline);
+void                            clutter_timeline_rewind                         (ClutterTimeline          *timeline);
+void                            clutter_timeline_skip                           (ClutterTimeline          *timeline,
+                                                                                 guint                     msecs);
+void                            clutter_timeline_advance                        (ClutterTimeline          *timeline,
+                                                                                 guint                     msecs);
+guint                           clutter_timeline_get_elapsed_time               (ClutterTimeline          *timeline);
+gdouble                         clutter_timeline_get_progress                   (ClutterTimeline          *timeline);
+gboolean                        clutter_timeline_is_playing                     (ClutterTimeline          *timeline);
+void                            clutter_timeline_set_delay                      (ClutterTimeline          *timeline,
+                                                                                 guint                     msecs);
+guint                           clutter_timeline_get_delay                      (ClutterTimeline          *timeline);
+guint                           clutter_timeline_get_delta                      (ClutterTimeline          *timeline);
+void                            clutter_timeline_add_marker_at_time             (ClutterTimeline          *timeline,
+                                                                                 const gchar              *marker_name,
+                                                                                 guint                     msecs);
+void                            clutter_timeline_remove_marker                  (ClutterTimeline          *timeline,
+                                                                                 const gchar              *marker_name);
+gchar **                        clutter_timeline_list_markers                   (ClutterTimeline          *timeline,
+                                                                                 gint                      msecs,
+                                                                                 gsize                    *n_markers) G_GNUC_MALLOC;
+gboolean                        clutter_timeline_has_marker                     (ClutterTimeline          *timeline,
+                                                                                 const gchar              *marker_name);
+void                            clutter_timeline_advance_to_marker              (ClutterTimeline          *timeline,
+                                                                                 const gchar              *marker_name);
 CLUTTER_AVAILABLE_IN_1_10
-void                            clutter_timeline_set_progress_func      (ClutterTimeline          *timeline,
-                                                                         ClutterTimelineProgressFunc func,
-                                                                         gpointer                  data,
-                                                                         GDestroyNotify            notify);
+void                            clutter_timeline_set_progress_func              (ClutterTimeline          *timeline,
+                                                                                 ClutterTimelineProgressFunc func,
+                                                                                 gpointer                  data,
+                                                                                 GDestroyNotify            notify);
 CLUTTER_AVAILABLE_IN_1_10
-void                            clutter_timeline_set_progress_mode      (ClutterTimeline          *timeline,
-                                                                         ClutterAnimationMode      mode);
+void                            clutter_timeline_set_progress_mode              (ClutterTimeline          *timeline,
+                                                                                 ClutterAnimationMode      mode);
 CLUTTER_AVAILABLE_IN_1_10
-ClutterAnimationMode            clutter_timeline_get_progress_mode      (ClutterTimeline          *timeline);
+ClutterAnimationMode            clutter_timeline_get_progress_mode              (ClutterTimeline          *timeline);
 CLUTTER_AVAILABLE_IN_1_12
-void                            clutter_timeline_set_step_progress      (ClutterTimeline          *timeline,
-                                                                         gint                      n_steps,
-                                                                         ClutterStepMode           step_mode);
+void                            clutter_timeline_set_step_progress              (ClutterTimeline          *timeline,
+                                                                                 gint                      n_steps,
+                                                                                 ClutterStepMode           step_mode);
 CLUTTER_AVAILABLE_IN_1_12
-gboolean                        clutter_timeline_get_step_progress      (ClutterTimeline          *timeline,
-                                                                         gint                     *n_steps,
-                                                                         ClutterStepMode          *step_mode);
+gboolean                        clutter_timeline_get_step_progress              (ClutterTimeline          *timeline,
+                                                                                 gint                     *n_steps,
+                                                                                 ClutterStepMode          *step_mode);
+CLUTTER_AVAILABLE_IN_1_12
+void                            clutter_timeline_set_cubic_bezier_progress      (ClutterTimeline          *timeline,
+                                                                                 const ClutterPoint       *c_1,
+                                                                                 const ClutterPoint       *c_2);
+CLUTTER_AVAILABLE_IN_1_12
+gboolean                        clutter_timeline_get_cubic_bezier_progress      (ClutterTimeline          *timeline,
+                                                                                 ClutterPoint             *c_1,
+                                                                                 ClutterPoint             *c_2);
 
 CLUTTER_AVAILABLE_IN_1_10
-gint64                          clutter_timeline_get_duration_hint      (ClutterTimeline          *timeline);
+gint64                          clutter_timeline_get_duration_hint              (ClutterTimeline          *timeline);
 CLUTTER_AVAILABLE_IN_1_10
-gint                            clutter_timeline_get_current_repeat     (ClutterTimeline          *timeline);
+gint                            clutter_timeline_get_current_repeat             (ClutterTimeline          *timeline);
 
 G_END_DECLS
 
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index 66b791c..7b032f6 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -1453,6 +1453,7 @@ clutter_timeline_new
 clutter_timeline_clone
 clutter_timeline_direction_get_type
 clutter_timeline_get_auto_reverse
+clutter_timeline_get_cubic_bezier_progress
 clutter_timeline_get_current_repeat
 clutter_timeline_get_delay
 clutter_timeline_get_delta
@@ -1473,6 +1474,7 @@ clutter_timeline_pause
 clutter_timeline_remove_marker
 clutter_timeline_rewind
 clutter_timeline_set_auto_reverse
+clutter_timeline_set_cubic_bezier_progress
 clutter_timeline_set_delay
 clutter_timeline_set_direction
 clutter_timeline_set_duration



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]