blob: e204cc7bbc68e01e2602587a3f1f3bb938e47f2c [file] [log] [blame]
Keith Whitwell23caf202000-11-16 21:05:34 +00001
2/*
3 * Mesa 3-D graphics library
Brian Paul1e091f42003-01-08 16:42:47 +00004 * Version: 5.1
Gareth Hughes22144ab2001-03-12 00:48:37 +00005 *
Brian Paul1e091f42003-01-08 16:42:47 +00006 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
Gareth Hughes22144ab2001-03-12 00:48:37 +00007 *
Keith Whitwell23caf202000-11-16 21:05:34 +00008 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
Gareth Hughes22144ab2001-03-12 00:48:37 +000014 *
Keith Whitwell23caf202000-11-16 21:05:34 +000015 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
Gareth Hughes22144ab2001-03-12 00:48:37 +000017 *
Keith Whitwell23caf202000-11-16 21:05:34 +000018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27/*
28 * Matrix operations
29 *
30 * NOTES:
31 * 1. 4x4 transformation matrices are stored in memory in column major order.
32 * 2. Points/vertices are to be thought of as column vectors.
33 * 3. Transformation of a point p by a matrix M is: p' = M * p
34 */
35
Keith Whitwell23caf202000-11-16 21:05:34 +000036#include "glheader.h"
Brian Paul4e9676f2002-06-29 19:48:15 +000037#include "imports.h"
Keith Whitwell23caf202000-11-16 21:05:34 +000038#include "macros.h"
Brian Paul3c634522002-10-24 23:57:19 +000039#include "imports.h"
Keith Whitwell23caf202000-11-16 21:05:34 +000040
41#include "m_matrix.h"
42
Keith Whitwellf4b02d12001-01-05 05:31:42 +000043
Keith Whitwell23caf202000-11-16 21:05:34 +000044static const char *types[] = {
45 "MATRIX_GENERAL",
46 "MATRIX_IDENTITY",
47 "MATRIX_3D_NO_ROT",
48 "MATRIX_PERSPECTIVE",
49 "MATRIX_2D",
50 "MATRIX_2D_NO_ROT",
51 "MATRIX_3D"
52};
53
54
55static GLfloat Identity[16] = {
56 1.0, 0.0, 0.0, 0.0,
57 0.0, 1.0, 0.0, 0.0,
58 0.0, 0.0, 1.0, 0.0,
59 0.0, 0.0, 0.0, 1.0
60};
61
62
63
64
65/*
Gareth Hughes22144ab2001-03-12 00:48:37 +000066 * This matmul was contributed by Thomas Malik
Keith Whitwell23caf202000-11-16 21:05:34 +000067 *
68 * Perform a 4x4 matrix multiplication (product = a x b).
69 * Input: a, b - matrices to multiply
70 * Output: product - product of a and b
71 * WARNING: (product != b) assumed
Gareth Hughes22144ab2001-03-12 00:48:37 +000072 * NOTE: (product == a) allowed
Keith Whitwell23caf202000-11-16 21:05:34 +000073 *
74 * KW: 4*16 = 64 muls
75 */
76#define A(row,col) a[(col<<2)+row]
77#define B(row,col) b[(col<<2)+row]
78#define P(row,col) product[(col<<2)+row]
79
80static void matmul4( GLfloat *product, const GLfloat *a, const GLfloat *b )
81{
82 GLint i;
83 for (i = 0; i < 4; i++) {
84 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
85 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
86 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
87 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
88 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
89 }
90}
91
92
93/* Multiply two matrices known to occupy only the top three rows, such
Gareth Hughes22144ab2001-03-12 00:48:37 +000094 * as typical model matrices, and ortho matrices.
Keith Whitwell23caf202000-11-16 21:05:34 +000095 */
96static void matmul34( GLfloat *product, const GLfloat *a, const GLfloat *b )
97{
98 GLint i;
99 for (i = 0; i < 3; i++) {
100 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
101 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0);
102 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1);
103 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2);
104 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3;
105 }
106 P(3,0) = 0;
107 P(3,1) = 0;
108 P(3,2) = 0;
109 P(3,3) = 1;
110}
111
112
113#undef A
114#undef B
115#undef P
116
117
118/*
119 * Multiply a matrix by an array of floats with known properties.
120 */
121static void matrix_multf( GLmatrix *mat, const GLfloat *m, GLuint flags )
122{
123 mat->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
124
125 if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D))
126 matmul34( mat->m, mat->m, m );
Gareth Hughes22144ab2001-03-12 00:48:37 +0000127 else
128 matmul4( mat->m, mat->m, m );
Keith Whitwell23caf202000-11-16 21:05:34 +0000129}
130
131
132static void print_matrix_floats( const GLfloat m[16] )
133{
134 int i;
135 for (i=0;i<4;i++) {
Brian Paul4e9676f2002-06-29 19:48:15 +0000136 _mesa_debug(NULL,"\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
Keith Whitwell23caf202000-11-16 21:05:34 +0000137 }
138}
139
Gareth Hughes22144ab2001-03-12 00:48:37 +0000140void
Keith Whitwell23caf202000-11-16 21:05:34 +0000141_math_matrix_print( const GLmatrix *m )
142{
Brian Paul4e9676f2002-06-29 19:48:15 +0000143 _mesa_debug(NULL, "Matrix type: %s, flags: %x\n", types[m->type], m->flags);
Keith Whitwell23caf202000-11-16 21:05:34 +0000144 print_matrix_floats(m->m);
Brian Paul4e9676f2002-06-29 19:48:15 +0000145 _mesa_debug(NULL, "Inverse: \n");
Keith Whitwell23caf202000-11-16 21:05:34 +0000146 if (m->inv) {
147 GLfloat prod[16];
148 print_matrix_floats(m->inv);
149 matmul4(prod, m->m, m->inv);
Brian Paul4e9676f2002-06-29 19:48:15 +0000150 _mesa_debug(NULL, "Mat * Inverse:\n");
Keith Whitwell23caf202000-11-16 21:05:34 +0000151 print_matrix_floats(prod);
152 }
153 else {
Brian Paul4e9676f2002-06-29 19:48:15 +0000154 _mesa_debug(NULL, " - not available\n");
Keith Whitwell23caf202000-11-16 21:05:34 +0000155 }
156}
157
158
159
160
161#define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
162#define MAT(m,r,c) (m)[(c)*4+(r)]
163
164/*
165 * Compute inverse of 4x4 transformation matrix.
166 * Code contributed by Jacques Leroy jle@star.be
167 * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
168 */
169static GLboolean invert_matrix_general( GLmatrix *mat )
170{
171 const GLfloat *m = mat->m;
172 GLfloat *out = mat->inv;
173 GLfloat wtmp[4][8];
174 GLfloat m0, m1, m2, m3, s;
175 GLfloat *r0, *r1, *r2, *r3;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000176
Keith Whitwell23caf202000-11-16 21:05:34 +0000177 r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
Gareth Hughes22144ab2001-03-12 00:48:37 +0000178
Keith Whitwell23caf202000-11-16 21:05:34 +0000179 r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
180 r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
181 r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
Gareth Hughes22144ab2001-03-12 00:48:37 +0000182
Keith Whitwell23caf202000-11-16 21:05:34 +0000183 r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
184 r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
185 r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
Gareth Hughes22144ab2001-03-12 00:48:37 +0000186
Keith Whitwell23caf202000-11-16 21:05:34 +0000187 r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
188 r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
189 r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
Gareth Hughes22144ab2001-03-12 00:48:37 +0000190
Keith Whitwell23caf202000-11-16 21:05:34 +0000191 r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
192 r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
193 r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000194
Keith Whitwell23caf202000-11-16 21:05:34 +0000195 /* choose pivot - or die */
196 if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
197 if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
198 if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
199 if (0.0 == r0[0]) return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000200
Keith Whitwell23caf202000-11-16 21:05:34 +0000201 /* eliminate first variable */
202 m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
203 s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
204 s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
205 s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
206 s = r0[4];
207 if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
208 s = r0[5];
209 if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
210 s = r0[6];
211 if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
212 s = r0[7];
213 if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000214
Keith Whitwell23caf202000-11-16 21:05:34 +0000215 /* choose pivot - or die */
216 if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
217 if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
218 if (0.0 == r1[1]) return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000219
Keith Whitwell23caf202000-11-16 21:05:34 +0000220 /* eliminate second variable */
221 m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
222 r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
223 r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
224 s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
225 s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
226 s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
227 s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000228
Keith Whitwell23caf202000-11-16 21:05:34 +0000229 /* choose pivot - or die */
230 if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
231 if (0.0 == r2[2]) return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000232
Keith Whitwell23caf202000-11-16 21:05:34 +0000233 /* eliminate third variable */
234 m3 = r3[2]/r2[2];
235 r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
236 r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
237 r3[7] -= m3 * r2[7];
Gareth Hughes22144ab2001-03-12 00:48:37 +0000238
Keith Whitwell23caf202000-11-16 21:05:34 +0000239 /* last check */
240 if (0.0 == r3[3]) return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000241
Karl Schultz7b9fe822001-09-18 23:06:14 +0000242 s = 1.0F/r3[3]; /* now back substitute row 3 */
Keith Whitwell23caf202000-11-16 21:05:34 +0000243 r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000244
Keith Whitwell23caf202000-11-16 21:05:34 +0000245 m2 = r2[3]; /* now back substitute row 2 */
Karl Schultz7b9fe822001-09-18 23:06:14 +0000246 s = 1.0F/r2[2];
Keith Whitwell23caf202000-11-16 21:05:34 +0000247 r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
248 r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
249 m1 = r1[3];
250 r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
251 r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
252 m0 = r0[3];
253 r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
254 r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000255
Keith Whitwell23caf202000-11-16 21:05:34 +0000256 m1 = r1[2]; /* now back substitute row 1 */
Karl Schultz7b9fe822001-09-18 23:06:14 +0000257 s = 1.0F/r1[1];
Keith Whitwell23caf202000-11-16 21:05:34 +0000258 r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
259 r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
260 m0 = r0[2];
261 r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
262 r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000263
Keith Whitwell23caf202000-11-16 21:05:34 +0000264 m0 = r0[1]; /* now back substitute row 0 */
Karl Schultz7b9fe822001-09-18 23:06:14 +0000265 s = 1.0F/r0[0];
Keith Whitwell23caf202000-11-16 21:05:34 +0000266 r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
267 r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
Gareth Hughes22144ab2001-03-12 00:48:37 +0000268
Keith Whitwell23caf202000-11-16 21:05:34 +0000269 MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
270 MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
271 MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
272 MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
273 MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
274 MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
275 MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
Gareth Hughes22144ab2001-03-12 00:48:37 +0000276 MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
277
Keith Whitwell23caf202000-11-16 21:05:34 +0000278 return GL_TRUE;
279}
280#undef SWAP_ROWS
281
282
283/* Adapted from graphics gems II.
Gareth Hughes22144ab2001-03-12 00:48:37 +0000284 */
Keith Whitwell23caf202000-11-16 21:05:34 +0000285static GLboolean invert_matrix_3d_general( GLmatrix *mat )
286{
287 const GLfloat *in = mat->m;
288 GLfloat *out = mat->inv;
289 GLfloat pos, neg, t;
290 GLfloat det;
291
292 /* Calculate the determinant of upper left 3x3 submatrix and
Gareth Hughes22144ab2001-03-12 00:48:37 +0000293 * determine if the matrix is singular.
Keith Whitwell23caf202000-11-16 21:05:34 +0000294 */
295 pos = neg = 0.0;
296 t = MAT(in,0,0) * MAT(in,1,1) * MAT(in,2,2);
297 if (t >= 0.0) pos += t; else neg += t;
298
299 t = MAT(in,1,0) * MAT(in,2,1) * MAT(in,0,2);
300 if (t >= 0.0) pos += t; else neg += t;
301
302 t = MAT(in,2,0) * MAT(in,0,1) * MAT(in,1,2);
303 if (t >= 0.0) pos += t; else neg += t;
304
305 t = -MAT(in,2,0) * MAT(in,1,1) * MAT(in,0,2);
306 if (t >= 0.0) pos += t; else neg += t;
307
308 t = -MAT(in,1,0) * MAT(in,0,1) * MAT(in,2,2);
309 if (t >= 0.0) pos += t; else neg += t;
310
311 t = -MAT(in,0,0) * MAT(in,2,1) * MAT(in,1,2);
312 if (t >= 0.0) pos += t; else neg += t;
313
314 det = pos + neg;
315
Gareth Hughes22144ab2001-03-12 00:48:37 +0000316 if (det*det < 1e-25)
Keith Whitwell23caf202000-11-16 21:05:34 +0000317 return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000318
Karl Schultz7b9fe822001-09-18 23:06:14 +0000319 det = 1.0F / det;
Keith Whitwell23caf202000-11-16 21:05:34 +0000320 MAT(out,0,0) = ( (MAT(in,1,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,1,2) )*det);
321 MAT(out,0,1) = (- (MAT(in,0,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,0,2) )*det);
322 MAT(out,0,2) = ( (MAT(in,0,1)*MAT(in,1,2) - MAT(in,1,1)*MAT(in,0,2) )*det);
323 MAT(out,1,0) = (- (MAT(in,1,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,1,2) )*det);
324 MAT(out,1,1) = ( (MAT(in,0,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,0,2) )*det);
325 MAT(out,1,2) = (- (MAT(in,0,0)*MAT(in,1,2) - MAT(in,1,0)*MAT(in,0,2) )*det);
326 MAT(out,2,0) = ( (MAT(in,1,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,1,1) )*det);
327 MAT(out,2,1) = (- (MAT(in,0,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,0,1) )*det);
328 MAT(out,2,2) = ( (MAT(in,0,0)*MAT(in,1,1) - MAT(in,1,0)*MAT(in,0,1) )*det);
329
330 /* Do the translation part */
331 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
332 MAT(in,1,3) * MAT(out,0,1) +
333 MAT(in,2,3) * MAT(out,0,2) );
334 MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
335 MAT(in,1,3) * MAT(out,1,1) +
336 MAT(in,2,3) * MAT(out,1,2) );
337 MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
338 MAT(in,1,3) * MAT(out,2,1) +
339 MAT(in,2,3) * MAT(out,2,2) );
Gareth Hughes22144ab2001-03-12 00:48:37 +0000340
Keith Whitwell23caf202000-11-16 21:05:34 +0000341 return GL_TRUE;
342}
343
344
345static GLboolean invert_matrix_3d( GLmatrix *mat )
346{
347 const GLfloat *in = mat->m;
348 GLfloat *out = mat->inv;
349
350 if (!TEST_MAT_FLAGS(mat, MAT_FLAGS_ANGLE_PRESERVING)) {
351 return invert_matrix_3d_general( mat );
352 }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000353
Keith Whitwell23caf202000-11-16 21:05:34 +0000354 if (mat->flags & MAT_FLAG_UNIFORM_SCALE) {
355 GLfloat scale = (MAT(in,0,0) * MAT(in,0,0) +
356 MAT(in,0,1) * MAT(in,0,1) +
357 MAT(in,0,2) * MAT(in,0,2));
358
Gareth Hughes22144ab2001-03-12 00:48:37 +0000359 if (scale == 0.0)
Keith Whitwell23caf202000-11-16 21:05:34 +0000360 return GL_FALSE;
361
Karl Schultz7b9fe822001-09-18 23:06:14 +0000362 scale = 1.0F / scale;
Keith Whitwell23caf202000-11-16 21:05:34 +0000363
364 /* Transpose and scale the 3 by 3 upper-left submatrix. */
365 MAT(out,0,0) = scale * MAT(in,0,0);
366 MAT(out,1,0) = scale * MAT(in,0,1);
367 MAT(out,2,0) = scale * MAT(in,0,2);
368 MAT(out,0,1) = scale * MAT(in,1,0);
369 MAT(out,1,1) = scale * MAT(in,1,1);
370 MAT(out,2,1) = scale * MAT(in,1,2);
371 MAT(out,0,2) = scale * MAT(in,2,0);
372 MAT(out,1,2) = scale * MAT(in,2,1);
373 MAT(out,2,2) = scale * MAT(in,2,2);
374 }
375 else if (mat->flags & MAT_FLAG_ROTATION) {
376 /* Transpose the 3 by 3 upper-left submatrix. */
377 MAT(out,0,0) = MAT(in,0,0);
378 MAT(out,1,0) = MAT(in,0,1);
379 MAT(out,2,0) = MAT(in,0,2);
380 MAT(out,0,1) = MAT(in,1,0);
381 MAT(out,1,1) = MAT(in,1,1);
382 MAT(out,2,1) = MAT(in,1,2);
383 MAT(out,0,2) = MAT(in,2,0);
384 MAT(out,1,2) = MAT(in,2,1);
385 MAT(out,2,2) = MAT(in,2,2);
386 }
387 else {
388 /* pure translation */
389 MEMCPY( out, Identity, sizeof(Identity) );
390 MAT(out,0,3) = - MAT(in,0,3);
391 MAT(out,1,3) = - MAT(in,1,3);
392 MAT(out,2,3) = - MAT(in,2,3);
393 return GL_TRUE;
394 }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000395
Keith Whitwell23caf202000-11-16 21:05:34 +0000396 if (mat->flags & MAT_FLAG_TRANSLATION) {
397 /* Do the translation part */
398 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
399 MAT(in,1,3) * MAT(out,0,1) +
400 MAT(in,2,3) * MAT(out,0,2) );
401 MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
402 MAT(in,1,3) * MAT(out,1,1) +
403 MAT(in,2,3) * MAT(out,1,2) );
404 MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
405 MAT(in,1,3) * MAT(out,2,1) +
406 MAT(in,2,3) * MAT(out,2,2) );
407 }
408 else {
409 MAT(out,0,3) = MAT(out,1,3) = MAT(out,2,3) = 0.0;
410 }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000411
Keith Whitwell23caf202000-11-16 21:05:34 +0000412 return GL_TRUE;
413}
414
Gareth Hughes22144ab2001-03-12 00:48:37 +0000415
Keith Whitwell23caf202000-11-16 21:05:34 +0000416
417static GLboolean invert_matrix_identity( GLmatrix *mat )
418{
419 MEMCPY( mat->inv, Identity, sizeof(Identity) );
420 return GL_TRUE;
421}
422
423
424static GLboolean invert_matrix_3d_no_rot( GLmatrix *mat )
425{
426 const GLfloat *in = mat->m;
427 GLfloat *out = mat->inv;
428
Gareth Hughes22144ab2001-03-12 00:48:37 +0000429 if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0 || MAT(in,2,2) == 0 )
Keith Whitwell23caf202000-11-16 21:05:34 +0000430 return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000431
Keith Whitwell23caf202000-11-16 21:05:34 +0000432 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
Karl Schultz7b9fe822001-09-18 23:06:14 +0000433 MAT(out,0,0) = 1.0F / MAT(in,0,0);
434 MAT(out,1,1) = 1.0F / MAT(in,1,1);
435 MAT(out,2,2) = 1.0F / MAT(in,2,2);
Keith Whitwell23caf202000-11-16 21:05:34 +0000436
437 if (mat->flags & MAT_FLAG_TRANSLATION) {
438 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
439 MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
440 MAT(out,2,3) = - (MAT(in,2,3) * MAT(out,2,2));
441 }
442
443 return GL_TRUE;
444}
445
446
447static GLboolean invert_matrix_2d_no_rot( GLmatrix *mat )
448{
449 const GLfloat *in = mat->m;
450 GLfloat *out = mat->inv;
451
Gareth Hughes22144ab2001-03-12 00:48:37 +0000452 if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0)
Keith Whitwell23caf202000-11-16 21:05:34 +0000453 return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000454
Keith Whitwell23caf202000-11-16 21:05:34 +0000455 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
Karl Schultz7b9fe822001-09-18 23:06:14 +0000456 MAT(out,0,0) = 1.0F / MAT(in,0,0);
457 MAT(out,1,1) = 1.0F / MAT(in,1,1);
Keith Whitwell23caf202000-11-16 21:05:34 +0000458
459 if (mat->flags & MAT_FLAG_TRANSLATION) {
460 MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
461 MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
462 }
463
464 return GL_TRUE;
465}
466
467
Brian Paul4e9676f2002-06-29 19:48:15 +0000468#if 0
469/* broken */
Keith Whitwell23caf202000-11-16 21:05:34 +0000470static GLboolean invert_matrix_perspective( GLmatrix *mat )
471{
472 const GLfloat *in = mat->m;
473 GLfloat *out = mat->inv;
474
475 if (MAT(in,2,3) == 0)
476 return GL_FALSE;
477
478 MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
479
Karl Schultz7b9fe822001-09-18 23:06:14 +0000480 MAT(out,0,0) = 1.0F / MAT(in,0,0);
481 MAT(out,1,1) = 1.0F / MAT(in,1,1);
Keith Whitwell23caf202000-11-16 21:05:34 +0000482
483 MAT(out,0,3) = MAT(in,0,2);
484 MAT(out,1,3) = MAT(in,1,2);
485
486 MAT(out,2,2) = 0;
487 MAT(out,2,3) = -1;
488
Karl Schultz7b9fe822001-09-18 23:06:14 +0000489 MAT(out,3,2) = 1.0F / MAT(in,2,3);
Keith Whitwell23caf202000-11-16 21:05:34 +0000490 MAT(out,3,3) = MAT(in,2,2) * MAT(out,3,2);
491
492 return GL_TRUE;
493}
Brian Paul4e9676f2002-06-29 19:48:15 +0000494#endif
Keith Whitwell23caf202000-11-16 21:05:34 +0000495
496
497typedef GLboolean (*inv_mat_func)( GLmatrix *mat );
498
499
500static inv_mat_func inv_mat_tab[7] = {
501 invert_matrix_general,
502 invert_matrix_identity,
503 invert_matrix_3d_no_rot,
Brian Paula68b8df2002-03-29 17:18:08 +0000504#if 0
505 /* Don't use this function for now - it fails when the projection matrix
506 * is premultiplied by a translation (ala Chromium's tilesort SPU).
507 */
Keith Whitwell23caf202000-11-16 21:05:34 +0000508 invert_matrix_perspective,
Brian Paula68b8df2002-03-29 17:18:08 +0000509#else
510 invert_matrix_general,
511#endif
Keith Whitwell23caf202000-11-16 21:05:34 +0000512 invert_matrix_3d, /* lazy! */
513 invert_matrix_2d_no_rot,
514 invert_matrix_3d
515};
516
517
518static GLboolean matrix_invert( GLmatrix *mat )
519{
520 if (inv_mat_tab[mat->type](mat)) {
521 mat->flags &= ~MAT_FLAG_SINGULAR;
522 return GL_TRUE;
523 } else {
524 mat->flags |= MAT_FLAG_SINGULAR;
525 MEMCPY( mat->inv, Identity, sizeof(Identity) );
526 return GL_FALSE;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000527 }
Keith Whitwell23caf202000-11-16 21:05:34 +0000528}
529
530
531
532
533
534
535/*
536 * Generate a 4x4 transformation matrix from glRotate parameters, and
537 * postmultiply the input matrix by it.
Brian Paul4991d0f2002-09-12 16:26:04 +0000538 * This function contributed by Erich Boleyn (erich@uruk.org).
539 * Optimizatios contributed by Rudolf Opalla (rudi@khm.de).
Keith Whitwell23caf202000-11-16 21:05:34 +0000540 */
Gareth Hughes22144ab2001-03-12 00:48:37 +0000541void
542_math_matrix_rotate( GLmatrix *mat,
Keith Whitwell23caf202000-11-16 21:05:34 +0000543 GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
544{
Brian Paul4991d0f2002-09-12 16:26:04 +0000545 GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
Keith Whitwell23caf202000-11-16 21:05:34 +0000546 GLfloat m[16];
Brian Paul4991d0f2002-09-12 16:26:04 +0000547 GLboolean optimized;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000548
Karl Schultz7b9fe822001-09-18 23:06:14 +0000549 s = (GLfloat) sin( angle * DEG2RAD );
550 c = (GLfloat) cos( angle * DEG2RAD );
Keith Whitwell23caf202000-11-16 21:05:34 +0000551
Brian Paul4991d0f2002-09-12 16:26:04 +0000552 MEMCPY(m, Identity, sizeof(GLfloat)*16);
553 optimized = GL_FALSE;
Keith Whitwell23caf202000-11-16 21:05:34 +0000554
555#define M(row,col) m[col*4+row]
556
Brian Paul4991d0f2002-09-12 16:26:04 +0000557 if (x == 0.0F) {
558 if (y == 0.0F) {
559 if (z != 0.0F) {
560 optimized = GL_TRUE;
561 /* rotate only around z-axis */
562 M(0,0) = c;
563 M(1,1) = c;
564 if (z < 0.0F) {
565 M(0,1) = s;
566 M(1,0) = -s;
567 }
568 else {
569 M(0,1) = -s;
570 M(1,0) = s;
571 }
572 }
573 }
574 else if (z == 0.0F) {
575 optimized = GL_TRUE;
576 /* rotate only around y-axis */
577 M(0,0) = c;
578 M(2,2) = c;
579 if (y < 0.0F) {
580 M(0,2) = -s;
581 M(2,0) = s;
582 }
583 else {
584 M(0,2) = s;
585 M(2,0) = -s;
586 }
587 }
588 }
589 else if (y == 0.0F) {
590 if (z == 0.0F) {
591 optimized = GL_TRUE;
592 /* rotate only around x-axis */
593 M(1,1) = c;
594 M(2,2) = c;
Brian Paul1e091f42003-01-08 16:42:47 +0000595 if (x < 0.0F) {
Brian Paul4991d0f2002-09-12 16:26:04 +0000596 M(1,2) = s;
597 M(2,1) = -s;
598 }
599 else {
600 M(1,2) = -s;
601 M(2,1) = s;
602 }
603 }
604 }
Keith Whitwell23caf202000-11-16 21:05:34 +0000605
Brian Paul4991d0f2002-09-12 16:26:04 +0000606 if (!optimized) {
Brian Paul27558a12003-03-01 01:50:20 +0000607 const GLfloat mag = SQRTF(x * x + y * y + z * z);
Keith Whitwell23caf202000-11-16 21:05:34 +0000608
Brian Paul4991d0f2002-09-12 16:26:04 +0000609 if (mag <= 1.0e-4) {
610 /* no rotation, leave mat as-is */
611 return;
612 }
Keith Whitwell23caf202000-11-16 21:05:34 +0000613
Brian Paul4991d0f2002-09-12 16:26:04 +0000614 x /= mag;
615 y /= mag;
616 z /= mag;
Keith Whitwell23caf202000-11-16 21:05:34 +0000617
Keith Whitwell23caf202000-11-16 21:05:34 +0000618
Brian Paul4991d0f2002-09-12 16:26:04 +0000619 /*
620 * Arbitrary axis rotation matrix.
621 *
622 * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
623 * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
624 * (which is about the X-axis), and the two composite transforms
625 * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
626 * from the arbitrary axis to the X-axis then back. They are
627 * all elementary rotations.
628 *
629 * Rz' is a rotation about the Z-axis, to bring the axis vector
630 * into the x-z plane. Then Ry' is applied, rotating about the
631 * Y-axis to bring the axis vector parallel with the X-axis. The
632 * rotation about the X-axis is then performed. Ry and Rz are
633 * simply the respective inverse transforms to bring the arbitrary
634 * axis back to it's original orientation. The first transforms
635 * Rz' and Ry' are considered inverses, since the data from the
636 * arbitrary axis gives you info on how to get to it, not how
637 * to get away from it, and an inverse must be applied.
638 *
639 * The basic calculation used is to recognize that the arbitrary
640 * axis vector (x, y, z), since it is of unit length, actually
641 * represents the sines and cosines of the angles to rotate the
642 * X-axis to the same orientation, with theta being the angle about
643 * Z and phi the angle about Y (in the order described above)
644 * as follows:
645 *
646 * cos ( theta ) = x / sqrt ( 1 - z^2 )
647 * sin ( theta ) = y / sqrt ( 1 - z^2 )
648 *
649 * cos ( phi ) = sqrt ( 1 - z^2 )
650 * sin ( phi ) = z
651 *
652 * Note that cos ( phi ) can further be inserted to the above
653 * formulas:
654 *
655 * cos ( theta ) = x / cos ( phi )
656 * sin ( theta ) = y / sin ( phi )
657 *
658 * ...etc. Because of those relations and the standard trigonometric
659 * relations, it is pssible to reduce the transforms down to what
660 * is used below. It may be that any primary axis chosen will give the
661 * same results (modulo a sign convention) using thie method.
662 *
663 * Particularly nice is to notice that all divisions that might
664 * have caused trouble when parallel to certain planes or
665 * axis go away with care paid to reducing the expressions.
666 * After checking, it does perform correctly under all cases, since
667 * in all the cases of division where the denominator would have
668 * been zero, the numerator would have been zero as well, giving
669 * the expected result.
670 */
Keith Whitwell23caf202000-11-16 21:05:34 +0000671
Brian Paul4991d0f2002-09-12 16:26:04 +0000672 xx = x * x;
673 yy = y * y;
674 zz = z * z;
675 xy = x * y;
676 yz = y * z;
677 zx = z * x;
678 xs = x * s;
679 ys = y * s;
680 zs = z * s;
681 one_c = 1.0F - c;
682
683 /* We already hold the identity-matrix so we can skip some statements */
684 M(0,0) = (one_c * xx) + c;
685 M(0,1) = (one_c * xy) - zs;
686 M(0,2) = (one_c * zx) + ys;
687/* M(0,3) = 0.0F; */
688
689 M(1,0) = (one_c * xy) + zs;
690 M(1,1) = (one_c * yy) + c;
691 M(1,2) = (one_c * yz) - xs;
692/* M(1,3) = 0.0F; */
693
694 M(2,0) = (one_c * zx) - ys;
695 M(2,1) = (one_c * yz) + xs;
696 M(2,2) = (one_c * zz) + c;
697/* M(2,3) = 0.0F; */
698
699/*
700 M(3,0) = 0.0F;
701 M(3,1) = 0.0F;
702 M(3,2) = 0.0F;
703 M(3,3) = 1.0F;
704*/
705 }
Keith Whitwell23caf202000-11-16 21:05:34 +0000706#undef M
707
708 matrix_multf( mat, m, MAT_FLAG_ROTATION );
709}
710
711
Brian Paul4991d0f2002-09-12 16:26:04 +0000712
Keith Whitwell23caf202000-11-16 21:05:34 +0000713void
Gareth Hughes22144ab2001-03-12 00:48:37 +0000714_math_matrix_frustum( GLmatrix *mat,
Brian Pauld8bc5a92001-02-05 18:48:52 +0000715 GLfloat left, GLfloat right,
Gareth Hughes22144ab2001-03-12 00:48:37 +0000716 GLfloat bottom, GLfloat top,
Brian Pauld8bc5a92001-02-05 18:48:52 +0000717 GLfloat nearval, GLfloat farval )
Keith Whitwell23caf202000-11-16 21:05:34 +0000718{
719 GLfloat x, y, a, b, c, d;
720 GLfloat m[16];
721
Karl Schultz7b9fe822001-09-18 23:06:14 +0000722 x = (2.0F*nearval) / (right-left);
723 y = (2.0F*nearval) / (top-bottom);
Keith Whitwell23caf202000-11-16 21:05:34 +0000724 a = (right+left) / (right-left);
725 b = (top+bottom) / (top-bottom);
726 c = -(farval+nearval) / ( farval-nearval);
Karl Schultz7b9fe822001-09-18 23:06:14 +0000727 d = -(2.0F*farval*nearval) / (farval-nearval); /* error? */
Keith Whitwell23caf202000-11-16 21:05:34 +0000728
729#define M(row,col) m[col*4+row]
730 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
731 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
732 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
733 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
734#undef M
735
736 matrix_multf( mat, m, MAT_FLAG_PERSPECTIVE );
737}
738
739void
Gareth Hughes22144ab2001-03-12 00:48:37 +0000740_math_matrix_ortho( GLmatrix *mat,
Keith Whitwell23caf202000-11-16 21:05:34 +0000741 GLfloat left, GLfloat right,
Gareth Hughes22144ab2001-03-12 00:48:37 +0000742 GLfloat bottom, GLfloat top,
Keith Whitwell23caf202000-11-16 21:05:34 +0000743 GLfloat nearval, GLfloat farval )
744{
745 GLfloat x, y, z;
746 GLfloat tx, ty, tz;
747 GLfloat m[16];
748
Karl Schultz7b9fe822001-09-18 23:06:14 +0000749 x = 2.0F / (right-left);
750 y = 2.0F / (top-bottom);
751 z = -2.0F / (farval-nearval);
Keith Whitwell23caf202000-11-16 21:05:34 +0000752 tx = -(right+left) / (right-left);
753 ty = -(top+bottom) / (top-bottom);
754 tz = -(farval+nearval) / (farval-nearval);
755
756#define M(row,col) m[col*4+row]
757 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = 0.0F; M(0,3) = tx;
758 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = 0.0F; M(1,3) = ty;
759 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = z; M(2,3) = tz;
760 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F;
761#undef M
762
763 matrix_multf( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));
764}
765
766
767#define ZERO(x) (1<<x)
768#define ONE(x) (1<<(x+16))
769
770#define MASK_NO_TRX (ZERO(12) | ZERO(13) | ZERO(14))
771#define MASK_NO_2D_SCALE ( ONE(0) | ONE(5))
772
773#define MASK_IDENTITY ( ONE(0) | ZERO(4) | ZERO(8) | ZERO(12) |\
774 ZERO(1) | ONE(5) | ZERO(9) | ZERO(13) |\
775 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
776 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
777
778#define MASK_2D_NO_ROT ( ZERO(4) | ZERO(8) | \
779 ZERO(1) | ZERO(9) | \
780 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
781 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
782
783#define MASK_2D ( ZERO(8) | \
784 ZERO(9) | \
785 ZERO(2) | ZERO(6) | ONE(10) | ZERO(14) |\
786 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
787
788
789#define MASK_3D_NO_ROT ( ZERO(4) | ZERO(8) | \
790 ZERO(1) | ZERO(9) | \
791 ZERO(2) | ZERO(6) | \
792 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
793
794#define MASK_3D ( \
795 \
796 \
797 ZERO(3) | ZERO(7) | ZERO(11) | ONE(15) )
798
799
800#define MASK_PERSPECTIVE ( ZERO(4) | ZERO(12) |\
801 ZERO(1) | ZERO(13) |\
802 ZERO(2) | ZERO(6) | \
803 ZERO(3) | ZERO(7) | ZERO(15) )
804
805#define SQ(x) ((x)*(x))
Gareth Hughes22144ab2001-03-12 00:48:37 +0000806
Keith Whitwell23caf202000-11-16 21:05:34 +0000807/* Determine type and flags from scratch. This is expensive enough to
808 * only want to do it once.
809 */
Keith Whitwellad2ac212000-11-24 10:25:05 +0000810static void analyse_from_scratch( GLmatrix *mat )
Keith Whitwell23caf202000-11-16 21:05:34 +0000811{
812 const GLfloat *m = mat->m;
813 GLuint mask = 0;
814 GLuint i;
815
816 for (i = 0 ; i < 16 ; i++) {
817 if (m[i] == 0.0) mask |= (1<<i);
818 }
Gareth Hughes22144ab2001-03-12 00:48:37 +0000819
Keith Whitwell23caf202000-11-16 21:05:34 +0000820 if (m[0] == 1.0F) mask |= (1<<16);
821 if (m[5] == 1.0F) mask |= (1<<21);
822 if (m[10] == 1.0F) mask |= (1<<26);
823 if (m[15] == 1.0F) mask |= (1<<31);
824
825 mat->flags &= ~MAT_FLAGS_GEOMETRY;
826
Gareth Hughes22144ab2001-03-12 00:48:37 +0000827 /* Check for translation - no-one really cares
Keith Whitwell23caf202000-11-16 21:05:34 +0000828 */
Gareth Hughes22144ab2001-03-12 00:48:37 +0000829 if ((mask & MASK_NO_TRX) != MASK_NO_TRX)
830 mat->flags |= MAT_FLAG_TRANSLATION;
Keith Whitwell23caf202000-11-16 21:05:34 +0000831
832 /* Do the real work
833 */
Brian Paulb51b0a82001-03-07 05:06:11 +0000834 if (mask == (GLuint) MASK_IDENTITY) {
Keith Whitwell23caf202000-11-16 21:05:34 +0000835 mat->type = MATRIX_IDENTITY;
836 }
Brian Paulb51b0a82001-03-07 05:06:11 +0000837 else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) {
Keith Whitwell23caf202000-11-16 21:05:34 +0000838 mat->type = MATRIX_2D_NO_ROT;
Gareth Hughes22144ab2001-03-12 00:48:37 +0000839
Keith Whitwell23caf202000-11-16 21:05:34 +0000840 if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
841 mat->flags = MAT_FLAG_GENERAL_SCALE;
842 }
Brian Paulb51b0a82001-03-07 05:06:11 +0000843 else if ((mask & MASK_2D) == (GLuint) MASK_2D) {
Keith Whitwell23caf202000-11-16 21:05:34 +0000844 GLfloat mm = DOT2(m, m);
845 GLfloat m4m4 = DOT2(m+4,m+4);
846 GLfloat mm4 = DOT2(m,m+4);
847
848 mat->type = MATRIX_2D;
849
850 /* Check for scale */
851 if (SQ(mm-1) > SQ(1e-6) ||
Gareth Hughes22144ab2001-03-12 00:48:37 +0000852 SQ(m4m4-1) > SQ(1e-6))
Keith Whitwell23caf202000-11-16 21:05:34 +0000853 mat->flags |= MAT_FLAG_GENERAL_SCALE;
854
855 /* Check for rotation */
856 if (SQ(mm4) > SQ(1e-6))
857 mat->flags |= MAT_FLAG_GENERAL_3D;
858 else
859 mat->flags |= MAT_FLAG_ROTATION;
860
861 }
Brian Paulb51b0a82001-03-07 05:06:11 +0000862 else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) {
Keith Whitwell23caf202000-11-16 21:05:34 +0000863 mat->type = MATRIX_3D_NO_ROT;
864
865 /* Check for scale */
Gareth Hughes22144ab2001-03-12 00:48:37 +0000866 if (SQ(m[0]-m[5]) < SQ(1e-6) &&
Keith Whitwell23caf202000-11-16 21:05:34 +0000867 SQ(m[0]-m[10]) < SQ(1e-6)) {
868 if (SQ(m[0]-1.0) > SQ(1e-6)) {
869 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
870 }
871 }
872 else {
873 mat->flags |= MAT_FLAG_GENERAL_SCALE;
874 }
875 }
Brian Paulb51b0a82001-03-07 05:06:11 +0000876 else if ((mask & MASK_3D) == (GLuint) MASK_3D) {
Keith Whitwell23caf202000-11-16 21:05:34 +0000877 GLfloat c1 = DOT3(m,m);
878 GLfloat c2 = DOT3(m+4,m+4);
879 GLfloat c3 = DOT3(m+8,m+8);
880 GLfloat d1 = DOT3(m, m+4);
881 GLfloat cp[3];
882
883 mat->type = MATRIX_3D;
884
885 /* Check for scale */
886 if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) {
887 if (SQ(c1-1.0) > SQ(1e-6))
888 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
889 /* else no scale at all */
890 }
891 else {
892 mat->flags |= MAT_FLAG_GENERAL_SCALE;
893 }
894
895 /* Check for rotation */
896 if (SQ(d1) < SQ(1e-6)) {
897 CROSS3( cp, m, m+4 );
898 SUB_3V( cp, cp, (m+8) );
Gareth Hughes22144ab2001-03-12 00:48:37 +0000899 if (LEN_SQUARED_3FV(cp) < SQ(1e-6))
Keith Whitwell23caf202000-11-16 21:05:34 +0000900 mat->flags |= MAT_FLAG_ROTATION;
901 else
902 mat->flags |= MAT_FLAG_GENERAL_3D;
903 }
904 else {
905 mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
906 }
907 }
908 else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) {
909 mat->type = MATRIX_PERSPECTIVE;
910 mat->flags |= MAT_FLAG_GENERAL;
911 }
912 else {
913 mat->type = MATRIX_GENERAL;
914 mat->flags |= MAT_FLAG_GENERAL;
915 }
916}
917
918
919/* Analyse a matrix given that its flags are accurate - this is the
Gareth Hughes22144ab2001-03-12 00:48:37 +0000920 * more common operation, hopefully.
Keith Whitwell23caf202000-11-16 21:05:34 +0000921 */
Keith Whitwellad2ac212000-11-24 10:25:05 +0000922static void analyse_from_flags( GLmatrix *mat )
Keith Whitwell23caf202000-11-16 21:05:34 +0000923{
924 const GLfloat *m = mat->m;
925
926 if (TEST_MAT_FLAGS(mat, 0)) {
927 mat->type = MATRIX_IDENTITY;
928 }
929 else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION |
930 MAT_FLAG_UNIFORM_SCALE |
931 MAT_FLAG_GENERAL_SCALE))) {
932 if ( m[10]==1.0F && m[14]==0.0F ) {
933 mat->type = MATRIX_2D_NO_ROT;
934 }
935 else {
936 mat->type = MATRIX_3D_NO_ROT;
937 }
938 }
939 else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) {
Gareth Hughes22144ab2001-03-12 00:48:37 +0000940 if ( m[ 8]==0.0F
Keith Whitwell23caf202000-11-16 21:05:34 +0000941 && m[ 9]==0.0F
942 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F) {
943 mat->type = MATRIX_2D;
944 }
945 else {
946 mat->type = MATRIX_3D;
947 }
948 }
949 else if ( m[4]==0.0F && m[12]==0.0F
950 && m[1]==0.0F && m[13]==0.0F
951 && m[2]==0.0F && m[6]==0.0F
952 && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
953 mat->type = MATRIX_PERSPECTIVE;
954 }
955 else {
956 mat->type = MATRIX_GENERAL;
957 }
958}
959
960
Gareth Hughes22144ab2001-03-12 00:48:37 +0000961void
962_math_matrix_analyse( GLmatrix *mat )
Keith Whitwell23caf202000-11-16 21:05:34 +0000963{
964 if (mat->flags & MAT_DIRTY_TYPE) {
Gareth Hughes22144ab2001-03-12 00:48:37 +0000965 if (mat->flags & MAT_DIRTY_FLAGS)
Keith Whitwellad2ac212000-11-24 10:25:05 +0000966 analyse_from_scratch( mat );
Keith Whitwell23caf202000-11-16 21:05:34 +0000967 else
Keith Whitwellad2ac212000-11-24 10:25:05 +0000968 analyse_from_flags( mat );
Keith Whitwell23caf202000-11-16 21:05:34 +0000969 }
970
971 if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) {
972 matrix_invert( mat );
973 }
974
975 mat->flags &= ~(MAT_DIRTY_FLAGS|
976 MAT_DIRTY_TYPE|
977 MAT_DIRTY_INVERSE);
978}
979
980
Gareth Hughes22144ab2001-03-12 00:48:37 +0000981void
Keith Whitwell23caf202000-11-16 21:05:34 +0000982_math_matrix_copy( GLmatrix *to, const GLmatrix *from )
983{
984 MEMCPY( to->m, from->m, sizeof(Identity) );
985 to->flags = from->flags;
986 to->type = from->type;
987
988 if (to->inv != 0) {
989 if (from->inv == 0) {
990 matrix_invert( to );
991 }
992 else {
993 MEMCPY(to->inv, from->inv, sizeof(GLfloat)*16);
994 }
995 }
996}
997
998
Gareth Hughes22144ab2001-03-12 00:48:37 +0000999void
Keith Whitwell23caf202000-11-16 21:05:34 +00001000_math_matrix_scale( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
1001{
1002 GLfloat *m = mat->m;
1003 m[0] *= x; m[4] *= y; m[8] *= z;
1004 m[1] *= x; m[5] *= y; m[9] *= z;
1005 m[2] *= x; m[6] *= y; m[10] *= z;
1006 m[3] *= x; m[7] *= y; m[11] *= z;
1007
1008 if (fabs(x - y) < 1e-8 && fabs(x - z) < 1e-8)
1009 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
1010 else
1011 mat->flags |= MAT_FLAG_GENERAL_SCALE;
1012
Gareth Hughes22144ab2001-03-12 00:48:37 +00001013 mat->flags |= (MAT_DIRTY_TYPE |
Keith Whitwell23caf202000-11-16 21:05:34 +00001014 MAT_DIRTY_INVERSE);
1015}
1016
1017
Gareth Hughes22144ab2001-03-12 00:48:37 +00001018void
Keith Whitwell23caf202000-11-16 21:05:34 +00001019_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
Gareth Hughes22144ab2001-03-12 00:48:37 +00001027 mat->flags |= (MAT_FLAG_TRANSLATION |
1028 MAT_DIRTY_TYPE |
Keith Whitwell23caf202000-11-16 21:05:34 +00001029 MAT_DIRTY_INVERSE);
1030}
1031
1032
Gareth Hughes22144ab2001-03-12 00:48:37 +00001033void
Keith Whitwell23caf202000-11-16 21:05:34 +00001034_math_matrix_loadf( GLmatrix *mat, const GLfloat *m )
1035{
1036 MEMCPY( mat->m, m, 16*sizeof(GLfloat) );
1037 mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY);
1038}
1039
Gareth Hughes22144ab2001-03-12 00:48:37 +00001040void
Keith Whitwell23caf202000-11-16 21:05:34 +00001041_math_matrix_ctr( GLmatrix *m )
1042{
Brian Paul30f51ae2001-12-18 04:06:44 +00001043 m->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
1044 if (m->m)
1045 MEMCPY( m->m, Identity, sizeof(Identity) );
1046 m->inv = NULL;
Keith Whitwell23caf202000-11-16 21:05:34 +00001047 m->type = MATRIX_IDENTITY;
1048 m->flags = 0;
1049}
1050
Gareth Hughes22144ab2001-03-12 00:48:37 +00001051void
Keith Whitwell23caf202000-11-16 21:05:34 +00001052_math_matrix_dtr( GLmatrix *m )
1053{
Brian Paul30f51ae2001-12-18 04:06:44 +00001054 if (m->m) {
Keith Whitwell23caf202000-11-16 21:05:34 +00001055 ALIGN_FREE( m->m );
Brian Paul30f51ae2001-12-18 04:06:44 +00001056 m->m = NULL;
Keith Whitwell23caf202000-11-16 21:05:34 +00001057 }
Brian Paul30f51ae2001-12-18 04:06:44 +00001058 if (m->inv) {
Keith Whitwell23caf202000-11-16 21:05:34 +00001059 ALIGN_FREE( m->inv );
Brian Paul30f51ae2001-12-18 04:06:44 +00001060 m->inv = NULL;
Keith Whitwell23caf202000-11-16 21:05:34 +00001061 }
1062}
1063
1064
Gareth Hughes22144ab2001-03-12 00:48:37 +00001065void
Keith Whitwell23caf202000-11-16 21:05:34 +00001066_math_matrix_alloc_inv( GLmatrix *m )
1067{
Brian Paul30f51ae2001-12-18 04:06:44 +00001068 if (!m->inv) {
Keith Whitwell23caf202000-11-16 21:05:34 +00001069 m->inv = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
Brian Paul30f51ae2001-12-18 04:06:44 +00001070 if (m->inv)
1071 MEMCPY( m->inv, Identity, 16 * sizeof(GLfloat) );
Keith Whitwell23caf202000-11-16 21:05:34 +00001072 }
1073}
1074
1075
Gareth Hughes22144ab2001-03-12 00:48:37 +00001076void
Keith Whitwell23caf202000-11-16 21:05:34 +00001077_math_matrix_mul_matrix( GLmatrix *dest, const GLmatrix *a, const GLmatrix *b )
1078{
1079 dest->flags = (a->flags |
1080 b->flags |
Gareth Hughes22144ab2001-03-12 00:48:37 +00001081 MAT_DIRTY_TYPE |
Keith Whitwell23caf202000-11-16 21:05:34 +00001082 MAT_DIRTY_INVERSE);
1083
1084 if (TEST_MAT_FLAGS(dest, MAT_FLAGS_3D))
1085 matmul34( dest->m, a->m, b->m );
Gareth Hughes22144ab2001-03-12 00:48:37 +00001086 else
Keith Whitwell23caf202000-11-16 21:05:34 +00001087 matmul4( dest->m, a->m, b->m );
1088}
1089
1090
Gareth Hughes22144ab2001-03-12 00:48:37 +00001091void
Keith Whitwell23caf202000-11-16 21:05:34 +00001092_math_matrix_mul_floats( GLmatrix *dest, const GLfloat *m )
1093{
1094 dest->flags |= (MAT_FLAG_GENERAL |
Gareth Hughes22144ab2001-03-12 00:48:37 +00001095 MAT_DIRTY_TYPE |
Keith Whitwell23caf202000-11-16 21:05:34 +00001096 MAT_DIRTY_INVERSE);
1097
Gareth Hughes22144ab2001-03-12 00:48:37 +00001098 matmul4( dest->m, dest->m, m );
Keith Whitwell23caf202000-11-16 21:05:34 +00001099}
1100
Gareth Hughes22144ab2001-03-12 00:48:37 +00001101void
Keith Whitwell23caf202000-11-16 21:05:34 +00001102_math_matrix_set_identity( GLmatrix *mat )
1103{
1104 MEMCPY( mat->m, Identity, 16*sizeof(GLfloat) );
1105
1106 if (mat->inv)
1107 MEMCPY( mat->inv, Identity, 16*sizeof(GLfloat) );
1108
1109 mat->type = MATRIX_IDENTITY;
1110 mat->flags &= ~(MAT_DIRTY_FLAGS|
1111 MAT_DIRTY_TYPE|
1112 MAT_DIRTY_INVERSE);
1113}
1114
1115
1116
Gareth Hughes22144ab2001-03-12 00:48:37 +00001117void
Keith Whitwell23caf202000-11-16 21:05:34 +00001118_math_transposef( GLfloat to[16], const GLfloat from[16] )
1119{
1120 to[0] = from[0];
1121 to[1] = from[4];
1122 to[2] = from[8];
1123 to[3] = from[12];
1124 to[4] = from[1];
1125 to[5] = from[5];
1126 to[6] = from[9];
1127 to[7] = from[13];
1128 to[8] = from[2];
1129 to[9] = from[6];
1130 to[10] = from[10];
1131 to[11] = from[14];
1132 to[12] = from[3];
1133 to[13] = from[7];
1134 to[14] = from[11];
1135 to[15] = from[15];
1136}
1137
1138
Gareth Hughes22144ab2001-03-12 00:48:37 +00001139void
Keith Whitwell23caf202000-11-16 21:05:34 +00001140_math_transposed( GLdouble to[16], const GLdouble from[16] )
1141{
1142 to[0] = from[0];
1143 to[1] = from[4];
1144 to[2] = from[8];
1145 to[3] = from[12];
1146 to[4] = from[1];
1147 to[5] = from[5];
1148 to[6] = from[9];
1149 to[7] = from[13];
1150 to[8] = from[2];
1151 to[9] = from[6];
1152 to[10] = from[10];
1153 to[11] = from[14];
1154 to[12] = from[3];
1155 to[13] = from[7];
1156 to[14] = from[11];
1157 to[15] = from[15];
1158}
1159
Gareth Hughes22144ab2001-03-12 00:48:37 +00001160void
Keith Whitwell23caf202000-11-16 21:05:34 +00001161_math_transposefd( GLfloat to[16], const GLdouble from[16] )
1162{
Karl Schultz7b9fe822001-09-18 23:06:14 +00001163 to[0] = (GLfloat) from[0];
1164 to[1] = (GLfloat) from[4];
1165 to[2] = (GLfloat) from[8];
1166 to[3] = (GLfloat) from[12];
1167 to[4] = (GLfloat) from[1];
1168 to[5] = (GLfloat) from[5];
1169 to[6] = (GLfloat) from[9];
1170 to[7] = (GLfloat) from[13];
1171 to[8] = (GLfloat) from[2];
1172 to[9] = (GLfloat) from[6];
1173 to[10] = (GLfloat) from[10];
1174 to[11] = (GLfloat) from[14];
1175 to[12] = (GLfloat) from[3];
1176 to[13] = (GLfloat) from[7];
1177 to[14] = (GLfloat) from[11];
1178 to[15] = (GLfloat) from[15];
Keith Whitwell23caf202000-11-16 21:05:34 +00001179}