1 /* $Id: matrix.c,v 1.23 1997/12/29 23:48:53 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.6
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: matrix.c,v $
26 * Revision 1.23 1997/12/29 23:48:53 brianp
27 * call Driver.NearFar() in gl_LoadMatrixf() for projection matrix
28 *
29 * Revision 1.22 1997/10/16 23:37:23 brianp
30 * fixed scotter's email address
31 *
32 * Revision 1.21 1997/08/13 01:54:34 brianp
33 * new matrix invert code from Scott McCaskill
34 *
35 * Revision 1.20 1997/07/24 01:23:16 brianp
36 * changed precompiled header symbol from PCH to PC_HEADER
37 *
38 * Revision 1.19 1997/05/30 02:21:43 brianp
39 * gl_PopMatrix() set ctx->New*Matrix flag incorrectly
40 *
41 * Revision 1.18 1997/05/28 04:06:03 brianp
42 * implemented projection near/far value stack for Driver.NearFar() function
43 *
44 * Revision 1.17 1997/05/28 03:25:43 brianp
45 * added precompiled header (PCH) support
46 *
47 * Revision 1.16 1997/05/01 01:39:40 brianp
48 * replace sqrt() with GL_SQRT()
49 *
50 * Revision 1.15 1997/04/21 01:20:41 brianp
51 * added MATRIX_2D_NO_ROT
52 *
53 * Revision 1.14 1997/04/20 20:28:49 brianp
54 * replaced abort() with gl_problem()
55 *
56 * Revision 1.13 1997/04/20 16:31:08 brianp
57 * added NearFar device driver function
58 *
59 * Revision 1.12 1997/04/20 16:18:15 brianp
60 * added glOrtho and glFrustum API pointers
61 *
62 * Revision 1.11 1997/04/01 04:23:53 brianp
63 * added gl_analyze_*_matrix() functions
64 *
65 * Revision 1.10 1997/02/10 19:47:53 brianp
66 * moved buffer resize code out of gl_Viewport() into gl_ResizeBuffersMESA()
67 *
68 * Revision 1.9 1997/01/31 23:32:40 brianp
69 * now clear depth buffer after reallocation due to window resize
70 *
71 * Revision 1.8 1997/01/29 19:06:04 brianp
72 * removed extra, local definition of Identity[] matrix
73 *
74 * Revision 1.7 1997/01/28 22:19:17 brianp
75 * new matrix inversion code from Stephane Rehel
76 *
77 * Revision 1.6 1996/12/22 17:53:11 brianp
78 * faster invert_matrix() function from scotter@iname.com
79 *
80 * Revision 1.5 1996/12/02 18:58:34 brianp
81 * gl_rotation_matrix() now returns identity matrix if given a 0 rotation axis
82 *
83 * Revision 1.4 1996/09/27 01:29:05 brianp
84 * added missing default cases to switches
85 *
86 * Revision 1.3 1996/09/15 14:18:37 brianp
87 * now use GLframebuffer and GLvisual
88 *
89 * Revision 1.2 1996/09/14 06:46:04 brianp
90 * better matmul() from Jacques Leroy
91 *
92 * Revision 1.1 1996/09/13 01:38:16 brianp
93 * Initial revision
94 *
95 */
96
97
98 /*
99 * Matrix operations
100 *
101 *
102 * NOTES:
103 * 1. 4x4 transformation matrices are stored in memory in column major order.
104 * 2. Points/vertices are to be thought of as column vectors.
105 * 3. Transformation of a point p by a matrix M is: p' = M * p
106 *
107 */
108
109
110 #ifdef PC_HEADER
111 #include "all.h"
112 #else
113 #include <math.h>
114 #include <stdio.h>
115 #include <stdlib.h>
116 #include <string.h>
117 #include "context.h"
118 #include "dlist.h"
119 #include "macros.h"
120 #include "matrix.h"
121 #include "mmath.h"
122 #include "types.h"
123 #endif
124
125
126
127 static GLfloat Identity[16] = {
128 1.0, 0.0, 0.0, 0.0,
129 0.0, 1.0, 0.0, 0.0,
130 0.0, 0.0, 1.0, 0.0,
131 0.0, 0.0, 0.0, 1.0
132 };
133
134
135 #if 0
136 static void print_matrix( const GLfloat m[16] )
137 {
138 int i;
139
140 for (i=0;i<4;i++) {
141 printf("%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
142 }
143 }
144 #endif
145
146
147 /*
148 * Perform a 4x4 matrix multiplication (product = a x b).
149 * Input: a, b - matrices to multiply
150 * Output: product - product of a and b
151 * WARNING: (product != b) assumed
152 * NOTE: (product == a) allowed
153 */
matmul(GLfloat * product,const GLfloat * a,const GLfloat * b)154 static void matmul( GLfloat *product, const GLfloat *a, const GLfloat *b )
155 {
156 /* This matmul was contributed by Thomas Malik */
157 GLint i;
158
159 #define A(row,col) a[(col<<2)+row]
160 #define B(row,col) b[(col<<2)+row]
161 #define P(row,col) product[(col<<2)+row]
162
163 /* i-te Zeile */
164 for (i = 0; i < 4; i++) {
165 GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
166 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
167 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
168 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
169 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
170 }
171
172 #undef A
173 #undef B
174 #undef P
175 }
176
177
178
179 /*
180 * Compute the inverse of a 4x4 matrix.
181 *
182 * From an algorithm by V. Strassen, 1969, _Numerishe Mathematik_, vol. 13,
183 * pp. 354-356.
184 * 60 multiplies, 24 additions, 10 subtractions, 8 negations, 2 divisions,
185 * 48 assignments, _0_ branches
186 *
187 * This implementation by Scott McCaskill
188 */
189
190 typedef GLfloat Mat2[2][2];
191
192 enum {
193 M00 = 0, M01 = 4, M02 = 8, M03 = 12,
194 M10 = 1, M11 = 5, M12 = 9, M13 = 13,
195 M20 = 2, M21 = 6, M22 = 10,M23 = 14,
196 M30 = 3, M31 = 7, M32 = 11,M33 = 15
197 };
198
invert_matrix_general(const GLfloat * m,GLfloat * out)199 static void invert_matrix_general( const GLfloat *m, GLfloat *out )
200 {
201 Mat2 r1, r2, r3, r4, r5, r6, r7;
202 const GLfloat * A = m;
203 GLfloat * C = out;
204 GLfloat one_over_det;
205
206 /*
207 * A is the 4x4 source matrix (to be inverted).
208 * C is the 4x4 destination matrix
209 * a11 is the 2x2 matrix in the upper left quadrant of A
210 * a12 is the 2x2 matrix in the upper right quadrant of A
211 * a21 is the 2x2 matrix in the lower left quadrant of A
212 * a22 is the 2x2 matrix in the lower right quadrant of A
213 * similarly, cXX are the 2x2 quadrants of the destination matrix
214 */
215
216 /* R1 = inverse( a11 ) */
217 one_over_det = 1.0f / ( ( A[M00] * A[M11] ) - ( A[M10] * A[M01] ) );
218 r1[0][0] = one_over_det * A[M11];
219 r1[0][1] = one_over_det * -A[M01];
220 r1[1][0] = one_over_det * -A[M10];
221 r1[1][1] = one_over_det * A[M00];
222
223 /* R2 = a21 x R1 */
224 r2[0][0] = A[M20] * r1[0][0] + A[M21] * r1[1][0];
225 r2[0][1] = A[M20] * r1[0][1] + A[M21] * r1[1][1];
226 r2[1][0] = A[M30] * r1[0][0] + A[M31] * r1[1][0];
227 r2[1][1] = A[M30] * r1[0][1] + A[M31] * r1[1][1];
228
229 /* R3 = R1 x a12 */
230 r3[0][0] = r1[0][0] * A[M02] + r1[0][1] * A[M12];
231 r3[0][1] = r1[0][0] * A[M03] + r1[0][1] * A[M13];
232 r3[1][0] = r1[1][0] * A[M02] + r1[1][1] * A[M12];
233 r3[1][1] = r1[1][0] * A[M03] + r1[1][1] * A[M13];
234
235 /* R4 = a21 x R3 */
236 r4[0][0] = A[M20] * r3[0][0] + A[M21] * r3[1][0];
237 r4[0][1] = A[M20] * r3[0][1] + A[M21] * r3[1][1];
238 r4[1][0] = A[M30] * r3[0][0] + A[M31] * r3[1][0];
239 r4[1][1] = A[M30] * r3[0][1] + A[M31] * r3[1][1];
240
241 /* R5 = R4 - a22 */
242 r5[0][0] = r4[0][0] - A[M22];
243 r5[0][1] = r4[0][1] - A[M23];
244 r5[1][0] = r4[1][0] - A[M32];
245 r5[1][1] = r4[1][1] - A[M33];
246
247 /* R6 = inverse( R5 ) */
248 one_over_det = 1.0f / ( ( r5[0][0] * r5[1][1] ) - ( r5[1][0] * r5[0][1] ) );
249 r6[0][0] = one_over_det * r5[1][1];
250 r6[0][1] = one_over_det * -r5[0][1];
251 r6[1][0] = one_over_det * -r5[1][0];
252 r6[1][1] = one_over_det * r5[0][0];
253
254 /* c12 = R3 x R6 */
255 C[M02] = r3[0][0] * r6[0][0] + r3[0][1] * r6[1][0];
256 C[M03] = r3[0][0] * r6[0][1] + r3[0][1] * r6[1][1];
257 C[M12] = r3[1][0] * r6[0][0] + r3[1][1] * r6[1][0];
258 C[M13] = r3[1][0] * r6[0][1] + r3[1][1] * r6[1][1];
259
260 /* c21 = R6 x R2 */
261 C[M20] = r6[0][0] * r2[0][0] + r6[0][1] * r2[1][0];
262 C[M21] = r6[0][0] * r2[0][1] + r6[0][1] * r2[1][1];
263 C[M30] = r6[1][0] * r2[0][0] + r6[1][1] * r2[1][0];
264 C[M31] = r6[1][0] * r2[0][1] + r6[1][1] * r2[1][1];
265
266 /* R7 = R3 x c21 */
267 r7[0][0] = r3[0][0] * C[M20] + r3[0][1] * C[M30];
268 r7[0][1] = r3[0][0] * C[M21] + r3[0][1] * C[M31];
269 r7[1][0] = r3[1][0] * C[M20] + r3[1][1] * C[M30];
270 r7[1][1] = r3[1][0] * C[M21] + r3[1][1] * C[M31];
271
272 /* c11 = R1 - R7 */
273 C[M00] = r1[0][0] - r7[0][0];
274 C[M01] = r1[0][1] - r7[0][1];
275 C[M10] = r1[1][0] - r7[1][0];
276 C[M11] = r1[1][1] - r7[1][1];
277
278 /* c22 = -R6 */
279 C[M22] = -r6[0][0];
280 C[M23] = -r6[0][1];
281 C[M32] = -r6[1][0];
282 C[M33] = -r6[1][1];
283 }
284
285
286 /*
287 * Invert matrix m. This algorithm contributed by Stephane Rehel
288 * <rehel@worldnet.fr>
289 */
invert_matrix(const GLfloat * m,GLfloat * out)290 static void invert_matrix( const GLfloat *m, GLfloat *out )
291 {
292 /* NB. OpenGL Matrices are COLUMN major. */
293 #define MAT(m,r,c) (m)[(c)*4+(r)]
294
295 /* Here's some shorthand converting standard (row,column) to index. */
296 #define m11 MAT(m,0,0)
297 #define m12 MAT(m,0,1)
298 #define m13 MAT(m,0,2)
299 #define m14 MAT(m,0,3)
300 #define m21 MAT(m,1,0)
301 #define m22 MAT(m,1,1)
302 #define m23 MAT(m,1,2)
303 #define m24 MAT(m,1,3)
304 #define m31 MAT(m,2,0)
305 #define m32 MAT(m,2,1)
306 #define m33 MAT(m,2,2)
307 #define m34 MAT(m,2,3)
308 #define m41 MAT(m,3,0)
309 #define m42 MAT(m,3,1)
310 #define m43 MAT(m,3,2)
311 #define m44 MAT(m,3,3)
312
313 register GLfloat det;
314 GLfloat tmp[16]; /* Allow out == in. */
315
316 if( m41 != 0. || m42 != 0. || m43 != 0. || m44 != 1. ) {
317 invert_matrix_general(m, out);
318 return;
319 }
320
321 /* Inverse = adjoint / det. (See linear algebra texts.)*/
322
323 tmp[0]= m22 * m33 - m23 * m32;
324 tmp[1]= m23 * m31 - m21 * m33;
325 tmp[2]= m21 * m32 - m22 * m31;
326
327 /* Compute determinant as early as possible using these cofactors. */
328 det= m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2];
329
330 /* Run singularity test. */
331 if (det == 0.0F) {
332 /* printf("invert_matrix: Warning: Singular matrix.\n"); */
333 MEMCPY( out, Identity, 16*sizeof(GLfloat) );
334 }
335 else {
336 GLfloat d12, d13, d23, d24, d34, d41;
337 register GLfloat im11, im12, im13, im14;
338
339 det= 1. / det;
340
341 /* Compute rest of inverse. */
342 tmp[0] *= det;
343 tmp[1] *= det;
344 tmp[2] *= det;
345 tmp[3] = 0.;
346
347 im11= m11 * det;
348 im12= m12 * det;
349 im13= m13 * det;
350 im14= m14 * det;
351 tmp[4] = im13 * m32 - im12 * m33;
352 tmp[5] = im11 * m33 - im13 * m31;
353 tmp[6] = im12 * m31 - im11 * m32;
354 tmp[7] = 0.;
355
356 /* Pre-compute 2x2 dets for first two rows when computing */
357 /* cofactors of last two rows. */
358 d12 = im11*m22 - m21*im12;
359 d13 = im11*m23 - m21*im13;
360 d23 = im12*m23 - m22*im13;
361 d24 = im12*m24 - m22*im14;
362 d34 = im13*m24 - m23*im14;
363 d41 = im14*m21 - m24*im11;
364
365 tmp[8] = d23;
366 tmp[9] = -d13;
367 tmp[10] = d12;
368 tmp[11] = 0.;
369
370 tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23);
371 tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13);
372 tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12);
373 tmp[15] = 1.;
374
375 MEMCPY(out, tmp, 16*sizeof(GLfloat));
376 }
377
378 #undef m11
379 #undef m12
380 #undef m13
381 #undef m14
382 #undef m21
383 #undef m22
384 #undef m23
385 #undef m24
386 #undef m31
387 #undef m32
388 #undef m33
389 #undef m34
390 #undef m41
391 #undef m42
392 #undef m43
393 #undef m44
394 #undef MAT
395 }
396
397
398
399 /*
400 * Determine if the given matrix is the identity matrix.
401 */
is_identity(const GLfloat m[16])402 static GLboolean is_identity( const GLfloat m[16] )
403 {
404 if ( m[0]==1.0F && m[4]==0.0F && m[ 8]==0.0F && m[12]==0.0F
405 && m[1]==0.0F && m[5]==1.0F && m[ 9]==0.0F && m[13]==0.0F
406 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
407 && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
408 return GL_TRUE;
409 }
410 else {
411 return GL_FALSE;
412 }
413 }
414
415
416 /*
417 * Examine the current modelview matrix to determine its type.
418 * Later we use the matrix type to optimize vertex transformations.
419 */
gl_analyze_modelview_matrix(GLcontext * ctx)420 void gl_analyze_modelview_matrix( GLcontext *ctx )
421 {
422 const GLfloat *m = ctx->ModelViewMatrix;
423 if (is_identity(m)) {
424 ctx->ModelViewMatrixType = MATRIX_IDENTITY;
425 }
426 else if ( m[4]==0.0F && m[ 8]==0.0F
427 && m[1]==0.0F && m[ 9]==0.0F
428 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
429 && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
430 ctx->ModelViewMatrixType = MATRIX_2D_NO_ROT;
431 }
432 else if ( m[ 8]==0.0F
433 && m[ 9]==0.0F
434 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
435 && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
436 ctx->ModelViewMatrixType = MATRIX_2D;
437 }
438 else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
439 ctx->ModelViewMatrixType = MATRIX_3D;
440 }
441 else {
442 ctx->ModelViewMatrixType = MATRIX_GENERAL;
443 }
444
445 invert_matrix( ctx->ModelViewMatrix, ctx->ModelViewInv );
446 ctx->NewModelViewMatrix = GL_FALSE;
447 }
448
449
450
451 /*
452 * Examine the current projection matrix to determine its type.
453 * Later we use the matrix type to optimize vertex transformations.
454 */
gl_analyze_projection_matrix(GLcontext * ctx)455 void gl_analyze_projection_matrix( GLcontext *ctx )
456 {
457 /* look for common-case ortho and perspective matrices */
458 const GLfloat *m = ctx->ProjectionMatrix;
459 if (is_identity(m)) {
460 ctx->ProjectionMatrixType = MATRIX_IDENTITY;
461 }
462 else if ( m[4]==0.0F && m[8] ==0.0F
463 && m[1]==0.0F && m[9] ==0.0F
464 && m[2]==0.0F && m[6]==0.0F
465 && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
466 ctx->ProjectionMatrixType = MATRIX_ORTHO;
467 }
468 else if ( m[4]==0.0F && m[12]==0.0F
469 && m[1]==0.0F && m[13]==0.0F
470 && m[2]==0.0F && m[6]==0.0F
471 && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
472 ctx->ProjectionMatrixType = MATRIX_PERSPECTIVE;
473 }
474 else {
475 ctx->ProjectionMatrixType = MATRIX_GENERAL;
476 }
477
478 ctx->NewProjectionMatrix = GL_FALSE;
479 }
480
481
482
483 /*
484 * Examine the current texture matrix to determine its type.
485 * Later we use the matrix type to optimize texture coordinate transformations.
486 */
gl_analyze_texture_matrix(GLcontext * ctx)487 void gl_analyze_texture_matrix( GLcontext *ctx )
488 {
489 const GLfloat *m = ctx->TextureMatrix;
490 if (is_identity(m)) {
491 ctx->TextureMatrixType = MATRIX_IDENTITY;
492 }
493 else if ( m[ 8]==0.0F
494 && m[ 9]==0.0F
495 && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
496 && m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
497 ctx->TextureMatrixType = MATRIX_2D;
498 }
499 else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
500 ctx->TextureMatrixType = MATRIX_3D;
501 }
502 else {
503 ctx->TextureMatrixType = MATRIX_GENERAL;
504 }
505
506 ctx->NewTextureMatrix = GL_FALSE;
507 }
508
509
510
gl_Frustum(GLcontext * ctx,GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble nearval,GLdouble farval)511 void gl_Frustum( GLcontext *ctx,
512 GLdouble left, GLdouble right,
513 GLdouble bottom, GLdouble top,
514 GLdouble nearval, GLdouble farval )
515 {
516 GLfloat x, y, a, b, c, d;
517 GLfloat m[16];
518
519 if (nearval<=0.0 || farval<=0.0) {
520 gl_error( ctx, GL_INVALID_VALUE, "glFrustum(near or far)" );
521 }
522
523 x = (2.0*nearval) / (right-left);
524 y = (2.0*nearval) / (top-bottom);
525 a = (right+left) / (right-left);
526 b = (top+bottom) / (top-bottom);
527 c = -(farval+nearval) / ( farval-nearval);
528 d = -(2.0*farval*nearval) / (farval-nearval); /* error? */
529
530 #define M(row,col) m[col*4+row]
531 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
532 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
533 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
534 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
535 #undef M
536
537 gl_MultMatrixf( ctx, m );
538
539
540 /* Need to keep a stack of near/far values in case the user push/pops
541 * the projection matrix stack so that we can call Driver.NearFar()
542 * after a pop.
543 */
544 ctx->NearFarStack[ctx->ProjectionStackDepth][0] = nearval;
545 ctx->NearFarStack[ctx->ProjectionStackDepth][1] = farval;
546
547 if (ctx->Driver.NearFar) {
548 (*ctx->Driver.NearFar)( ctx, nearval, farval );
549 }
550 }
551
552
gl_Ortho(GLcontext * ctx,GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble nearval,GLdouble farval)553 void gl_Ortho( GLcontext *ctx,
554 GLdouble left, GLdouble right,
555 GLdouble bottom, GLdouble top,
556 GLdouble nearval, GLdouble farval )
557 {
558 GLfloat x, y, z;
559 GLfloat tx, ty, tz;
560 GLfloat m[16];
561
562 x = 2.0 / (right-left);
563 y = 2.0 / (top-bottom);
564 z = -2.0 / (farval-nearval);
565 tx = -(right+left) / (right-left);
566 ty = -(top+bottom) / (top-bottom);
567 tz = -(farval+nearval) / (farval-nearval);
568
569 #define M(row,col) m[col*4+row]
570 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = 0.0F; M(0,3) = tx;
571 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = 0.0F; M(1,3) = ty;
572 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = z; M(2,3) = tz;
573 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F;
574 #undef M
575
576 gl_MultMatrixf( ctx, m );
577
578 if (ctx->Driver.NearFar) {
579 (*ctx->Driver.NearFar)( ctx, nearval, farval );
580 }
581 }
582
583
gl_MatrixMode(GLcontext * ctx,GLenum mode)584 void gl_MatrixMode( GLcontext *ctx, GLenum mode )
585 {
586 if (INSIDE_BEGIN_END(ctx)) {
587 gl_error( ctx, GL_INVALID_OPERATION, "glMatrixMode" );
588 return;
589 }
590 switch (mode) {
591 case GL_MODELVIEW:
592 case GL_PROJECTION:
593 case GL_TEXTURE:
594 ctx->Transform.MatrixMode = mode;
595 break;
596 default:
597 gl_error( ctx, GL_INVALID_ENUM, "glMatrixMode" );
598 }
599 }
600
601
602
gl_PushMatrix(GLcontext * ctx)603 void gl_PushMatrix( GLcontext *ctx )
604 {
605 if (INSIDE_BEGIN_END(ctx)) {
606 gl_error( ctx, GL_INVALID_OPERATION, "glPushMatrix" );
607 return;
608 }
609 switch (ctx->Transform.MatrixMode) {
610 case GL_MODELVIEW:
611 if (ctx->ModelViewStackDepth>=MAX_MODELVIEW_STACK_DEPTH-1) {
612 gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
613 return;
614 }
615 MEMCPY( ctx->ModelViewStack[ctx->ModelViewStackDepth],
616 ctx->ModelViewMatrix,
617 16*sizeof(GLfloat) );
618 ctx->ModelViewStackDepth++;
619 break;
620 case GL_PROJECTION:
621 if (ctx->ProjectionStackDepth>=MAX_PROJECTION_STACK_DEPTH) {
622 gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
623 return;
624 }
625 MEMCPY( ctx->ProjectionStack[ctx->ProjectionStackDepth],
626 ctx->ProjectionMatrix,
627 16*sizeof(GLfloat) );
628 ctx->ProjectionStackDepth++;
629
630 /* Save near and far projection values */
631 ctx->NearFarStack[ctx->ProjectionStackDepth][0]
632 = ctx->NearFarStack[ctx->ProjectionStackDepth-1][0];
633 ctx->NearFarStack[ctx->ProjectionStackDepth][1]
634 = ctx->NearFarStack[ctx->ProjectionStackDepth-1][1];
635 break;
636 case GL_TEXTURE:
637 if (ctx->TextureStackDepth>=MAX_TEXTURE_STACK_DEPTH) {
638 gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
639 return;
640 }
641 MEMCPY( ctx->TextureStack[ctx->TextureStackDepth],
642 ctx->TextureMatrix,
643 16*sizeof(GLfloat) );
644 ctx->TextureStackDepth++;
645 break;
646 default:
647 gl_problem(ctx, "Bad matrix mode in gl_PushMatrix");
648 }
649 }
650
651
652
gl_PopMatrix(GLcontext * ctx)653 void gl_PopMatrix( GLcontext *ctx )
654 {
655 if (INSIDE_BEGIN_END(ctx)) {
656 gl_error( ctx, GL_INVALID_OPERATION, "glPopMatrix" );
657 return;
658 }
659 switch (ctx->Transform.MatrixMode) {
660 case GL_MODELVIEW:
661 if (ctx->ModelViewStackDepth==0) {
662 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
663 return;
664 }
665 ctx->ModelViewStackDepth--;
666 MEMCPY( ctx->ModelViewMatrix,
667 ctx->ModelViewStack[ctx->ModelViewStackDepth],
668 16*sizeof(GLfloat) );
669 ctx->NewModelViewMatrix = GL_TRUE;
670 break;
671 case GL_PROJECTION:
672 if (ctx->ProjectionStackDepth==0) {
673 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
674 return;
675 }
676 ctx->ProjectionStackDepth--;
677 MEMCPY( ctx->ProjectionMatrix,
678 ctx->ProjectionStack[ctx->ProjectionStackDepth],
679 16*sizeof(GLfloat) );
680 ctx->NewProjectionMatrix = GL_TRUE;
681
682 /* Device driver near/far values */
683 {
684 GLfloat nearVal = ctx->NearFarStack[ctx->ProjectionStackDepth][0];
685 GLfloat farVal = ctx->NearFarStack[ctx->ProjectionStackDepth][1];
686 if (ctx->Driver.NearFar) {
687 (*ctx->Driver.NearFar)( ctx, nearVal, farVal );
688 }
689 }
690 break;
691 case GL_TEXTURE:
692 if (ctx->TextureStackDepth==0) {
693 gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
694 return;
695 }
696 ctx->TextureStackDepth--;
697 MEMCPY( ctx->TextureMatrix,
698 ctx->TextureStack[ctx->TextureStackDepth],
699 16*sizeof(GLfloat) );
700 ctx->NewTextureMatrix = GL_TRUE;
701 break;
702 default:
703 gl_problem(ctx, "Bad matrix mode in gl_PopMatrix");
704 }
705 }
706
707
708
gl_LoadIdentity(GLcontext * ctx)709 void gl_LoadIdentity( GLcontext *ctx )
710 {
711 if (INSIDE_BEGIN_END(ctx)) {
712 gl_error( ctx, GL_INVALID_OPERATION, "glLoadIdentity" );
713 return;
714 }
715 switch (ctx->Transform.MatrixMode) {
716 case GL_MODELVIEW:
717 MEMCPY( ctx->ModelViewMatrix, Identity, 16*sizeof(GLfloat) );
718 MEMCPY( ctx->ModelViewInv, Identity, 16*sizeof(GLfloat) );
719 ctx->ModelViewMatrixType = MATRIX_IDENTITY;
720 ctx->NewModelViewMatrix = GL_FALSE;
721 break;
722 case GL_PROJECTION:
723 MEMCPY( ctx->ProjectionMatrix, Identity, 16*sizeof(GLfloat) );
724 ctx->ProjectionMatrixType = MATRIX_IDENTITY;
725 ctx->NewProjectionMatrix = GL_FALSE;
726 break;
727 case GL_TEXTURE:
728 MEMCPY( ctx->TextureMatrix, Identity, 16*sizeof(GLfloat) );
729 ctx->TextureMatrixType = MATRIX_IDENTITY;
730 ctx->NewTextureMatrix = GL_FALSE;
731 break;
732 default:
733 gl_problem(ctx, "Bad matrix mode in gl_LoadIdentity");
734 }
735 }
736
737
gl_LoadMatrixf(GLcontext * ctx,const GLfloat * m)738 void gl_LoadMatrixf( GLcontext *ctx, const GLfloat *m )
739 {
740 if (INSIDE_BEGIN_END(ctx)) {
741 gl_error( ctx, GL_INVALID_OPERATION, "glLoadMatrix" );
742 return;
743 }
744 switch (ctx->Transform.MatrixMode) {
745 case GL_MODELVIEW:
746 MEMCPY( ctx->ModelViewMatrix, m, 16*sizeof(GLfloat) );
747 ctx->NewModelViewMatrix = GL_TRUE;
748 break;
749 case GL_PROJECTION:
750 MEMCPY( ctx->ProjectionMatrix, m, 16*sizeof(GLfloat) );
751 ctx->NewProjectionMatrix = GL_TRUE;
752 {
753 float n,f,c,d;
754
755 #define M(row,col) m[col*4+row]
756 c = M(2,2);
757 d = M(2,3);
758 #undef M
759 n = d / (c-1);
760 f = d / (c+1);
761
762 /* Need to keep a stack of near/far values in case the user
763 * push/pops the projection matrix stack so that we can call
764 * Driver.NearFar() after a pop.
765 */
766 ctx->NearFarStack[ctx->ProjectionStackDepth][0] = n;
767 ctx->NearFarStack[ctx->ProjectionStackDepth][1] = f;
768
769 if (ctx->Driver.NearFar) {
770 (*ctx->Driver.NearFar)( ctx, n, f );
771 }
772 }
773 break;
774 case GL_TEXTURE:
775 MEMCPY( ctx->TextureMatrix, m, 16*sizeof(GLfloat) );
776 ctx->NewTextureMatrix = GL_TRUE;
777 break;
778 default:
779 gl_problem(ctx, "Bad matrix mode in gl_LoadMatrixf");
780 }
781 }
782
783
784
gl_MultMatrixf(GLcontext * ctx,const GLfloat * m)785 void gl_MultMatrixf( GLcontext *ctx, const GLfloat *m )
786 {
787 if (INSIDE_BEGIN_END(ctx)) {
788 gl_error( ctx, GL_INVALID_OPERATION, "glMultMatrix" );
789 return;
790 }
791 switch (ctx->Transform.MatrixMode) {
792 case GL_MODELVIEW:
793 matmul( ctx->ModelViewMatrix, ctx->ModelViewMatrix, m );
794 ctx->NewModelViewMatrix = GL_TRUE;
795 break;
796 case GL_PROJECTION:
797 matmul( ctx->ProjectionMatrix, ctx->ProjectionMatrix, m );
798 ctx->NewProjectionMatrix = GL_TRUE;
799 break;
800 case GL_TEXTURE:
801 matmul( ctx->TextureMatrix, ctx->TextureMatrix, m );
802 ctx->NewTextureMatrix = GL_TRUE;
803 break;
804 default:
805 gl_problem(ctx, "Bad matrix mode in gl_MultMatrixf");
806 }
807 }
808
809
810
811 /*
812 * Generate a 4x4 transformation matrix from glRotate parameters.
813 */
gl_rotation_matrix(GLfloat angle,GLfloat x,GLfloat y,GLfloat z,GLfloat m[])814 void gl_rotation_matrix( GLfloat angle, GLfloat x, GLfloat y, GLfloat z,
815 GLfloat m[] )
816 {
817 /* This function contributed by Erich Boleyn (erich@uruk.org) */
818 GLfloat mag, s, c;
819 GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
820
821 s = sin( angle * DEG2RAD );
822 c = cos( angle * DEG2RAD );
823
824 mag = GL_SQRT( x*x + y*y + z*z );
825
826 if (mag == 0.0) {
827 /* generate an identity matrix and return */
828 MEMCPY(m, Identity, sizeof(GLfloat)*16);
829 return;
830 }
831
832 x /= mag;
833 y /= mag;
834 z /= mag;
835
836 #define M(row,col) m[col*4+row]
837
838 /*
839 * Arbitrary axis rotation matrix.
840 *
841 * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
842 * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
843 * (which is about the X-axis), and the two composite transforms
844 * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
845 * from the arbitrary axis to the X-axis then back. They are
846 * all elementary rotations.
847 *
848 * Rz' is a rotation about the Z-axis, to bring the axis vector
849 * into the x-z plane. Then Ry' is applied, rotating about the
850 * Y-axis to bring the axis vector parallel with the X-axis. The
851 * rotation about the X-axis is then performed. Ry and Rz are
852 * simply the respective inverse transforms to bring the arbitrary
853 * axis back to it's original orientation. The first transforms
854 * Rz' and Ry' are considered inverses, since the data from the
855 * arbitrary axis gives you info on how to get to it, not how
856 * to get away from it, and an inverse must be applied.
857 *
858 * The basic calculation used is to recognize that the arbitrary
859 * axis vector (x, y, z), since it is of unit length, actually
860 * represents the sines and cosines of the angles to rotate the
861 * X-axis to the same orientation, with theta being the angle about
862 * Z and phi the angle about Y (in the order described above)
863 * as follows:
864 *
865 * cos ( theta ) = x / sqrt ( 1 - z^2 )
866 * sin ( theta ) = y / sqrt ( 1 - z^2 )
867 *
868 * cos ( phi ) = sqrt ( 1 - z^2 )
869 * sin ( phi ) = z
870 *
871 * Note that cos ( phi ) can further be inserted to the above
872 * formulas:
873 *
874 * cos ( theta ) = x / cos ( phi )
875 * sin ( theta ) = y / sin ( phi )
876 *
877 * ...etc. Because of those relations and the standard trigonometric
878 * relations, it is pssible to reduce the transforms down to what
879 * is used below. It may be that any primary axis chosen will give the
880 * same results (modulo a sign convention) using thie method.
881 *
882 * Particularly nice is to notice that all divisions that might
883 * have caused trouble when parallel to certain planes or
884 * axis go away with care paid to reducing the expressions.
885 * After checking, it does perform correctly under all cases, since
886 * in all the cases of division where the denominator would have
887 * been zero, the numerator would have been zero as well, giving
888 * the expected result.
889 */
890
891 xx = x * x;
892 yy = y * y;
893 zz = z * z;
894 xy = x * y;
895 yz = y * z;
896 zx = z * x;
897 xs = x * s;
898 ys = y * s;
899 zs = z * s;
900 one_c = 1.0F - c;
901
902 M(0,0) = (one_c * xx) + c;
903 M(0,1) = (one_c * xy) - zs;
904 M(0,2) = (one_c * zx) + ys;
905 M(0,3) = 0.0F;
906
907 M(1,0) = (one_c * xy) + zs;
908 M(1,1) = (one_c * yy) + c;
909 M(1,2) = (one_c * yz) - xs;
910 M(1,3) = 0.0F;
911
912 M(2,0) = (one_c * zx) - ys;
913 M(2,1) = (one_c * yz) + xs;
914 M(2,2) = (one_c * zz) + c;
915 M(2,3) = 0.0F;
916
917 M(3,0) = 0.0F;
918 M(3,1) = 0.0F;
919 M(3,2) = 0.0F;
920 M(3,3) = 1.0F;
921
922 #undef M
923 }
924
925
926
gl_Rotatef(GLcontext * ctx,GLfloat angle,GLfloat x,GLfloat y,GLfloat z)927 void gl_Rotatef( GLcontext *ctx,
928 GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
929 {
930 GLfloat m[16];
931 gl_rotation_matrix( angle, x, y, z, m );
932 gl_MultMatrixf( ctx, m );
933 }
934
935
936
937 /*
938 * Execute a glScale call
939 */
gl_Scalef(GLcontext * ctx,GLfloat x,GLfloat y,GLfloat z)940 void gl_Scalef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
941 {
942 GLfloat *m;
943
944 if (INSIDE_BEGIN_END(ctx)) {
945 gl_error( ctx, GL_INVALID_OPERATION, "glScale" );
946 return;
947 }
948 switch (ctx->Transform.MatrixMode) {
949 case GL_MODELVIEW:
950 m = ctx->ModelViewMatrix;
951 ctx->NewModelViewMatrix = GL_TRUE;
952 break;
953 case GL_PROJECTION:
954 m = ctx->ProjectionMatrix;
955 ctx->NewProjectionMatrix = GL_TRUE;
956 break;
957 case GL_TEXTURE:
958 m = ctx->TextureMatrix;
959 ctx->NewTextureMatrix = GL_TRUE;
960 break;
961 default:
962 gl_problem(ctx, "Bad matrix mode in gl_Scalef");
963 return;
964 }
965 m[0] *= x; m[4] *= y; m[8] *= z;
966 m[1] *= x; m[5] *= y; m[9] *= z;
967 m[2] *= x; m[6] *= y; m[10] *= z;
968 m[3] *= x; m[7] *= y; m[11] *= z;
969 }
970
971
972
973 /*
974 * Execute a glTranslate call
975 */
gl_Translatef(GLcontext * ctx,GLfloat x,GLfloat y,GLfloat z)976 void gl_Translatef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
977 {
978 GLfloat *m;
979 if (INSIDE_BEGIN_END(ctx)) {
980 gl_error( ctx, GL_INVALID_OPERATION, "glTranslate" );
981 return;
982 }
983 switch (ctx->Transform.MatrixMode) {
984 case GL_MODELVIEW:
985 m = ctx->ModelViewMatrix;
986 ctx->NewModelViewMatrix = GL_TRUE;
987 break;
988 case GL_PROJECTION:
989 m = ctx->ProjectionMatrix;
990 ctx->NewProjectionMatrix = GL_TRUE;
991 break;
992 case GL_TEXTURE:
993 m = ctx->TextureMatrix;
994 ctx->NewTextureMatrix = GL_TRUE;
995 break;
996 default:
997 gl_problem(ctx, "Bad matrix mode in gl_Translatef");
998 return;
999 }
1000
1001 m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
1002 m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
1003 m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
1004 m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
1005 }
1006
1007
1008
1009
1010 /*
1011 * Define a new viewport and reallocate auxillary buffers if the size of
1012 * the window (color buffer) has changed.
1013 */
gl_Viewport(GLcontext * ctx,GLint x,GLint y,GLsizei width,GLsizei height)1014 void gl_Viewport( GLcontext *ctx,
1015 GLint x, GLint y, GLsizei width, GLsizei height )
1016 {
1017 if (width<0 || height<0) {
1018 gl_error( ctx, GL_INVALID_VALUE, "glViewport" );
1019 return;
1020 }
1021 if (INSIDE_BEGIN_END(ctx)) {
1022 gl_error( ctx, GL_INVALID_OPERATION, "glViewport" );
1023 return;
1024 }
1025
1026 /* clamp width, and height to implementation dependent range */
1027 width = CLAMP( width, 1, MAX_WIDTH );
1028 height = CLAMP( height, 1, MAX_HEIGHT );
1029
1030 /* Save viewport */
1031 ctx->Viewport.X = x;
1032 ctx->Viewport.Width = width;
1033 ctx->Viewport.Y = y;
1034 ctx->Viewport.Height = height;
1035
1036 /* compute scale and bias values */
1037 ctx->Viewport.Sx = (GLfloat) width / 2.0F;
1038 ctx->Viewport.Tx = ctx->Viewport.Sx + x;
1039 ctx->Viewport.Sy = (GLfloat) height / 2.0F;
1040 ctx->Viewport.Ty = ctx->Viewport.Sy + y;
1041
1042 ctx->NewState |= NEW_ALL; /* just to be safe */
1043
1044 /* Check if window/buffer has been resized and if so, reallocate the
1045 * ancillary buffers.
1046 */
1047 gl_ResizeBuffersMESA(ctx);
1048 }
1049