~gnome3-team/mutter/trunk

« back to all changes in this revision

Viewing changes to cogl/cogl/cogl-quaternion.c

  • Committer: Rui Matos
  • Date: 2016-04-27 16:36:25 UTC
  • mfrom: (0.87.3184)
  • Revision ID: git-v1:3fcbe1d3ec5c9208dde080f7e9dac24e4c379bc0
Merge cogl's cogl-1.22 branch into mutter

https://bugzilla.gnome.org/show_bug.cgi?id=760439

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cogl
 
3
 *
 
4
 * A Low Level GPU Graphics and Utilities API
 
5
 *
 
6
 * Copyright (C) 2010 Intel Corporation.
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person
 
9
 * obtaining a copy of this software and associated documentation
 
10
 * files (the "Software"), to deal in the Software without
 
11
 * restriction, including without limitation the rights to use, copy,
 
12
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 
13
 * of the Software, and to permit persons to whom the Software is
 
14
 * furnished to do so, subject to the following conditions:
 
15
 *
 
16
 * The above copyright notice and this permission notice shall be
 
17
 * included in all copies or substantial portions of the Software.
 
18
 *
 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
20
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
21
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
22
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
23
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
24
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
25
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
26
 * SOFTWARE.
 
27
 *
 
28
 * Authors:
 
29
 *   Robert Bragg <robert@linux.intel.com>
 
30
 *
 
31
 * Various references relating to quaternions:
 
32
 *
 
33
 * http://www.cs.caltech.edu/courses/cs171/quatut.pdf
 
34
 * http://mathworld.wolfram.com/Quaternion.html
 
35
 * http://www.gamedev.net/reference/articles/article1095.asp
 
36
 * http://www.cprogramming.com/tutorial/3d/quaternions.html
 
37
 * http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm
 
38
 * http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
 
39
 * 3D Maths Primer for Graphics and Game Development ISBN-10: 1556229119
 
40
 */
 
41
 
 
42
#ifdef HAVE_CONFIG_H
 
43
#include "config.h"
 
44
#endif
 
45
 
 
46
#include <cogl-util.h>
 
47
#include <cogl-quaternion.h>
 
48
#include <cogl-quaternion-private.h>
 
49
#include <cogl-matrix.h>
 
50
#include <cogl-vector.h>
 
51
#include <cogl-euler.h>
 
52
#include "cogl-gtype-private.h"
 
53
 
 
54
#include <string.h>
 
55
#include <math.h>
 
56
 
 
57
#define FLOAT_EPSILON 1e-03
 
58
 
 
59
COGL_GTYPE_DEFINE_BOXED (Quaternion, quaternion,
 
60
                         cogl_quaternion_copy,
 
61
                         cogl_quaternion_free);
 
62
 
 
63
static CoglQuaternion zero_quaternion =
 
64
{
 
65
  0.0,  0.0, 0.0, 0.0,
 
66
};
 
67
 
 
68
static CoglQuaternion identity_quaternion =
 
69
{
 
70
  1.0,  0.0, 0.0, 0.0,
 
71
};
 
72
 
 
73
/* This function is just here to be called from GDB so we don't really
 
74
   want to put a declaration in a header and we just add it here to
 
75
   avoid a warning */
 
76
void
 
77
_cogl_quaternion_print (CoglQuaternion *quarternion);
 
78
 
 
79
void
 
80
_cogl_quaternion_print (CoglQuaternion *quaternion)
 
81
{
 
82
  g_print ("[ %6.4f (%6.4f, %6.4f, %6.4f)]\n",
 
83
           quaternion->w,
 
84
           quaternion->x,
 
85
           quaternion->y,
 
86
           quaternion->z);
 
87
}
 
88
 
 
89
void
 
90
cogl_quaternion_init (CoglQuaternion *quaternion,
 
91
                      float angle,
 
92
                      float x,
 
93
                      float y,
 
94
                      float z)
 
95
{
 
96
  float axis[3] = { x, y, z};
 
97
  cogl_quaternion_init_from_angle_vector (quaternion, angle, axis);
 
98
}
 
99
 
 
100
void
 
101
cogl_quaternion_init_from_angle_vector (CoglQuaternion *quaternion,
 
102
                                        float angle,
 
103
                                        const float *axis3f_in)
 
