[clutter] Migrated internal ClutterBezier to float.
- From: Erick Pérez Castellanos <erickpc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter] Migrated internal ClutterBezier to float.
- Date: Sat, 4 May 2013 14:48:41 +0000 (UTC)
commit 7c6d0251dd19328c911a02c3cafdac55859257ee
Author: Erick Pérez Castellanos <erick red gmail com>
Date: Sat Apr 13 12:50:33 2013 -0400
Migrated internal ClutterBezier to float.
Initial stage of ClutterPath migration to using float.
Naive implementation of ClutterBezier, for now the points along
the curve doesn't move at a regular speed. It is required a more
precise calculation of the length of the curve for that to happen.
Anyway the old implementation worked like this.
clutter/clutter-bezier.c | 481 ++++++++++++++++------------------------------
clutter/clutter-bezier.h | 42 ++--
clutter/clutter-path.c | 3 +-
3 files changed, 185 insertions(+), 341 deletions(-)
---
diff --git a/clutter/clutter-bezier.c b/clutter/clutter-bezier.c
index 7b6ba3c..304d051 100644
--- a/clutter/clutter-bezier.c
+++ b/clutter/clutter-bezier.c
@@ -6,6 +6,7 @@
* Authored By Tomas Frydrych <tf openedhand com>
*
* Copyright (C) 2007 OpenedHand
+ * Copyright (C) 2013 Erick Pérez Castellanos <erick red gmail com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,97 +22,105 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <glib.h>
#include <string.h>
+#include <math.h>
+
+#include <glib.h>
#include "clutter-bezier.h"
#include "clutter-debug.h"
-/*
- * We have some experimental code here to allow for constant velocity
- * movement of actors along the bezier path, this macro enables it.
- */
-#undef CBZ_L2T_INTERPOLATION
-
/****************************************************************************
- * ClutterBezier -- represenation of a cubic bezier curve *
+ * ClutterBezier -- representation of a cubic bezier curve *
* (private; a building block for the public bspline object) *
****************************************************************************/
/*
- * The t parameter of the bezier is from interval <0,1>, so we can use
- * 14.18 format and special multiplication functions that preserve
- * more of the least significant bits but would overflow if the value
- * is > 1
+ * Constants for sampling of the bezier. Float point.
*/
-#define CBZ_T_Q 18
-#define CBZ_T_ONE (1 << CBZ_T_Q)
-#define CBZ_T_MUL(x,y) ((((x) >> 3) * ((y) >> 3)) >> 12)
-#define CBZ_T_POW2(x) CBZ_T_MUL (x, x)
-#define CBZ_T_POW3(x) CBZ_T_MUL (CBZ_T_POW2 (x), x)
-#define CBZ_T_DIV(x,y) ((((x) << 9)/(y)) << 9)
-
-/*
- * Constants for sampling of the bezier
- */
-#define CBZ_T_SAMPLES 128
-#define CBZ_T_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
-#define CBZ_L_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
-
-typedef gint32 _FixedT;
+#define CBZ_T_SAMPLES 128.0
+#define CBZ_T_STEP (1.0 / CBZ_T_SAMPLES)
/*
* This is a private type representing a single cubic bezier
*/
struct _ClutterBezier
{
- /*
- * bezier coefficients -- these are calculated using multiplication and
- * addition from integer input, so these are also integers
- */
- gint ax;
- gint bx;
- gint cx;
- gint dx;
-
- gint ay;
- gint by;
- gint cy;
- gint dy;
-
+ /* bezier coefficients */
+ gfloat ax;
+ gfloat bx;
+ gfloat cx;
+ gfloat dx;
+
+ gfloat ay;
+ gfloat by;
+ gfloat cy;
+ gfloat dy;
+
/* length of the bezier */
- guint length;
-
-#ifdef CBZ_L2T_INTERPOLATION
- /*
- * coefficients for the L -> t bezier; these are calculated from fixed
- * point input, and more specifically numbers that have been normalised
- * to fit <0,1>, so these are also fixed point, and we can used the
- * _FixedT type here.
- */
- _FixedT La;
- _FixedT Lb;
- _FixedT Lc;
- /* _FixedT Ld; == 0 */
-#endif
+ gfloat length;
};
+static gfloat
+_clutter_bezier_t2x (const ClutterBezier *b,
+ gfloat t)
+{
+ return b->ax * (1 - t) * (1 - t) * (1 - t) +
+ b->bx * (1 - t) * (1 - t) * t +
+ b->cx * (1 - t) * t * t +
+ b->dx * t * t * t;
+}
+
+static gfloat
+_clutter_bezier_t2y (const ClutterBezier *b,
+ gfloat t)
+{
+ return b->ay * (1 - t) * (1 - t) * (1 - t) +
+ b->by * (1 - t) * (1 - t) * t +
+ b->cy * (1 - t) * t * t +
+ b->dy * t * t * t;
+}
+
+/*
+ * _clutter_bezier_new:
+ *
+ * Allocate the bezier
+ *
+ * Return value: The new bezier object.
+ */
ClutterBezier *
_clutter_bezier_new (void)
{
return g_slice_new0 (ClutterBezier);
}
+/*
+ * _clutter_bezier_free:
+ * @b: The bezier to free
+ *
+ * Free the object
+ */
void
-_clutter_bezier_free (ClutterBezier * b)
+_clutter_bezier_free (ClutterBezier *b)
{
if (G_LIKELY (b))
- {
- g_slice_free (ClutterBezier, b);
- }
+ g_slice_free (ClutterBezier, b);
}
+/*
+ * _clutter_bezier_clone_and_move:
+ * @b: A #ClutterBezier for cloning
+ * @x: The x coordinates of the new end of the bezier
+ * @y: The y coordinates of the new end of the bezier
+ *
+ * Clone the bezier and move th end-point, leaving both control
+ * points in place.
+ *
+ * Return value: The new bezier object.
+ */
ClutterBezier *
-_clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y)
+_clutter_bezier_clone_and_move (const ClutterBezier *b,
+ gfloat x,
+ gfloat y)
{
ClutterBezier * b2 = _clutter_bezier_new ();
memcpy (b2, b, sizeof (ClutterBezier));
@@ -122,294 +131,124 @@ _clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y)
return b2;
}
-#ifdef CBZ_L2T_INTERPOLATION
/*
- * L is relative advance along the bezier curve from interval <0,1>
+ * _clutter_bezier_advance:
+ * @b: A #ClutterBezier
+ * @L: A relative length
+ * @knot: The point whith the calculated position
+ *
+ * Advances along the bezier @b to relative length @L and returns the coordinances
+ * in @knot
*/
-static _FixedT
-_clutter_bezier_L2t (const ClutterBezier *b, _FixedT L)
+void
+_clutter_bezier_advance (const ClutterBezier *b,
+ gfloat L,
+ ClutterKnot *knot)
{
- _FixedT t = CBZ_T_MUL (b->La, CBZ_T_POW3(L))
- + CBZ_T_MUL (b->Lb, CBZ_T_POW2(L))
- + CBZ_T_MUL (b->Lc, L);
-
- if (t > CBZ_T_ONE)
- t = CBZ_T_ONE;
- else if (t < 0)
- t = 0;
-
- return t;
-}
-#endif
+ gfloat t;
+ t = L;
-static gint
-_clutter_bezier_t2x (const ClutterBezier * b, _FixedT t)
-{
- /*
- * NB -- the int coefficients can be at most 8192 for the multiplication
- * to work in this fashion due to the limits of the 14.18 fixed.
- */
- return ((b->ax*CBZ_T_POW3(t) + b->bx*CBZ_T_POW2(t) + b->cx*t) >> CBZ_T_Q)
- + b->dx;
-}
+ knot->x = _clutter_bezier_t2x (b, t);
+ knot->y = _clutter_bezier_t2y (b, t);
-static gint
-_clutter_bezier_t2y (const ClutterBezier * b, _FixedT t)
-{
- /*
- * NB -- the int coefficients can be at most 8192 for the multiplication
- * to work in this fashion due to the limits of the 14.18 fixed.
- */
- return ((b->ay*CBZ_T_POW3(t) + b->by*CBZ_T_POW2(t) + b->cy*t) >> CBZ_T_Q)
- + b->dy;
+ CLUTTER_NOTE (MISC,
+ "advancing to relative point {%d,%d} by moving a distance equals to: %f, with t: %f",
+ knot->x, knot->y, L, t);
}
/*
- * Advances along the bezier to relative length L and returns the coordinances
- * in knot
+ * _clutter_bezier_init:
+ * @b: A #ClutterBezier
+ * @x_0: x coordinates of the start point of the cubic bezier
+ * @y_0: y coordinates of the start point of the cubic bezier
+ * @x_1: x coordinates of the first control point
+ * @y_1: y coordinates of the first control point
+ * @x_2: x coordinates of the second control point
+ * @y_2: y coordinates of the second control point
+ * @x_3: x coordinates of the end point of the cubic bezier
+ * @y_3: y coordinates of the end point of the cubic bezier
+ *
+ * Initialize the data of the bezier object @b.
*/
void
-_clutter_bezier_advance (const ClutterBezier *b, gint L, ClutterKnot * knot)
-{
-#ifdef CBZ_L2T_INTERPOLATION
- _FixedT t = clutter_bezier_L2t (b, L);
-#else
- _FixedT t = L;
-#endif
-
- knot->x = _clutter_bezier_t2x (b, t);
- knot->y = _clutter_bezier_t2y (b, t);
-
- CLUTTER_NOTE (MISC, "advancing to relative pt %f: t %f, {%d,%d}",
- (double) L / (double) CBZ_T_ONE,
- (double) t / (double) CBZ_T_ONE,
- knot->x, knot->y);
-}
-
-void
_clutter_bezier_init (ClutterBezier *b,
- gint x_0, gint y_0,
- gint x_1, gint y_1,
- gint x_2, gint y_2,
- gint x_3, gint y_3)
+ gfloat x_0,
+ gfloat y_0,
+ gfloat x_1,
+ gfloat y_1,
+ gfloat x_2,
+ gfloat y_2,
+ gfloat x_3,
+ gfloat y_3)
{
- _FixedT t;
- int i;
- int xp = x_0;
- int yp = y_0;
- _FixedT length [CBZ_T_SAMPLES + 1];
-
-#ifdef CBZ_L2T_INTERPOLATION
- int j, k;
- _FixedT L;
- _FixedT t_equalized [CBZ_T_SAMPLES + 1];
-#endif
-
-#if 0
- g_debug ("Initializing bezier at {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
- x0, y0, x1, y1, x2, y2, x3, y3);
-#endif
-
- b->dx = x_0;
- b->dy = y_0;
-
- b->cx = 3 * (x_1 - x_0);
- b->cy = 3 * (y_1 - y_0);
-
- b->bx = 3 * (x_2 - x_1) - b->cx;
- b->by = 3 * (y_2 - y_1) - b->cy;
-
- b->ax = x_3 - 3 * x_2 + 3 * x_1 - x_0;
- b->ay = y_3 - 3 * y_2 + 3 * y_1 - y_0;
-
-#if 0
- g_debug ("Cooeficients {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
- b->ax, b->ay, b->bx, b->by, b->cx, b->cy, b->dx, b->dy);
-#endif
-
- /*
- * Because of the way we do the multiplication in bezeir_t2x,y
- * these coefficients need to be at most 0x1fff; this should be the case,
- * I think, but have added this warning to catch any problems -- if it
- * triggers, we need to change those two functions a bit.
- */
- if (b->ax > 0x1fff || b->bx > 0x1fff || b->cx > 0x1fff)
- g_warning ("Calculated coefficents will result in multiplication "
- "overflow in clutter_bezier_t2x and clutter_bezier_t2y.");
-
- /*
- * Sample the bezier with CBZ_T_SAMPLES and calculate length at
- * each point.
- *
- * We are working with integers here, so we use the fast sqrti function.
- */
- length[0] = 0;
-
+ gfloat t;
+ gint i;
+
+ gfloat xp;
+ gfloat yp;
+
+ CLUTTER_NOTE (MISC,
+ "Initializing bezier at {{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
+ x_0, y_0, x_1, y_1, x_2, y_2, x_3, y_3);
+
+ b->ax = x_0;
+ b->ay = y_0;
+ b->bx = 3 * x_1;
+ b->by = 3 * y_1;
+ b->cx = 3 * x_2;
+ b->cy = 3 * y_2;
+ b->dx = x_3;
+ b->dy = y_3;
+ b->length = 0.0;
+
+ CLUTTER_NOTE (MISC,
+ "Coefficients {{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
+ b->ax, b->ay, b->bx, b->by, b->cx, b->cy, b->dx, b->dy);
+
+ xp = b->ax;
+ yp = b->ay;
for (t = CBZ_T_STEP, i = 1; i <= CBZ_T_SAMPLES; ++i, t += CBZ_T_STEP)
{
- int x = _clutter_bezier_t2x (b, t);
- int y = _clutter_bezier_t2y (b, t);
-
- guint l = cogl_sqrti ((y - yp)*(y - yp) + (x - xp)*(x - xp));
-
- l += length[i-1];
+ gfloat x = _clutter_bezier_t2x (b, t);
+ gfloat y = _clutter_bezier_t2y (b, t);
- length[i] = l;
+ b->length += sqrtf ((y - yp)*(y - yp) + (x - xp)*(x - xp));
xp = x;
yp = y;
}
- b->length = length[CBZ_T_SAMPLES];
-
-#if 0
- g_debug ("length %d", b->length);
-#endif
-
-#ifdef CBZ_L2T_INTERPOLATION
- /*
- * Now normalize the length values, converting them into _FixedT
- */
- for (i = 0; i <= CBZ_T_SAMPLES; ++i)
- {
- length[i] = (length[i] << CBZ_T_Q) / b->length;
- }
-
- /*
- * Now generate a L -> t table such that the L will equidistant
- * over <0,1>
- */
- t_equalized[0] = 0;
-
- for (i = 1, j = 1, L = CBZ_L_STEP; i < CBZ_T_SAMPLES; ++i, L += CBZ_L_STEP)
- {
- _FixedT l1, l2;
- _FixedT d1, d2, d;
- _FixedT t1, t2;
-
- /* find the band for our L */
- for (k = j; k < CBZ_T_SAMPLES; ++k)
- {
- if (L < length[k])
- break;
- }
-
- /*
- * Now we know that L is from (length[k-1],length[k]>
- * We remember k-1 in order not to have to iterate over the
- * whole length array in the next iteration of the main loop
- */
- j = k - 1;
-
- /*
- * Now interpolate equlised t as a weighted average
- */
- l1 = length[k-1];
- l2 = length[k];
- d1 = l2 - L;
- d2 = L - l1;
- d = l2 - l1;
- t1 = (k - 1) * CBZ_T_STEP;
- t2 = k * CBZ_T_STEP;
-
- t_equalized[i] = (t1*d1 + t2*d2)/d;
-
- if (t_equalized[i] < t_equalized[i-1])
- g_debug ("wrong t: L %f, l1 %f, l2 %f, t1 %f, t2 %f",
- (double) (L)/(double)CBZ_T_ONE,
- (double) (l1)/(double)CBZ_T_ONE,
- (double) (l2)/(double)CBZ_T_ONE,
- (double) (t1)/(double)CBZ_T_ONE,
- (double) (t2)/(double)CBZ_T_ONE);
-
- }
-
- t_equalized[CBZ_T_SAMPLES] = CBZ_T_ONE;
-
- /* We now fit a bezier -- at this stage, do a single fit through our values
- * at 0, 1/3, 2/3 and 1
- *
- * FIXME -- do we need to use a better fitting approach to choose the best
- * beziere. The actual curve we acquire this way is not too bad shapwise,
- * but (probably due to rounding errors) the resulting curve no longer
- * satisfies the necessary condition that for L2 > L1, t2 > t1, which
- * causes oscilation.
- */
-
-#if 0
- /*
- * These are the control points we use to calculate the curve coefficients
- * for bezier t(L); these are not needed directly, but are implied in the
- * calculations below.
- *
- * (p0 is 0,0, and p3 is 1,1)
- */
- p1 = (18 * t_equalized[CBZ_T_SAMPLES/3] -
- 9 * t_equalized[2*CBZ_T_SAMPLES/3] +
- 2 << CBZ_T_Q) / 6;
-
- p2 = (18 * t_equalized[2*CBZ_T_SAMPLES/3] -
- 9 * t_equalized[CBZ_T_SAMPLES/3] -
- (5 << CBZ_T_Q)) / 6;
-#endif
-
- b->Lc = (18 * t_equalized[CBZ_T_SAMPLES/3] -
- 9 * t_equalized[2*CBZ_T_SAMPLES/3] +
- (2 << CBZ_T_Q)) >> 1;
-
- b->Lb = (36 * t_equalized[2*CBZ_T_SAMPLES/3] -
- 45 * t_equalized[CBZ_T_SAMPLES/3] -
- (9 << CBZ_T_Q)) >> 1;
-
- b->La = ((27 * (t_equalized[CBZ_T_SAMPLES/3] -
- t_equalized[2*CBZ_T_SAMPLES/3]) +
- (7 << CBZ_T_Q)) >> 1) + CBZ_T_ONE;
-
- g_debug ("t(1/3) %f, t(2/3) %f",
- (double)t_equalized[CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE,
- (double)t_equalized[2*CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE);
-
- g_debug ("L -> t coefficients: %f, %f, %f",
- (double)b->La/(double)CBZ_T_ONE,
- (double)b->Lb/(double)CBZ_T_ONE,
- (double)b->Lc/(double)CBZ_T_ONE);
-
-
- /*
- * For debugging, you can load these values into a spreadsheet and graph
- * them to see how well the approximation matches the data
- */
- for (i = 0; i < CBZ_T_SAMPLES; ++i)
- {
- g_print ("%f, %f, %f\n",
- (double)(i*CBZ_T_STEP)/(double)CBZ_T_ONE,
- (double)(t_equalized[i])/(double)CBZ_T_ONE,
- (double)(clutter_bezier_L2t(b,i*CBZ_T_STEP))/(double)CBZ_T_ONE);
- }
-#endif
+ CLUTTER_NOTE (MISC, "length %f", b->length);
}
/*
- * Moves a control point at indx to location represented by knot
+ * _clutter_bezier_adjust:
+ * @b: A #ClutterBezier object
+ * @knot: The new position of the control point
+ @ @indx: The index of the control point you want to move.
+ *
+ * Moves a control point at index @indx to location represented by @knot
*/
void
-_clutter_bezier_adjust (ClutterBezier * b, ClutterKnot * knot, guint indx)
+_clutter_bezier_adjust (ClutterBezier *b,
+ ClutterKnot *knot,
+ guint indx)
{
- guint x[4], y[4];
+ gfloat x[4], y[4];
g_assert (indx < 4);
-
- x[0] = b->dx;
- y[0] = b->dy;
- x[1] = b->cx / 3 + x[0];
- y[1] = b->cy / 3 + y[0];
+ x[0] = b->ax;
+ y[0] = b->ay;
+
+ x[1] = b->bx;
+ y[1] = b->by;
- x[2] = b->bx / 3 + b->cx + x[1];
- y[2] = b->by / 3 + b->cy + y[1];
+ x[2] = b->cx;
+ y[2] = b->cy;
- x[3] = b->ax + x[0] + b->cx + b->bx;
- y[3] = b->ay + y[0] + b->cy + b->by;
+ x[3] = b->dx;
+ y[3] = b->dy;
x[indx] = knot->x;
y[indx] = knot->y;
@@ -417,7 +256,13 @@ _clutter_bezier_adjust (ClutterBezier * b, ClutterKnot * knot, guint indx)
_clutter_bezier_init (b, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
}
-guint
+/*
+ * _clutter_bezier_get_length:
+ * @b: A #ClutterBezier
+ *
+ * Return value: Returns the length of the bezier
+ */
+gfloat
_clutter_bezier_get_length (const ClutterBezier *b)
{
return b->length;
diff --git a/clutter/clutter-bezier.h b/clutter/clutter-bezier.h
index df9f617..885372f 100644
--- a/clutter/clutter-bezier.h
+++ b/clutter/clutter-bezier.h
@@ -6,6 +6,7 @@
* Authored By Tomas Frydrych <tf openedhand com>
*
* Copyright (C) 2006, 2007 OpenedHand
+ * Copyright (C) 2013 Erick Pérez Castellanos <erick red gmail com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,36 +30,35 @@
G_BEGIN_DECLS
-/* This is used in _clutter_bezier_advance to represent the full
- length of the bezier curve. Anything less than that represents a
- fraction of the length */
-#define CLUTTER_BEZIER_MAX_LENGTH (1 << 18)
-
typedef struct _ClutterBezier ClutterBezier;
-ClutterBezier *_clutter_bezier_new ();
+ClutterBezier *_clutter_bezier_new ();
-void _clutter_bezier_free (ClutterBezier * b);
+void _clutter_bezier_free (ClutterBezier *b);
ClutterBezier *_clutter_bezier_clone_and_move (const ClutterBezier *b,
- gint x,
- gint y);
+ gfloat x,
+ gfloat y);
-void _clutter_bezier_advance (const ClutterBezier *b,
- gint L,
- ClutterKnot *knot);
+void _clutter_bezier_advance (const ClutterBezier *b,
+ gfloat L,
+ ClutterKnot *knot);
-void _clutter_bezier_init (ClutterBezier *b,
- gint x_0, gint y_0,
- gint x_1, gint y_1,
- gint x_2, gint y_2,
- gint x_3, gint y_3);
+void _clutter_bezier_init (ClutterBezier *b,
+ gfloat x_0,
+ gfloat y_0,
+ gfloat x_1,
+ gfloat y_1,
+ gfloat x_2,
+ gfloat y_2,
+ gfloat x_3,
+ gfloat y_3);
-void _clutter_bezier_adjust (ClutterBezier *b,
- ClutterKnot *knot,
- guint indx);
+void _clutter_bezier_adjust (ClutterBezier *b,
+ ClutterKnot *knot,
+ guint indx);
-guint _clutter_bezier_get_length (const ClutterBezier *b);
+gfloat _clutter_bezier_get_length (const ClutterBezier *b);
G_END_DECLS
diff --git a/clutter/clutter-path.c b/clutter/clutter-path.c
index 85c7b13..86aea54 100644
--- a/clutter/clutter-path.c
+++ b/clutter/clutter-path.c
@@ -1458,8 +1458,7 @@ clutter_path_get_position (ClutterPath *path,
else
{
_clutter_bezier_advance (node->bezier,
- point_distance * CLUTTER_BEZIER_MAX_LENGTH
- / node->length,
+ (gfloat) point_distance / (gfloat) node->length,
position);
}
break;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]