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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 */ 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 */ 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