bring in Keith's _math_matrix_ortho() compiler work-around
[mesa.git] / src / mesa / math / m_matrix.c
1 /**
2 * \file m_matrix.c
3 * Matrix operations.
4 *
5 * \note
6 * -# 4x4 transformation matrices are stored in memory in column major order.
7 * -# Points/vertices are to be thought of as column vectors.
8 * -# Transformation of a point p by a matrix M is: p' = M * p
9 */
10
11 /*
12 * Mesa 3-D graphics library
13 * Version: 6.0.1
14 *
15 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a
18 * copy of this software and associated documentation files (the "Software"),
19 * to deal in the Software without restriction, including without limitation
20 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 * and/or sell copies of the Software, and to permit persons to whom the
22 * Software is furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included
25 * in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
31 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 */
34
35
36 #include "glheader.h"
37 #include "imports.h"
38 #include "macros.h"
39 #include "imports.h"
40
41 #include "m_matrix.h"
42
43
44 /**
45 * Names of the corresponding GLmatrixtype values.
46 */
47 static const char *types[] = {
48 "MATRIX_GENERAL",
49 "MATRIX_IDENTITY",
50 "MATRIX_3D_NO_ROT",
51 "MATRIX_PERSPECTIVE",
52 "MATRIX_2D",
53 "MATRIX_2D_NO_ROT",
54 "MATRIX_3D"
55 };
56
57
58 /**
59 * Identity matrix.
60 */
61 static GLfloat Identity[16] = {
62 1.0, 0.0, 0.0, 0.0,
63 0.0, 1.0, 0.0, 0.0,
64 0.0, 0.0, 1.0, 0.0,
65 0.0, 0.0, 0.0, 1.0
66 };
67
68
69
70 /**********************************************************************/
71 /** \name Matrix multiplication */
72 /*@{*/
73
74 #define A(row,col) a[(col<<2)+row]
75 #define B(row,col) b[(col<<2)+row]
76 #define P(row,col) product[(col<<2)+row]
77
78 /**
79 * Perform a full 4x4 matrix multiplication.
80 *
81 * \param a matrix.
82 * \param b matrix.
83 * \param product will receive the product of \p a and \p b.
84 *
85 * \warning Is assumed that \p product != \p b. \p product == \p a is allowed.
86 *
87 * \note KW: 4*16 = 64 multiplications
88 *
89 * \author This \c matmul was contributed by Thomas Malik
90 */
91 static void matmul4( GLfloat *product, const GLfloat *a, const GLfloat *b )
92 {
93 GLint i;
94 for (i = 0; i < 4; i++) {
95 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
96 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
97 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
98 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
99 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
100 }
101 }
102
103 /**
104 * Multiply two matrices known to occupy only the top three rows, such
105 * as typical model matrices, and orthogonal matrices.
106 *
107 * \param a matrix.
108 * \param b matrix.
109 * \param product will receive the product of \p a and \p b.
110 */
111 static void matmul34( GLfloat *product, const GLfloat *a, const GLfloat *b )
112 {
113 GLint i;
114 for (i = 0; i < 3; i++) {
115 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
116 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0);
117 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1);
118 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2);
119 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3;
120 }
121 P(3,0) = 0;
122 P(3,1) = 0;
123 P(3,2) = 0;
124 P(3,3) = 1;
125 }
126
127 #undef A
128 #undef B
129 #undef P
130
131 /**
132 * Multiply a matrix by an array of floats with known properties.
133 *
134 * \param mat pointer to a GLmatrix structure containing the left multiplication
135 * matrix, and that will receive the product result.
136 * \param m right multiplication matrix array.
137 * \param flags flags of the matrix \p m.
138 *
139 * Joins both flags and marks the type and inverse as dirty. Calls matmul34()
140 * if both matrices are 3D, or matmul4() otherwise.
141 */
142 static void matrix_multf( GLmatrix *mat, const GLfloat *m, GLuint flags )
143 {
144 mat->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
145
146 if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D))
147 matmul34( mat->m, mat->m, m );
148 else
149 matmul4( mat->m, mat->m, m );
150 }
151
152 /**
153 * Matrix multiplication.
154 *
155 * \param dest destination matrix.
156 * \param a left matrix.
157 * \param b right matrix.
158 *
159 * Joins both flags and marks the type and inverse as dirty. Calls matmul34()
160 * if both matrices are 3D, or matmul4() otherwise.
161 */
162 void
163 _math_matrix_mul_matrix( GLmatrix *dest, const GLmatrix *a, const GLmatrix *b )
164 {
165 dest->flags = (a->flags |
166 b->flags |
167 MAT_DIRTY_TYPE |
168 MAT_DIRTY_INVERSE);
169
170 if (TEST_MAT_FLAGS(dest, MAT_FLAGS_3D))
171 matmul34( dest->m, a->m, b->m );
172 else
173 matmul4( dest->m, a->m, b->m );
174 }
175
176 /**
177 * Matrix multiplication.
178 *
179 * \param dest left and destination matrix.
180 * \param m right matrix array.
181 *
182 * Marks the matrix flags with general flag, and type and inverse dirty flags.
183 * Calls matmul4() for the multiplication.
184 */
185 void
186 _math_matrix_mul_floats( GLmatrix *dest, const GLfloat *m )
187 {
188 dest->flags |= (MAT_FLAG_GENERAL |
189 MAT_DIRTY_TYPE |
190 MAT_DIRTY_INVERSE);
191
192 matmul4( dest->m, dest->m, m );
193 }
194
195 /*@}*/
196
197
198 /**********************************************************************/
199 /** \name Matrix output */
200 /*@{*/
201
202 /**
203 * Print a matrix array.
204 *
205 * \param m matrix array.
206 *
207 * Called by _math_matrix_print() to print a matrix or its inverse.
208 */
209 static void print_matrix_floats( const GLfloat m[16] )
210 {
211 int i;
212 for (i=0;i<4;i++) {
213 _mesa_debug(NULL,"\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
214 }
215 }
216
217 /**
218 * Dumps the contents of a GLmatrix structure.
219 *
220 * \param m pointer to the GLmatrix structure.
221 */
222 void
223 _math_matrix_print( const GLmatrix *m )
224 {
225 _mesa_debug(NULL, "Matrix type: %s, flags: %x\n", types[m->type], m->flags);
226 print_matrix_floats(m->m);
227 _mesa_debug(NULL, "Inverse: \n");
228 if (m->inv) {
229 GLfloat prod[16];
230 print_matrix_floats(m->inv);
231 matmul4(prod, m->m, m->inv);
232 _mesa_debug(NULL, "Mat * Inverse:\n");
233 print_matrix_floats(prod);
234 }
235 else {
236 _mesa_debug(NULL, " - not available\n");
237 }
238 }
239
240 /*@}*/
241
242
243 /**
244 * References an element of 4x4 matrix.
245 *
246 * \param m matrix array.
247 * \param c column of the desired element.
248 * \param r row of the desired element.
249 *
250 * \return value of the desired element.
251 *
252 * Calculate the linear storage index of the element and references it.
253 */
254 #define MAT(m,r,c) (m)[(c)*4+(r)]
255
256
257 /**********************************************************************/
258 /** \name Matrix inversion */
259 /*@{*/
260
261 /**
262 * Swaps the values of two floating pointer variables.
263 *
264 * Used by invert_matrix_general() to swap the row pointers.
265 */
266 #define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
267
268 /**
269 * Compute inverse of 4x4 transformation matrix.
270 *
271 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
272 * stored in the GLmatrix::inv attribute.
273 *
274 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
275 *
276 * \author
277 * Code contributed by Jacques Leroy jle@star.be
278 *
279 * Calculates the inverse matrix by performing the gaussian matrix reduction
280 * with partial pivoting followed by back/substitution with the loops manually
281 * unrolled.
282 */
283 static GLboolean invert_matrix_general( GLmatrix *mat )
284 {
285 const GLfloat *m = mat->m;
286 GLfloat *out = mat->inv;
287 GLfloat wtmp[4][8];
288 GLfloat m0, m1, m2, m3, s;
289 GLfloat *r0, *r1, *r2, *r3;
290
291 r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
292
293 r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
294 r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
295 r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
296
297 r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
298 r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
299 r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
300
301 r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
302 r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
303 r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
304
305 r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
306 r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
307 r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
308
309 /* choose pivot - or die */
310 if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
311 if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
312 if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
313 if (0.0 == r0[0]) return GL_FALSE;
314
315 /* eliminate first variable */
316 m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
317 s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
318 s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
319 s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
320 s = r0[4];
321 if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
322 s = r0[5];
323 if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
324 s = r0[6];
325 if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
326 s = r0[7];
327 if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
328
329 /* choose pivot - or die */
330 if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
331 if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
332 if (0.0 == r1[1]) return GL_FALSE;
333
334 /* eliminate second variable */
335 m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
336 r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
337 r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
338 s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
339 s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
340 s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
341 s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
342
343 /* choose pivot - or die */
344 if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
345 if (0.0 == r2[2]) return GL_FALSE;
346
347 /* eliminate third variable */
348 m3 = r3[2]/r2[2];
349 r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
350 r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
351 r3[7] -= m3 * r2[7];
352
353 /* last check */
354 if (0.0 == r3[3]) return GL_FALSE;
355
356 s = 1.0F/r3[3]; /* now back substitute row 3 */
357 r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
358
359 m2 = r2[3]; /* now back substitute row 2 */
360 s = 1.0F/r2[2];
361 r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
362 r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
363 m1 = r1[3];
364 r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
365 r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
366 m0 = r0[3];
367 r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
368 r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
369
370 m1 = r1[2]; /* now back substitute row 1 */
371 s = 1.0F/r1[1];
372 r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
373 r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
374 m0 = r0[2];
375 r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
376 r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
377
378 m0 = r0[1]; /* now back substitute row 0 */
379 s = 1.0F/r0[0];
380 r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
381 r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
382
383 MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
384 MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
385 MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
386 MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
387 MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
388 MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
389 MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
390 MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
391
392 return GL_TRUE;
393 }
394 #undef SWAP_ROWS
395
396 /**
397 * Compute inverse of a general 3d transformation matrix.
398 *
399 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
400 * stored in the GLmatrix::inv attribute.
401 *
402 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
403 *
404 * \author Adapted from graphics gems II.
405 *
406 * Calculates the inverse of the upper left by first calculating its
407 * determinant and multiplying it to the symmetric adjust matrix of each
408 * element. Finally deals with the translation part by transforming the
409 * original translation vector using by the calculated submatrix inverse.
410 */
411 static GLboolean invert_matrix_3d_general( GLmatrix *mat )
412 {
413 const GLfloat *in = mat->m;
414 GLfloat *out = mat->inv;
415 GLfloat pos, neg, t;
416 GLfloat det;
417
418 /* Calculate the determinant of upper left 3x3 submatrix and
419 * determine if the matrix is singular.
420 */
421 pos = neg = 0.0;
422 t = MAT(in,0,0) * MAT(in,1,1) * MAT(in,2,2);
423 if (t >= 0.0) pos += t; else neg += t;
424
425 t = MAT(in,1,0) * MAT(in,2,1) * MAT(in,0,2);
426 if (t >= 0.0) pos += t; else neg += t;
427
428 t = MAT(in,2,0) * MAT(in,0,1) * MAT(in,1,2);
429 if (t >= 0.0) pos += t; else neg += t;
430
431 t = -MAT(in,2,0) * MAT(in,1,1) * MAT(in,0,2);
432 if (t >= 0.0) pos += t; else neg += t;
433
434 t = -MAT(in,1,0) * MAT(in,0,1) * MAT(in,2,2);
435 if (t >= 0.0) pos += t; else neg += t;
436
437 t = -MAT(in,0,0) * MAT(in,2,1) * MAT(in,1,2);
438 if (t >= 0.0) pos += t; else neg += t;
439
440 det = pos + neg;
441
442 if (det*det < 1e-25)
443 return GL_FALSE;
444
445 det = 1.0F / det;
446 MAT(out,0,0) = ( (MAT(in,1,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,1,2) )*det);
447 MAT(out,0,1) = (- (MAT(in,0,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,0,2) )*det);
448 MAT(out,0,2) = ( (MAT(in,0,1)*MAT(in,1,2) - MAT(in,1,1)*MAT(in,0,2) )*det);
449 MAT(out,1,0) = (- (MAT(in,1,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,1,2) )*det);
450 MAT(out,1,1) = ( (MAT(in,0,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,0,2) )*det);
451 MAT(out,1,2) = (- (MAT(in,0,0)*MAT(in,1,2) - MAT(in,1,0)*MAT(in,0,2) )*det);
452 MAT(out,2,0) = ( (MAT(in,1,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,1,1) )*det);
453 MAT(out,2,1) = (- (MAT(in,0,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,0,1) )*det);
454 MAT(out,2,2) = ( (MAT(in,0,0)*MAT(in,1,1) - MAT(in,1,0)*MAT(in,0,1) )*det);
455
456 /* Do the translation part */
457 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
458 MAT(in,1,3) * MAT(out,0,1) +
459 MAT(in,2,3) * MAT(out,0,2) );
460 MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
461 MAT(in,1,3) * MAT(out,1,1) +
462 MAT(in,2,3) * MAT(out,1,2) );
463 MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
464 MAT(in,1,3) * MAT(out,2,1) +
465 MAT(in,2,3) * MAT(out,2,2) );
466
467 return GL_TRUE;
468 }
469
470 /**
471 * Compute inverse of a 3d transformation matrix.
472 *
473 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
474 * stored in the GLmatrix::inv attribute.
475 *
476 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
477 *
478 * If the matrix is not an angle preserving matrix then calls
479 * invert_matrix_3d_general for the actual calculation. Otherwise calculates
480 * the inverse matrix analyzing and inverting each of the scaling, rotation and
481 * translation parts.
482 */
483 static GLboolean invert_matrix_3d( GLmatrix *mat )
484 {
485 const GLfloat *in = mat->m;
486 GLfloat *out = mat->inv;
487
488 if (!TEST_MAT_FLAGS(mat, MAT_FLAGS_ANGLE_PRESERVING)) {
489 return invert_matrix_3d_general( mat );
490 }
491
492 if (mat->flags & MAT_FLAG_UNIFORM_SCALE) {
493 GLfloat scale = (MAT(in,0,0) * MAT(in,0,0) +
494 MAT(in,0,1) * MAT(in,0,1) +
495 MAT(in,0,2) * MAT(in,0,2));
496
497 if (scale == 0.0)
498 return GL_FALSE;
499
500 scale = 1.0F / scale;
501
502 /* Transpose and scale the 3 by 3 upper-left submatrix. */
503 MAT(out,0,0) = scale * MAT(in,0,0);
504 MAT(out,1,0) = scale * MAT(in,0,1);
505 MAT(out,2,0) = scale * MAT(in,0,2);
506 MAT(out,0,1) = scale * MAT(in,1,0);
507 MAT(out,1,1) = scale * MAT(in,1,1);
508 MAT(out,2,1) = scale * MAT(in,1,2);
509 MAT(out,0,2) = scale * MAT(in,2,0);
510 MAT(out,1,2) = scale * MAT(in,2,1);
511 MAT(out,2,2) = scale * MAT(in,2,2);
512 }
513 else if (mat->flags & MAT_FLAG_ROTATION) {
514 /* Transpose the 3 by 3 upper-left submatrix. */
515 MAT(out,0,0) = MAT(in,0,0);
516 MAT(out,1,0) = MAT(in,0,1);
517 MAT(out,2,0) = MAT(in,0,2);
518 MAT(out,0,1) = MAT(in,1,0);
519 MAT(out,1,1) = MAT(in,1,1);
520 MAT(out,2,1) = MAT(in,1,2);
521 MAT(out,0,2) = MAT(in,2,0);
522 MAT(out,1,2) = MAT(in,2,1);
523 MAT(out,2,2) = MAT(in,2,2);
524 }
525 else {
526 /* pure translation */
527 MEMCPY( out, Identity, sizeof(Identity) );
528 MAT(out,0,3) = - MAT(in,0,3);
529 MAT(out,1,3) = - MAT(in,1,3);
530 MAT(out,2,3) = - MAT(in,2,3);
531 return GL_TRUE;
532 }
533
534 if (mat->flags & MAT_FLAG_TRANSLATION) {
535 /* Do the translation part */
536 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
537 MAT(in,1,3) * MAT(out,0,1) +
538 MAT(in,2,3) * MAT(out,0,2) );
539 MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
540 MAT(in,1,3) * MAT(out,1,1) +
541 MAT(in,2,3) * MAT(out,1,2) );
542 MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
543 MAT(in,1,3) * MAT(out,2,1) +
544 MAT(in,2,3) * MAT(out,2,2) );
545 }
546 else {
547 MAT(out,0,3) = MAT(out,1,3) = MAT(out,2,3) = 0.0;
548 }
549
550 return GL_TRUE;
551 }
552
553 /**
554 * Compute inverse of an identity transformation matrix.
555 *
556 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
557 * stored in the GLmatrix::inv attribute.
558 *
559 * \return always GL_TRUE.
560 *
561 * Simply copies Identity into GLmatrix::inv.
562 */
563 static GLboolean invert_matrix_identity( GLmatrix *mat )
564 {
565 MEMCPY( mat->inv, Identity, sizeof(Identity) );
566 return GL_TRUE;
567 }
568
569 /**
570 * Compute inverse of a no-rotation 3d transformation matrix.
571 *
572 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
573 * stored in the GLmatrix::inv attribute.
574 *
575 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
576 *
577 * Calculates the
578 */
579 static GLboolean invert_matrix_3d_no_rot( GLmatrix *mat )
580 {
581 const GLfloat *in = mat->m;
582 GLfloat *out = mat->inv;
583
584 if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0 || MAT(in,2,2) == 0 )
585 return GL_FALSE;
586
587 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
588 MAT(out,0,0) = 1.0F / MAT(in,0,0);
589 MAT(out,1,1) = 1.0F / MAT(in,1,1);
590 MAT(out,2,2) = 1.0F / MAT(in,2,2);
591
592 if (mat->flags & MAT_FLAG_TRANSLATION) {
593 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
594 MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
595 MAT(out,2,3) = - (MAT(in,2,3) * MAT(out,2,2));
596 }
597
598 return GL_TRUE;
599 }
600
601 /**
602 * Compute inverse of a no-rotation 2d transformation matrix.
603 *
604 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
605 * stored in the GLmatrix::inv attribute.
606 *
607 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
608 *
609 * Calculates the inverse matrix by applying the inverse scaling and
610 * translation to the identity matrix.
611 */
612 static GLboolean invert_matrix_2d_no_rot( GLmatrix *mat )
613 {
614 const GLfloat *in = mat->m;
615 GLfloat *out = mat->inv;
616
617 if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0)
618 return GL_FALSE;
619
620 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
621 MAT(out,0,0) = 1.0F / MAT(in,0,0);
622 MAT(out,1,1) = 1.0F / MAT(in,1,1);
623
624 if (mat->flags & MAT_FLAG_TRANSLATION) {
625 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
626 MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
627 }
628
629 return GL_TRUE;
630 }
631
632 #if 0
633 /* broken */
634 static GLboolean invert_matrix_perspective( GLmatrix *mat )
635 {
636 const GLfloat *in = mat->m;
637 GLfloat *out = mat->inv;
638
639 if (MAT(in,2,3) == 0)
640 return GL_FALSE;
641
642 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
643
644 MAT(out,0,0) = 1.0F / MAT(in,0,0);
645 MAT(out,1,1) = 1.0F / MAT(in,1,1);
646
647 MAT(out,0,3) = MAT(in,0,2);
648 MAT(out,1,3) = MAT(in,1,2);
649
650 MAT(out,2,2) = 0;
651 MAT(out,2,3) = -1;
652
653 MAT(out,3,2) = 1.0F / MAT(in,2,3);
654 MAT(out,3,3) = MAT(in,2,2) * MAT(out,3,2);
655
656 return GL_TRUE;
657 }
658 #endif
659
660 /**
661 * Matrix inversion function pointer type.
662 */
663 typedef GLboolean (*inv_mat_func)( GLmatrix *mat );
664
665 /**
666 * Table of the matrix inversion functions according to the matrix type.
667 */
668 static inv_mat_func inv_mat_tab[7] = {
669 invert_matrix_general,
670 invert_matrix_identity,
671 invert_matrix_3d_no_rot,
672 #if 0
673 /* Don't use this function for now - it fails when the projection matrix
674 * is premultiplied by a translation (ala Chromium's tilesort SPU).
675 */
676 invert_matrix_perspective,
677 #else
678 invert_matrix_general,
679 #endif
680 invert_matrix_3d, /* lazy! */
681 invert_matrix_2d_no_rot,
682 invert_matrix_3d
683 };
684
685 /**
686 * Compute inverse of a transformation matrix.
687 *
688 * \param mat pointer to a GLmatrix structure. The matrix inverse will be
689 * stored in the GLmatrix::inv attribute.
690 *
691 * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
692 *
693 * Calls the matrix inversion function in inv_mat_tab corresponding to the
694 * given matrix type. In case of failure, updates the MAT_FLAG_SINGULAR flag,
695 * and copies the identity matrix into GLmatrix::inv.
696 */
697 static GLboolean matrix_invert( GLmatrix *mat )
698 {
699 if (inv_mat_tab[mat->type](mat)) {
700 mat->flags &= ~MAT_FLAG_SINGULAR;
701 return GL_TRUE;
702 } else {
703 mat->flags |= MAT_FLAG_SINGULAR;
704 MEMCPY( mat->inv, Identity, sizeof(Identity) );
705 return GL_FALSE;
706 }
707 }
708
709 /*@}*/
710
711
712 /**********************************************************************/
713 /** \name Matrix generation */
714 /*@{*/
715
716 /**
717 * Generate a 4x4 transformation matrix from glRotate parameters, and
718 * post-multiply the input matrix by it.
719 *
720 * \author
721 * This function was contributed by Erich Boleyn (erich@uruk.org).
722 * Optimizations contributed by Rudolf Opalla (rudi@khm.de).
723 */
724 void
725 _math_matrix_rotate( GLmatrix *mat,
726 GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
727 {
728 GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
729 GLfloat m[16];
730 GLboolean optimized;
731
732 s = (GLfloat) sin( angle * DEG2RAD );
733 c = (GLfloat) cos( angle * DEG2RAD );
734
735 MEMCPY(m, Identity, sizeof(GLfloat)*16);
736 optimized = GL_FALSE;
737
738 #define M(row,col) m[col*4+row]
739
740 if (x == 0.0F) {
741 if (y == 0.0F) {
742 if (z != 0.0F) {
743 optimized = GL_TRUE;
744 /* rotate only around z-axis */
745 M(0,0) = c;
746 M(1,1) = c;
747 if (z < 0.0F) {
748 M(0,1) = s;
749 M(1,0) = -s;
750 }
751 else {
752 M(0,1) = -s;
753 M(1,0) = s;
754 }
755 }
756 }
757 else if (z == 0.0F) {
758 optimized = GL_TRUE;
759 /* rotate only around y-axis */
760 M(0,0) = c;
761 M(2,2) = c;
762 if (y < 0.0F) {
763 M(0,2) = -s;
764 M(2,0) = s;
765 }
766 else {
767 M(0,2) = s;
768 M(2,0) = -s;
769 }
770 }
771 }
772 else if (y == 0.0F) {
773 if (z == 0.0F) {
774 optimized = GL_TRUE;
775 /* rotate only around x-axis */
776 M(1,1) = c;
777 M(2,2) = c;
778 if (x < 0.0F) {
779 M(1,2) = s;
780 M(2,1) = -s;
781 }
782 else {
783 M(1,2) = -s;
784 M(2,1) = s;
785 }
786 }
787 }
788
789 if (!optimized) {
790 const GLfloat mag = SQRTF(x * x + y * y + z * z);
791
792 if (mag <= 1.0e-4) {
793 /* no rotation, leave mat as-is */
794 return;
795 }
796
797 x /= mag;
798 y /= mag;
799 z /= mag;
800
801
802 /*
803 * Arbitrary axis rotation matrix.
804 *
805 * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
806 * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
807 * (which is about the X-axis), and the two composite transforms
808 * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
809 * from the arbitrary axis to the X-axis then back. They are
810 * all elementary rotations.
811 *
812 * Rz' is a rotation about the Z-axis, to bring the axis vector
813 * into the x-z plane. Then Ry' is applied, rotating about the
814 * Y-axis to bring the axis vector parallel with the X-axis. The
815 * rotation about the X-axis is then performed. Ry and Rz are
816 * simply the respective inverse transforms to bring the arbitrary
817 * axis back to it's original orientation. The first transforms
818 * Rz' and Ry' are considered inverses, since the data from the
819 * arbitrary axis gives you info on how to get to it, not how
820 * to get away from it, and an inverse must be applied.
821 *
822 * The basic calculation used is to recognize that the arbitrary
823 * axis vector (x, y, z), since it is of unit length, actually
824 * represents the sines and cosines of the angles to rotate the
825 * X-axis to the same orientation, with theta being the angle about
826 * Z and phi the angle about Y (in the order described above)
827 * as follows:
828 *
829 * cos ( theta ) = x / sqrt ( 1 - z^2 )
830 * sin ( theta ) = y / sqrt ( 1 - z^2 )
831 *
832 * cos ( phi ) = sqrt ( 1 - z^2 )
833 * sin ( phi ) = z
834 *
835 * Note that cos ( phi ) can further be inserted to the above
836 * formulas:
837 *
838 * cos ( theta ) = x / cos ( phi )
839 * sin ( theta ) = y / sin ( phi )
840 *
841 * ...etc. Because of those relations and the standard trigonometric
842 * relations, it is pssible to reduce the transforms down to what
843 * is used below. It may be that any primary axis chosen will give the
844 * same results (modulo a sign convention) using thie method.
845 *
846 * Particularly nice is to notice that all divisions that might
847 * have caused trouble when parallel to certain planes or
848 * axis go away with care paid to reducing the expressions.
849 * After checking, it does perform correctly under all cases, since
850 * in all the cases of division where the denominator would have
851 * been zero, the numerator would have been zero as well, giving
852 * the expected result.
853 */
854
855 xx = x * x;
856 yy = y * y;
857 zz = z * z;
858 xy = x * y;
859 yz = y * z;
860 zx = z * x;
861 xs = x * s;
862 ys = y * s;
863 zs = z * s;
864 one_c = 1.0F - c;
865
866 /* We already hold the identity-matrix so we can skip some statements */
867 M(0,0) = (one_c * xx) + c;
868 M(0,1) = (one_c * xy) - zs;
869 M(0,2) = (one_c * zx) + ys;
870 /* M(0,3) = 0.0F; */
871
872 M(1,0) = (one_c * xy) + zs;
873 M(1,1) = (one_c * yy) + c;
874 M(1,2) = (one_c * yz) - xs;
875 /* M(1,3) = 0.0F; */
876
877 M(2,0) = (one_c * zx) - ys;
878 M(2,1) = (one_c * yz) + xs;
879 M(2,2) = (one_c * zz) + c;
880 /* M(2,3) = 0.0F; */
881
882 /*
883 M(3,0) = 0.0F;
884 M(3,1) = 0.0F;
885 M(3,2) = 0.0F;
886 M(3,3) = 1.0F;
887 */
888 }
889 #undef M
890
891 matrix_multf( mat, m, MAT_FLAG_ROTATION );
892 }
893
894 /**
895 * Apply a perspective projection matrix.
896 *
897 * \param mat matrix to apply the projection.
898 * \param left left clipping plane coordinate.
899 * \param right right clipping plane coordinate.
900 * \param bottom bottom clipping plane coordinate.
901 * \param top top clipping plane coordinate.
902 * \param nearval distance to the near clipping plane.
903 * \param farval distance to the far clipping plane.
904 *
905 * Creates the projection matrix and multiplies it with \p mat, marking the
906 * MAT_FLAG_PERSPECTIVE flag.
907 */
908 void
909 _math_matrix_frustum( GLmatrix *mat,
910 GLfloat left, GLfloat right,
911 GLfloat bottom, GLfloat top,
912 GLfloat nearval, GLfloat farval )
913 {
914 GLfloat x, y, a, b, c, d;
915 GLfloat m[16];
916
917 x = (2.0F*nearval) / (right-left);
918 y = (2.0F*nearval) / (top-bottom);
919 a = (right+left) / (right-left);
920 b = (top+bottom) / (top-bottom);
921 c = -(farval+nearval) / ( farval-nearval);
922 d = -(2.0F*farval*nearval) / (farval-nearval); /* error? */
923
924 #define M(row,col) m[col*4+row]
925 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
926 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
927 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
928 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
929 #undef M
930
931 matrix_multf( mat, m, MAT_FLAG_PERSPECTIVE );
932 }
933
934 /**
935 * Apply an orthographic projection matrix.
936 *
937 * \param mat matrix to apply the projection.
938 * \param left left clipping plane coordinate.
939 * \param right right clipping plane coordinate.
940 * \param bottom bottom clipping plane coordinate.
941 * \param top top clipping plane coordinate.
942 * \param nearval distance to the near clipping plane.
943 * \param farval distance to the far clipping plane.
944 *
945 * Creates the projection matrix and multiplies it with \p mat, marking the
946 * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags.
947 */
948 void
949 _math_matrix_ortho( GLmatrix *mat,
950 GLfloat left, GLfloat right,
951 GLfloat bottom, GLfloat top,
952 GLfloat nearval, GLfloat farval )
953 {
954 GLfloat m[16];
955
956 #define M(row,col) m[col*4+row]
957 M(0,0) = 2.0F / (right-left);
958 M(0,1) = 0.0F;
959 M(0,2) = 0.0F;
960 M(0,3) = -(right+left) / (right-left);
961
962 M(1,0) = 0.0F;
963 M(1,1) = 2.0F / (top-bottom);
964 M(1,2) = 0.0F;
965 M(1,3) = -(top+bottom) / (top-bottom);
966
967 M(2,0) = 0.0F;
968 M(2,1) = 0.0F;
969 M(2,2) = -2.0F / (farval-nearval);
970 M(2,3) = -(farval+nearval) / (farval-nearval);
971
972 M(3,0) = 0.0F;
973 M(3,1) = 0.0F;
974 M(3,2) = 0.0F;
975 M(3,3) = 1.0F;
976 #undef M
977
978 matrix_multf( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));
979 }
980
981 /**
982 * Multiply a matrix with a general scaling matrix.
983 *
984 * \param mat matrix.
985 * \param x x axis scale factor.
986 * \param y y axis scale factor.
987 * \param z z axis scale factor.
988 *
989 * Multiplies in-place the elements of \p mat by the scale factors. Checks if
990 * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE
991 * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and
992 * MAT_DIRTY_INVERSE dirty flags.
993 */
994 void
995 _math_matrix_scale( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
996 {
997 GLfloat *m = mat->m;
998 m[0] *= x; m[4] *= y; m[8] *= z;
999 m[1] *= x; m[5] *= y; m[9] *= z;
1000 m[2] *= x; m[6] *= y; m[10] *= z;
1001 m[3] *= x; m[7] *= y; m[11] *= z;
1002
1003 if (fabs(x - y) < 1e-8 && fabs(x - z) < 1e-8)
1004 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1005 else
1006 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1007
1008 mat->flags |= (MAT_DIRTY_TYPE |
1009 MAT_DIRTY_INVERSE);
1010 }
1011
1012 /**
1013 * Multiply a matrix with a translation matrix.
1014 *
1015 * \param mat matrix.
1016 * \param x translation vector x coordinate.
1017 * \param y translation vector y coordinate.
1018 * \param z translation vector z coordinate.
1019 *
1020 * Adds the translation coordinates to the elements of \p mat in-place. Marks
1021 * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE
1022 * dirty flags.
1023 */
1024 void
1025 _math_matrix_translate( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
1026 {
1027 GLfloat *m = mat->m;
1028 m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
1029 m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
1030 m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
1031 m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
1032
1033 mat->flags |= (MAT_FLAG_TRANSLATION |
1034 MAT_DIRTY_TYPE |
1035 MAT_DIRTY_INVERSE);
1036 }
1037
1038 /**
1039 * Set a matrix to the identity matrix.
1040 *
1041 * \param mat matrix.
1042 *
1043 * Copies ::Identity into \p GLmatrix::m, and into GLmatrix::inv if not NULL.
1044 * Sets the matrix type to identity, and clear the dirty flags.
1045 */
1046 void
1047 _math_matrix_set_identity( GLmatrix *mat )
1048 {
1049 MEMCPY( mat->m, Identity, 16*sizeof(GLfloat) );
1050
1051 if (mat->inv)
1052 MEMCPY( mat->inv, Identity, 16*sizeof(GLfloat) );
1053
1054 mat->type = MATRIX_IDENTITY;
1055 mat->flags &= ~(MAT_DIRTY_FLAGS|
1056 MAT_DIRTY_TYPE|
1057 MAT_DIRTY_INVERSE);
1058 }
1059
1060 /*@}*/
1061
1062
1063 /**********************************************************************/
1064 /** \name Matrix analysis */
1065 /*@{*/
1066
1067 #define ZERO(x) (1<<x)
1068 #define ONE(x) (1<<(x+16))
1069
1070 #define MASK_NO_TRX (ZERO(12) | ZERO(13) | ZERO(14))
1071 #define MASK_NO_2D_SCALE ( ONE(0) | ONE(5))
1072
1073 #define MASK_IDENTITY ( ONE(0) | ZERO(4) | ZERO(8) | ZERO(12) |\
1074 ZERO(1) | ONE(5) | ZERO(9) | ZERO(13) |\
1075 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
1076 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
1077
1078 #define MASK_2D_NO_ROT ( ZERO(4) | ZERO(8) | \
1079 ZERO(1) | ZERO(9) | \
1080 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
1081 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
1082
1083 #define MASK_2D ( ZERO(8) | \
1084 ZERO(9) | \
1085 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
1086 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
1087
1088
1089 #define MASK_3D_NO_ROT ( ZERO(4) | ZERO(8) | \
1090 ZERO(1) | ZERO(9) | \
1091 ZERO(2) | ZERO(6) | \
1092 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
1093
1094 #define MASK_3D ( \
1095 \
1096 \
1097 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
1098
1099
1100 #define MASK_PERSPECTIVE ( ZERO(4) | ZERO(12) |\
1101 ZERO(1) | ZERO(13) |\
1102 ZERO(2) | ZERO(6) | \
1103 ZERO(3) | ZERO(7) | ZERO(15) )
1104
1105 #define SQ(x) ((x)*(x))
1106
1107 /**
1108 * Determine type and flags from scratch.
1109 *
1110 * \param mat matrix.
1111 *
1112 * This is expensive enough to only want to do it once.
1113 */
1114 static void analyse_from_scratch( GLmatrix *mat )
1115 {
1116 const GLfloat *m = mat->m;
1117 GLuint mask = 0;
1118 GLuint i;
1119
1120 for (i = 0 ; i < 16 ; i++) {
1121 if (m[i] == 0.0) mask |= (1<<i);
1122 }
1123
1124 if (m[0] == 1.0F) mask |= (1<<16);
1125 if (m[5] == 1.0F) mask |= (1<<21);
1126 if (m[10] == 1.0F) mask |= (1<<26);
1127 if (m[15] == 1.0F) mask |= (1<<31);
1128
1129 mat->flags &= ~MAT_FLAGS_GEOMETRY;
1130
1131 /* Check for translation - no-one really cares
1132 */
1133 if ((mask & MASK_NO_TRX) != MASK_NO_TRX)
1134 mat->flags |= MAT_FLAG_TRANSLATION;
1135
1136 /* Do the real work
1137 */
1138 if (mask == (GLuint) MASK_IDENTITY) {
1139 mat->type = MATRIX_IDENTITY;
1140 }
1141 else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) {
1142 mat->type = MATRIX_2D_NO_ROT;
1143
1144 if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
1145 mat->flags = MAT_FLAG_GENERAL_SCALE;
1146 }
1147 else if ((mask & MASK_2D) == (GLuint) MASK_2D) {
1148 GLfloat mm = DOT2(m, m);
1149 GLfloat m4m4 = DOT2(m+4,m+4);
1150 GLfloat mm4 = DOT2(m,m+4);
1151
1152 mat->type = MATRIX_2D;
1153
1154 /* Check for scale */
1155 if (SQ(mm-1) > SQ(1e-6) ||
1156 SQ(m4m4-1) > SQ(1e-6))
1157 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1158
1159 /* Check for rotation */
1160 if (SQ(mm4) > SQ(1e-6))
1161 mat->flags |= MAT_FLAG_GENERAL_3D;
1162 else
1163 mat->flags |= MAT_FLAG_ROTATION;
1164
1165 }
1166 else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) {
1167 mat->type = MATRIX_3D_NO_ROT;
1168
1169 /* Check for scale */
1170 if (SQ(m[0]-m[5]) < SQ(1e-6) &&
1171 SQ(m[0]-m[10]) < SQ(1e-6)) {
1172 if (SQ(m[0]-1.0) > SQ(1e-6)) {
1173 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1174 }
1175 }
1176 else {
1177 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1178 }
1179 }
1180 else if ((mask & MASK_3D) == (GLuint) MASK_3D) {
1181 GLfloat c1 = DOT3(m,m);
1182 GLfloat c2 = DOT3(m+4,m+4);
1183 GLfloat c3 = DOT3(m+8,m+8);
1184 GLfloat d1 = DOT3(m, m+4);
1185 GLfloat cp[3];
1186
1187 mat->type = MATRIX_3D;
1188
1189 /* Check for scale */
1190 if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) {
1191 if (SQ(c1-1.0) > SQ(1e-6))
1192 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1193 /* else no scale at all */
1194 }
1195 else {
1196 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1197 }
1198
1199 /* Check for rotation */
1200 if (SQ(d1) < SQ(1e-6)) {
1201 CROSS3( cp, m, m+4 );
1202 SUB_3V( cp, cp, (m+8) );
1203 if (LEN_SQUARED_3FV(cp) < SQ(1e-6))
1204 mat->flags |= MAT_FLAG_ROTATION;
1205 else
1206 mat->flags |= MAT_FLAG_GENERAL_3D;
1207 }
1208 else {
1209 mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
1210 }
1211 }
1212 else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) {
1213 mat->type = MATRIX_PERSPECTIVE;
1214 mat->flags |= MAT_FLAG_GENERAL;
1215 }
1216 else {
1217 mat->type = MATRIX_GENERAL;
1218 mat->flags |= MAT_FLAG_GENERAL;
1219 }
1220 }
1221
1222 /**
1223 * Analyze a matrix given that its flags are accurate.
1224 *
1225 * This is the more common operation, hopefully.
1226 */
1227 static void analyse_from_flags( GLmatrix *mat )
1228 {
1229 const GLfloat *m = mat->m;
1230
1231 if (TEST_MAT_FLAGS(mat, 0)) {
1232 mat->type = MATRIX_IDENTITY;
1233 }
1234 else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION |
1235 MAT_FLAG_UNIFORM_SCALE |
1236 MAT_FLAG_GENERAL_SCALE))) {
1237 if ( m[10]==1.0F && m[14]==0.0F ) {
1238 mat->type = MATRIX_2D_NO_ROT;
1239 }
1240 else {
1241 mat->type = MATRIX_3D_NO_ROT;
1242 }
1243 }
1244 else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) {
1245 if ( m[ 8]==0.0F
1246 && m[ 9]==0.0F
1247 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F) {
1248 mat->type = MATRIX_2D;
1249 }
1250 else {
1251 mat->type = MATRIX_3D;
1252 }
1253 }
1254 else if ( m[4]==0.0F && m[12]==0.0F
1255 && m[1]==0.0F && m[13]==0.0F
1256 && m[2]==0.0F && m[6]==0.0F
1257 && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
1258 mat->type = MATRIX_PERSPECTIVE;
1259 }
1260 else {
1261 mat->type = MATRIX_GENERAL;
1262 }
1263 }
1264
1265 /**
1266 * Analyze and update a matrix.
1267 *
1268 * \param mat matrix.
1269 *
1270 * If the matrix type is dirty then calls either analyse_from_scratch() or
1271 * analyse_from_flags() to determine its type, according to whether the flags
1272 * are dirty or not, respectively. If the matrix has an inverse and it's dirty
1273 * then calls matrix_invert(). Finally clears the dirty flags.
1274 */
1275 void
1276 _math_matrix_analyse( GLmatrix *mat )
1277 {
1278 if (mat->flags & MAT_DIRTY_TYPE) {
1279 if (mat->flags & MAT_DIRTY_FLAGS)
1280 analyse_from_scratch( mat );
1281 else
1282 analyse_from_flags( mat );
1283 }
1284
1285 if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) {
1286 matrix_invert( mat );
1287 }
1288
1289 mat->flags &= ~(MAT_DIRTY_FLAGS|
1290 MAT_DIRTY_TYPE|
1291 MAT_DIRTY_INVERSE);
1292 }
1293
1294 /*@}*/
1295
1296
1297 /**********************************************************************/
1298 /** \name Matrix setup */
1299 /*@{*/
1300
1301 /**
1302 * Copy a matrix.
1303 *
1304 * \param to destination matrix.
1305 * \param from source matrix.
1306 *
1307 * Copies all fields in GLmatrix, creating an inverse array if necessary.
1308 */
1309 void
1310 _math_matrix_copy( GLmatrix *to, const GLmatrix *from )
1311 {
1312 MEMCPY( to->m, from->m, sizeof(Identity) );
1313 to->flags = from->flags;
1314 to->type = from->type;
1315
1316 if (to->inv != 0) {
1317 if (from->inv == 0) {
1318 matrix_invert( to );
1319 }
1320 else {
1321 MEMCPY(to->inv, from->inv, sizeof(GLfloat)*16);
1322 }
1323 }
1324 }
1325
1326 /**
1327 * Loads a matrix array into GLmatrix.
1328 *
1329 * \param m matrix array.
1330 * \param mat matrix.
1331 *
1332 * Copies \p m into GLmatrix::m and marks the MAT_FLAG_GENERAL and MAT_DIRTY
1333 * flags.
1334 */
1335 void
1336 _math_matrix_loadf( GLmatrix *mat, const GLfloat *m )
1337 {
1338 MEMCPY( mat->m, m, 16*sizeof(GLfloat) );
1339 mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY);
1340 }
1341
1342 /**
1343 * Matrix constructor.
1344 *
1345 * \param m matrix.
1346 *
1347 * Initialize the GLmatrix fields.
1348 */
1349 void
1350 _math_matrix_ctr( GLmatrix *m )
1351 {
1352 m->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
1353 if (m->m)
1354 MEMCPY( m->m, Identity, sizeof(Identity) );
1355 m->inv = NULL;
1356 m->type = MATRIX_IDENTITY;
1357 m->flags = 0;
1358 }
1359
1360 /**
1361 * Matrix destructor.
1362 *
1363 * \param m matrix.
1364 *
1365 * Frees the data in a GLmatrix.
1366 */
1367 void
1368 _math_matrix_dtr( GLmatrix *m )
1369 {
1370 if (m->m) {
1371 ALIGN_FREE( m->m );
1372 m->m = NULL;
1373 }
1374 if (m->inv) {
1375 ALIGN_FREE( m->inv );
1376 m->inv = NULL;
1377 }
1378 }
1379
1380 /**
1381 * Allocate a matrix inverse.
1382 *
1383 * \param m matrix.
1384 *
1385 * Allocates the matrix inverse, GLmatrix::inv, and sets it to Identity.
1386 */
1387 void
1388 _math_matrix_alloc_inv( GLmatrix *m )
1389 {
1390 if (!m->inv) {
1391 m->inv = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
1392 if (m->inv)
1393 MEMCPY( m->inv, Identity, 16 * sizeof(GLfloat) );
1394 }
1395 }
1396
1397 /*@}*/
1398
1399
1400 /**********************************************************************/
1401 /** \name Matrix transpose */
1402 /*@{*/
1403
1404 /**
1405 * Transpose a GLfloat matrix.
1406 *
1407 * \param to destination array.
1408 * \param from source array.
1409 */
1410 void
1411 _math_transposef( GLfloat to[16], const GLfloat from[16] )
1412 {
1413 to[0] = from[0];
1414 to[1] = from[4];
1415 to[2] = from[8];
1416 to[3] = from[12];
1417 to[4] = from[1];
1418 to[5] = from[5];
1419 to[6] = from[9];
1420 to[7] = from[13];
1421 to[8] = from[2];
1422 to[9] = from[6];
1423 to[10] = from[10];
1424 to[11] = from[14];
1425 to[12] = from[3];
1426 to[13] = from[7];
1427 to[14] = from[11];
1428 to[15] = from[15];
1429 }
1430
1431 /**
1432 * Transpose a GLdouble matrix.
1433 *
1434 * \param to destination array.
1435 * \param from source array.
1436 */
1437 void
1438 _math_transposed( GLdouble to[16], const GLdouble from[16] )
1439 {
1440 to[0] = from[0];
1441 to[1] = from[4];
1442 to[2] = from[8];
1443 to[3] = from[12];
1444 to[4] = from[1];
1445 to[5] = from[5];
1446 to[6] = from[9];
1447 to[7] = from[13];
1448 to[8] = from[2];
1449 to[9] = from[6];
1450 to[10] = from[10];
1451 to[11] = from[14];
1452 to[12] = from[3];
1453 to[13] = from[7];
1454 to[14] = from[11];
1455 to[15] = from[15];
1456 }
1457
1458 /**
1459 * Transpose a GLdouble matrix and convert to GLfloat.
1460 *
1461 * \param to destination array.
1462 * \param from source array.
1463 */
1464 void
1465 _math_transposefd( GLfloat to[16], const GLdouble from[16] )
1466 {
1467 to[0] = (GLfloat) from[0];
1468 to[1] = (GLfloat) from[4];
1469 to[2] = (GLfloat) from[8];
1470 to[3] = (GLfloat) from[12];
1471 to[4] = (GLfloat) from[1];
1472 to[5] = (GLfloat) from[5];
1473 to[6] = (GLfloat) from[9];
1474 to[7] = (GLfloat) from[13];
1475 to[8] = (GLfloat) from[2];
1476 to[9] = (GLfloat) from[6];
1477 to[10] = (GLfloat) from[10];
1478 to[11] = (GLfloat) from[14];
1479 to[12] = (GLfloat) from[3];
1480 to[13] = (GLfloat) from[7];
1481 to[14] = (GLfloat) from[11];
1482 to[15] = (GLfloat) from[15];
1483 }
1484
1485 /*@}*/
1486