m_matrix.c revision 6dc85575000127630489b407c50a4b3ea87c9acb
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:  5.1
14 *
15 * Copyright (C) 1999-2003  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 */
47static 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 */
61static 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 */
91static 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 */
111static 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 */
142static 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 */
162void
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 */
185void
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 */
209static 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 */
222void
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 */
283static 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 */
411static 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 */
483static 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 */
563static 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 */
579static 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 */
612static 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 */
634static 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 */
663typedef GLboolean (*inv_mat_func)( GLmatrix *mat );
664
665/**
666 * Table of the matrix inversion functions according to the matrix type.
667 */
668static 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 */
697static 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 */
724void
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 */
908void
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 */
948void
949_math_matrix_ortho( GLmatrix *mat,
950		    GLfloat left, GLfloat right,
951		    GLfloat bottom, GLfloat top,
952		    GLfloat nearval, GLfloat farval )
953{
954   GLfloat x, y, z;
955   GLfloat tx, ty, tz;
956   GLfloat m[16];
957
958   x = 2.0F / (right-left);
959   y = 2.0F / (top-bottom);
960   z = -2.0F / (farval-nearval);
961   tx = -(right+left) / (right-left);
962   ty = -(top+bottom) / (top-bottom);
963   tz = -(farval+nearval) / (farval-nearval);
964
965#define M(row,col)  m[col*4+row]
966   M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = 0.0F;  M(0,3) = tx;
967   M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = 0.0F;  M(1,3) = ty;
968   M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = z;     M(2,3) = tz;
969   M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = 0.0F;  M(3,3) = 1.0F;
970#undef M
971
972   matrix_multf( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));
973}
974
975/**
976 * Multiply a matrix with a general scaling matrix.
977 *
978 * \param mat matrix.
979 * \param x x axis scale factor.
980 * \param y y axis scale factor.
981 * \param z z axis scale factor.
982 *
983 * Multiplies in-place the elements of \p mat by the scale factors. Checks if
984 * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE
985 * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and
986 * MAT_DIRTY_INVERSE dirty flags.
987 */
988void
989_math_matrix_scale( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
990{
991   GLfloat *m = mat->m;
992   m[0] *= x;   m[4] *= y;   m[8]  *= z;
993   m[1] *= x;   m[5] *= y;   m[9]  *= z;
994   m[2] *= x;   m[6] *= y;   m[10] *= z;
995   m[3] *= x;   m[7] *= y;   m[11] *= z;
996
997   if (fabs(x - y) < 1e-8 && fabs(x - z) < 1e-8)
998      mat->flags |= MAT_FLAG_UNIFORM_SCALE;
999   else
1000      mat->flags |= MAT_FLAG_GENERAL_SCALE;
1001
1002   mat->flags |= (MAT_DIRTY_TYPE |
1003		  MAT_DIRTY_INVERSE);
1004}
1005
1006/**
1007 * Multiply a matrix with a translation matrix.
1008 *
1009 * \param mat matrix.
1010 * \param x translation vector x coordinate.
1011 * \param y translation vector y coordinate.
1012 * \param z translation vector z coordinate.
1013 *
1014 * Adds the translation coordinates to the elements of \p mat in-place.  Marks
1015 * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE
1016 * dirty flags.
1017 */
1018void
1019_math_matrix_translate( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
1020{
1021   GLfloat *m = mat->m;
1022   m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
1023   m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
1024   m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
1025   m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
1026
1027   mat->flags |= (MAT_FLAG_TRANSLATION |
1028		  MAT_DIRTY_TYPE |
1029		  MAT_DIRTY_INVERSE);
1030}
1031
1032/**
1033 * Set a matrix to the identity matrix.
1034 *
1035 * \param mat matrix.
1036 *
1037 * Copies ::Identity into \p GLmatrix::m, and into GLmatrix::inv if not NULL.
1038 * Sets the matrix type to identity, and clear the dirty flags.
1039 */
1040void
1041_math_matrix_set_identity( GLmatrix *mat )
1042{
1043   MEMCPY( mat->m, Identity, 16*sizeof(GLfloat) );
1044
1045   if (mat->inv)
1046      MEMCPY( mat->inv, Identity, 16*sizeof(GLfloat) );
1047
1048   mat->type = MATRIX_IDENTITY;
1049   mat->flags &= ~(MAT_DIRTY_FLAGS|
1050		   MAT_DIRTY_TYPE|
1051		   MAT_DIRTY_INVERSE);
1052}
1053
1054/*@}*/
1055
1056
1057/**********************************************************************/
1058/** \name Matrix analysis */
1059/*@{*/
1060
1061#define ZERO(x) (1<<x)
1062#define ONE(x)  (1<<(x+16))
1063
1064#define MASK_NO_TRX      (ZERO(12) | ZERO(13) | ZERO(14))
1065#define MASK_NO_2D_SCALE ( ONE(0)  | ONE(5))
1066
1067#define MASK_IDENTITY    ( ONE(0)  | ZERO(4)  | ZERO(8)  | ZERO(12) |\
1068			  ZERO(1)  |  ONE(5)  | ZERO(9)  | ZERO(13) |\
1069			  ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
1070			  ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
1071
1072#define MASK_2D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
1073			  ZERO(1)  |            ZERO(9)  |           \
1074			  ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
1075			  ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
1076
1077#define MASK_2D          (                      ZERO(8)  |           \
1078			                        ZERO(9)  |           \
1079			  ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
1080			  ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
1081
1082
1083#define MASK_3D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
1084			  ZERO(1)  |            ZERO(9)  |           \
1085			  ZERO(2)  | ZERO(6)  |                      \
1086			  ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
1087
1088#define MASK_3D          (                                           \
1089			                                             \
1090			                                             \
1091			  ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
1092
1093
1094#define MASK_PERSPECTIVE (           ZERO(4)  |            ZERO(12) |\
1095			  ZERO(1)  |                       ZERO(13) |\
1096			  ZERO(2)  | ZERO(6)  |                      \
1097			  ZERO(3)  | ZERO(7)  |            ZERO(15) )
1098
1099#define SQ(x) ((x)*(x))
1100
1101/**
1102 * Determine type and flags from scratch.
1103 *
1104 * \param mat matrix.
1105 *
1106 * This is expensive enough to only want to do it once.
1107 */
1108static void analyse_from_scratch( GLmatrix *mat )
1109{
1110   const GLfloat *m = mat->m;
1111   GLuint mask = 0;
1112   GLuint i;
1113
1114   for (i = 0 ; i < 16 ; i++) {
1115      if (m[i] == 0.0) mask |= (1<<i);
1116   }
1117
1118   if (m[0] == 1.0F) mask |= (1<<16);
1119   if (m[5] == 1.0F) mask |= (1<<21);
1120   if (m[10] == 1.0F) mask |= (1<<26);
1121   if (m[15] == 1.0F) mask |= (1<<31);
1122
1123   mat->flags &= ~MAT_FLAGS_GEOMETRY;
1124
1125   /* Check for translation - no-one really cares
1126    */
1127   if ((mask & MASK_NO_TRX) != MASK_NO_TRX)
1128      mat->flags |= MAT_FLAG_TRANSLATION;
1129
1130   /* Do the real work
1131    */
1132   if (mask == (GLuint) MASK_IDENTITY) {
1133      mat->type = MATRIX_IDENTITY;
1134   }
1135   else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) {
1136      mat->type = MATRIX_2D_NO_ROT;
1137
1138      if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
1139	 mat->flags = MAT_FLAG_GENERAL_SCALE;
1140   }
1141   else if ((mask & MASK_2D) == (GLuint) MASK_2D) {
1142      GLfloat mm = DOT2(m, m);
1143      GLfloat m4m4 = DOT2(m+4,m+4);
1144      GLfloat mm4 = DOT2(m,m+4);
1145
1146      mat->type = MATRIX_2D;
1147
1148      /* Check for scale */
1149      if (SQ(mm-1) > SQ(1e-6) ||
1150	  SQ(m4m4-1) > SQ(1e-6))
1151	 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1152
1153      /* Check for rotation */
1154      if (SQ(mm4) > SQ(1e-6))
1155	 mat->flags |= MAT_FLAG_GENERAL_3D;
1156      else
1157	 mat->flags |= MAT_FLAG_ROTATION;
1158
1159   }
1160   else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) {
1161      mat->type = MATRIX_3D_NO_ROT;
1162
1163      /* Check for scale */
1164      if (SQ(m[0]-m[5]) < SQ(1e-6) &&
1165	  SQ(m[0]-m[10]) < SQ(1e-6)) {
1166	 if (SQ(m[0]-1.0) > SQ(1e-6)) {
1167	    mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1168         }
1169      }
1170      else {
1171	 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1172      }
1173   }
1174   else if ((mask & MASK_3D) == (GLuint) MASK_3D) {
1175      GLfloat c1 = DOT3(m,m);
1176      GLfloat c2 = DOT3(m+4,m+4);
1177      GLfloat c3 = DOT3(m+8,m+8);
1178      GLfloat d1 = DOT3(m, m+4);
1179      GLfloat cp[3];
1180
1181      mat->type = MATRIX_3D;
1182
1183      /* Check for scale */
1184      if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) {
1185	 if (SQ(c1-1.0) > SQ(1e-6))
1186	    mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1187	 /* else no scale at all */
1188      }
1189      else {
1190	 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1191      }
1192
1193      /* Check for rotation */
1194      if (SQ(d1) < SQ(1e-6)) {
1195	 CROSS3( cp, m, m+4 );
1196	 SUB_3V( cp, cp, (m+8) );
1197	 if (LEN_SQUARED_3FV(cp) < SQ(1e-6))
1198	    mat->flags |= MAT_FLAG_ROTATION;
1199	 else
1200	    mat->flags |= MAT_FLAG_GENERAL_3D;
1201      }
1202      else {
1203	 mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
1204      }
1205   }
1206   else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) {
1207      mat->type = MATRIX_PERSPECTIVE;
1208      mat->flags |= MAT_FLAG_GENERAL;
1209   }
1210   else {
1211      mat->type = MATRIX_GENERAL;
1212      mat->flags |= MAT_FLAG_GENERAL;
1213   }
1214}
1215
1216/**
1217 * Analyze a matrix given that its flags are accurate.
1218 *
1219 * This is the more common operation, hopefully.
1220 */
1221static void analyse_from_flags( GLmatrix *mat )
1222{
1223   const GLfloat *m = mat->m;
1224
1225   if (TEST_MAT_FLAGS(mat, 0)) {
1226      mat->type = MATRIX_IDENTITY;
1227   }
1228   else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION |
1229				 MAT_FLAG_UNIFORM_SCALE |
1230				 MAT_FLAG_GENERAL_SCALE))) {
1231      if ( m[10]==1.0F && m[14]==0.0F ) {
1232	 mat->type = MATRIX_2D_NO_ROT;
1233      }
1234      else {
1235	 mat->type = MATRIX_3D_NO_ROT;
1236      }
1237   }
1238   else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) {
1239      if (                                 m[ 8]==0.0F
1240            &&                             m[ 9]==0.0F
1241            && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F) {
1242	 mat->type = MATRIX_2D;
1243      }
1244      else {
1245	 mat->type = MATRIX_3D;
1246      }
1247   }
1248   else if (                 m[4]==0.0F                 && m[12]==0.0F
1249            && m[1]==0.0F                               && m[13]==0.0F
1250            && m[2]==0.0F && m[6]==0.0F
1251            && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
1252      mat->type = MATRIX_PERSPECTIVE;
1253   }
1254   else {
1255      mat->type = MATRIX_GENERAL;
1256   }
1257}
1258
1259/**
1260 * Analyze and update a matrix.
1261 *
1262 * \param mat matrix.
1263 *
1264 * If the matrix type is dirty then calls either analyse_from_scratch() or
1265 * analyse_from_flags() to determine its type, according to whether the flags
1266 * are dirty or not, respectively. If the matrix has an inverse and it's dirty
1267 * then calls matrix_invert(). Finally clears the dirty flags.
1268 */
1269void
1270_math_matrix_analyse( GLmatrix *mat )
1271{
1272   if (mat->flags & MAT_DIRTY_TYPE) {
1273      if (mat->flags & MAT_DIRTY_FLAGS)
1274	 analyse_from_scratch( mat );
1275      else
1276	 analyse_from_flags( mat );
1277   }
1278
1279   if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) {
1280      matrix_invert( mat );
1281   }
1282
1283   mat->flags &= ~(MAT_DIRTY_FLAGS|
1284		   MAT_DIRTY_TYPE|
1285		   MAT_DIRTY_INVERSE);
1286}
1287
1288/*@}*/
1289
1290
1291/**********************************************************************/
1292/** \name Matrix setup */
1293/*@{*/
1294
1295/**
1296 * Copy a matrix.
1297 *
1298 * \param to destination matrix.
1299 * \param from source matrix.
1300 *
1301 * Copies all fields in GLmatrix, creating an inverse array if necessary.
1302 */
1303void
1304_math_matrix_copy( GLmatrix *to, const GLmatrix *from )
1305{
1306   MEMCPY( to->m, from->m, sizeof(Identity) );
1307   to->flags = from->flags;
1308   to->type = from->type;
1309
1310   if (to->inv != 0) {
1311      if (from->inv == 0) {
1312	 matrix_invert( to );
1313      }
1314      else {
1315	 MEMCPY(to->inv, from->inv, sizeof(GLfloat)*16);
1316      }
1317   }
1318}
1319
1320/**
1321 * Loads a matrix array into GLmatrix.
1322 *
1323 * \param m matrix array.
1324 * \param mat matrix.
1325 *
1326 * Copies \p m into GLmatrix::m and marks the MAT_FLAG_GENERAL and MAT_DIRTY
1327 * flags.
1328 */
1329void
1330_math_matrix_loadf( GLmatrix *mat, const GLfloat *m )
1331{
1332   MEMCPY( mat->m, m, 16*sizeof(GLfloat) );
1333   mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY);
1334}
1335
1336/**
1337 * Matrix constructor.
1338 *
1339 * \param m matrix.
1340 *
1341 * Initialize the GLmatrix fields.
1342 */
1343void
1344_math_matrix_ctr( GLmatrix *m )
1345{
1346   m->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
1347   if (m->m)
1348      MEMCPY( m->m, Identity, sizeof(Identity) );
1349   m->inv = NULL;
1350   m->type = MATRIX_IDENTITY;
1351   m->flags = 0;
1352}
1353
1354/**
1355 * Matrix destructor.
1356 *
1357 * \param m matrix.
1358 *
1359 * Frees the data in a GLmatrix.
1360 */
1361void
1362_math_matrix_dtr( GLmatrix *m )
1363{
1364   if (m->m) {
1365      ALIGN_FREE( m->m );
1366      m->m = NULL;
1367   }
1368   if (m->inv) {
1369      ALIGN_FREE( m->inv );
1370      m->inv = NULL;
1371   }
1372}
1373
1374/**
1375 * Allocate a matrix inverse.
1376 *
1377 * \param m matrix.
1378 *
1379 * Allocates the matrix inverse, GLmatrix::inv, and sets it to Identity.
1380 */
1381void
1382_math_matrix_alloc_inv( GLmatrix *m )
1383{
1384   if (!m->inv) {
1385      m->inv = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
1386      if (m->inv)
1387         MEMCPY( m->inv, Identity, 16 * sizeof(GLfloat) );
1388   }
1389}
1390
1391/*@}*/
1392
1393
1394/**********************************************************************/
1395/** \name Matrix transpose */
1396/*@{*/
1397
1398/**
1399 * Transpose a GLfloat matrix.
1400 *
1401 * \param to destination array.
1402 * \param from source array.
1403 */
1404void
1405_math_transposef( GLfloat to[16], const GLfloat from[16] )
1406{
1407   to[0] = from[0];
1408   to[1] = from[4];
1409   to[2] = from[8];
1410   to[3] = from[12];
1411   to[4] = from[1];
1412   to[5] = from[5];
1413   to[6] = from[9];
1414   to[7] = from[13];
1415   to[8] = from[2];
1416   to[9] = from[6];
1417   to[10] = from[10];
1418   to[11] = from[14];
1419   to[12] = from[3];
1420   to[13] = from[7];
1421   to[14] = from[11];
1422   to[15] = from[15];
1423}
1424
1425/**
1426 * Transpose a GLdouble matrix.
1427 *
1428 * \param to destination array.
1429 * \param from source array.
1430 */
1431void
1432_math_transposed( GLdouble to[16], const GLdouble from[16] )
1433{
1434   to[0] = from[0];
1435   to[1] = from[4];
1436   to[2] = from[8];
1437   to[3] = from[12];
1438   to[4] = from[1];
1439   to[5] = from[5];
1440   to[6] = from[9];
1441   to[7] = from[13];
1442   to[8] = from[2];
1443   to[9] = from[6];
1444   to[10] = from[10];
1445   to[11] = from[14];
1446   to[12] = from[3];
1447   to[13] = from[7];
1448   to[14] = from[11];
1449   to[15] = from[15];
1450}
1451
1452/**
1453 * Transpose a GLdouble matrix and convert to GLfloat.
1454 *
1455 * \param to destination array.
1456 * \param from source array.
1457 */
1458void
1459_math_transposefd( GLfloat to[16], const GLdouble from[16] )
1460{
1461   to[0] = (GLfloat) from[0];
1462   to[1] = (GLfloat) from[4];
1463   to[2] = (GLfloat) from[8];
1464   to[3] = (GLfloat) from[12];
1465   to[4] = (GLfloat) from[1];
1466   to[5] = (GLfloat) from[5];
1467   to[6] = (GLfloat) from[9];
1468   to[7] = (GLfloat) from[13];
1469   to[8] = (GLfloat) from[2];
1470   to[9] = (GLfloat) from[6];
1471   to[10] = (GLfloat) from[10];
1472   to[11] = (GLfloat) from[14];
1473   to[12] = (GLfloat) from[3];
1474   to[13] = (GLfloat) from[7];
1475   to[14] = (GLfloat) from[11];
1476   to[15] = (GLfloat) from[15];
1477}
1478
1479/*@}*/
1480
1481