104
{
 
105
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
106
   * in this form:
 
107
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
108
   */
 
109
  float axis[3];
 
110
  float half_angle;
 
111
  float sin_half_angle;
 
112
 
 
113
  /* XXX: Should we make cogl_vector3_normalize have separate in and
 
114
   * out args? */
 
115
  axis[0] = axis3f_in[0];
 
116
  axis[1] = axis3f_in[1];
 
117
  axis[2] = axis3f_in[2];
 
118
  cogl_vector3_normalize (axis);
 
119
 
 
120
  half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f;
 
121
  sin_half_angle = sinf (half_angle);
 
122
 
 
123
  quaternion->w = cosf (half_angle);
 
124
 
 
125
  quaternion->x = axis[0] * sin_half_angle;
 
126
  quaternion->y = axis[1] * sin_half_angle;
 
127
  quaternion->z = axis[2] * sin_half_angle;
 
128
 
 
129
  cogl_quaternion_normalize (quaternion);
 
130
}
 
131
 
 
132
void
 
133
cogl_quaternion_init_identity (CoglQuaternion *quaternion)
 
134
{
 
135
  quaternion->w = 1.0;
 
136
 
 
137
  quaternion->x = 0.0;
 
138
  quaternion->y = 0.0;
 
139
  quaternion->z = 0.0;
 
140
}
 
141
 
 
142
void
 
143
cogl_quaternion_init_from_array (CoglQuaternion *quaternion,
 
144
                                 const float *array)
 
145
{
 
146
  quaternion->w = array[0];
 
147
  quaternion->x = array[1];
 
148
  quaternion->y = array[2];
 
149
  quaternion->z = array[3];
 
150
}
 
151
 
 
152
void
 
153
cogl_quaternion_init_from_x_rotation (CoglQuaternion *quaternion,
 
154
                                      float angle)
 
155
{
 
156
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
157
   * in this form:
 
158
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
159
   */
 
160
  float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f;
 
161
 
 
162
  quaternion->w = cosf (half_angle);
 
163
 
 
164
  quaternion->x = sinf (half_angle);
 
165
  quaternion->y = 0.0f;
 
166
  quaternion->z = 0.0f;
 
167
}
 
168
 
 
169
void
 
170
cogl_quaternion_init_from_y_rotation (CoglQuaternion *quaternion,
 
171
                                      float angle)
 
172
{
 
173
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
174
   * in this form:
 
175
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
176
   */
 
177
  float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f;
 
178
 
 
179
  quaternion->w = cosf (half_angle);
 
180
 
 
181
  quaternion->x = 0.0f;
 
182
  quaternion->y = sinf (half_angle);
 
183
  quaternion->z = 0.0f;
 
184
}
 
185
 
 
186
void
 
187
cogl_quaternion_init_from_z_rotation (CoglQuaternion *quaternion,
 
188
                                      float angle)
 
189
{
 
190
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
191
   * in this form:
 
192
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
193
   */
 
194
  float half_angle = angle * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f;
 
195
 
 
196
  quaternion->w = cosf (half_angle);
 
197
 
 
198
  quaternion->x = 0.0f;
 
199
  quaternion->y = 0.0f;
 
200
  quaternion->z = sinf (half_angle);
 
201
}
 
202
 
 
203
void
 
204
cogl_quaternion_init_from_euler (CoglQuaternion *quaternion,
 
205
                                 const CoglEuler *euler)
 
