1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Tomas Frydrych  <tf@openedhand.com>
7  *
8  * Copyright (C) 2007 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "clutter-build-config.h"
25 
26 #include <glib.h>
27 #include <string.h>
28 #include "clutter-bezier.h"
29 #include "clutter-debug.h"
30 
31 /*
32  * We have some experimental code here to allow for constant velocity
33  * movement of actors along the bezier path, this macro enables it.
34  */
35 #undef CBZ_L2T_INTERPOLATION
36 
37 /****************************************************************************
38  * ClutterBezier -- represenation of a cubic bezier curve                   *
39  * (private; a building block for the public bspline object)                *
40  ****************************************************************************/
41 
42 /*
43  * The t parameter of the bezier is from interval <0,1>, so we can use
44  * 14.18 format and special multiplication functions that preserve
45  * more of the least significant bits but would overflow if the value
46  * is > 1
47  */
48 #define CBZ_T_Q 18
49 #define CBZ_T_ONE (1 << CBZ_T_Q)
50 #define CBZ_T_MUL(x,y) ((((x) >> 3) * ((y) >> 3)) >> 12)
51 #define CBZ_T_POW2(x) CBZ_T_MUL (x, x)
52 #define CBZ_T_POW3(x) CBZ_T_MUL (CBZ_T_POW2 (x), x)
53 #define CBZ_T_DIV(x,y) ((((x) << 9)/(y)) << 9)
54 
55 /*
56  * Constants for sampling of the bezier
57  */
58 #define CBZ_T_SAMPLES 128
59 #define CBZ_T_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
60 #define CBZ_L_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
61 
62 #define FIXED_BITS (32)
63 #define FIXED_Q (FIXED_BITS - 16)
64 #define FIXED_FROM_INT(x) ((x) << FIXED_Q)
65 
66 typedef gint32 _FixedT;
67 
68 /*
69  * This is a private type representing a single cubic bezier
70  */
71 struct _ClutterBezier
72 {
73   /*
74    * bezier coefficients -- these are calculated using multiplication and
75    * addition from integer input, so these are also integers
76    */
77   gint ax;
78   gint bx;
79   gint cx;
80   gint dx;
81 
82   gint ay;
83   gint by;
84   gint cy;
85   gint dy;
86 
87   /* length of the bezier */
88   guint length;
89 
90 #ifdef CBZ_L2T_INTERPOLATION
91   /*
92    * coefficients for the L -> t bezier; these are calculated from fixed
93    * point input, and more specifically numbers that have been normalised
94    * to fit <0,1>, so these are also fixed point, and we can used the
95    * _FixedT type here.
96    */
97   _FixedT La;
98   _FixedT Lb;
99   _FixedT Lc;
100   /*  _FixedT Ld; == 0 */
101 #endif
102 };
103 
104 ClutterBezier *
_clutter_bezier_new(void)105 _clutter_bezier_new (void)
106 {
107   return g_slice_new0 (ClutterBezier);
108 }
109 
110 void
_clutter_bezier_free(ClutterBezier * b)111 _clutter_bezier_free (ClutterBezier * b)
112 {
113   if (G_LIKELY (b))
114     {
115       g_slice_free (ClutterBezier, b);
116     }
117 }
118 
119 ClutterBezier *
_clutter_bezier_clone_and_move(const ClutterBezier * b,gint x,gint y)120 _clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y)
121 {
122   ClutterBezier * b2 = _clutter_bezier_new ();
123   memcpy (b2, b, sizeof (ClutterBezier));
124 
125   b2->dx += x;
126   b2->dy += y;
127 
128   return b2;
129 }
130 
131 #ifdef CBZ_L2T_INTERPOLATION
132 /*
133  * L is relative advance along the bezier curve from interval <0,1>
134  */
135 static _FixedT
_clutter_bezier_L2t(const ClutterBezier * b,_FixedT L)136 _clutter_bezier_L2t (const ClutterBezier *b, _FixedT L)
137 {
138   _FixedT t = CBZ_T_MUL (b->La, CBZ_T_POW3(L))
139     +  CBZ_T_MUL (b->Lb, CBZ_T_POW2(L))
140     +  CBZ_T_MUL (b->Lc, L);
141 
142   if (t > CBZ_T_ONE)
143     t = CBZ_T_ONE;
144   else if (t < 0)
145     t = 0;
146 
147   return t;
148 }
149 #endif
150 
151 static gint
_clutter_bezier_t2x(const ClutterBezier * b,_FixedT t)152 _clutter_bezier_t2x (const ClutterBezier * b, _FixedT t)
153 {
154   /*
155    * NB -- the int coefficients can be at most 8192 for the multiplication
156    * to work in this fashion due to the limits of the 14.18 fixed.
157    */
158   return ((b->ax*CBZ_T_POW3(t) + b->bx*CBZ_T_POW2(t) + b->cx*t) >> CBZ_T_Q)
159     + b->dx;
160 }
161 
162 static gint
_clutter_bezier_t2y(const ClutterBezier * b,_FixedT t)163 _clutter_bezier_t2y (const ClutterBezier * b, _FixedT t)
164 {
165   /*
166    * NB -- the int coefficients can be at most 8192 for the multiplication
167    * to work in this fashion due to the limits of the 14.18 fixed.
168    */
169   return ((b->ay*CBZ_T_POW3(t) + b->by*CBZ_T_POW2(t) + b->cy*t) >> CBZ_T_Q)
170     + b->dy;
171 }
172 
173 /*
174  * Advances along the bezier to relative length L and returns the coordinances
175  * in knot
176  */
177 void
_clutter_bezier_advance(const ClutterBezier * b,gint L,ClutterKnot * knot)178 _clutter_bezier_advance (const ClutterBezier *b, gint L, ClutterKnot * knot)
179 {
180 #ifdef CBZ_L2T_INTERPOLATION
181   _FixedT t = clutter_bezier_L2t (b, L);
182 #else
183   _FixedT t = L;
184 #endif
185 
186   knot->x = _clutter_bezier_t2x (b, t);
187   knot->y = _clutter_bezier_t2y (b, t);
188 
189   CLUTTER_NOTE (MISC, "advancing to relative pt %f: t %f, {%d,%d}",
190                 (double) L / (double) CBZ_T_ONE,
191                 (double) t / (double) CBZ_T_ONE,
192                 knot->x, knot->y);
193 }
194 
195 static int
sqrti(int number)196 sqrti (int number)
197 {
198 #if defined __SSE2__
199     /* The GCC built-in with SSE2 (sqrtsd) is up to twice as fast as
200      * the pure integer code below. It is also more accurate.
201      */
202     return __builtin_sqrt (number);
203 #else
204     /* This is a fixed point implementation of the Quake III sqrt algorithm,
205      * described, for example, at
206      *   http://www.codemaestro.com/reviews/review00000105.html
207      *
208      * While the original QIII is extremely fast, the use of floating division
209      * and multiplication makes it perform very on arm processors without FPU.
210      *
211      * The key to successfully replacing the floating point operations with
212      * fixed point is in the choice of the fixed point format. The QIII
213      * algorithm does not calculate the square root, but its reciprocal ('y'
214      * below), which is only at the end turned to the inverse value. In order
215      * for the algorithm to produce satisfactory results, the reciprocal value
216      * must be represented with sufficient precission; the 16.16 we use
217      * elsewhere in clutter is not good enough, and 10.22 is used instead.
218      */
219     _FixedT x;
220     uint32_t y_1;        /* 10.22 fixed point */
221     uint32_t f = 0x600000; /* '1.5' as 10.22 fixed */
222 
223     union
224     {
225 	float f;
226 	uint32_t i;
227     } flt, flt2;
228 
229     flt.f = number;
230 
231     x = FIXED_FROM_INT (number) / 2;
232 
233     /* The QIII initial estimate */
234     flt.i = 0x5f3759df - ( flt.i >> 1 );
235 
236     /* Now, we convert the float to 10.22 fixed. We exploit the mechanism
237      * described at http://www.d6.com/users/checker/pdfs/gdmfp.pdf.
238      *
239      * We want 22 bit fraction; a single precission float uses 23 bit
240      * mantisa, so we only need to add 2^(23-22) (no need for the 1.5
241      * multiplier as we are only dealing with positive numbers).
242      *
243      * Note: we have to use two separate variables here -- for some reason,
244      * if we try to use just the flt variable, gcc on ARM optimises the whole
245      * addition out, and it all goes pear shape, since without it, the bits
246      * in the float will not be correctly aligned.
247      */
248     flt2.f = flt.f + 2.0;
249     flt2.i &= 0x7FFFFF;
250 
251     /* Now we correct the estimate */
252     y_1 = (flt2.i >> 11) * (flt2.i >> 11);
253     y_1 = (y_1 >> 8) * (x >> 8);
254 
255     y_1 = f - y_1;
256     flt2.i = (flt2.i >> 11) * (y_1 >> 11);
257 
258     /* If the original argument is less than 342, we do another
259      * iteration to improve precission (for arguments >= 342, the single
260      * iteration produces generally better results).
261      */
262     if (x < 171)
263       {
264 	y_1 = (flt2.i >> 11) * (flt2.i >> 11);
265 	y_1 = (y_1 >> 8) * (x >> 8);
266 
267 	y_1 = f - y_1;
268 	flt2.i = (flt2.i >> 11) * (y_1 >> 11);
269       }
270 
271     /* Invert, round and convert from 10.22 to an integer
272      * 0x1e3c68 is a magical rounding constant that produces slightly
273      * better results than 0x200000.
274      */
275     return (number * flt2.i + 0x1e3c68) >> 22;
276 #endif
277 }
278 
279 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)280 _clutter_bezier_init (ClutterBezier *b,
281 		     gint x_0, gint y_0,
282 		     gint x_1, gint y_1,
283 		     gint x_2, gint y_2,
284 		     gint x_3, gint y_3)
285 {
286   _FixedT t;
287   int i;
288   int xp = x_0;
289   int yp = y_0;
290   _FixedT length [CBZ_T_SAMPLES + 1];
291 
292 #ifdef CBZ_L2T_INTERPOLATION
293   int j, k;
294   _FixedT L;
295   _FixedT t_equalized [CBZ_T_SAMPLES + 1];
296 #endif
297 
298 #if 0
299   g_debug ("Initializing bezier at {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
300            x0, y0, x1, y1, x2, y2, x3, y3);
301 #endif
302 
303   b->dx = x_0;
304   b->dy = y_0;
305 
306   b->cx = 3 * (x_1 - x_0);
307   b->cy = 3 * (y_1 - y_0);
308 
309   b->bx = 3 * (x_2 - x_1) - b->cx;
310   b->by = 3 * (y_2 - y_1) - b->cy;
311 
312   b->ax = x_3 - 3 * x_2 + 3 * x_1 - x_0;
313   b->ay = y_3 - 3 * y_2 + 3 * y_1 - y_0;
314 
315 #if 0
316   g_debug ("Cooeficients {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
317            b->ax, b->ay, b->bx, b->by, b->cx, b->cy, b->dx, b->dy);
318 #endif
319 
320   /*
321    * Because of the way we do the multiplication in bezeir_t2x,y
322    * these coefficients need to be at most 0x1fff; this should be the case,
323    * I think, but have added this warning to catch any problems -- if it
324    * triggers, we need to change those two functions a bit.
325    */
326   if (b->ax > 0x1fff || b->bx > 0x1fff || b->cx > 0x1fff)
327     g_warning ("Calculated coefficients will result in multiplication "
328                "overflow in clutter_bezier_t2x and clutter_bezier_t2y.");
329 
330   /*
331    * Sample the bezier with CBZ_T_SAMPLES and calculate length at
332    * each point.
333    *
334    * We are working with integers here, so we use the fast sqrti function.
335    */
336   length[0] = 0;
337 
338   for (t = CBZ_T_STEP, i = 1; i <= CBZ_T_SAMPLES; ++i, t += CBZ_T_STEP)
339     {
340       int x = _clutter_bezier_t2x (b, t);
341       int y = _clutter_bezier_t2y (b, t);
342 
343       guint l = sqrti ((y - yp)*(y - yp) + (x - xp)*(x - xp));
344 
345       l += length[i-1];
346 
347       length[i] = l;
348 
349       xp = x;
350       yp = y;
351     }
352 
353   b->length = length[CBZ_T_SAMPLES];
354 
355 #if 0
356   g_debug ("length %d", b->length);
357 #endif
358 
359 #ifdef CBZ_L2T_INTERPOLATION
360   /*
361    * Now normalize the length values, converting them into _FixedT
362    */
363   for (i = 0; i <= CBZ_T_SAMPLES; ++i)
364     {
365       length[i] = (length[i] << CBZ_T_Q) / b->length;
366     }
367 
368   /*
369    * Now generate a L -> t table such that the L will equidistant
370    * over <0,1>
371    */
372   t_equalized[0] = 0;
373 
374   for (i = 1, j = 1, L = CBZ_L_STEP; i < CBZ_T_SAMPLES; ++i, L += CBZ_L_STEP)
375     {
376       _FixedT l1, l2;
377       _FixedT d1, d2, d;
378       _FixedT t1, t2;
379 
380       /* find the band for our L */
381       for (k = j; k < CBZ_T_SAMPLES; ++k)
382 	{
383           if (L < length[k])
384             break;
385 	}
386 
387       /*
388        * Now we know that L is from (length[k-1],length[k]>
389        * We remember k-1 in order not to have to iterate over the
390        * whole length array in the next iteration of the main loop
391        */
392       j = k - 1;
393 
394       /*
395        * Now interpolate equlised t as a weighted average
396        */
397       l1 = length[k-1];
398       l2 = length[k];
399       d1 = l2 - L;
400       d2 = L - l1;
401       d = l2 - l1;
402       t1 = (k - 1) * CBZ_T_STEP;
403       t2 = k * CBZ_T_STEP;
404 
405       t_equalized[i] = (t1*d1 + t2*d2)/d;
406 
407       if (t_equalized[i] < t_equalized[i-1])
408         g_debug ("wrong t: L %f, l1 %f, l2 %f, t1 %f, t2 %f",
409                  (double) (L)/(double)CBZ_T_ONE,
410                  (double) (l1)/(double)CBZ_T_ONE,
411                  (double) (l2)/(double)CBZ_T_ONE,
412                  (double) (t1)/(double)CBZ_T_ONE,
413                  (double) (t2)/(double)CBZ_T_ONE);
414 
415     }
416 
417   t_equalized[CBZ_T_SAMPLES] = CBZ_T_ONE;
418 
419   /* We now fit a bezier -- at this stage, do a single fit through our values
420    * at 0, 1/3, 2/3 and 1
421    *
422    * FIXME -- do we need to  use a better fitting approach to choose the best
423    * beziere. The actual curve we acquire this way is not too bad shapwise,
424    * but (probably due to rounding errors) the resulting curve no longer
425    * satisfies the necessary condition that for L2 > L1, t2 > t1, which
426    * causes oscilation.
427    */
428 
429 #if 0
430   /*
431    * These are the control points we use to calculate the curve coefficients
432    * for bezier t(L); these are not needed directly, but are implied in the
433    * calculations below.
434    *
435    * (p0 is 0,0, and p3 is 1,1)
436    */
437   p1 = (18 * t_equalized[CBZ_T_SAMPLES/3] -
438         9 * t_equalized[2*CBZ_T_SAMPLES/3] +
439         2 << CBZ_T_Q) / 6;
440 
441   p2 = (18 * t_equalized[2*CBZ_T_SAMPLES/3] -
442         9 * t_equalized[CBZ_T_SAMPLES/3] -
443         (5 << CBZ_T_Q)) / 6;
444 #endif
445 
446   b->Lc = (18 * t_equalized[CBZ_T_SAMPLES/3] -
447            9 * t_equalized[2*CBZ_T_SAMPLES/3] +
448            (2 << CBZ_T_Q)) >> 1;
449 
450   b->Lb = (36 * t_equalized[2*CBZ_T_SAMPLES/3] -
451            45 * t_equalized[CBZ_T_SAMPLES/3] -
452            (9 << CBZ_T_Q)) >> 1;
453 
454   b->La = ((27 * (t_equalized[CBZ_T_SAMPLES/3] -
455                  t_equalized[2*CBZ_T_SAMPLES/3]) +
456             (7 << CBZ_T_Q)) >> 1) + CBZ_T_ONE;
457 
458   g_debug ("t(1/3) %f, t(2/3) %f",
459            (double)t_equalized[CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE,
460            (double)t_equalized[2*CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE);
461 
462   g_debug ("L -> t coefficients: %f, %f, %f",
463            (double)b->La/(double)CBZ_T_ONE,
464            (double)b->Lb/(double)CBZ_T_ONE,
465            (double)b->Lc/(double)CBZ_T_ONE);
466 
467 
468   /*
469    * For debugging, you can load these values into a spreadsheet and graph
470    * them to see how well the approximation matches the data
471    */
472   for (i = 0; i < CBZ_T_SAMPLES; ++i)
473     {
474       g_print ("%f, %f, %f\n",
475                (double)(i*CBZ_T_STEP)/(double)CBZ_T_ONE,
476                (double)(t_equalized[i])/(double)CBZ_T_ONE,
477                (double)(clutter_bezier_L2t(b,i*CBZ_T_STEP))/(double)CBZ_T_ONE);
478     }
479 #endif
480 }
481 
482 /*
483  * Moves a control point at indx to location represented by knot
484  */
485 void
_clutter_bezier_adjust(ClutterBezier * b,ClutterKnot * knot,guint indx)486 _clutter_bezier_adjust (ClutterBezier * b, ClutterKnot * knot, guint indx)
487 {
488   guint x[4], y[4];
489 
490   g_assert (indx < 4);
491 
492   x[0] = b->dx;
493   y[0] = b->dy;
494 
495   x[1] = b->cx / 3 + x[0];
496   y[1] = b->cy / 3 + y[0];
497 
498   x[2] = b->bx / 3 + b->cx + x[1];
499   y[2] = b->by / 3 + b->cy + y[1];
500 
501   x[3] = b->ax + x[0] + b->cx + b->bx;
502   y[3] = b->ay + y[0] + b->cy + b->by;
503 
504   x[indx] = knot->x;
505   y[indx] = knot->y;
506 
507   _clutter_bezier_init (b, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
508 }
509 
510 guint
_clutter_bezier_get_length(const ClutterBezier * b)511 _clutter_bezier_get_length (const ClutterBezier *b)
512 {
513   return b->length;
514 }
515