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