xref: /reactos/dll/opengl/mesa/matrix.c (revision 5f2bebf7)
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