206
{
 
207
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
208
   * in this form:
 
209
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
210
   */
 
211
  float sin_heading =
 
212
    sinf (euler->heading * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
213
  float sin_pitch =
 
214
    sinf (euler->pitch * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
215
  float sin_roll =
 
216
    sinf (euler->roll * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
217
  float cos_heading =
 
218
    cosf (euler->heading * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
219
  float cos_pitch =
 
220
    cosf (euler->pitch * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
221
  float cos_roll =
 
222
    cosf (euler->roll * _COGL_QUATERNION_DEGREES_TO_RADIANS * 0.5f);
 
223
 
 
224
  quaternion->w =
 
225
    cos_heading * cos_pitch * cos_roll +
 
226
    sin_heading * sin_pitch * sin_roll;
 
227
 
 
228
  quaternion->x =
 
229
    cos_heading * sin_pitch * cos_roll +
 
230
    sin_heading * cos_pitch * sin_roll;
 
231
  quaternion->y =
 
232
    sin_heading * cos_pitch * cos_roll -
 
233
    cos_heading * sin_pitch * sin_roll;
 
234
  quaternion->z =
 
235
    cos_heading * cos_pitch * sin_roll -
 
236
    sin_heading * sin_pitch * cos_roll;
 
237
}
 
238
 
 
239
void
 
240
cogl_quaternion_init_from_quaternion (CoglQuaternion *quaternion,
 
241
                                      CoglQuaternion *src)
 
242
{
 
243
  memcpy (quaternion, src, sizeof (float) * 4);
 
244
}
 
245
 
 
246
/* XXX: it could be nice to make something like this public... */
 
247
/*
 
248
 * COGL_MATRIX_READ:
 
249
 * @MATRIX: A 4x4 transformation matrix
 
250
 * @ROW: The row of the value you want to read
 
251
 * @COLUMN: The column of the value you want to read
 
252
 *
 
253
 * Reads a value from the given matrix using integers to index
 
254
 * into the matrix.
 
255
 */
 
256
#define COGL_MATRIX_READ(MATRIX, ROW, COLUMN) \
 
257
  (((const float *)matrix)[COLUMN * 4 + ROW])
 
258
 
 
259
void
 
260
cogl_quaternion_init_from_matrix (CoglQuaternion *quaternion,
 
261
                                  const CoglMatrix *matrix)
 
262
{
 
263
  /* Algorithm devised by Ken Shoemake, Ref:
 
264
   * http://campar.in.tum.de/twiki/pub/Chair/DwarfTutorial/quatut.pdf
 
265
   */
 
266
 
 
267
  /* 3D maths literature refers to the diagonal of a matrix as the
 
268
   * "trace" of a matrix... */
 
269
  float trace = matrix->xx + matrix->yy + matrix->zz;
 
270
  float root;
 
271
 
 
272
  if (trace > 0.0f)
 
273
    {
 
274
      root = sqrtf (trace + 1);
 
275
      quaternion->w = root * 0.5f;
 
276
      root = 0.5f / root;
 
277
      quaternion->x = (matrix->zy - matrix->yz) * root;
 
278
      quaternion->y = (matrix->xz - matrix->zx) * root;
 
279
      quaternion->z = (matrix->yx - matrix->xy) * root;
 
280
    }
 
281
  else
 
282
    {
 
283
#define X 0
 
284
#define Y 1
 
285
#define Z 2
 
286
#define W 3
 
287
      int h = X;
 
288
      if (matrix->yy > matrix->xx)
 
289
        h = Y;
 
290
      if (matrix->zz > COGL_MATRIX_READ (matrix, h, h))
 
291
        h = Z;
 
292
      switch (h)
 
293
        {
 
294
#define CASE_MACRO(i, j, k, I, J, K) \
 
295
        case I: \
 
296
          root = sqrtf ((COGL_MATRIX_READ (matrix, I, I) - \
 
297
                         (COGL_MATRIX_READ (matrix, J, J) + \
 
298
                          COGL_MATRIX_READ (matrix, K, K))) + \
 
299
                        COGL_MATRIX_READ (matrix, W, W)); \
 
300
          quaternion->i = root * 0.5f;\
 
301
          root = 0.5f / root;\
 
302
          quaternion->j = (COGL_MATRIX_READ (matrix, I, J) + \
 
303
                           COGL_MATRIX_READ (matrix, J, I)) * root; \
 
304
          quaternion->k = (COGL_MATRIX_READ (matrix, K, I) + \
 
305
                           COGL_MATRIX_READ (matrix, I, K)) * root; \
 
306
          quaternion->w = (COGL_MATRIX_READ (matrix, K, J) - \
 
307
                           COGL_MATRIX_READ (matrix, J, K)) * root;\
 
308
          break
 
309
          CASE_MACRO (x, y, z, X, Y, Z);
 
310
          CASE_MACRO (y, z, x, Y, Z, X);
 
311
          CASE_MACRO (z, x, y, Z, X, Y);
 
312
#undef CASE_MACRO
 
313
#undef X
 
314
#undef Y
 
315
#undef Z
 
316
        }
 
317
    }
 
318
 
 
319
  if (matrix->ww != 1.0f)
 
320
    {
 
321
      float s = 1.0 / sqrtf (matrix->ww);
 
322
      quaternion->w *= s;
 
323
      quaternion->x *= s;
 
324
      quaternion->y *= s;
 
325
      quaternion->z *= s;
 
326
    }
 
327
}
 
328
 
 
329
CoglBool
 
330
cogl_quaternion_equal (const void *v1, const void *v2)
 
331
{
 
332
  const CoglQuaternion *a = v1;
 
333
  const CoglQuaternion *b = v2;
 
334
 
 
335
  _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE);
 
336
  _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE);
 
337
 
 
338
  if (v1 == v2)
 
339
    return TRUE;
 
340
 
 
341
  return (a->w == b->w &&
 
342
          a->x == b->x &&
 
343
          a->y == b->y &&
 
344
          a->z == b->z);
 
345
}
 
346
 
 
347
CoglQuaternion *
 
348
cogl_quaternion_copy (const CoglQuaternion *src)
 
349
{
 
350
  if (G_LIKELY (src))
 
351
    {
 
352
      CoglQuaternion *new = g_slice_new (CoglQuaternion);
 
353
      memcpy (new, src, sizeof (float) * 4);
 
354
      return new;
 
355
    }
 
356
  else
 
357
    return NULL;
 
358
}
 
359
 
 
360
void
 
361
cogl_quaternion_free (CoglQuaternion *quaternion)
 
362
{
 
363
  g_slice_free (CoglQuaternion, quaternion);
 
364
}
 
365
 
 
366
float
 
367
cogl_quaternion_get_rotation_angle (const CoglQuaternion *quaternion)
 
368
{
 
369
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
370
   * in this form:
 
371
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
372
   */
 
373
 
 
374
  /* FIXME: clamp [-1, 1] */
 
375
  return 2.0f * acosf (quaternion->w) * _COGL_QUATERNION_RADIANS_TO_DEGREES;
 
376
}
 
377
 
 
378
void
 
379
cogl_quaternion_get_rotation_axis (const CoglQuaternion *quaternion,
 
380
                                   float *vector3)
 
381
{
 
382
  float sin_half_angle_sqr;
 
383
  float one_over_sin_angle_over_2;
 
384
 
 
385
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
386
   * in this form:
 
387
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
388
   */
 
389
 
 
390
  /* NB: sin²(𝜃) + cos²(𝜃) = 1 */
 
391
 
 
392
  sin_half_angle_sqr = 1.0f - quaternion->w * quaternion->w;
 
393
 
 
394
  if (sin_half_angle_sqr <= 0.0f)
 
395
    {
 
396
      /* Either an identity quaternion or numerical imprecision.
 
397
       * Either way we return an arbitrary vector. */
 
398
      vector3[0] = 1;
 
399
      vector3[1] = 0;
 
400
      vector3[2] = 0;
 
401
      return;
 
402
    }
 
403
 
 
404
  /* Calculate 1 / sin(𝜃/2) */
 
405
  one_over_sin_angle_over_2 = 1.0f / sqrtf (sin_half_angle_sqr);
 
406
 
 
407
  vector3[0] = quaternion->x * one_over_sin_angle_over_2;
 
408
  vector3[1] = quaternion->y * one_over_sin_angle_over_2;
 
409
  vector3[2] = quaternion->z * one_over_sin_angle_over_2;
 
410
}
 
411
 
 
412
void
 
413
cogl_quaternion_normalize (CoglQuaternion *quaternion)
 
414
{
 
415
  float slen = _COGL_QUATERNION_NORM (quaternion);
 
416
  float factor = 1.0f / sqrtf (slen);
 
417
 
 
418
  quaternion->x *= factor;
 
419
  quaternion->y *= factor;
 
420
  quaternion->z *= factor;
 
421
 
 
422
  quaternion->w *= factor;
 
423
 
 
424
  return;
 
425
}
 
426
 
 
427
float
 
428
cogl_quaternion_dot_product (const CoglQuaternion *a,
 
429
                             const CoglQuaternion *b)
 
430
{
 
431
  return a->w * b->w + a->x * b->x + a->y * b->y + a->z * b->z;
 
432
}
 
433
 
 
434
void
 
435
cogl_quaternion_invert (CoglQuaternion *quaternion)
 
436
{
 
437
  quaternion->x = -quaternion->x;
 
438
  quaternion->y = -quaternion->y;
 
439
  quaternion->z = -quaternion->z;
 
440
}
 
441
 
 
442
void
 
443
cogl_quaternion_multiply (CoglQuaternion *result,
 
444
                          const CoglQuaternion *a,
 
445
                          const CoglQuaternion *b)
 
446
{
 
447
  float w = a->w;
 
448
  float x = a->x;
 
449
  float y = a->y;
 
450
  float z = a->z;
 
451
 
 
452
  _COGL_RETURN_IF_FAIL (b != result);
 
453
 
 
454
  result->w = w * b->w - x * b->x - y * b->y - z * b->z;
 
455
 
 
456
  result->x = w * b->x + x * b->w + y * b->z - z * b->y;
 
457
  result->y = w * b->y + y * b->w + z * b->x - x * b->z;
 
458
  result->z = w * b->z + z * b->w + x * b->y - y * b->x;
 
459
}
 
460
 
 
461
void
 
462
cogl_quaternion_pow (CoglQuaternion *quaternion, float exponent)
 
463
{
 
464
  float half_angle;
 
465
  float new_half_angle;
 
466
  float factor;
 
467
 
 
468
  /* Try and identify and nop identity quaternions to avoid
 
469
   * dividing by zero */
 
470
  if (fabs (quaternion->w) > 0.9999f)
 
471
    return;
 
472
 
 
473
  /* NB: We are using quaternions to represent an axis (a), angle (𝜃) pair
 
474
   * in this form:
 
475
   * [w=cos(𝜃/2) ( x=sin(𝜃/2)*a.x, y=sin(𝜃/2)*a.y, z=sin(𝜃/2)*a.x )]
 
476
   */
 
477
 
 
478
  /* FIXME: clamp [-1, 1] */
 
479
  /* Extract 𝜃/2 from w */
 
480
  half_angle = acosf (quaternion->w);
 
481
 
 
482
  /* Compute the new 𝜃/2 */
 
483
  new_half_angle = half_angle * exponent;
 
484
 
 
485
  /* Compute the new w value */
 
486
  quaternion->w = cosf (new_half_angle);
 
487
 
 
488
  /* And new xyz values */
 
489
  factor = sinf (new_half_angle) / sinf (half_angle);
 
490
  quaternion->x *= factor;
 
491
  quaternion->y *= factor;
 
492
  quaternion->z *= factor;
 
493
}
 
494
 
 
495
void
 
496
cogl_quaternion_slerp (CoglQuaternion *result,
 
497
                       const CoglQuaternion *a,
 
498
                       const CoglQuaternion *b,
 
499
                       float t)
 
500
{
 
501
  float cos_difference;
 
502
  float qb_w;
 
503
  float qb_x;
 
504
  float qb_y;
 
505
  float qb_z;
 
506
  float fa;
 
507
  float fb;
 
508
 
 
509
  _COGL_RETURN_IF_FAIL (t >=0 && t <= 1.0f);
 
510
 
 
511
  if (t == 0)
 
512
    {
 
513
      *result = *a;
 
514
      return;
 
515
    }
 
516
  else if (t == 1)
 
517
    {
 
518
      *result = *b;
 
519
      return;
 
520
    }
 
521
 
 
522
  /* compute the cosine of the angle between the two given quaternions */
 
523
  cos_difference = cogl_quaternion_dot_product (a, b);
 
524
 
 
525
  /* If negative, use -b. Two quaternions q and -q represent the same angle but
 
526
   * may produce a different slerp. We choose b or -b to rotate using the acute
 
527
   * angle.
 
528
   */
 
529
  if (cos_difference < 0.0f)
 
530
    {
 
531
      qb_w = -b->w;
 
532
      qb_x = -b->x;
 
533
      qb_y = -b->y;
 
534
      qb_z = -b->z;
 
535
      cos_difference = -cos_difference;
 
536
    }
 
537
  else
 
538
    {
 
539
      qb_w = b->w;
 
540
      qb_x = b->x;
 
541
      qb_y = b->y;
 
542
      qb_z = b->z;
 
543
    }
 
544
 
 
545
  /* If we have two unit quaternions the dot should be <= 1.0 */
 
546
  g_assert (cos_difference < 1.1f);
 
547
 
 
548
 
 
549
  /* Determine the interpolation factors for each quaternion, simply using
 
550
   * linear interpolation for quaternions that are nearly exactly the same.
 
551
   * (this will avoid divisions by zero)
 
552
   */
 
553
 
 
554
  if (cos_difference > 0.9999f)
 
555
    {
 
556
      fa = 1.0f - t;
 
557
      fb = t;
 
558
 
 
559
      /* XXX: should we also normalize() at the end in this case? */
 
560
    }
 
561
  else
 
562
    {
 
563
      /* Calculate the sin of the angle between the two quaternions using the
 
564
       * trig identity: sin²(𝜃) + cos²(𝜃) = 1
 
565
       */
 
566
      float sin_difference =  sqrtf (1.0f - cos_difference * cos_difference);
 
567
 
 
568
      float difference = atan2f (sin_difference, cos_difference);
 
569
      float one_over_sin_difference = 1.0f / sin_difference;
 
570
      fa = sinf ((1.0f - t) * difference) * one_over_sin_difference;
 
571
      fb = sinf (t * difference) * one_over_sin_difference;
 
572
    }
 
573
 
 
574
  /* Finally interpolate the two quaternions */
 
575
 
 
576
  result->x = fa * a->x + fb * qb_x;
 
577
  result->y = fa * a->y + fb * qb_y;
 
578
  result->z = fa * a->z + fb * qb_z;
 
579
  result->w = fa * a->w + fb * qb_w;
 
580
}
 
581
 
 
582
void
 
583
cogl_quaternion_nlerp (CoglQuaternion *result,
 
584
                       const CoglQuaternion *a,
 
585
                       const CoglQuaternion *b,
 
586
                       float t)
 
587
{
 
588
  float cos_difference;
 
589
  float qb_w;
 
590
  float qb_x;
 
591
  float qb_y;
 
592
  float qb_z;
 
593
  float fa;
 
594
  float fb;
 
595
 
 
596
  _COGL_RETURN_IF_FAIL (t >=0 && t <= 1.0f);
 
597
 
 
598
  if (t == 0)
 
599
    {
 
600
      *result = *a;
 
601
      return;
 
602
    }
 
603
  else if (t == 1)
 
604
    {
 
605
      *result = *b;
 
606
      return;
 
607
    }
 
608
 
 
609
  /* compute the cosine of the angle between the two given quaternions */
 
610
  cos_difference = cogl_quaternion_dot_product (a, b);
 
611
 
 
612
  /* If negative, use -b. Two quaternions q and -q represent the same angle but
 
613
   * may produce a different slerp. We choose b or -b to rotate using the acute
 
614
   * angle.
 
615
   */
 
616
  if (cos_difference < 0.0f)
 
617
    {
 
618
      qb_w = -b->w;
 
619
      qb_x = -b->x;
 
620
      qb_y = -b->y;
 
621
      qb_z = -b->z;
 
622
      cos_difference = -cos_difference;
 
623
    }
 
624
  else
 
625
    {
 
626
      qb_w = b->w;
 
627
      qb_x = b->x;
 
628
      qb_y = b->y;
 
629
      qb_z = b->z;
 
630
    }
 
631
 
 
632
  /* If we have two unit quaternions the dot should be <= 1.0 */
 
633
  g_assert (cos_difference < 1.1f);
 
634
 
 
635
  fa = 1.0f - t;
 
636
  fb = t;
 
637
 
 
638
  result->x = fa * a->x + fb * qb_x;
 
639
  result->y = fa * a->y + fb * qb_y;
 
640
  result->z = fa * a->z + fb * qb_z;
 
641
  result->w = fa * a->w + fb * qb_w;
 
642
 
 
643
  cogl_quaternion_normalize (result);
 
644
}
 
645
 
 
646
void
 
647
cogl_quaternion_squad (CoglQuaternion *result,
 
648
                       const CoglQuaternion *prev,
 
649
                       const CoglQuaternion *a,
 
650
                       const CoglQuaternion *b,
 
651
                       const CoglQuaternion *next,
 
652
                       float t)
 
653
{
 
654
  CoglQuaternion slerp0;
 
655
  CoglQuaternion slerp1;
 
656
 
 
657
  cogl_quaternion_slerp (&slerp0, a, b, t);
 
658
  cogl_quaternion_slerp (&slerp1, prev, next, t);
 
659
  cogl_quaternion_slerp (result, &slerp0, &slerp1, 2.0f * t * (1.0f - t));
 
660
}
 
661
 
 
662
const CoglQuaternion *
 
663
cogl_get_static_identity_quaternion (void)
 
664
{
 
665
  return &identity_quaternion;
 
666
}
 
667
 
 
668
const CoglQuaternion *
 
669
cogl_get_static_zero_quaternion (void)
 
670
{
 
671
  return &zero_quaternion;
 
672
}
 
673