1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2009,2010,2011 Intel Corporation.
7  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use, copy,
13  * modify, merge, publish, distribute, sublicense, and/or sell copies
14  * of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  * Authors:
30  *   Robert Bragg <robert@linux.intel.com>
31  */
32 /*
33  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
34  *
35  * Permission is hereby granted, free of charge, to any person obtaining a
36  * copy of this software and associated documentation files (the "Software"),
37  * to deal in the Software without restriction, including without limitation
38  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
39  * and/or sell copies of the Software, and to permit persons to whom the
40  * Software is furnished to do so, subject to the following conditions:
41  *
42  * The above copyright notice and this permission notice shall be included
43  * in all copies or substantial portions of the Software.
44  *
45  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
46  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
48  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
49  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
50  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51  */
52 
53 /*
54  * Note: a lot of this code is based on code that was taken from Mesa.
55  *
56  * Changes compared to the original code from Mesa:
57  *
58  * - instead of allocating matrix->m and matrix->inv using malloc, our
59  *   public CoglMatrix typedef is large enough to directly contain the
60  *   matrix, its inverse, a type and a set of flags.
61  * - instead of having a _cogl_matrix_analyse which updates the type,
62  *   flags and inverse, we have _cogl_matrix_update_inverse which
63  *   essentially does the same thing (internally making use of
64  *   _cogl_matrix_update_type_and_flags()) but with additional guards in
65  *   place to bail out when the inverse matrix is still valid.
66  * - when initializing a matrix with the identity matrix we don't
67  *   immediately initialize the inverse matrix; rather we just set the
68  *   dirty flag for the inverse (since it's likely the user won't request
69  *   the inverse of the identity matrix)
70  */
71 
72 #ifdef HAVE_CONFIG_H
73 #include "cogl-config.h"
74 #endif
75 
76 #include <cogl-util.h>
77 #include <cogl-debug.h>
78 #include <cogl-quaternion.h>
79 #include <cogl-quaternion-private.h>
80 #include <cogl-matrix.h>
81 #include <cogl-matrix-private.h>
82 #include <cogl-quaternion-private.h>
83 
84 #include <glib.h>
85 #include <math.h>
86 #include <string.h>
87 
88 #include <cogl-gtype-private.h>
89 COGL_GTYPE_DEFINE_BOXED (Matrix, matrix,
90                          cogl_matrix_copy,
91                          cogl_matrix_free);
92 
93 /*
94  * Symbolic names to some of the entries in the matrix
95  *
96  * These are handy for the viewport mapping, which is expressed as a matrix.
97  */
98 #define MAT_SX 0
99 #define MAT_SY 5
100 #define MAT_SZ 10
101 #define MAT_TX 12
102 #define MAT_TY 13
103 #define MAT_TZ 14
104 
105 /*
106  * These identify different kinds of 4x4 transformation matrices and we use
107  * this information to find fast-paths when available.
108  */
109 enum CoglMatrixType {
110    COGL_MATRIX_TYPE_GENERAL,	/**< general 4x4 matrix */
111    COGL_MATRIX_TYPE_IDENTITY,	/**< identity matrix */
112    COGL_MATRIX_TYPE_3D_NO_ROT,	/**< orthogonal projection and others... */
113    COGL_MATRIX_TYPE_PERSPECTIVE,	/**< perspective projection matrix */
114    COGL_MATRIX_TYPE_2D,		/**< 2-D transformation */
115    COGL_MATRIX_TYPE_2D_NO_ROT,	/**< 2-D scale & translate only */
116    COGL_MATRIX_TYPE_3D,		/**< 3-D transformation */
117    COGL_MATRIX_N_TYPES
118 } ;
119 
120 #define DEG2RAD (G_PI/180.0)
121 
122 /* Dot product of two 2-element vectors */
123 #define DOT2(A,B)  ( (A)[0]*(B)[0] + (A)[1]*(B)[1] )
124 
125 /* Dot product of two 3-element vectors */
126 #define DOT3(A,B)  ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] )
127 
128 #define CROSS3(N, U, V) \
129 do { \
130     (N)[0] = (U)[1]*(V)[2] - (U)[2]*(V)[1]; \
131     (N)[1] = (U)[2]*(V)[0] - (U)[0]*(V)[2]; \
132     (N)[2] = (U)[0]*(V)[1] - (U)[1]*(V)[0]; \
133 } while (0)
134 
135 #define SUB_3V(DST, SRCA, SRCB) \
136 do { \
137     (DST)[0] = (SRCA)[0] - (SRCB)[0]; \
138     (DST)[1] = (SRCA)[1] - (SRCB)[1]; \
139     (DST)[2] = (SRCA)[2] - (SRCB)[2]; \
140 } while (0)
141 
142 #define LEN_SQUARED_3FV( V ) ((V)[0]*(V)[0]+(V)[1]*(V)[1]+(V)[2]*(V)[2])
143 
144 /*
145  * \defgroup MatFlags MAT_FLAG_XXX-flags
146  *
147  * Bitmasks to indicate different kinds of 4x4 matrices in CoglMatrix::flags
148  */
149 #define MAT_FLAG_IDENTITY       0     /*< is an identity matrix flag.
150                                        *   (Not actually used - the identity
151                                        *   matrix is identified by the absense
152                                        *   of all other flags.)
153                                        */
154 #define MAT_FLAG_GENERAL        0x1   /*< is a general matrix flag */
155 #define MAT_FLAG_ROTATION       0x2   /*< is a rotation matrix flag */
156 #define MAT_FLAG_TRANSLATION    0x4   /*< is a translation matrix flag */
157 #define MAT_FLAG_UNIFORM_SCALE  0x8   /*< is an uniform scaling matrix flag */
158 #define MAT_FLAG_GENERAL_SCALE  0x10  /*< is a general scaling matrix flag */
159 #define MAT_FLAG_GENERAL_3D     0x20  /*< general 3D matrix flag */
160 #define MAT_FLAG_PERSPECTIVE    0x40  /*< is a perspective proj matrix flag */
161 #define MAT_FLAG_SINGULAR       0x80  /*< is a singular matrix flag */
162 #define MAT_DIRTY_TYPE          0x100  /*< matrix type is dirty */
163 #define MAT_DIRTY_FLAGS         0x200  /*< matrix flags are dirty */
164 #define MAT_DIRTY_INVERSE       0x400  /*< matrix inverse is dirty */
165 
166 /* angle preserving matrix flags mask */
167 #define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \
168 				    MAT_FLAG_TRANSLATION | \
169 				    MAT_FLAG_UNIFORM_SCALE)
170 
171 /* geometry related matrix flags mask */
172 #define MAT_FLAGS_GEOMETRY (MAT_FLAG_GENERAL | \
173 			    MAT_FLAG_ROTATION | \
174 			    MAT_FLAG_TRANSLATION | \
175 			    MAT_FLAG_UNIFORM_SCALE | \
176 			    MAT_FLAG_GENERAL_SCALE | \
177 			    MAT_FLAG_GENERAL_3D | \
178 			    MAT_FLAG_PERSPECTIVE | \
179 	                    MAT_FLAG_SINGULAR)
180 
181 /* length preserving matrix flags mask */
182 #define MAT_FLAGS_LENGTH_PRESERVING (MAT_FLAG_ROTATION | \
183 				     MAT_FLAG_TRANSLATION)
184 
185 
186 /* 3D (non-perspective) matrix flags mask */
187 #define MAT_FLAGS_3D (MAT_FLAG_ROTATION | \
188 		      MAT_FLAG_TRANSLATION | \
189 		      MAT_FLAG_UNIFORM_SCALE | \
190 		      MAT_FLAG_GENERAL_SCALE | \
191 		      MAT_FLAG_GENERAL_3D)
192 
193 /* dirty matrix flags mask */
194 #define MAT_DIRTY_ALL      (MAT_DIRTY_TYPE | \
195 			    MAT_DIRTY_FLAGS | \
196 			    MAT_DIRTY_INVERSE)
197 
198 
199 /*
200  * Test geometry related matrix flags.
201  *
202  * @mat a pointer to a CoglMatrix structure.
203  * @a flags mask.
204  *
205  * Returns: non-zero if all geometry related matrix flags are contained within
206  * the mask, or zero otherwise.
207  */
208 #define TEST_MAT_FLAGS(mat, a)  \
209     ((MAT_FLAGS_GEOMETRY & (~(a)) & ((mat)->flags) ) == 0)
210 
211 
212 
213 /*
214  * Names of the corresponding CoglMatrixType values.
215  */
216 static const char *types[] = {
217    "COGL_MATRIX_TYPE_GENERAL",
218    "COGL_MATRIX_TYPE_IDENTITY",
219    "COGL_MATRIX_TYPE_3D_NO_ROT",
220    "COGL_MATRIX_TYPE_PERSPECTIVE",
221    "COGL_MATRIX_TYPE_2D",
222    "COGL_MATRIX_TYPE_2D_NO_ROT",
223    "COGL_MATRIX_TYPE_3D"
224 };
225 
226 
227 /*
228  * Identity matrix.
229  */
230 static float identity[16] = {
231    1.0, 0.0, 0.0, 0.0,
232    0.0, 1.0, 0.0, 0.0,
233    0.0, 0.0, 1.0, 0.0,
234    0.0, 0.0, 0.0, 1.0
235 };
236 
237 
238 #define A(row,col)  a[(col<<2)+row]
239 #define B(row,col)  b[(col<<2)+row]
240 #define R(row,col)  result[(col<<2)+row]
241 
242 /*
243  * Perform a full 4x4 matrix multiplication.
244  *
245  * <note>It's assumed that @result != @b. @product == @a is allowed.</note>
246  *
247  * <note>KW: 4*16 = 64 multiplications</note>
248  */
249 static void
matrix_multiply4x4(float * result,const float * a,const float * b)250 matrix_multiply4x4 (float *result, const float *a, const float *b)
251 {
252   int i;
253   for (i = 0; i < 4; i++)
254     {
255       const float ai0 = A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
256       R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
257       R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
258       R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
259       R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
260     }
261 }
262 
263 /*
264  * Multiply two matrices known to occupy only the top three rows, such
265  * as typical model matrices, and orthogonal matrices.
266  *
267  * @a matrix.
268  * @b matrix.
269  * @product will receive the product of \p a and \p b.
270  */
271 static void
matrix_multiply3x4(float * result,const float * a,const float * b)272 matrix_multiply3x4 (float *result, const float *a, const float *b)
273 {
274   int i;
275   for (i = 0; i < 3; i++)
276     {
277       const float ai0 = A(i,0), ai1 = A(i,1), ai2 = A(i,2), ai3 = A(i,3);
278       R(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0);
279       R(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1);
280       R(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2);
281       R(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3;
282     }
283   R(3,0) = 0;
284   R(3,1) = 0;
285   R(3,2) = 0;
286   R(3,3) = 1;
287 }
288 
289 #undef A
290 #undef B
291 #undef R
292 
293 /*
294  * Multiply a matrix by an array of floats with known properties.
295  *
296  * @mat pointer to a CoglMatrix structure containing the left multiplication
297  * matrix, and that will receive the product result.
298  * @m right multiplication matrix array.
299  * @flags flags of the matrix \p m.
300  *
301  * Joins both flags and marks the type and inverse as dirty.  Calls
302  * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4()
303  * otherwise.
304  */
305 static void
matrix_multiply_array_with_flags(CoglMatrix * result,const float * array,unsigned int flags)306 matrix_multiply_array_with_flags (CoglMatrix *result,
307                                   const float *array,
308                                   unsigned int flags)
309 {
310   result->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
311 
312   if (TEST_MAT_FLAGS (result, MAT_FLAGS_3D))
313     matrix_multiply3x4 ((float *)result, (float *)result, array);
314   else
315     matrix_multiply4x4 ((float *)result, (float *)result, array);
316 }
317 
318 /* Joins both flags and marks the type and inverse as dirty.  Calls
319  * matrix_multiply3x4() if both matrices are 3D, or matrix_multiply4x4()
320  * otherwise.
321  */
322 static void
_cogl_matrix_multiply(CoglMatrix * result,const CoglMatrix * a,const CoglMatrix * b)323 _cogl_matrix_multiply (CoglMatrix *result,
324                        const CoglMatrix *a,
325                        const CoglMatrix *b)
326 {
327   result->flags = (a->flags |
328                    b->flags |
329                    MAT_DIRTY_TYPE |
330                    MAT_DIRTY_INVERSE);
331 
332   if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D))
333     matrix_multiply3x4 ((float *)result, (float *)a, (float *)b);
334   else
335     matrix_multiply4x4 ((float *)result, (float *)a, (float *)b);
336 }
337 
338 void
cogl_matrix_multiply(CoglMatrix * result,const CoglMatrix * a,const CoglMatrix * b)339 cogl_matrix_multiply (CoglMatrix *result,
340 		      const CoglMatrix *a,
341 		      const CoglMatrix *b)
342 {
343   _cogl_matrix_multiply (result, a, b);
344   _COGL_MATRIX_DEBUG_PRINT (result);
345 }
346 
347 #if 0
348 /* Marks the matrix flags with general flag, and type and inverse dirty flags.
349  * Calls matrix_multiply4x4() for the multiplication.
350  */
351 static void
352 _cogl_matrix_multiply_array (CoglMatrix *result, const float *array)
353 {
354   result->flags |= (MAT_FLAG_GENERAL |
355                   MAT_DIRTY_TYPE |
356                   MAT_DIRTY_INVERSE |
357                   MAT_DIRTY_FLAGS);
358 
359   matrix_multiply4x4 ((float *)result, (float *)result, (float *)array);
360 }
361 #endif
362 
363 /*
364  * Print a matrix array.
365  *
366  * Called by _cogl_matrix_print() to print a matrix or its inverse.
367  */
368 static void
print_matrix_floats(const char * prefix,const float m[16])369 print_matrix_floats (const char *prefix, const float m[16])
370 {
371   int i;
372   for (i = 0;i < 4; i++)
373     g_print ("%s\t%f %f %f %f\n", prefix, m[i], m[4+i], m[8+i], m[12+i] );
374 }
375 
376 void
_cogl_matrix_prefix_print(const char * prefix,const CoglMatrix * matrix)377 _cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix)
378 {
379   if (!(matrix->flags & MAT_DIRTY_TYPE))
380     {
381       _COGL_RETURN_IF_FAIL (matrix->type < COGL_MATRIX_N_TYPES);
382       g_print ("%sMatrix type: %s, flags: %x\n",
383                prefix, types[matrix->type], (int)matrix->flags);
384     }
385   else
386     g_print ("%sMatrix type: DIRTY, flags: %x\n",
387              prefix, (int)matrix->flags);
388 
389   print_matrix_floats (prefix, (float *)matrix);
390   g_print ("%sInverse: \n", prefix);
391   if (!(matrix->flags & MAT_DIRTY_INVERSE))
392     {
393       float prod[16];
394       print_matrix_floats (prefix, matrix->inv);
395       matrix_multiply4x4 (prod, (float *)matrix, matrix->inv);
396       g_print ("%sMat * Inverse:\n", prefix);
397       print_matrix_floats (prefix, prod);
398     }
399   else
400     g_print ("%s  - not available\n", prefix);
401 }
402 
403 /*
404  * Dumps the contents of a CoglMatrix structure.
405  */
406 void
cogl_debug_matrix_print(const CoglMatrix * matrix)407 cogl_debug_matrix_print (const CoglMatrix *matrix)
408 {
409   _cogl_matrix_prefix_print ("", matrix);
410 }
411 
412 /*
413  * References an element of 4x4 matrix.
414  *
415  * @m matrix array.
416  * @c column of the desired element.
417  * @r row of the desired element.
418  *
419  * Returns: value of the desired element.
420  *
421  * Calculate the linear storage index of the element and references it.
422  */
423 #define MAT(m,r,c) (m)[(c)*4+(r)]
424 
425 /*
426  * Swaps the values of two floating pointer variables.
427  *
428  * Used by invert_matrix_general() to swap the row pointers.
429  */
430 #define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
431 
432 /*
433  * Compute inverse of 4x4 transformation matrix.
434  *
435  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
436  * stored in the CoglMatrix::inv attribute.
437  *
438  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
439  *
440  * \author
441  * Code contributed by Jacques Leroy jle@star.be
442  *
443  * Calculates the inverse matrix by performing the gaussian matrix reduction
444  * with partial pivoting followed by back/substitution with the loops manually
445  * unrolled.
446  */
447 static CoglBool
invert_matrix_general(CoglMatrix * matrix)448 invert_matrix_general (CoglMatrix *matrix)
449 {
450   const float *m = (float *)matrix;
451   float *out = matrix->inv;
452   float wtmp[4][8];
453   float m0, m1, m2, m3, s;
454   float *r0, *r1, *r2, *r3;
455 
456   r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
457 
458   r0[0] = MAT (m, 0, 0), r0[1] = MAT (m, 0, 1),
459     r0[2] = MAT (m, 0, 2), r0[3] = MAT (m, 0, 3),
460     r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
461 
462     r1[0] = MAT (m, 1, 0), r1[1] = MAT (m, 1, 1),
463     r1[2] = MAT (m, 1, 2), r1[3] = MAT (m, 1, 3),
464     r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
465 
466     r2[0] = MAT (m, 2, 0), r2[1] = MAT (m, 2, 1),
467     r2[2] = MAT (m, 2, 2), r2[3] = MAT (m, 2, 3),
468     r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
469 
470     r3[0] = MAT (m, 3, 0), r3[1] = MAT (m, 3, 1),
471     r3[2] = MAT (m, 3, 2), r3[3] = MAT (m, 3, 3),
472     r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
473 
474   /* choose pivot - or die */
475   if (fabsf (r3[0]) > fabsf (r2[0]))
476     SWAP_ROWS (r3, r2);
477   if (fabsf (r2[0]) > fabsf (r1[0]))
478     SWAP_ROWS (r2, r1);
479   if (fabsf (r1[0]) > fabsf (r0[0]))
480     SWAP_ROWS (r1, r0);
481   if (0.0 == r0[0])
482     return FALSE;
483 
484   /* eliminate first variable     */
485   m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
486   s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
487   s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
488   s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
489   s = r0[4];
490   if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
491   s = r0[5];
492   if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
493   s = r0[6];
494   if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
495   s = r0[7];
496   if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
497 
498   /* choose pivot - or die */
499   if (fabsf (r3[1]) > fabsf (r2[1]))
500     SWAP_ROWS (r3, r2);
501   if (fabsf (r2[1]) > fabsf (r1[1]))
502     SWAP_ROWS (r2, r1);
503   if (0.0 == r1[1])
504     return FALSE;
505 
506   /* eliminate second variable */
507   m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1];
508   r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
509   r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
510   s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
511   s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
512   s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
513   s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
514 
515   /* choose pivot - or die */
516   if (fabsf (r3[2]) > fabsf (r2[2]))
517     SWAP_ROWS (r3, r2);
518   if (0.0 == r2[2])
519     return FALSE;
520 
521   /* eliminate third variable */
522   m3 = r3[2] / r2[2];
523   r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
524     r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
525     r3[7] -= m3 * r2[7];
526 
527   /* last check */
528   if (0.0 == r3[3])
529     return FALSE;
530 
531   s = 1.0f / r3[3];             /* now back substitute row 3 */
532   r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
533 
534   m2 = r2[3];                 /* now back substitute row 2 */
535   s  = 1.0f / r2[2];
536   r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
537     r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
538   m1 = r1[3];
539   r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
540     r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
541   m0 = r0[3];
542   r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
543     r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
544 
545   m1 = r1[2];                 /* now back substitute row 1 */
546   s  = 1.0f / r1[1];
547   r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
548     r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
549   m0 = r0[2];
550   r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
551     r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
552 
553   m0 = r0[1];                 /* now back substitute row 0 */
554   s  = 1.0f / r0[0];
555   r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
556     r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
557 
558   MAT (out, 0, 0) = r0[4]; MAT (out, 0, 1) = r0[5],
559     MAT (out, 0, 2) = r0[6]; MAT (out, 0, 3) = r0[7],
560     MAT (out, 1, 0) = r1[4]; MAT (out, 1, 1) = r1[5],
561     MAT (out, 1, 2) = r1[6]; MAT (out, 1, 3) = r1[7],
562     MAT (out, 2, 0) = r2[4]; MAT (out, 2, 1) = r2[5],
563     MAT (out, 2, 2) = r2[6]; MAT (out, 2, 3) = r2[7],
564     MAT (out, 3, 0) = r3[4]; MAT (out, 3, 1) = r3[5],
565     MAT (out, 3, 2) = r3[6]; MAT (out, 3, 3) = r3[7];
566 
567   return TRUE;
568 }
569 #undef SWAP_ROWS
570 
571 /*
572  * Compute inverse of a general 3d transformation matrix.
573  *
574  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
575  * stored in the CoglMatrix::inv attribute.
576  *
577  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
578  *
579  * \author Adapted from graphics gems II.
580  *
581  * Calculates the inverse of the upper left by first calculating its
582  * determinant and multiplying it to the symmetric adjust matrix of each
583  * element. Finally deals with the translation part by transforming the
584  * original translation vector using by the calculated submatrix inverse.
585  */
586 static CoglBool
invert_matrix_3d_general(CoglMatrix * matrix)587 invert_matrix_3d_general (CoglMatrix *matrix)
588 {
589   const float *in = (float *)matrix;
590   float *out = matrix->inv;
591   float pos, neg, t;
592   float det;
593 
594   /* Calculate the determinant of upper left 3x3 submatrix and
595    * determine if the matrix is singular.
596    */
597   pos = neg = 0.0;
598   t =  MAT (in,0,0) * MAT (in,1,1) * MAT (in,2,2);
599   if (t >= 0.0) pos += t; else neg += t;
600 
601   t =  MAT (in,1,0) * MAT (in,2,1) * MAT (in,0,2);
602   if (t >= 0.0) pos += t; else neg += t;
603 
604   t =  MAT (in,2,0) * MAT (in,0,1) * MAT (in,1,2);
605   if (t >= 0.0) pos += t; else neg += t;
606 
607   t = -MAT (in,2,0) * MAT (in,1,1) * MAT (in,0,2);
608   if (t >= 0.0) pos += t; else neg += t;
609 
610   t = -MAT (in,1,0) * MAT (in,0,1) * MAT (in,2,2);
611   if (t >= 0.0) pos += t; else neg += t;
612 
613   t = -MAT (in,0,0) * MAT (in,2,1) * MAT (in,1,2);
614   if (t >= 0.0) pos += t; else neg += t;
615 
616   det = pos + neg;
617 
618   if (det*det < 1e-25)
619     return FALSE;
620 
621   det = 1.0f / det;
622   MAT (out,0,0) =
623     (  (MAT (in, 1, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 1, 2) )*det);
624   MAT (out,0,1) =
625     (- (MAT (in, 0, 1)*MAT (in, 2, 2) - MAT (in, 2, 1)*MAT (in, 0, 2) )*det);
626   MAT (out,0,2) =
627     (  (MAT (in, 0, 1)*MAT (in, 1, 2) - MAT (in, 1, 1)*MAT (in, 0, 2) )*det);
628   MAT (out,1,0) =
629     (- (MAT (in,1,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,1,2) )*det);
630   MAT (out,1,1) =
631     (  (MAT (in,0,0)*MAT (in,2,2) - MAT (in,2,0)*MAT (in,0,2) )*det);
632   MAT (out,1,2) =
633     (- (MAT (in,0,0)*MAT (in,1,2) - MAT (in,1,0)*MAT (in,0,2) )*det);
634   MAT (out,2,0) =
635     (  (MAT (in,1,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,1,1) )*det);
636   MAT (out,2,1) =
637     (- (MAT (in,0,0)*MAT (in,2,1) - MAT (in,2,0)*MAT (in,0,1) )*det);
638   MAT (out,2,2) =
639     (  (MAT (in,0,0)*MAT (in,1,1) - MAT (in,1,0)*MAT (in,0,1) )*det);
640 
641   /* Do the translation part */
642   MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) +
643                     MAT (in, 1, 3) * MAT (out, 0, 1) +
644                     MAT (in, 2, 3) * MAT (out, 0, 2) );
645   MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) +
646                     MAT (in, 1, 3) * MAT (out, 1, 1) +
647                     MAT (in, 2, 3) * MAT (out, 1, 2) );
648   MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2 ,0) +
649                     MAT (in, 1, 3) * MAT (out, 2, 1) +
650                     MAT (in, 2, 3) * MAT (out, 2, 2) );
651 
652   return TRUE;
653 }
654 
655 /*
656  * Compute inverse of a 3d transformation matrix.
657  *
658  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
659  * stored in the CoglMatrix::inv attribute.
660  *
661  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
662  *
663  * If the matrix is not an angle preserving matrix then calls
664  * invert_matrix_3d_general for the actual calculation. Otherwise calculates
665  * the inverse matrix analyzing and inverting each of the scaling, rotation and
666  * translation parts.
667  */
668 static CoglBool
invert_matrix_3d(CoglMatrix * matrix)669 invert_matrix_3d (CoglMatrix *matrix)
670 {
671   const float *in = (float *)matrix;
672   float *out = matrix->inv;
673 
674   memcpy (out, identity, 16 * sizeof (float));
675 
676   if (!TEST_MAT_FLAGS(matrix, MAT_FLAGS_ANGLE_PRESERVING))
677     return invert_matrix_3d_general (matrix);
678 
679   if (matrix->flags & MAT_FLAG_UNIFORM_SCALE)
680     {
681       float scale = (MAT (in, 0, 0) * MAT (in, 0, 0) +
682                      MAT (in, 0, 1) * MAT (in, 0, 1) +
683                      MAT (in, 0, 2) * MAT (in, 0, 2));
684 
685       if (scale == 0.0)
686         return FALSE;
687 
688       scale = 1.0f / scale;
689 
690       /* Transpose and scale the 3 by 3 upper-left submatrix. */
691       MAT (out, 0, 0) = scale * MAT (in, 0, 0);
692       MAT (out, 1, 0) = scale * MAT (in, 0, 1);
693       MAT (out, 2, 0) = scale * MAT (in, 0, 2);
694       MAT (out, 0, 1) = scale * MAT (in, 1, 0);
695       MAT (out, 1, 1) = scale * MAT (in, 1, 1);
696       MAT (out, 2, 1) = scale * MAT (in, 1, 2);
697       MAT (out, 0, 2) = scale * MAT (in, 2, 0);
698       MAT (out, 1, 2) = scale * MAT (in, 2, 1);
699       MAT (out, 2, 2) = scale * MAT (in, 2, 2);
700     }
701   else if (matrix->flags & MAT_FLAG_ROTATION)
702     {
703       /* Transpose the 3 by 3 upper-left submatrix. */
704       MAT (out, 0, 0) = MAT (in, 0, 0);
705       MAT (out, 1, 0) = MAT (in, 0, 1);
706       MAT (out, 2, 0) = MAT (in, 0, 2);
707       MAT (out, 0, 1) = MAT (in, 1, 0);
708       MAT (out, 1, 1) = MAT (in, 1, 1);
709       MAT (out, 2, 1) = MAT (in, 1, 2);
710       MAT (out, 0, 2) = MAT (in, 2, 0);
711       MAT (out, 1, 2) = MAT (in, 2, 1);
712       MAT (out, 2, 2) = MAT (in, 2, 2);
713     }
714   else
715     {
716       /* pure translation */
717       memcpy (out, identity, 16 * sizeof (float));
718       MAT (out, 0, 3) = - MAT (in, 0, 3);
719       MAT (out, 1, 3) = - MAT (in, 1, 3);
720       MAT (out, 2, 3) = - MAT (in, 2, 3);
721       return TRUE;
722     }
723 
724   if (matrix->flags & MAT_FLAG_TRANSLATION)
725     {
726       /* Do the translation part */
727       MAT (out,0,3) = - (MAT (in, 0, 3) * MAT (out, 0, 0) +
728                         MAT (in, 1, 3) * MAT (out, 0, 1) +
729                         MAT (in, 2, 3) * MAT (out, 0, 2) );
730       MAT (out,1,3) = - (MAT (in, 0, 3) * MAT (out, 1, 0) +
731                         MAT (in, 1, 3) * MAT (out, 1, 1) +
732                         MAT (in, 2, 3) * MAT (out, 1, 2) );
733       MAT (out,2,3) = - (MAT (in, 0, 3) * MAT (out, 2, 0) +
734                         MAT (in, 1, 3) * MAT (out, 2, 1) +
735                         MAT (in, 2, 3) * MAT (out, 2, 2) );
736     }
737   else
738     MAT (out, 0, 3) = MAT (out, 1, 3) = MAT (out, 2, 3) = 0.0;
739 
740   return TRUE;
741 }
742 
743 /*
744  * Compute inverse of an identity transformation matrix.
745  *
746  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
747  * stored in the CoglMatrix::inv attribute.
748  *
749  * Returns: always %TRUE.
750  *
751  * Simply copies identity into CoglMatrix::inv.
752  */
753 static CoglBool
invert_matrix_identity(CoglMatrix * matrix)754 invert_matrix_identity (CoglMatrix *matrix)
755 {
756   memcpy (matrix->inv, identity, 16 * sizeof (float));
757   return TRUE;
758 }
759 
760 /*
761  * Compute inverse of a no-rotation 3d transformation matrix.
762  *
763  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
764  * stored in the CoglMatrix::inv attribute.
765  *
766  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
767  *
768  * Calculates the
769  */
770 static CoglBool
invert_matrix_3d_no_rotation(CoglMatrix * matrix)771 invert_matrix_3d_no_rotation (CoglMatrix *matrix)
772 {
773   const float *in = (float *)matrix;
774   float *out = matrix->inv;
775 
776   if (MAT (in,0,0) == 0 || MAT (in,1,1) == 0 || MAT (in,2,2) == 0)
777     return FALSE;
778 
779   memcpy (out, identity, 16 * sizeof (float));
780   MAT (out,0,0) = 1.0f / MAT (in,0,0);
781   MAT (out,1,1) = 1.0f / MAT (in,1,1);
782   MAT (out,2,2) = 1.0f / MAT (in,2,2);
783 
784   if (matrix->flags & MAT_FLAG_TRANSLATION)
785     {
786       MAT (out,0,3) = - (MAT (in,0,3) * MAT (out,0,0));
787       MAT (out,1,3) = - (MAT (in,1,3) * MAT (out,1,1));
788       MAT (out,2,3) = - (MAT (in,2,3) * MAT (out,2,2));
789     }
790 
791   return TRUE;
792 }
793 
794 /*
795  * Compute inverse of a no-rotation 2d transformation matrix.
796  *
797  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
798  * stored in the CoglMatrix::inv attribute.
799  *
800  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
801  *
802  * Calculates the inverse matrix by applying the inverse scaling and
803  * translation to the identity matrix.
804  */
805 static CoglBool
invert_matrix_2d_no_rotation(CoglMatrix * matrix)806 invert_matrix_2d_no_rotation (CoglMatrix *matrix)
807 {
808   const float *in = (float *)matrix;
809   float *out = matrix->inv;
810 
811   if (MAT (in, 0, 0) == 0 || MAT (in, 1, 1) == 0)
812     return FALSE;
813 
814   memcpy (out, identity, 16 * sizeof (float));
815   MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0);
816   MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1);
817 
818   if (matrix->flags & MAT_FLAG_TRANSLATION)
819     {
820       MAT (out, 0, 3) = - (MAT (in, 0, 3) * MAT (out, 0, 0));
821       MAT (out, 1, 3) = - (MAT (in, 1, 3) * MAT (out, 1, 1));
822     }
823 
824   return TRUE;
825 }
826 
827 #if 0
828 /* broken */
829 static CoglBool
830 invert_matrix_perspective (CoglMatrix *matrix)
831 {
832   const float *in = matrix;
833   float *out = matrix->inv;
834 
835   if (MAT (in,2,3) == 0)
836     return FALSE;
837 
838   memcpy( out, identity, 16 * sizeof(float) );
839 
840   MAT (out, 0, 0) = 1.0f / MAT (in, 0, 0);
841   MAT (out, 1, 1) = 1.0f / MAT (in, 1, 1);
842 
843   MAT (out, 0, 3) = MAT (in, 0, 2);
844   MAT (out, 1, 3) = MAT (in, 1, 2);
845 
846   MAT (out,2,2) = 0;
847   MAT (out,2,3) = -1;
848 
849   MAT (out,3,2) = 1.0f / MAT (in,2,3);
850   MAT (out,3,3) = MAT (in,2,2) * MAT (out,3,2);
851 
852   return TRUE;
853 }
854 #endif
855 
856 /*
857  * Matrix inversion function pointer type.
858  */
859 typedef CoglBool (*inv_mat_func)(CoglMatrix *matrix);
860 
861 /*
862  * Table of the matrix inversion functions according to the matrix type.
863  */
864 static inv_mat_func inv_mat_tab[7] = {
865     invert_matrix_general,
866     invert_matrix_identity,
867     invert_matrix_3d_no_rotation,
868 #if 0
869     /* Don't use this function for now - it fails when the projection matrix
870      * is premultiplied by a translation (ala Chromium's tilesort SPU).
871      */
872     invert_matrix_perspective,
873 #else
874     invert_matrix_general,
875 #endif
876     invert_matrix_3d,		/* lazy! */
877     invert_matrix_2d_no_rotation,
878     invert_matrix_3d
879 };
880 
881 #define ZERO(x) (1<<x)
882 #define ONE(x)  (1<<(x+16))
883 
884 #define MASK_NO_TRX      (ZERO(12) | ZERO(13) | ZERO(14))
885 #define MASK_NO_2D_SCALE ( ONE(0)  | ONE(5))
886 
887 #define MASK_IDENTITY    ( ONE(0)  | ZERO(4)  | ZERO(8)  | ZERO(12) |\
888                           ZERO(1)  |  ONE(5)  | ZERO(9)  | ZERO(13) |\
889                           ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
890                           ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
891 
892 #define MASK_2D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
893                           ZERO(1)  |            ZERO(9)  |           \
894                           ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
895                           ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
896 
897 #define MASK_2D          (                      ZERO(8)  |           \
898                           ZERO(9)  |           \
899                           ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
900                           ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
901 
902 
903 #define MASK_3D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
904                           ZERO(1)  |            ZERO(9)  |           \
905                           ZERO(2)  | ZERO(6)  |                      \
906                           ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
907 
908 #define MASK_3D          (                                           \
909                           \
910                           \
911                           ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
912 
913 
914 #define MASK_PERSPECTIVE (           ZERO(4)  |            ZERO(12) |\
915                           ZERO(1)  |                       ZERO(13) |\
916                           ZERO(2)  | ZERO(6)  |                      \
917                           ZERO(3)  | ZERO(7)  |            ZERO(15) )
918 
919 #define SQ(x) ((x)*(x))
920 
921 /*
922  * Determine type and flags from scratch.
923  *
924  * This is expensive enough to only want to do it once.
925  */
926 static void
analyse_from_scratch(CoglMatrix * matrix)927 analyse_from_scratch (CoglMatrix *matrix)
928 {
929   const float *m = (float *)matrix;
930   unsigned int mask = 0;
931   unsigned int i;
932 
933   for (i = 0 ; i < 16 ; i++)
934     {
935       if (m[i] == 0.0) mask |= (1<<i);
936     }
937 
938   if (m[0] == 1.0f) mask |= (1<<16);
939   if (m[5] == 1.0f) mask |= (1<<21);
940   if (m[10] == 1.0f) mask |= (1<<26);
941   if (m[15] == 1.0f) mask |= (1<<31);
942 
943   matrix->flags &= ~MAT_FLAGS_GEOMETRY;
944 
945   /* Check for translation - no-one really cares
946   */
947   if ((mask & MASK_NO_TRX) != MASK_NO_TRX)
948     matrix->flags |= MAT_FLAG_TRANSLATION;
949 
950   /* Do the real work
951   */
952   if (mask == (unsigned int) MASK_IDENTITY)
953     matrix->type = COGL_MATRIX_TYPE_IDENTITY;
954   else if ((mask & MASK_2D_NO_ROT) == (unsigned int) MASK_2D_NO_ROT)
955     {
956       matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT;
957 
958       if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
959         matrix->flags |= MAT_FLAG_GENERAL_SCALE;
960     }
961   else if ((mask & MASK_2D) == (unsigned int) MASK_2D)
962     {
963       float mm = DOT2 (m, m);
964       float m4m4 = DOT2 (m+4,m+4);
965       float mm4 = DOT2 (m,m+4);
966 
967       matrix->type = COGL_MATRIX_TYPE_2D;
968 
969       /* Check for scale */
970       if (SQ (mm-1) > SQ (1e-6) ||
971           SQ (m4m4-1) > SQ (1e-6))
972         matrix->flags |= MAT_FLAG_GENERAL_SCALE;
973 
974       /* Check for rotation */
975       if (SQ (mm4) > SQ (1e-6))
976         matrix->flags |= MAT_FLAG_GENERAL_3D;
977       else
978         matrix->flags |= MAT_FLAG_ROTATION;
979 
980     }
981   else if ((mask & MASK_3D_NO_ROT) == (unsigned int) MASK_3D_NO_ROT)
982     {
983       matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT;
984 
985       /* Check for scale */
986       if (SQ (m[0]-m[5]) < SQ (1e-6) &&
987           SQ (m[0]-m[10]) < SQ (1e-6))
988         {
989           if (SQ (m[0]-1.0) > SQ (1e-6))
990             matrix->flags |= MAT_FLAG_UNIFORM_SCALE;
991         }
992       else
993         matrix->flags |= MAT_FLAG_GENERAL_SCALE;
994     }
995   else if ((mask & MASK_3D) == (unsigned int) MASK_3D)
996     {
997       float c1 = DOT3 (m,m);
998       float c2 = DOT3 (m+4,m+4);
999       float c3 = DOT3 (m+8,m+8);
1000       float d1 = DOT3 (m, m+4);
1001       float cp[3];
1002 
1003       matrix->type = COGL_MATRIX_TYPE_3D;
1004 
1005       /* Check for scale */
1006       if (SQ (c1-c2) < SQ (1e-6) && SQ (c1-c3) < SQ (1e-6))
1007         {
1008           if (SQ (c1-1.0) > SQ (1e-6))
1009             matrix->flags |= MAT_FLAG_UNIFORM_SCALE;
1010           /* else no scale at all */
1011         }
1012       else
1013         matrix->flags |= MAT_FLAG_GENERAL_SCALE;
1014 
1015       /* Check for rotation */
1016       if (SQ (d1) < SQ (1e-6))
1017         {
1018           CROSS3 ( cp, m, m+4);
1019           SUB_3V ( cp, cp, (m+8));
1020           if (LEN_SQUARED_3FV(cp) < SQ(1e-6))
1021             matrix->flags |= MAT_FLAG_ROTATION;
1022           else
1023             matrix->flags |= MAT_FLAG_GENERAL_3D;
1024         }
1025       else
1026         matrix->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
1027     }
1028   else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0f)
1029     {
1030       matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE;
1031       matrix->flags |= MAT_FLAG_GENERAL;
1032     }
1033   else
1034     {
1035       matrix->type = COGL_MATRIX_TYPE_GENERAL;
1036       matrix->flags |= MAT_FLAG_GENERAL;
1037     }
1038 }
1039 
1040 /*
1041  * Analyze a matrix given that its flags are accurate.
1042  *
1043  * This is the more common operation, hopefully.
1044  */
1045 static void
analyse_from_flags(CoglMatrix * matrix)1046 analyse_from_flags (CoglMatrix *matrix)
1047 {
1048   const float *m = (float *)matrix;
1049 
1050   if (TEST_MAT_FLAGS(matrix, 0))
1051     matrix->type = COGL_MATRIX_TYPE_IDENTITY;
1052   else if (TEST_MAT_FLAGS(matrix, (MAT_FLAG_TRANSLATION |
1053                                    MAT_FLAG_UNIFORM_SCALE |
1054                                    MAT_FLAG_GENERAL_SCALE)))
1055     {
1056       if ( m[10] == 1.0f && m[14] == 0.0f )
1057         matrix->type = COGL_MATRIX_TYPE_2D_NO_ROT;
1058       else
1059         matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT;
1060     }
1061   else if (TEST_MAT_FLAGS (matrix, MAT_FLAGS_3D))
1062     {
1063       if (                               m[ 8]==0.0f
1064           &&                             m[ 9]==0.0f
1065           && m[2]==0.0f && m[6]==0.0f && m[10]==1.0f && m[14]==0.0f)
1066         {
1067           matrix->type = COGL_MATRIX_TYPE_2D;
1068         }
1069       else
1070         matrix->type = COGL_MATRIX_TYPE_3D;
1071     }
1072   else if (                 m[4]==0.0f                 && m[12]==0.0f
1073            && m[1]==0.0f                               && m[13]==0.0f
1074            && m[2]==0.0f && m[6]==0.0f
1075            && m[3]==0.0f && m[7]==0.0f && m[11]==-1.0f && m[15]==0.0f)
1076     {
1077       matrix->type = COGL_MATRIX_TYPE_PERSPECTIVE;
1078     }
1079   else
1080     matrix->type = COGL_MATRIX_TYPE_GENERAL;
1081 }
1082 
1083 /*
1084  * Analyze and update the type and flags of a matrix.
1085  *
1086  * If the matrix type is dirty then calls either analyse_from_scratch() or
1087  * analyse_from_flags() to determine its type, according to whether the flags
1088  * are dirty or not, respectively. If the matrix has an inverse and it's dirty
1089  * then calls matrix_invert(). Finally clears the dirty flags.
1090  */
1091 static void
_cogl_matrix_update_type_and_flags(CoglMatrix * matrix)1092 _cogl_matrix_update_type_and_flags (CoglMatrix *matrix)
1093 {
1094   if (matrix->flags & MAT_DIRTY_TYPE)
1095     {
1096       if (matrix->flags & MAT_DIRTY_FLAGS)
1097         analyse_from_scratch (matrix);
1098       else
1099         analyse_from_flags (matrix);
1100     }
1101 
1102   matrix->flags &= ~(MAT_DIRTY_FLAGS | MAT_DIRTY_TYPE);
1103 }
1104 
1105 /*
1106  * Compute inverse of a transformation matrix.
1107  *
1108  * @mat pointer to a CoglMatrix structure. The matrix inverse will be
1109  * stored in the CoglMatrix::inv attribute.
1110  *
1111  * Returns: %TRUE for success, %FALSE for failure (\p singular matrix).
1112  *
1113  * Calls the matrix inversion function in inv_mat_tab corresponding to the
1114  * given matrix type.  In case of failure, updates the MAT_FLAG_SINGULAR flag,
1115  * and copies the identity matrix into CoglMatrix::inv.
1116  */
1117 static CoglBool
_cogl_matrix_update_inverse(CoglMatrix * matrix)1118 _cogl_matrix_update_inverse (CoglMatrix *matrix)
1119 {
1120   if (matrix->flags & MAT_DIRTY_FLAGS ||
1121       matrix->flags & MAT_DIRTY_INVERSE)
1122     {
1123       _cogl_matrix_update_type_and_flags (matrix);
1124 
1125       if (inv_mat_tab[matrix->type](matrix))
1126         matrix->flags &= ~MAT_FLAG_SINGULAR;
1127       else
1128         {
1129           matrix->flags |= MAT_FLAG_SINGULAR;
1130           memcpy (matrix->inv, identity, 16 * sizeof (float));
1131         }
1132 
1133       matrix->flags &= ~MAT_DIRTY_INVERSE;
1134     }
1135 
1136   if (matrix->flags & MAT_FLAG_SINGULAR)
1137     return FALSE;
1138   else
1139     return TRUE;
1140 }
1141 
1142 CoglBool
cogl_matrix_get_inverse(const CoglMatrix * matrix,CoglMatrix * inverse)1143 cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
1144 {
1145   if (_cogl_matrix_update_inverse ((CoglMatrix *)matrix))
1146     {
1147       cogl_matrix_init_from_array (inverse, matrix->inv);
1148       return TRUE;
1149     }
1150   else
1151     {
1152       cogl_matrix_init_identity (inverse);
1153       return FALSE;
1154     }
1155 }
1156 
1157 /*
1158  * Generate a 4x4 transformation matrix from glRotate parameters, and
1159  * post-multiply the input matrix by it.
1160  *
1161  * \author
1162  * This function was contributed by Erich Boleyn (erich@uruk.org).
1163  * Optimizations contributed by Rudolf Opalla (rudi@khm.de).
1164  */
1165 static void
_cogl_matrix_rotate(CoglMatrix * matrix,float angle,float x,float y,float z)1166 _cogl_matrix_rotate (CoglMatrix *matrix,
1167                      float angle,
1168                      float x,
1169                      float y,
1170                      float z)
1171 {
1172   float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
1173   float m[16];
1174   CoglBool optimized;
1175 
1176   s = sinf (angle * DEG2RAD);
1177   c = cosf (angle * DEG2RAD);
1178 
1179   memcpy (m, identity, 16 * sizeof (float));
1180   optimized = FALSE;
1181 
1182 #define M(row,col)  m[col*4+row]
1183 
1184   if (x == 0.0f)
1185     {
1186       if (y == 0.0f)
1187         {
1188           if (z != 0.0f)
1189             {
1190               optimized = TRUE;
1191               /* rotate only around z-axis */
1192               M (0,0) = c;
1193               M (1,1) = c;
1194               if (z < 0.0f)
1195                 {
1196                   M (0,1) = s;
1197                   M (1,0) = -s;
1198                 }
1199               else
1200                 {
1201                   M (0,1) = -s;
1202                   M (1,0) = s;
1203                 }
1204             }
1205         }
1206       else if (z == 0.0f)
1207         {
1208           optimized = TRUE;
1209           /* rotate only around y-axis */
1210           M (0,0) = c;
1211           M (2,2) = c;
1212           if (y < 0.0f)
1213             {
1214               M (0,2) = -s;
1215               M (2,0) = s;
1216             }
1217           else
1218             {
1219               M (0,2) = s;
1220               M (2,0) = -s;
1221             }
1222         }
1223     }
1224   else if (y == 0.0f)
1225     {
1226       if (z == 0.0f)
1227         {
1228           optimized = TRUE;
1229           /* rotate only around x-axis */
1230           M (1,1) = c;
1231           M (2,2) = c;
1232           if (x < 0.0f)
1233             {
1234               M (1,2) = s;
1235               M (2,1) = -s;
1236             }
1237           else
1238             {
1239               M (1,2) = -s;
1240               M (2,1) = s;
1241             }
1242         }
1243     }
1244 
1245   if (!optimized)
1246     {
1247       const float mag = sqrtf (x * x + y * y + z * z);
1248 
1249       if (mag <= 1.0e-4)
1250         {
1251           /* no rotation, leave mat as-is */
1252           return;
1253         }
1254 
1255       x /= mag;
1256       y /= mag;
1257       z /= mag;
1258 
1259 
1260       /*
1261        *     Arbitrary axis rotation matrix.
1262        *
1263        *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
1264        *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
1265        *  (which is about the X-axis), and the two composite transforms
1266        *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
1267        *  from the arbitrary axis to the X-axis then back.  They are
1268        *  all elementary rotations.
1269        *
1270        *  Rz' is a rotation about the Z-axis, to bring the axis vector
1271        *  into the x-z plane.  Then Ry' is applied, rotating about the
1272        *  Y-axis to bring the axis vector parallel with the X-axis.  The
1273        *  rotation about the X-axis is then performed.  Ry and Rz are
1274        *  simply the respective inverse transforms to bring the arbitrary
1275        *  axis back to it's original orientation.  The first transforms
1276        *  Rz' and Ry' are considered inverses, since the data from the
1277        *  arbitrary axis gives you info on how to get to it, not how
1278        *  to get away from it, and an inverse must be applied.
1279        *
1280        *  The basic calculation used is to recognize that the arbitrary
1281        *  axis vector (x, y, z), since it is of unit length, actually
1282        *  represents the sines and cosines of the angles to rotate the
1283        *  X-axis to the same orientation, with theta being the angle about
1284        *  Z and phi the angle about Y (in the order described above)
1285        *  as follows:
1286        *
1287        *  cos ( theta ) = x / sqrt ( 1 - z^2 )
1288        *  sin ( theta ) = y / sqrt ( 1 - z^2 )
1289        *
1290        *  cos ( phi ) = sqrt ( 1 - z^2 )
1291        *  sin ( phi ) = z
1292        *
1293        *  Note that cos ( phi ) can further be inserted to the above
1294        *  formulas:
1295        *
1296        *  cos ( theta ) = x / cos ( phi )
1297        *  sin ( theta ) = y / sin ( phi )
1298        *
1299        *  ...etc.  Because of those relations and the standard trigonometric
1300        *  relations, it is pssible to reduce the transforms down to what
1301        *  is used below.  It may be that any primary axis chosen will give the
1302        *  same results (modulo a sign convention) using thie method.
1303        *
1304        *  Particularly nice is to notice that all divisions that might
1305        *  have caused trouble when parallel to certain planes or
1306        *  axis go away with care paid to reducing the expressions.
1307        *  After checking, it does perform correctly under all cases, since
1308        *  in all the cases of division where the denominator would have
1309        *  been zero, the numerator would have been zero as well, giving
1310        *  the expected result.
1311        */
1312 
1313       xx = x * x;
1314       yy = y * y;
1315       zz = z * z;
1316       xy = x * y;
1317       yz = y * z;
1318       zx = z * x;
1319       xs = x * s;
1320       ys = y * s;
1321       zs = z * s;
1322       one_c = 1.0f - c;
1323 
1324       /* We already hold the identity-matrix so we can skip some statements */
1325       M (0,0) = (one_c * xx) + c;
1326       M (0,1) = (one_c * xy) - zs;
1327       M (0,2) = (one_c * zx) + ys;
1328       /*    M (0,3) = 0.0f; */
1329 
1330       M (1,0) = (one_c * xy) + zs;
1331       M (1,1) = (one_c * yy) + c;
1332       M (1,2) = (one_c * yz) - xs;
1333       /*    M (1,3) = 0.0f; */
1334 
1335       M (2,0) = (one_c * zx) - ys;
1336       M (2,1) = (one_c * yz) + xs;
1337       M (2,2) = (one_c * zz) + c;
1338       /*    M (2,3) = 0.0f; */
1339 
1340       /*
1341          M (3,0) = 0.0f;
1342          M (3,1) = 0.0f;
1343          M (3,2) = 0.0f;
1344          M (3,3) = 1.0f;
1345          */
1346     }
1347 #undef M
1348 
1349   matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_ROTATION);
1350 }
1351 
1352 void
cogl_matrix_rotate(CoglMatrix * matrix,float angle,float x,float y,float z)1353 cogl_matrix_rotate (CoglMatrix *matrix,
1354 		    float angle,
1355 		    float x,
1356 		    float y,
1357 		    float z)
1358 {
1359   _cogl_matrix_rotate (matrix, angle, x, y, z);
1360   _COGL_MATRIX_DEBUG_PRINT (matrix);
1361 }
1362 
1363 void
cogl_matrix_rotate_quaternion(CoglMatrix * matrix,const CoglQuaternion * quaternion)1364 cogl_matrix_rotate_quaternion (CoglMatrix *matrix,
1365                                const CoglQuaternion *quaternion)
1366 {
1367   CoglMatrix rotation_transform;
1368 
1369   cogl_matrix_init_from_quaternion (&rotation_transform, quaternion);
1370   cogl_matrix_multiply (matrix, matrix, &rotation_transform);
1371 }
1372 
1373 void
cogl_matrix_rotate_euler(CoglMatrix * matrix,const CoglEuler * euler)1374 cogl_matrix_rotate_euler (CoglMatrix *matrix,
1375                           const CoglEuler *euler)
1376 {
1377   CoglMatrix rotation_transform;
1378 
1379   cogl_matrix_init_from_euler (&rotation_transform, euler);
1380   cogl_matrix_multiply (matrix, matrix, &rotation_transform);
1381 }
1382 
1383 /*
1384  * Apply a perspective projection matrix.
1385  *
1386  * Creates the projection matrix and multiplies it with matrix, marking the
1387  * MAT_FLAG_PERSPECTIVE flag.
1388  */
1389 static void
_cogl_matrix_frustum(CoglMatrix * matrix,float left,float right,float bottom,float top,float nearval,float farval)1390 _cogl_matrix_frustum (CoglMatrix *matrix,
1391                       float left,
1392                       float right,
1393                       float bottom,
1394                       float top,
1395                       float nearval,
1396                       float farval)
1397 {
1398   float x, y, a, b, c, d;
1399   float m[16];
1400 
1401   x = (2.0f * nearval) / (right - left);
1402   y = (2.0f * nearval) / (top - bottom);
1403   a = (right + left) / (right - left);
1404   b = (top + bottom) / (top - bottom);
1405   c = -(farval + nearval) / ( farval - nearval);
1406   d = -(2.0f * farval * nearval) / (farval - nearval);  /* error? */
1407 
1408 #define M(row,col)  m[col*4+row]
1409   M (0,0) = x;     M (0,1) = 0.0f;  M (0,2) = a;      M (0,3) = 0.0f;
1410   M (1,0) = 0.0f;  M (1,1) = y;     M (1,2) = b;      M (1,3) = 0.0f;
1411   M (2,0) = 0.0f;  M (2,1) = 0.0f;  M (2,2) = c;      M (2,3) = d;
1412   M (3,0) = 0.0f;  M (3,1) = 0.0f;  M (3,2) = -1.0f;  M (3,3) = 0.0f;
1413 #undef M
1414 
1415   matrix_multiply_array_with_flags (matrix, m, MAT_FLAG_PERSPECTIVE);
1416 }
1417 
1418 void
cogl_matrix_frustum(CoglMatrix * matrix,float left,float right,float bottom,float top,float z_near,float z_far)1419 cogl_matrix_frustum (CoglMatrix *matrix,
1420                      float       left,
1421                      float       right,
1422                      float       bottom,
1423                      float       top,
1424                      float       z_near,
1425                      float       z_far)
1426 {
1427   _cogl_matrix_frustum (matrix, left, right, bottom, top, z_near, z_far);
1428   _COGL_MATRIX_DEBUG_PRINT (matrix);
1429 }
1430 
1431 void
cogl_matrix_perspective(CoglMatrix * matrix,float fov_y,float aspect,float z_near,float z_far)1432 cogl_matrix_perspective (CoglMatrix *matrix,
1433                          float       fov_y,
1434                          float       aspect,
1435                          float       z_near,
1436                          float       z_far)
1437 {
1438   float ymax = z_near * tan (fov_y * G_PI / 360.0);
1439 
1440   cogl_matrix_frustum (matrix,
1441                        -ymax * aspect,  /* left */
1442                        ymax * aspect,   /* right */
1443                        -ymax,           /* bottom */
1444                        ymax,            /* top */
1445                        z_near,
1446                        z_far);
1447   _COGL_MATRIX_DEBUG_PRINT (matrix);
1448 }
1449 
1450 /*
1451  * Apply an orthographic projection matrix.
1452  *
1453  * Creates the projection matrix and multiplies it with matrix, marking the
1454  * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags.
1455  */
1456 static void
_cogl_matrix_orthographic(CoglMatrix * matrix,float x_1,float y_1,float x_2,float y_2,float nearval,float farval)1457 _cogl_matrix_orthographic (CoglMatrix *matrix,
1458                            float x_1,
1459                            float y_1,
1460                            float x_2,
1461                            float y_2,
1462                            float nearval,
1463                            float farval)
1464 {
1465   float m[16];
1466 
1467 #define M(row, col)  m[col * 4 + row]
1468   M (0,0) = 2.0f / (x_2 - x_1);
1469   M (0,1) = 0.0f;
1470   M (0,2) = 0.0f;
1471   M (0,3) = -(x_2 + x_1) / (x_2 - x_1);
1472 
1473   M (1,0) = 0.0f;
1474   M (1,1) = 2.0f / (y_1 - y_2);
1475   M (1,2) = 0.0f;
1476   M (1,3) = -(y_1 + y_2) / (y_1 - y_2);
1477 
1478   M (2,0) = 0.0f;
1479   M (2,1) = 0.0f;
1480   M (2,2) = -2.0f / (farval - nearval);
1481   M (2,3) = -(farval + nearval) / (farval - nearval);
1482 
1483   M (3,0) = 0.0f;
1484   M (3,1) = 0.0f;
1485   M (3,2) = 0.0f;
1486   M (3,3) = 1.0f;
1487 #undef M
1488 
1489   matrix_multiply_array_with_flags (matrix, m,
1490                                     (MAT_FLAG_GENERAL_SCALE |
1491                                      MAT_FLAG_TRANSLATION));
1492 }
1493 
1494 void
cogl_matrix_ortho(CoglMatrix * matrix,float left,float right,float bottom,float top,float near,float far)1495 cogl_matrix_ortho (CoglMatrix *matrix,
1496                    float left,
1497                    float right,
1498                    float bottom,
1499                    float top,
1500                    float near,
1501                    float far)
1502 {
1503   _cogl_matrix_orthographic (matrix, left, top, right, bottom, near, far);
1504   _COGL_MATRIX_DEBUG_PRINT (matrix);
1505 }
1506 
1507 void
cogl_matrix_orthographic(CoglMatrix * matrix,float x_1,float y_1,float x_2,float y_2,float near,float far)1508 cogl_matrix_orthographic (CoglMatrix *matrix,
1509                           float x_1,
1510                           float y_1,
1511                           float x_2,
1512                           float y_2,
1513                           float near,
1514                           float far)
1515 {
1516   _cogl_matrix_orthographic (matrix, x_1, y_1, x_2, y_2, near, far);
1517   _COGL_MATRIX_DEBUG_PRINT (matrix);
1518 }
1519 
1520 /*
1521  * Multiply a matrix with a general scaling matrix.
1522  *
1523  * Multiplies in-place the elements of matrix by the scale factors. Checks if
1524  * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE
1525  * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and
1526  * MAT_DIRTY_INVERSE dirty flags.
1527  */
1528 static void
_cogl_matrix_scale(CoglMatrix * matrix,float x,float y,float z)1529 _cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z)
1530 {
1531   float *m = (float *)matrix;
1532   m[0] *= x;   m[4] *= y;   m[8]  *= z;
1533   m[1] *= x;   m[5] *= y;   m[9]  *= z;
1534   m[2] *= x;   m[6] *= y;   m[10] *= z;
1535   m[3] *= x;   m[7] *= y;   m[11] *= z;
1536 
1537   if (fabsf (x - y) < 1e-8 && fabsf (x - z) < 1e-8)
1538     matrix->flags |= MAT_FLAG_UNIFORM_SCALE;
1539   else
1540     matrix->flags |= MAT_FLAG_GENERAL_SCALE;
1541 
1542   matrix->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
1543 }
1544 
1545 void
cogl_matrix_scale(CoglMatrix * matrix,float sx,float sy,float sz)1546 cogl_matrix_scale (CoglMatrix *matrix,
1547 		   float sx,
1548 		   float sy,
1549 		   float sz)
1550 {
1551   _cogl_matrix_scale (matrix, sx, sy, sz);
1552   _COGL_MATRIX_DEBUG_PRINT (matrix);
1553 }
1554 
1555 /*
1556  * Multiply a matrix with a translation matrix.
1557  *
1558  * Adds the translation coordinates to the elements of matrix in-place.  Marks
1559  * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE
1560  * dirty flags.
1561  */
1562 static void
_cogl_matrix_translate(CoglMatrix * matrix,float x,float y,float z)1563 _cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z)
1564 {
1565   float *m = (float *)matrix;
1566   m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
1567   m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
1568   m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
1569   m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
1570 
1571   matrix->flags |= (MAT_FLAG_TRANSLATION |
1572                     MAT_DIRTY_TYPE |
1573                     MAT_DIRTY_INVERSE);
1574 }
1575 
1576 void
cogl_matrix_translate(CoglMatrix * matrix,float x,float y,float z)1577 cogl_matrix_translate (CoglMatrix *matrix,
1578 		       float x,
1579 		       float y,
1580 		       float z)
1581 {
1582   _cogl_matrix_translate (matrix, x, y, z);
1583   _COGL_MATRIX_DEBUG_PRINT (matrix);
1584 }
1585 
1586 #if 0
1587 /*
1588  * Set matrix to do viewport and depthrange mapping.
1589  * Transforms Normalized Device Coords to window/Z values.
1590  */
1591 static void
1592 _cogl_matrix_viewport (CoglMatrix *matrix,
1593                        float x, float y,
1594                        float width, float height,
1595                        float zNear, float zFar, float depthMax)
1596 {
1597   float *m = (float *)matrix;
1598   m[MAT_SX] = width / 2.0f;
1599   m[MAT_TX] = m[MAT_SX] + x;
1600   m[MAT_SY] = height / 2.0f;
1601   m[MAT_TY] = m[MAT_SY] + y;
1602   m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0f);
1603   m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0f + zNear);
1604   matrix->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION;
1605   matrix->type = COGL_MATRIX_TYPE_3D_NO_ROT;
1606 }
1607 #endif
1608 
1609 /*
1610  * Set a matrix to the identity matrix.
1611  *
1612  * @mat matrix.
1613  *
1614  * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if
1615  * not NULL. Sets the matrix type to identity, resets the flags. It
1616  * doesn't initialize the inverse matrix, it just marks it dirty.
1617  */
1618 static void
_cogl_matrix_init_identity(CoglMatrix * matrix)1619 _cogl_matrix_init_identity (CoglMatrix *matrix)
1620 {
1621   memcpy (matrix, identity, 16 * sizeof (float));
1622 
1623   matrix->type = COGL_MATRIX_TYPE_IDENTITY;
1624   matrix->flags = MAT_DIRTY_INVERSE;
1625 }
1626 
1627 void
cogl_matrix_init_identity(CoglMatrix * matrix)1628 cogl_matrix_init_identity (CoglMatrix *matrix)
1629 {
1630   _cogl_matrix_init_identity (matrix);
1631   _COGL_MATRIX_DEBUG_PRINT (matrix);
1632 }
1633 
1634 /*
1635  * Set a matrix to the (tx, ty, tz) translation matrix.
1636  *
1637  * @matix matrix.
1638  * @tx x coordinate of the translation vector
1639  * @ty y coordinate of the translation vector
1640  * @tz z coordinate of the translation vector
1641  */
1642 static void
_cogl_matrix_init_translation(CoglMatrix * matrix,float tx,float ty,float tz)1643 _cogl_matrix_init_translation (CoglMatrix *matrix,
1644                                float       tx,
1645                                float       ty,
1646                                float       tz)
1647 {
1648   memcpy (matrix, identity, 16 * sizeof (float));
1649 
1650   matrix->xw = tx;
1651   matrix->yw = ty;
1652   matrix->zw = tz;
1653 
1654   matrix->type = COGL_MATRIX_TYPE_3D;
1655   matrix->flags = MAT_FLAG_TRANSLATION | MAT_DIRTY_INVERSE;
1656 }
1657 
1658 void
cogl_matrix_init_translation(CoglMatrix * matrix,float tx,float ty,float tz)1659 cogl_matrix_init_translation (CoglMatrix *matrix,
1660                               float       tx,
1661                               float       ty,
1662                               float       tz)
1663 {
1664   _cogl_matrix_init_translation (matrix, tx, ty, tz);
1665   _COGL_MATRIX_DEBUG_PRINT (matrix);
1666 }
1667 
1668 #if 0
1669 /*
1670  * Test if the given matrix preserves vector lengths.
1671  */
1672 static CoglBool
1673 _cogl_matrix_is_length_preserving (const CoglMatrix *m)
1674 {
1675   return TEST_MAT_FLAGS (m, MAT_FLAGS_LENGTH_PRESERVING);
1676 }
1677 
1678 /*
1679  * Test if the given matrix does any rotation.
1680  * (or perhaps if the upper-left 3x3 is non-identity)
1681  */
1682 static CoglBool
1683 _cogl_matrix_has_rotation (const CoglMatrix *matrix)
1684 {
1685   if (matrix->flags & (MAT_FLAG_GENERAL |
1686                        MAT_FLAG_ROTATION |
1687                        MAT_FLAG_GENERAL_3D |
1688                        MAT_FLAG_PERSPECTIVE))
1689     return TRUE;
1690   else
1691     return FALSE;
1692 }
1693 
1694 static CoglBool
1695 _cogl_matrix_is_general_scale (const CoglMatrix *matrix)
1696 {
1697   return (matrix->flags & MAT_FLAG_GENERAL_SCALE) ? TRUE : FALSE;
1698 }
1699 
1700 static CoglBool
1701 _cogl_matrix_is_dirty (const CoglMatrix *matrix)
1702 {
1703   return (matrix->flags & MAT_DIRTY_ALL) ? TRUE : FALSE;
1704 }
1705 #endif
1706 
1707 /*
1708  * Loads a matrix array into CoglMatrix.
1709  *
1710  * @m matrix array.
1711  * @mat matrix.
1712  *
1713  * Copies \p m into CoglMatrix::m and marks the MAT_FLAG_GENERAL and
1714  * MAT_DIRTY_ALL
1715  * flags.
1716  */
1717 static void
_cogl_matrix_init_from_array(CoglMatrix * matrix,const float * array)1718 _cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
1719 {
1720   memcpy (matrix, array, 16 * sizeof (float));
1721   matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
1722 }
1723 
1724 void
cogl_matrix_init_from_array(CoglMatrix * matrix,const float * array)1725 cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
1726 {
1727   _cogl_matrix_init_from_array (matrix, array);
1728   _COGL_MATRIX_DEBUG_PRINT (matrix);
1729 }
1730 
1731 void
_cogl_matrix_init_from_matrix_without_inverse(CoglMatrix * matrix,const CoglMatrix * src)1732 _cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix,
1733                                                const CoglMatrix *src)
1734 {
1735   memcpy (matrix, src, 16 * sizeof (float));
1736   matrix->type = src->type;
1737   matrix->flags = src->flags | MAT_DIRTY_INVERSE;
1738 }
1739 
1740 static void
_cogl_matrix_init_from_quaternion(CoglMatrix * matrix,const CoglQuaternion * quaternion)1741 _cogl_matrix_init_from_quaternion (CoglMatrix *matrix,
1742                                    const CoglQuaternion *quaternion)
1743 {
1744   float qnorm = _COGL_QUATERNION_NORM (quaternion);
1745   float s = (qnorm > 0.0f) ? (2.0f / qnorm) : 0.0f;
1746   float xs = quaternion->x * s;
1747   float ys = quaternion->y * s;
1748   float zs = quaternion->z * s;
1749   float wx = quaternion->w * xs;
1750   float wy = quaternion->w * ys;
1751   float wz = quaternion->w * zs;
1752   float xx = quaternion->x * xs;
1753   float xy = quaternion->x * ys;
1754   float xz = quaternion->x * zs;
1755   float yy = quaternion->y * ys;
1756   float yz = quaternion->y * zs;
1757   float zz = quaternion->z * zs;
1758 
1759   matrix->xx = 1.0f - (yy + zz);
1760   matrix->yx = xy + wz;
1761   matrix->zx = xz - wy;
1762   matrix->xy = xy - wz;
1763   matrix->yy = 1.0f - (xx + zz);
1764   matrix->zy = yz + wx;
1765   matrix->xz = xz + wy;
1766   matrix->yz = yz - wx;
1767   matrix->zz = 1.0f - (xx + yy);
1768   matrix->xw = matrix->yw = matrix->zw = 0.0f;
1769   matrix->wx = matrix->wy = matrix->wz = 0.0f;
1770   matrix->ww = 1.0f;
1771 
1772   matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
1773 }
1774 
1775 void
cogl_matrix_init_from_quaternion(CoglMatrix * matrix,const CoglQuaternion * quaternion)1776 cogl_matrix_init_from_quaternion (CoglMatrix *matrix,
1777                                   const CoglQuaternion *quaternion)
1778 {
1779   _cogl_matrix_init_from_quaternion (matrix, quaternion);
1780 }
1781 
1782 void
cogl_matrix_init_from_euler(CoglMatrix * matrix,const CoglEuler * euler)1783 cogl_matrix_init_from_euler (CoglMatrix *matrix,
1784                              const CoglEuler *euler)
1785 {
1786   /* Convert angles to radians */
1787   float heading_rad = euler->heading / 180.0f * G_PI;
1788   float pitch_rad = euler->pitch / 180.0f * G_PI;
1789   float roll_rad = euler->roll / 180.0f * G_PI;
1790   /* Pre-calculate the sin and cos */
1791   float sin_heading = sinf (heading_rad);
1792   float cos_heading = cosf (heading_rad);
1793   float sin_pitch = sinf (pitch_rad);
1794   float cos_pitch = cosf (pitch_rad);
1795   float sin_roll = sinf (roll_rad);
1796   float cos_roll = cosf (roll_rad);
1797 
1798   /* These calculations are based on the following website but they
1799    * use a different order for the rotations so it has been modified
1800    * slightly.
1801    * http://www.euclideanspace.com/maths/geometry/
1802    *        rotations/conversions/eulerToMatrix/index.htm
1803    */
1804 
1805   /* Heading rotation x=0, y=1, z=0 gives:
1806    *
1807    * [ ch   0   sh   0 ]
1808    * [ 0    1   0    0 ]
1809    * [ -sh  0   ch   0 ]
1810    * [ 0    0   0    1 ]
1811    *
1812    * Pitch rotation x=1, y=0, z=0 gives:
1813    * [ 1    0   0    0 ]
1814    * [ 0    cp  -sp  0 ]
1815    * [ 0    sp  cp   0 ]
1816    * [ 0    0   0    1 ]
1817    *
1818    * Roll rotation x=0, y=0, z=1 gives:
1819    * [ cr   -sr 0    0 ]
1820    * [ sr   cr  0    0 ]
1821    * [ 0    0   1    0 ]
1822    * [ 0    0   0    1 ]
1823    *
1824    * Heading matrix * pitch matrix =
1825    * [ ch   sh*sp    cp*sh   0  ]
1826    * [ 0    cp       -sp     0  ]
1827    * [ -sh  ch*sp    ch*cp   0  ]
1828    * [ 0    0        0       1  ]
1829    *
1830    * That matrix * roll matrix =
1831    * [ ch*cr + sh*sp*sr   sh*sp*cr - ch*sr       sh*cp       0 ]
1832    * [     cp*sr                cp*cr             -sp        0 ]
1833    * [ ch*sp*sr - sh*cr   sh*sr + ch*sp*cr       ch*cp       0 ]
1834    * [       0                    0                0         1 ]
1835    */
1836 
1837   matrix->xx = cos_heading * cos_roll + sin_heading * sin_pitch * sin_roll;
1838   matrix->yx = cos_pitch * sin_roll;
1839   matrix->zx = cos_heading * sin_pitch * sin_roll - sin_heading * cos_roll;
1840   matrix->wx = 0.0f;
1841 
1842   matrix->xy = sin_heading * sin_pitch * cos_roll - cos_heading * sin_roll;
1843   matrix->yy = cos_pitch * cos_roll;
1844   matrix->zy = sin_heading * sin_roll + cos_heading * sin_pitch * cos_roll;
1845   matrix->wy = 0.0f;
1846 
1847   matrix->xz = sin_heading * cos_pitch;
1848   matrix->yz = -sin_pitch;
1849   matrix->zz = cos_heading * cos_pitch;
1850   matrix->wz = 0;
1851 
1852   matrix->xw = 0;
1853   matrix->yw = 0;
1854   matrix->zw = 0;
1855   matrix->ww = 1;
1856 
1857   matrix->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
1858 }
1859 
1860 /*
1861  * Transpose a float matrix.
1862  */
1863 static void
_cogl_matrix_util_transposef(float to[16],const float from[16])1864 _cogl_matrix_util_transposef (float to[16], const float from[16])
1865 {
1866   to[0] = from[0];
1867   to[1] = from[4];
1868   to[2] = from[8];
1869   to[3] = from[12];
1870   to[4] = from[1];
1871   to[5] = from[5];
1872   to[6] = from[9];
1873   to[7] = from[13];
1874   to[8] = from[2];
1875   to[9] = from[6];
1876   to[10] = from[10];
1877   to[11] = from[14];
1878   to[12] = from[3];
1879   to[13] = from[7];
1880   to[14] = from[11];
1881   to[15] = from[15];
1882 }
1883 
1884 void
cogl_matrix_view_2d_in_frustum(CoglMatrix * matrix,float left,float right,float bottom,float top,float z_near,float z_2d,float width_2d,float height_2d)1885 cogl_matrix_view_2d_in_frustum (CoglMatrix *matrix,
1886                                 float left,
1887                                 float right,
1888                                 float bottom,
1889                                 float top,
1890                                 float z_near,
1891                                 float z_2d,
1892                                 float width_2d,
1893                                 float height_2d)
1894 {
1895   float left_2d_plane = left / z_near * z_2d;
1896   float right_2d_plane = right / z_near * z_2d;
1897   float bottom_2d_plane = bottom / z_near * z_2d;
1898   float top_2d_plane = top / z_near * z_2d;
1899 
1900   float width_2d_start = right_2d_plane - left_2d_plane;
1901   float height_2d_start = top_2d_plane - bottom_2d_plane;
1902 
1903   /* Factors to scale from framebuffer geometry to frustum
1904    * cross-section geometry. */
1905   float width_scale = width_2d_start / width_2d;
1906   float height_scale = height_2d_start / height_2d;
1907 
1908   cogl_matrix_translate (matrix,
1909                          left_2d_plane, top_2d_plane, -z_2d);
1910 
1911   cogl_matrix_scale (matrix, width_scale, -height_scale, width_scale);
1912 }
1913 
1914 /* Assuming a symmetric perspective matrix is being used for your
1915  * projective transform this convenience function lets you compose a
1916  * view transform such that geometry on the z=0 plane will map to
1917  * screen coordinates with a top left origin of (0,0) and with the
1918  * given width and height.
1919  */
1920 void
cogl_matrix_view_2d_in_perspective(CoglMatrix * matrix,float fov_y,float aspect,float z_near,float z_2d,float width_2d,float height_2d)1921 cogl_matrix_view_2d_in_perspective (CoglMatrix *matrix,
1922                                     float fov_y,
1923                                     float aspect,
1924                                     float z_near,
1925                                     float z_2d,
1926                                     float width_2d,
1927                                     float height_2d)
1928 {
1929   float top = z_near * tan (fov_y * G_PI / 360.0);
1930   cogl_matrix_view_2d_in_frustum (matrix,
1931                                   -top * aspect,
1932                                   top * aspect,
1933                                   -top,
1934                                   top,
1935                                   z_near,
1936                                   z_2d,
1937                                   width_2d,
1938                                   height_2d);
1939 }
1940 
1941 CoglBool
cogl_matrix_equal(const void * v1,const void * v2)1942 cogl_matrix_equal (const void *v1, const void *v2)
1943 {
1944   const CoglMatrix *a = v1;
1945   const CoglMatrix *b = v2;
1946 
1947   _COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE);
1948   _COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE);
1949 
1950   /* We want to avoid having a fuzzy _equal() function (e.g. that uses
1951    * an arbitrary epsilon value) since this function noteably conforms
1952    * to the prototype suitable for use with g_hash_table_new() and a
1953    * fuzzy hash function isn't really appropriate for comparing hash
1954    * table keys since it's possible that you could end up fetching
1955    * different values if you end up with multiple similar keys in use
1956    * at the same time. If you consider that fuzzyness allows cases
1957    * such as A == B == C but A != C then you could also end up loosing
1958    * values in a hash table.
1959    *
1960    * We do at least use the == operator to compare values though so
1961    * that -0 is considered equal to 0.
1962    */
1963 
1964   /* XXX: We don't compare the flags, inverse matrix or padding */
1965   if (a->xx == b->xx &&
1966       a->xy == b->xy &&
1967       a->xz == b->xz &&
1968       a->xw == b->xw &&
1969       a->yx == b->yx &&
1970       a->yy == b->yy &&
1971       a->yz == b->yz &&
1972       a->yw == b->yw &&
1973       a->zx == b->zx &&
1974       a->zy == b->zy &&
1975       a->zz == b->zz &&
1976       a->zw == b->zw &&
1977       a->wx == b->wx &&
1978       a->wy == b->wy &&
1979       a->wz == b->wz &&
1980       a->ww == b->ww)
1981     return TRUE;
1982   else
1983     return FALSE;
1984 }
1985 
1986 CoglMatrix *
cogl_matrix_copy(const CoglMatrix * matrix)1987 cogl_matrix_copy (const CoglMatrix *matrix)
1988 {
1989   if (G_LIKELY (matrix))
1990     return g_slice_dup (CoglMatrix, matrix);
1991 
1992   return NULL;
1993 }
1994 
1995 void
cogl_matrix_free(CoglMatrix * matrix)1996 cogl_matrix_free (CoglMatrix *matrix)
1997 {
1998   g_slice_free (CoglMatrix, matrix);
1999 }
2000 
2001 const float *
cogl_matrix_get_array(const CoglMatrix * matrix)2002 cogl_matrix_get_array (const CoglMatrix *matrix)
2003 {
2004   return (float *)matrix;
2005 }
2006 
2007 void
cogl_matrix_transform_point(const CoglMatrix * matrix,float * x,float * y,float * z,float * w)2008 cogl_matrix_transform_point (const CoglMatrix *matrix,
2009                              float *x,
2010                              float *y,
2011                              float *z,
2012                              float *w)
2013 {
2014   float _x = *x, _y = *y, _z = *z, _w = *w;
2015 
2016   *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w;
2017   *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w;
2018   *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w;
2019   *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w;
2020 }
2021 
2022 typedef struct _Point2f
2023 {
2024   float x;
2025   float y;
2026 } Point2f;
2027 
2028 typedef struct _Point3f
2029 {
2030   float x;
2031   float y;
2032   float z;
2033 } Point3f;
2034 
2035 typedef struct _Point4f
2036 {
2037   float x;
2038   float y;
2039   float z;
2040   float w;
2041 } Point4f;
2042 
2043 static void
_cogl_matrix_transform_points_f2(const CoglMatrix * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2044 _cogl_matrix_transform_points_f2 (const CoglMatrix *matrix,
2045                                   size_t stride_in,
2046                                   const void *points_in,
2047                                   size_t stride_out,
2048                                   void *points_out,
2049                                   int n_points)
2050 {
2051   int i;
2052 
2053   for (i = 0; i < n_points; i++)
2054     {
2055       Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in);
2056       Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out);
2057 
2058       o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw;
2059       o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw;
2060       o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw;
2061     }
2062 }
2063 
2064 static void
_cogl_matrix_project_points_f2(const CoglMatrix * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2065 _cogl_matrix_project_points_f2 (const CoglMatrix *matrix,
2066                                 size_t stride_in,
2067                                 const void *points_in,
2068                                 size_t stride_out,
2069                                 void *points_out,
2070                                 int n_points)
2071 {
2072   int i;
2073 
2074   for (i = 0; i < n_points; i++)
2075     {
2076       Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in);
2077       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
2078 
2079       o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw;
2080       o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw;
2081       o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw;
2082       o->w = matrix->wx * p.x + matrix->wy * p.y + matrix->ww;
2083     }
2084 }
2085 
2086 static void
_cogl_matrix_transform_points_f3(const CoglMatrix * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2087 _cogl_matrix_transform_points_f3 (const CoglMatrix *matrix,
2088                                   size_t stride_in,
2089                                   const void *points_in,
2090                                   size_t stride_out,
2091                                   void *points_out,
2092                                   int n_points)
2093 {
2094   int i;
2095 
2096   for (i = 0; i < n_points; i++)
2097     {
2098       Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in);
2099       Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out);
2100 
2101       o->x = matrix->xx * p.x + matrix->xy * p.y +
2102              matrix->xz * p.z + matrix->xw;
2103       o->y = matrix->yx * p.x + matrix->yy * p.y +
2104              matrix->yz * p.z + matrix->yw;
2105       o->z = matrix->zx * p.x + matrix->zy * p.y +
2106              matrix->zz * p.z + matrix->zw;
2107     }
2108 }
2109 
2110 static void
_cogl_matrix_project_points_f3(const CoglMatrix * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2111 _cogl_matrix_project_points_f3 (const CoglMatrix *matrix,
2112                                 size_t stride_in,
2113                                 const void *points_in,
2114                                 size_t stride_out,
2115                                 void *points_out,
2116                                 int n_points)
2117 {
2118   int i;
2119 
2120   for (i = 0; i < n_points; i++)
2121     {
2122       Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in);
2123       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
2124 
2125       o->x = matrix->xx * p.x + matrix->xy * p.y +
2126              matrix->xz * p.z + matrix->xw;
2127       o->y = matrix->yx * p.x + matrix->yy * p.y +
2128              matrix->yz * p.z + matrix->yw;
2129       o->z = matrix->zx * p.x + matrix->zy * p.y +
2130              matrix->zz * p.z + matrix->zw;
2131       o->w = matrix->wx * p.x + matrix->wy * p.y +
2132              matrix->wz * p.z + matrix->ww;
2133     }
2134 }
2135 
2136 static void
_cogl_matrix_project_points_f4(const CoglMatrix * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2137 _cogl_matrix_project_points_f4 (const CoglMatrix *matrix,
2138                                 size_t stride_in,
2139                                 const void *points_in,
2140                                 size_t stride_out,
2141                                 void *points_out,
2142                                 int n_points)
2143 {
2144   int i;
2145 
2146   for (i = 0; i < n_points; i++)
2147     {
2148       Point4f p = *(Point4f *)((uint8_t *)points_in + i * stride_in);
2149       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
2150 
2151       o->x = matrix->xx * p.x + matrix->xy * p.y +
2152              matrix->xz * p.z + matrix->xw * p.w;
2153       o->y = matrix->yx * p.x + matrix->yy * p.y +
2154              matrix->yz * p.z + matrix->yw * p.w;
2155       o->z = matrix->zx * p.x + matrix->zy * p.y +
2156              matrix->zz * p.z + matrix->zw * p.w;
2157       o->w = matrix->wx * p.x + matrix->wy * p.y +
2158              matrix->wz * p.z + matrix->ww * p.w;
2159     }
2160 }
2161 
2162 void
cogl_matrix_transform_points(const CoglMatrix * matrix,int n_components,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2163 cogl_matrix_transform_points (const CoglMatrix *matrix,
2164                               int n_components,
2165                               size_t stride_in,
2166                               const void *points_in,
2167                               size_t stride_out,
2168                               void *points_out,
2169                               int n_points)
2170 {
2171   /* The results of transforming always have three components... */
2172   _COGL_RETURN_IF_FAIL (stride_out >= sizeof (Point3f));
2173 
2174   if (n_components == 2)
2175     _cogl_matrix_transform_points_f2 (matrix,
2176                                       stride_in, points_in,
2177                                       stride_out, points_out,
2178                                       n_points);
2179   else
2180     {
2181       _COGL_RETURN_IF_FAIL (n_components == 3);
2182 
2183       _cogl_matrix_transform_points_f3 (matrix,
2184                                         stride_in, points_in,
2185                                         stride_out, points_out,
2186                                         n_points);
2187     }
2188 }
2189 
2190 void
cogl_matrix_project_points(const CoglMatrix * matrix,int n_components,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)2191 cogl_matrix_project_points (const CoglMatrix *matrix,
2192                             int n_components,
2193                             size_t stride_in,
2194                             const void *points_in,
2195                             size_t stride_out,
2196                             void *points_out,
2197                             int n_points)
2198 {
2199   if (n_components == 2)
2200     _cogl_matrix_project_points_f2 (matrix,
2201                                     stride_in, points_in,
2202                                     stride_out, points_out,
2203                                     n_points);
2204   else if (n_components == 3)
2205     _cogl_matrix_project_points_f3 (matrix,
2206                                     stride_in, points_in,
2207                                     stride_out, points_out,
2208                                     n_points);
2209   else
2210     {
2211       _COGL_RETURN_IF_FAIL (n_components == 4);
2212 
2213       _cogl_matrix_project_points_f4 (matrix,
2214                                       stride_in, points_in,
2215                                       stride_out, points_out,
2216                                       n_points);
2217     }
2218 }
2219 
2220 CoglBool
cogl_matrix_is_identity(const CoglMatrix * matrix)2221 cogl_matrix_is_identity (const CoglMatrix *matrix)
2222 {
2223   if (!(matrix->flags & MAT_DIRTY_TYPE) &&
2224       matrix->type == COGL_MATRIX_TYPE_IDENTITY)
2225     return TRUE;
2226   else
2227     return memcmp (matrix, identity, sizeof (float) * 16) == 0;
2228 }
2229 
2230 void
cogl_matrix_look_at(CoglMatrix * matrix,float eye_position_x,float eye_position_y,float eye_position_z,float object_x,float object_y,float object_z,float world_up_x,float world_up_y,float world_up_z)2231 cogl_matrix_look_at (CoglMatrix *matrix,
2232                      float eye_position_x,
2233                      float eye_position_y,
2234                      float eye_position_z,
2235                      float object_x,
2236                      float object_y,
2237                      float object_z,
2238                      float world_up_x,
2239                      float world_up_y,
2240                      float world_up_z)
2241 {
2242   CoglMatrix tmp;
2243   float forward[3];
2244   float side[3];
2245   float up[3];
2246 
2247   /* Get a unit viewing direction vector */
2248   cogl_vector3_init (forward,
2249                      object_x - eye_position_x,
2250                      object_y - eye_position_y,
2251                      object_z - eye_position_z);
2252   cogl_vector3_normalize (forward);
2253 
2254   cogl_vector3_init (up, world_up_x, world_up_y, world_up_z);
2255 
2256   /* Take the sideways direction as being perpendicular to the viewing
2257    * direction and the word up vector. */
2258   cogl_vector3_cross_product (side, forward, up);
2259   cogl_vector3_normalize (side);
2260 
2261   /* Now we have unit sideways and forward-direction vectors calculate
2262    * a new mutually perpendicular up vector. */
2263   cogl_vector3_cross_product (up, side, forward);
2264 
2265   tmp.xx = side[0];
2266   tmp.yx = side[1];
2267   tmp.zx = side[2];
2268   tmp.wx = 0;
2269 
2270   tmp.xy = up[0];
2271   tmp.yy = up[1];
2272   tmp.zy = up[2];
2273   tmp.wy = 0;
2274 
2275   tmp.xz = -forward[0];
2276   tmp.yz = -forward[1];
2277   tmp.zz = -forward[2];
2278   tmp.wz = 0;
2279 
2280   tmp.xw = 0;
2281   tmp.yw = 0;
2282   tmp.zw = 0;
2283   tmp.ww = 1;
2284 
2285   tmp.flags = (MAT_FLAG_GENERAL_3D | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
2286 
2287   cogl_matrix_translate (&tmp, -eye_position_x, -eye_position_y, -eye_position_z);
2288 
2289   cogl_matrix_multiply (matrix, matrix, &tmp);
2290 }
2291 
2292 void
cogl_matrix_transpose(CoglMatrix * matrix)2293 cogl_matrix_transpose (CoglMatrix *matrix)
2294 {
2295   float new_values[16];
2296 
2297   /* We don't need to do anything if the matrix is the identity matrix */
2298   if (!(matrix->flags & MAT_DIRTY_TYPE) &&
2299       matrix->type == COGL_MATRIX_TYPE_IDENTITY)
2300     return;
2301 
2302   _cogl_matrix_util_transposef (new_values, cogl_matrix_get_array (matrix));
2303 
2304   cogl_matrix_init_from_array (matrix, new_values);
2305 }
2306 
2307 GType
cogl_gtype_matrix_get_type(void)2308 cogl_gtype_matrix_get_type (void)
2309 {
2310   return cogl_matrix_get_gtype ();
2311 }
2312