fix stores to vertex state program registers
[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: 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 */
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 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 */
988 void
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 */
1018 void
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 */
1040 void
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 */
1108 static 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 */
1221 static 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 */
1269 void
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 */
1303 void
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 */
1329 void
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 */
1343 void
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 */
1361 void
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 */
1381 void
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 */
1404 void
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 */
1431 void
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 */
1458 void
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