home *** CD-ROM | disk | FTP | other *** search
/ Amiga Magazin: Amiga-CD 2000 April & May / AMIGA_2000_04.iso / patches / mesa3.1 / mesa-3_1.lha / src / matrix.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-07  |  40.8 KB  |  1,459 lines

  1. /* $Id: matrix.c,v 1.8 1999/11/08 07:36:44 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  3.1
  6.  * 
  7.  * Copyright (C) 1999  Brian Paul   All Rights Reserved.
  8.  * 
  9.  * Permission is hereby granted, free of charge, to any person obtaining a
  10.  * copy of this software and associated documentation files (the "Software"),
  11.  * to deal in the Software without restriction, including without limitation
  12.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13.  * and/or sell copies of the Software, and to permit persons to whom the
  14.  * Software is furnished to do so, subject to the following conditions:
  15.  * 
  16.  * The above copyright notice and this permission notice shall be included
  17.  * in all copies or substantial portions of the Software.
  18.  * 
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  23.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27.  
  28.  
  29.  
  30.  
  31. /*
  32.  * Matrix operations
  33.  *
  34.  *
  35.  * NOTES:
  36.  * 1. 4x4 transformation matrices are stored in memory in column major order.
  37.  * 2. Points/vertices are to be thought of as column vectors.
  38.  * 3. Transformation of a point p by a matrix M is: p' = M * p
  39.  *
  40.  */
  41.  
  42.  
  43. #ifdef PC_HEADER
  44. #include "all.h"
  45. #else
  46. #ifndef XFree86Server
  47. #include <math.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #else
  52. #include "GL/xf86glx.h"
  53. #endif
  54. #include "context.h"
  55. #include "enums.h"
  56. #include "macros.h"
  57. #include "matrix.h"
  58. #include "mmath.h"
  59. #include "types.h"
  60. #endif
  61.  
  62.  
  63. static const char *types[] = {
  64.    "MATRIX_GENERAL",
  65.    "MATRIX_IDENTITY",
  66.    "MATRIX_3D_NO_ROT",
  67.    "MATRIX_PERSPECTIVE",
  68.    "MATRIX_2D",
  69.    "MATRIX_2D_NO_ROT",
  70.    "MATRIX_3D"
  71. };
  72. static void matmul4( GLfloat *product, const GLfloat *a, const GLfloat *b );
  73.  
  74.  
  75. static GLfloat Identity[16] = {
  76.    1.0, 0.0, 0.0, 0.0,
  77.    0.0, 1.0, 0.0, 0.0,
  78.    0.0, 0.0, 1.0, 0.0,
  79.    0.0, 0.0, 0.0, 1.0
  80. };
  81.  
  82.  
  83. static void print_matrix_floats( const GLfloat m[16] )
  84. {
  85.    int i;
  86.    for (i=0;i<4;i++) {
  87.       fprintf(stderr,"\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
  88.    }
  89. }
  90.  
  91. void gl_print_matrix( const GLmatrix *m )
  92. {
  93.    fprintf(stderr, "Matrix type: %s, flags: %x\n", types[m->type], m->flags);
  94.    print_matrix_floats(m->m);
  95. #if 1
  96.    fprintf(stderr, "Inverse: \n");
  97.    if (m->inv) {
  98.       GLfloat prod[16];
  99.       print_matrix_floats(m->inv);
  100.       matmul4(prod, m->m, m->inv);
  101.       fprintf(stderr, "Mat * Inverse:\n");
  102.       print_matrix_floats(prod);
  103.   } else 
  104.       fprintf(stderr, "  - not available\n");
  105. #endif
  106. }
  107.  
  108.  
  109.  
  110. /*
  111.  * This matmul was contributed by Thomas Malik 
  112.  *
  113.  * Perform a 4x4 matrix multiplication  (product = a x b).
  114.  * Input:  a, b - matrices to multiply
  115.  * Output:  product - product of a and b
  116.  * WARNING: (product != b) assumed
  117.  * NOTE:    (product == a) allowed    
  118.  *
  119.  * KW: 4*16 = 64 muls
  120.  */
  121. #define A(row,col)  a[(col<<2)+row]
  122. #define B(row,col)  b[(col<<2)+row]
  123. #define P(row,col)  product[(col<<2)+row]
  124.  
  125. static void matmul4( GLfloat *product, const GLfloat *a, const GLfloat *b )
  126. {
  127.    GLint i;
  128.    for (i = 0; i < 4; i++) {
  129.       GLfloat ai0=A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
  130.       P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
  131.       P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
  132.       P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
  133.       P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
  134.    }
  135. }
  136.  
  137.  
  138.  
  139.  
  140. /* Multiply two matrices known to occupy only the top three rows,
  141.  * such as typical modelling matrices, and ortho matrices.
  142.  *
  143.  * KW: 3*9 = 27 muls
  144.  */
  145. static void matmul34( GLfloat *product, const GLfloat *a, const GLfloat *b )
  146. {
  147.    GLint i;
  148.    for (i = 0; i < 3; i++) {
  149.       GLfloat ai0=A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
  150.       P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0);
  151.       P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1);
  152.       P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2);
  153.       P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3;
  154.    }
  155.    P(3,0) = 0;
  156.    P(3,1) = 0;
  157.    P(3,2) = 0;
  158.    P(3,3) = 1;
  159. }
  160.  
  161. static void matmul4fd( GLfloat *product, const GLfloat *a, const GLdouble *b )
  162. {
  163.    GLint i;
  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.  
  173. #undef A
  174. #undef B
  175. #undef P
  176.  
  177.  
  178.  
  179. #define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
  180. #define MAT(m,r,c) (m)[(c)*4+(r)]
  181.  
  182. /*
  183.  * Compute inverse of 4x4 transformation matrix.
  184.  * Code contributed by Jacques Leroy jle@star.be
  185.  * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
  186.  */
  187. static GLboolean invert_matrix_general( GLmatrix *mat )
  188. {
  189.    const GLfloat *m = mat->m;
  190.    GLfloat *out = mat->inv;
  191.    GLfloat wtmp[4][8];
  192.    GLfloat m0, m1, m2, m3, s;
  193.    GLfloat *r0, *r1, *r2, *r3;
  194.   
  195.    r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
  196.   
  197.    r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
  198.    r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
  199.    r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
  200.   
  201.    r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
  202.    r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
  203.    r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
  204.   
  205.    r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
  206.    r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
  207.    r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
  208.   
  209.    r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
  210.    r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
  211.    r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
  212.   
  213.    /* choose pivot - or die */
  214.    if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
  215.    if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
  216.    if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
  217.    if (0.0 == r0[0])  return GL_FALSE;
  218.   
  219.    /* eliminate first variable     */
  220.    m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
  221.    s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
  222.    s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
  223.    s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
  224.    s = r0[4];
  225.    if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
  226.    s = r0[5];
  227.    if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
  228.    s = r0[6];
  229.    if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
  230.    s = r0[7];
  231.    if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
  232.   
  233.    /* choose pivot - or die */
  234.    if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
  235.    if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
  236.    if (0.0 == r1[1])  return GL_FALSE;
  237.   
  238.    /* eliminate second variable */
  239.    m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
  240.    r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
  241.    r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
  242.    s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
  243.    s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
  244.    s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
  245.    s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
  246.   
  247.    /* choose pivot - or die */
  248.    if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
  249.    if (0.0 == r2[2])  return GL_FALSE;
  250.   
  251.    /* eliminate third variable */
  252.    m3 = r3[2]/r2[2];
  253.    r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
  254.    r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
  255.    r3[7] -= m3 * r2[7];
  256.   
  257.    /* last check */
  258.    if (0.0 == r3[3]) return GL_FALSE;
  259.   
  260.    s = 1.0/r3[3];              /* now back substitute row 3 */
  261.    r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
  262.   
  263.    m2 = r2[3];                 /* now back substitute row 2 */
  264.    s  = 1.0/r2[2];
  265.    r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
  266.    r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
  267.    m1 = r1[3];
  268.    r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
  269.    r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
  270.    m0 = r0[3];
  271.    r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
  272.    r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
  273.   
  274.    m1 = r1[2];                 /* now back substitute row 1 */
  275.    s  = 1.0/r1[1];
  276.    r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
  277.    r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
  278.    m0 = r0[2];
  279.    r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
  280.    r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
  281.   
  282.    m0 = r0[1];                 /* now back substitute row 0 */
  283.    s  = 1.0/r0[0];
  284.    r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
  285.    r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
  286.   
  287.    MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
  288.    MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
  289.    MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
  290.    MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
  291.    MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
  292.    MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
  293.    MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
  294.    MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; 
  295.   
  296.    return GL_TRUE;
  297. }
  298. #undef SWAP_ROWS
  299.  
  300. /* Adapted from graphics gems II.
  301.  */  
  302. static GLboolean invert_matrix_3d_general( GLmatrix *mat )
  303. {
  304.    const GLfloat *in = mat->m;
  305.    GLfloat *out = mat->inv;
  306.    GLfloat pos, neg, t;
  307.    GLfloat det;
  308.  
  309.    /* Calculate the determinant of upper left 3x3 submatrix and
  310.     * determine if the matrix is singular. 
  311.     */
  312.    pos = neg = 0.0;
  313.    t =  MAT(in,0,0) * MAT(in,1,1) * MAT(in,2,2);
  314.    if (t >= 0.0) pos += t; else neg += t;
  315.  
  316.    t =  MAT(in,1,0) * MAT(in,2,1) * MAT(in,0,2);
  317.    if (t >= 0.0) pos += t; else neg += t;
  318.  
  319.    t =  MAT(in,2,0) * MAT(in,0,1) * MAT(in,1,2);
  320.    if (t >= 0.0) pos += t; else neg += t;
  321.  
  322.    t = -MAT(in,2,0) * MAT(in,1,1) * MAT(in,0,2);
  323.    if (t >= 0.0) pos += t; else neg += t;
  324.  
  325.    t = -MAT(in,1,0) * MAT(in,0,1) * MAT(in,2,2);
  326.    if (t >= 0.0) pos += t; else neg += t;
  327.  
  328.    t = -MAT(in,0,0) * MAT(in,2,1) * MAT(in,1,2);
  329.    if (t >= 0.0) pos += t; else neg += t;
  330.  
  331.    det = pos + neg;
  332.  
  333.    if (det*det < 1e-25) 
  334.       return GL_FALSE;
  335.    
  336.    det = 1.0 / det;
  337.    MAT(out,0,0) = (  (MAT(in,1,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,1,2) )*det);
  338.    MAT(out,0,1) = (- (MAT(in,0,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,0,2) )*det);
  339.    MAT(out,0,2) = (  (MAT(in,0,1)*MAT(in,1,2) - MAT(in,1,1)*MAT(in,0,2) )*det);
  340.    MAT(out,1,0) = (- (MAT(in,1,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,1,2) )*det);
  341.    MAT(out,1,1) = (  (MAT(in,0,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,0,2) )*det);
  342.    MAT(out,1,2) = (- (MAT(in,0,0)*MAT(in,1,2) - MAT(in,1,0)*MAT(in,0,2) )*det);
  343.    MAT(out,2,0) = (  (MAT(in,1,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,1,1) )*det);
  344.    MAT(out,2,1) = (- (MAT(in,0,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,0,1) )*det);
  345.    MAT(out,2,2) = (  (MAT(in,0,0)*MAT(in,1,1) - MAT(in,1,0)*MAT(in,0,1) )*det);
  346.  
  347.    /* Do the translation part */
  348.    MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
  349.              MAT(in,1,3) * MAT(out,0,1) +
  350.              MAT(in,2,3) * MAT(out,0,2) );
  351.    MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
  352.              MAT(in,1,3) * MAT(out,1,1) +
  353.              MAT(in,2,3) * MAT(out,1,2) );
  354.    MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
  355.              MAT(in,1,3) * MAT(out,2,1) +
  356.              MAT(in,2,3) * MAT(out,2,2) );
  357.     
  358.    return GL_TRUE;
  359. }
  360.  
  361.  
  362. static GLboolean invert_matrix_3d( GLmatrix *mat )
  363. {
  364.    const GLfloat *in = mat->m;
  365.    GLfloat *out = mat->inv;
  366.  
  367.    if (!TEST_MAT_FLAGS(mat, MAT_FLAGS_ANGLE_PRESERVING))
  368.    {
  369.       return invert_matrix_3d_general( mat );
  370.    }
  371.    
  372.    if (mat->flags & MAT_FLAG_UNIFORM_SCALE)
  373.    {
  374.       GLfloat  scale = (MAT(in,0,0) * MAT(in,0,0) +
  375.             MAT(in,0,1) * MAT(in,0,1) +
  376.             MAT(in,0,2) * MAT(in,0,2));
  377.  
  378.       if (scale == 0.0) 
  379.          return GL_FALSE;
  380.  
  381.       scale = 1.0 / scale;
  382.  
  383.       /* Transpose and scale the 3 by 3 upper-left submatrix. */
  384.       MAT(out,0,0) = scale * MAT(in,0,0);
  385.       MAT(out,1,0) = scale * MAT(in,0,1);
  386.       MAT(out,2,0) = scale * MAT(in,0,2);
  387.       MAT(out,0,1) = scale * MAT(in,1,0);
  388.       MAT(out,1,1) = scale * MAT(in,1,1);
  389.       MAT(out,2,1) = scale * MAT(in,1,2);
  390.       MAT(out,0,2) = scale * MAT(in,2,0);
  391.       MAT(out,1,2) = scale * MAT(in,2,1);
  392.       MAT(out,2,2) = scale * MAT(in,2,2);
  393.    }
  394.    else if (mat->flags & MAT_FLAG_ROTATION)
  395.    {
  396.       /* Transpose the 3 by 3 upper-left submatrix. */
  397.       MAT(out,0,0) = MAT(in,0,0);
  398.       MAT(out,1,0) = MAT(in,0,1);
  399.       MAT(out,2,0) = MAT(in,0,2);
  400.       MAT(out,0,1) = MAT(in,1,0);
  401.       MAT(out,1,1) = MAT(in,1,1);
  402.       MAT(out,2,1) = MAT(in,1,2);
  403.       MAT(out,0,2) = MAT(in,2,0);
  404.       MAT(out,1,2) = MAT(in,2,1);
  405.       MAT(out,2,2) = MAT(in,2,2);
  406.    }
  407.    else /* pure translation */
  408.    {
  409.       MEMCPY( out, Identity, sizeof(Identity) );
  410.       MAT(out,0,3) = - MAT(in,0,3);
  411.       MAT(out,1,3) = - MAT(in,1,3);
  412.       MAT(out,2,3) = - MAT(in,2,3);
  413.       return GL_TRUE;
  414.    }
  415.     
  416.    if (mat->flags & MAT_FLAG_TRANSLATION)
  417.    {
  418.       /* Do the translation part */
  419.       MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
  420.             MAT(in,1,3) * MAT(out,0,1) +
  421.             MAT(in,2,3) * MAT(out,0,2) );
  422.       MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
  423.             MAT(in,1,3) * MAT(out,1,1) +
  424.             MAT(in,2,3) * MAT(out,1,2) );
  425.       MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
  426.             MAT(in,1,3) * MAT(out,2,1) +
  427.             MAT(in,2,3) * MAT(out,2,2) );
  428.    }
  429.    else 
  430.    {
  431.       MAT(out,0,3) = MAT(out,1,3) = MAT(out,2,3) = 0.0;
  432.    }
  433.     
  434.    return GL_TRUE;
  435. }
  436.  
  437.   
  438.  
  439. static GLboolean invert_matrix_identity( GLmatrix *mat )
  440. {
  441.    MEMCPY( mat->inv, Identity, sizeof(Identity) );
  442.    return GL_TRUE;
  443. }
  444.  
  445.  
  446. static GLboolean invert_matrix_3d_no_rot( GLmatrix *mat )
  447. {
  448.    const GLfloat *in = mat->m;
  449.    GLfloat *out = mat->inv;
  450.  
  451.    if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0 || MAT(in,2,2) == 0 )       
  452.       return GL_FALSE;
  453.   
  454.    MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
  455.    MAT(out,0,0) = 1.0 / MAT(in,0,0);
  456.    MAT(out,1,1) = 1.0 / MAT(in,1,1);
  457.    MAT(out,2,2) = 1.0 / MAT(in,2,2);
  458.  
  459.    if (mat->flags & MAT_FLAG_TRANSLATION)
  460.    {
  461.       MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
  462.       MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
  463.       MAT(out,2,3) = - (MAT(in,2,3) * MAT(out,2,2));
  464.    }
  465.  
  466.    return GL_TRUE;
  467. }
  468.  
  469.  
  470. static GLboolean invert_matrix_2d_no_rot( GLmatrix *mat )
  471. {
  472.    const GLfloat *in = mat->m;
  473.    GLfloat *out = mat->inv;
  474.  
  475.    if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0)       
  476.       return GL_FALSE;
  477.   
  478.    MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
  479.    MAT(out,0,0) = 1.0 / MAT(in,0,0);
  480.    MAT(out,1,1) = 1.0 / MAT(in,1,1);
  481.  
  482.    if (mat->flags & MAT_FLAG_TRANSLATION)
  483.    {
  484.       MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
  485.       MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
  486.    }
  487.  
  488.    return GL_TRUE;
  489. }
  490.  
  491.  
  492. static GLboolean invert_matrix_perspective( GLmatrix *mat )
  493. {
  494.    const GLfloat *in = mat->m;
  495.    GLfloat *out = mat->inv;
  496.  
  497.    if (MAT(in,2,3) == 0)
  498.       return GL_FALSE;
  499.  
  500.    MEMCPY( out, Identity, 16 * sizeof(GLfloat) );
  501.  
  502.    MAT(out,0,0) = 1.0 / MAT(in,0,0);
  503.    MAT(out,1,1) = 1.0 / MAT(in,1,1);
  504.  
  505.    MAT(out,0,3) = MAT(in,0,2);
  506.    MAT(out,1,3) = MAT(in,1,2);
  507.  
  508.    MAT(out,2,2) = 0;
  509.    MAT(out,2,3) = -1;
  510.  
  511.    MAT(out,3,2) = 1.0 / MAT(in,2,3);
  512.    MAT(out,3,3) = MAT(in,2,2) * MAT(out,3,2);
  513.  
  514.    return GL_TRUE;
  515. }
  516.  
  517.  
  518. typedef GLboolean (*inv_mat_func)( GLmatrix *mat );
  519.  
  520. static inv_mat_func inv_mat_tab[7] = {
  521.    invert_matrix_general,
  522.    invert_matrix_identity,
  523.    invert_matrix_3d_no_rot,
  524.    invert_matrix_perspective,
  525.    invert_matrix_3d,        /* lazy! */
  526.    invert_matrix_2d_no_rot,
  527.    invert_matrix_3d
  528. };
  529.  
  530.  
  531. GLboolean gl_matrix_invert( GLmatrix *mat )
  532. {
  533.    if (inv_mat_tab[mat->type](mat)) {
  534. #if 0
  535.       GLmatrix m; m.inv = 0; m.type = 0; m.flags = 0;
  536.       matmul4( m.m, mat->m, mat->inv );
  537.       printf("inverted matrix of type %s:\n", types[mat->type]);
  538.       gl_print_matrix( mat );
  539.       gl_print_matrix( &m );
  540. #endif
  541.       return GL_TRUE;
  542.    } else {
  543.       MEMCPY( mat->inv, Identity, sizeof(Identity) );
  544.       return GL_FALSE;
  545.    }  
  546. }
  547.  
  548.  
  549.  
  550. /*
  551.  * Generate a 4x4 transformation matrix from glRotate parameters.
  552.  */
  553. void gl_rotation_matrix( GLfloat angle, GLfloat x, GLfloat y, GLfloat z,
  554.                          GLfloat m[] )
  555. {
  556.    /* This function contributed by Erich Boleyn (erich@uruk.org) */
  557.    GLfloat mag, s, c;
  558.    GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
  559.  
  560.    s = sin( angle * DEG2RAD );
  561.    c = cos( angle * DEG2RAD );
  562.  
  563.    mag = GL_SQRT( x*x + y*y + z*z );
  564.  
  565.    if (mag == 0.0) {
  566.       /* generate an identity matrix and return */
  567.       MEMCPY(m, Identity, sizeof(GLfloat)*16);
  568.       return;
  569.    }
  570.  
  571.    x /= mag;
  572.    y /= mag;
  573.    z /= mag;
  574.  
  575. #define M(row,col)  m[col*4+row]
  576.  
  577.    /*
  578.     *     Arbitrary axis rotation matrix.
  579.     *
  580.     *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
  581.     *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
  582.     *  (which is about the X-axis), and the two composite transforms
  583.     *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
  584.     *  from the arbitrary axis to the X-axis then back.  They are
  585.     *  all elementary rotations.
  586.     *
  587.     *  Rz' is a rotation about the Z-axis, to bring the axis vector
  588.     *  into the x-z plane.  Then Ry' is applied, rotating about the
  589.     *  Y-axis to bring the axis vector parallel with the X-axis.  The
  590.     *  rotation about the X-axis is then performed.  Ry and Rz are
  591.     *  simply the respective inverse transforms to bring the arbitrary
  592.     *  axis back to it's original orientation.  The first transforms
  593.     *  Rz' and Ry' are considered inverses, since the data from the
  594.     *  arbitrary axis gives you info on how to get to it, not how
  595.     *  to get away from it, and an inverse must be applied.
  596.     *
  597.     *  The basic calculation used is to recognize that the arbitrary
  598.     *  axis vector (x, y, z), since it is of unit length, actually
  599.     *  represents the sines and cosines of the angles to rotate the
  600.     *  X-axis to the same orientation, with theta being the angle about
  601.     *  Z and phi the angle about Y (in the order described above)
  602.     *  as follows:
  603.     *
  604.     *  cos ( theta ) = x / sqrt ( 1 - z^2 )
  605.     *  sin ( theta ) = y / sqrt ( 1 - z^2 )
  606.     *
  607.     *  cos ( phi ) = sqrt ( 1 - z^2 )
  608.     *  sin ( phi ) = z
  609.     *
  610.     *  Note that cos ( phi ) can further be inserted to the above
  611.     *  formulas:
  612.     *
  613.     *  cos ( theta ) = x / cos ( phi )
  614.     *  sin ( theta ) = y / sin ( phi )
  615.     *
  616.     *  ...etc.  Because of those relations and the standard trigonometric
  617.     *  relations, it is pssible to reduce the transforms down to what
  618.     *  is used below.  It may be that any primary axis chosen will give the
  619.     *  same results (modulo a sign convention) using thie method.
  620.     *
  621.     *  Particularly nice is to notice that all divisions that might
  622.     *  have caused trouble when parallel to certain planes or
  623.     *  axis go away with care paid to reducing the expressions.
  624.     *  After checking, it does perform correctly under all cases, since
  625.     *  in all the cases of division where the denominator would have
  626.     *  been zero, the numerator would have been zero as well, giving
  627.     *  the expected result.
  628.     */
  629.  
  630.    xx = x * x;
  631.    yy = y * y;
  632.    zz = z * z;
  633.    xy = x * y;
  634.    yz = y * z;
  635.    zx = z * x;
  636.    xs = x * s;
  637.    ys = y * s;
  638.    zs = z * s;
  639.    one_c = 1.0F - c;
  640.  
  641.    M(0,0) = (one_c * xx) + c;
  642.    M(0,1) = (one_c * xy) - zs;
  643.    M(0,2) = (one_c * zx) + ys;
  644.    M(0,3) = 0.0F;
  645.  
  646.    M(1,0) = (one_c * xy) + zs;
  647.    M(1,1) = (one_c * yy) + c;
  648.    M(1,2) = (one_c * yz) - xs;
  649.    M(1,3) = 0.0F;
  650.  
  651.    M(2,0) = (one_c * zx) - ys;
  652.    M(2,1) = (one_c * yz) + xs;
  653.    M(2,2) = (one_c * zz) + c;
  654.    M(2,3) = 0.0F;
  655.  
  656.    M(3,0) = 0.0F;
  657.    M(3,1) = 0.0F;
  658.    M(3,2) = 0.0F;
  659.    M(3,3) = 1.0F;
  660.  
  661. #undef M
  662. }
  663.  
  664. #define ZERO(x) (1<<x)
  665. #define ONE(x)  (1<<(x+16))
  666.  
  667. #define MASK_NO_TRX      (ZERO(12) | ZERO(13) | ZERO(14))
  668. #define MASK_NO_2D_SCALE ( ONE(0)  | ONE(5))
  669.  
  670. #define MASK_IDENTITY    ( ONE(0)  | ZERO(4)  | ZERO(8)  | ZERO(12) |\
  671.               ZERO(1)  |  ONE(5)  | ZERO(9)  | ZERO(13) |\
  672.               ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
  673.               ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
  674.  
  675. #define MASK_2D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
  676.               ZERO(1)  |            ZERO(9)  |           \
  677.               ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
  678.               ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
  679.  
  680. #define MASK_2D          (                      ZERO(8)  |           \
  681.                                     ZERO(9)  |           \
  682.               ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
  683.               ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
  684.  
  685.  
  686. #define MASK_3D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
  687.               ZERO(1)  |            ZERO(9)  |           \
  688.               ZERO(2)  | ZERO(6)  |                      \
  689.               ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
  690.  
  691. #define MASK_3D          (                                           \
  692.                                                          \
  693.                                                          \
  694.               ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
  695.  
  696.  
  697. #define MASK_PERSPECTIVE (           ZERO(4)  |            ZERO(12) |\
  698.               ZERO(1)  |                       ZERO(13) |\
  699.               ZERO(2)  | ZERO(6)  |                      \
  700.               ZERO(3)  | ZERO(7)  |            ZERO(15) )
  701.  
  702. #define SQ(x) ((x)*(x))
  703.   
  704. /* Determine type and flags from scratch.  This is expensive enough to
  705.  * only want to do it once.
  706.  */
  707. static void analyze_from_scratch( GLmatrix *mat )
  708. {
  709.    const GLfloat *m = mat->m;
  710.    GLuint mask = 0;
  711.    GLuint i;
  712.  
  713.    for (i = 0 ; i < 16 ; i++) 
  714.    {
  715.       if (m[i] == 0.0) mask |= (1<<i);
  716.    }
  717.    
  718.    if (m[0] == 1.0F) mask |= (1<<16);
  719.    if (m[5] == 1.0F) mask |= (1<<21);
  720.    if (m[10] == 1.0F) mask |= (1<<26);
  721.    if (m[15] == 1.0F) mask |= (1<<31);
  722.  
  723.    mat->flags &= ~MAT_FLAGS_GEOMETRY;
  724.  
  725.    /* Check for translation - no-one really cares 
  726.     */
  727.    if ((mask & MASK_NO_TRX) != MASK_NO_TRX) 
  728.       mat->flags |= MAT_FLAG_TRANSLATION;      
  729.  
  730.    /* Do the real work
  731.     */
  732.    if (mask == MASK_IDENTITY) {
  733.       mat->type = MATRIX_IDENTITY;
  734.    }
  735.    else if ((mask & MASK_2D_NO_ROT) == MASK_2D_NO_ROT)  
  736.    {
  737.       mat->type = MATRIX_2D_NO_ROT;
  738.       
  739.       if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
  740.      mat->flags = MAT_FLAG_GENERAL_SCALE;
  741.    }
  742.    else if ((mask & MASK_2D) == MASK_2D)  
  743.    {
  744.       GLfloat mm = DOT2(m, m);
  745.       GLfloat m4m4 = DOT2(m+4,m+4);
  746.       GLfloat mm4 = DOT2(m,m+4);
  747.  
  748.       mat->type = MATRIX_2D;
  749.  
  750.       /* Check for scale */
  751.       if (SQ(mm-1) > SQ(1e-6) ||
  752.       SQ(m4m4-1) > SQ(1e-6)) 
  753.      mat->flags |= MAT_FLAG_GENERAL_SCALE;
  754.  
  755.       /* Check for rotation */
  756.       if (SQ(mm4) > SQ(1e-6))
  757.      mat->flags |= MAT_FLAG_GENERAL_3D;
  758.       else
  759.      mat->flags |= MAT_FLAG_ROTATION;
  760.  
  761.    }
  762.    else if ((mask & MASK_3D_NO_ROT) == MASK_3D_NO_ROT)
  763.    {
  764.       mat->type = MATRIX_3D_NO_ROT;
  765.  
  766.       /* Check for scale */
  767.       if (SQ(m[0]-m[5]) < SQ(1e-6) && 
  768.       SQ(m[0]-m[10]) < SQ(1e-6)) {
  769.      if (SQ(m[0]-1.0) > SQ(1e-6))
  770.         mat->flags |= MAT_FLAG_UNIFORM_SCALE;
  771.       } else
  772.      mat->flags |= MAT_FLAG_GENERAL_SCALE;
  773.    }
  774.    else if ((mask & MASK_3D) == MASK_3D)
  775.    {
  776.       GLfloat c1 = DOT3(m,m);
  777.       GLfloat c2 = DOT3(m+4,m+4);
  778.       GLfloat c3 = DOT3(m+8,m+8);
  779.       GLfloat d1 = DOT3(m, m+4);
  780.       GLfloat cp[3];
  781.  
  782.       mat->type = MATRIX_3D;
  783.  
  784.       /* Check for scale */
  785.       if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) {
  786.      if (SQ(c1-1.0) > SQ(1e-6))
  787.         mat->flags |= MAT_FLAG_UNIFORM_SCALE;
  788.      /* else no scale at all */
  789.       } else 
  790.      mat->flags |= MAT_FLAG_GENERAL_SCALE;
  791.  
  792.       /* Check for rotation */
  793.       if (SQ(d1) < SQ(1e-6)) {
  794.      CROSS3( cp, m, m+4 );
  795.      SUB_3V( cp, cp, (m+8) );
  796.      if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) 
  797.         mat->flags |= MAT_FLAG_ROTATION;
  798.      else
  799.         mat->flags |= MAT_FLAG_GENERAL_3D;
  800.       }
  801.       else
  802.      mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
  803.    }
  804.    else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) 
  805.    {
  806.       mat->type = MATRIX_PERSPECTIVE;
  807.       mat->flags |= MAT_FLAG_GENERAL;
  808.    }
  809.    else {
  810.       mat->type = MATRIX_GENERAL;
  811.       mat->flags |= MAT_FLAG_GENERAL;
  812.    }
  813. }
  814.  
  815.  
  816. /* Analyse a matrix given that its flags are accurate - this is the
  817.  * more common operation, hopefully. 
  818.  */
  819. static void analyze_from_flags( GLmatrix *mat )
  820. {
  821.    const GLfloat *m = mat->m;
  822.  
  823.    if (TEST_MAT_FLAGS(mat, 0)) {
  824.       mat->type = MATRIX_IDENTITY;
  825.    }
  826.    else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION |
  827.                  MAT_FLAG_UNIFORM_SCALE |
  828.                  MAT_FLAG_GENERAL_SCALE)))
  829.    {
  830.       if ( m[10]==1.0F && m[14]==0.0F ) {
  831.      mat->type = MATRIX_2D_NO_ROT;
  832.       }
  833.       else {
  834.      mat->type = MATRIX_3D_NO_ROT;
  835.       }
  836.    }
  837.    else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) {
  838.       if (                                 m[ 8]==0.0F               
  839.             &&                             m[ 9]==0.0F
  840.             && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F)
  841.       {
  842.      mat->type = MATRIX_2D;
  843.       }
  844.       else 
  845.       {
  846.      mat->type = MATRIX_3D;
  847.       }
  848.    }
  849.    else if (                 m[4]==0.0F                 && m[12]==0.0F
  850.             && m[1]==0.0F                               && m[13]==0.0F
  851.             && m[2]==0.0F && m[6]==0.0F
  852.             && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) 
  853.    {
  854.       mat->type = MATRIX_PERSPECTIVE;
  855.    }
  856.    else {
  857.       mat->type = MATRIX_GENERAL;
  858.    }
  859.  
  860. }
  861.  
  862.  
  863. void gl_matrix_analyze( GLmatrix *mat ) 
  864. {
  865.    if (mat->flags & MAT_DIRTY_TYPE) {
  866.       if (mat->flags & MAT_DIRTY_FLAGS) 
  867.      analyze_from_scratch( mat );
  868.       else
  869.      analyze_from_flags( mat );
  870.    }
  871.  
  872.    if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) {
  873.       gl_matrix_invert( mat );
  874.    }
  875.  
  876.    mat->flags &= ~(MAT_DIRTY_FLAGS|
  877.            MAT_DIRTY_TYPE|
  878.            MAT_DIRTY_INVERSE);
  879. }
  880.  
  881.  
  882. #define GET_ACTIVE_MATRIX(ctx, mat, flags, where)            \
  883. do {                                    \
  884.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, where);                      \
  885.    if (MESA_VERBOSE&VERBOSE_API) fprintf(stderr, "%s\n", where);        \
  886.    switch (ctx->Transform.MatrixMode) {                    \
  887.       case GL_MODELVIEW:                        \
  888.      mat = &ctx->ModelView;                        \
  889.      flags |= NEW_MODELVIEW;                    \
  890.      break;                                \
  891.       case GL_PROJECTION:                        \
  892.      mat = &ctx->ProjectionMatrix;                    \
  893.      flags |= NEW_PROJECTION;                    \
  894.      break;                                \
  895.       case GL_TEXTURE:                            \
  896.      mat = &ctx->TextureMatrix[ctx->Texture.CurrentTransformUnit];    \
  897.      flags |= NEW_TEXTURE_MATRIX;                    \
  898.      break;                                \
  899.       default:                                \
  900.          gl_problem(ctx, where);                    \
  901.    }                                    \
  902. } while (0)
  903.  
  904.  
  905. void gl_Frustum( GLcontext *ctx,
  906.                  GLdouble left, GLdouble right,
  907.           GLdouble bottom, GLdouble top,
  908.          GLdouble nearval, GLdouble farval )
  909. {
  910.    GLfloat x, y, a, b, c, d;
  911.    GLfloat m[16];
  912.    GLmatrix *mat = 0;
  913.  
  914.    GET_ACTIVE_MATRIX( ctx,  mat, ctx->NewState, "glFrustrum" );
  915.  
  916.    if ((nearval<=0.0 || farval<=0.0) || (nearval == farval) || (left == right) || (top == bottom)) {
  917.       gl_error( ctx,  GL_INVALID_VALUE, "glFrustum(near or far)" );
  918.       return;
  919.    }
  920.  
  921.    x = (2.0*nearval) / (right-left);
  922.    y = (2.0*nearval) / (top-bottom);
  923.    a = (right+left) / (right-left);
  924.    b = (top+bottom) / (top-bottom);
  925.    c = -(farval+nearval) / ( farval-nearval);
  926.    d = -(2.0*farval*nearval) / (farval-nearval);  /* error? */
  927.  
  928. #define M(row,col)  m[col*4+row]
  929.    M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
  930.    M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
  931.    M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = c;      M(2,3) = d;
  932.    M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = -1.0F;  M(3,3) = 0.0F;
  933. #undef M
  934.  
  935.  
  936.    gl_mat_mul_floats( mat, m, MAT_FLAG_PERSPECTIVE );
  937.  
  938.  
  939.    if (ctx->Transform.MatrixMode == GL_PROJECTION)
  940.    {
  941.       /* Need to keep a stack of near/far values in case the user push/pops
  942.        * the projection matrix stack so that we can call Driver.NearFar()
  943.        * after a pop.
  944.        */
  945.       ctx->NearFarStack[ctx->ProjectionStackDepth][0] = nearval;
  946.       ctx->NearFarStack[ctx->ProjectionStackDepth][1] = farval;
  947.       
  948.       if (ctx->Driver.NearFar) {
  949.      (*ctx->Driver.NearFar)( ctx, nearval, farval );
  950.       }
  951.    }
  952. }
  953.  
  954.  
  955. void gl_Ortho( GLcontext *ctx,
  956.                GLdouble left, GLdouble right,
  957.                GLdouble bottom, GLdouble top,
  958.                GLdouble nearval, GLdouble farval )
  959. {
  960.    GLfloat x, y, z;
  961.    GLfloat tx, ty, tz;
  962.    GLfloat m[16];
  963.    GLmatrix *mat = 0;
  964.  
  965.    GET_ACTIVE_MATRIX( ctx,  mat, ctx->NewState, "glOrtho" );
  966.  
  967.    if ((left == right) || (bottom == top) || (nearval == farval)) {
  968.       gl_error( ctx,  GL_INVALID_VALUE, "gl_Ortho((l = r) or (b = top) or (n=f)" );
  969.       return;
  970.    }
  971.  
  972.    x = 2.0 / (right-left);
  973.    y = 2.0 / (top-bottom);
  974.    z = -2.0 / (farval-nearval);
  975.    tx = -(right+left) / (right-left);
  976.    ty = -(top+bottom) / (top-bottom);
  977.    tz = -(farval+nearval) / (farval-nearval);
  978.  
  979. #define M(row,col)  m[col*4+row]
  980.    M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = 0.0F;  M(0,3) = tx;
  981.    M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = 0.0F;  M(1,3) = ty;
  982.    M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = z;     M(2,3) = tz;
  983.    M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = 0.0F;  M(3,3) = 1.0F;
  984. #undef M
  985.  
  986.    gl_mat_mul_floats( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));
  987.  
  988.    if (ctx->Driver.NearFar) {
  989.       (*ctx->Driver.NearFar)( ctx, nearval, farval );
  990.    }
  991. }
  992.  
  993.  
  994. void gl_MatrixMode( GLcontext *ctx, GLenum mode )
  995. {
  996.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glMatrixMode");
  997.    switch (mode) {
  998.       case GL_MODELVIEW:
  999.       case GL_PROJECTION:
  1000.       case GL_TEXTURE:
  1001.          ctx->Transform.MatrixMode = mode;
  1002.          break;
  1003.       default:
  1004.          gl_error( ctx,  GL_INVALID_ENUM, "glMatrixMode" );
  1005.    }
  1006. }
  1007.  
  1008.  
  1009.  
  1010. void gl_PushMatrix( GLcontext *ctx )
  1011. {
  1012.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPushMatrix");
  1013.  
  1014.    if (MESA_VERBOSE&VERBOSE_API)
  1015.       fprintf(stderr, "glPushMatrix %s\n", 
  1016.           gl_lookup_enum_by_nr(ctx->Transform.MatrixMode));
  1017.  
  1018.    switch (ctx->Transform.MatrixMode) {
  1019.       case GL_MODELVIEW:
  1020.          if (ctx->ModelViewStackDepth>=MAX_MODELVIEW_STACK_DEPTH-1) {
  1021.             gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  1022.             return;
  1023.          }
  1024.          gl_matrix_copy( &ctx->ModelViewStack[ctx->ModelViewStackDepth++],
  1025.              &ctx->ModelView );
  1026.          break;
  1027.       case GL_PROJECTION:
  1028.          if (ctx->ProjectionStackDepth>=MAX_PROJECTION_STACK_DEPTH) {
  1029.             gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  1030.             return;
  1031.          }
  1032.          gl_matrix_copy( &ctx->ProjectionStack[ctx->ProjectionStackDepth++],
  1033.              &ctx->ProjectionMatrix );
  1034.  
  1035.          /* Save near and far projection values */
  1036.          ctx->NearFarStack[ctx->ProjectionStackDepth][0]
  1037.             = ctx->NearFarStack[ctx->ProjectionStackDepth-1][0];
  1038.          ctx->NearFarStack[ctx->ProjectionStackDepth][1]
  1039.             = ctx->NearFarStack[ctx->ProjectionStackDepth-1][1];
  1040.          break;
  1041.       case GL_TEXTURE:
  1042.          {
  1043.             GLuint t = ctx->Texture.CurrentTransformUnit;
  1044.             if (ctx->TextureStackDepth[t] >= MAX_TEXTURE_STACK_DEPTH) {
  1045.                gl_error( ctx,  GL_STACK_OVERFLOW, "glPushMatrix");
  1046.                return;
  1047.             }
  1048.         gl_matrix_copy( &ctx->TextureStack[t][ctx->TextureStackDepth[t]++],
  1049.                 &ctx->TextureMatrix[t] );
  1050.          }
  1051.          break;
  1052.       default:
  1053.          gl_problem(ctx, "Bad matrix mode in gl_PushMatrix");
  1054.    }
  1055. }
  1056.  
  1057.  
  1058.  
  1059. void gl_PopMatrix( GLcontext *ctx )
  1060. {
  1061.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glPopMatrix");
  1062.  
  1063.    if (MESA_VERBOSE&VERBOSE_API)
  1064.       fprintf(stderr, "glPopMatrix %s\n", 
  1065.           gl_lookup_enum_by_nr(ctx->Transform.MatrixMode));
  1066.  
  1067.    switch (ctx->Transform.MatrixMode) {
  1068.       case GL_MODELVIEW:
  1069.          if (ctx->ModelViewStackDepth==0) {
  1070.             gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  1071.             return;
  1072.          }
  1073.          gl_matrix_copy( &ctx->ModelView,
  1074.              &ctx->ModelViewStack[--ctx->ModelViewStackDepth] );
  1075.      ctx->NewState |= NEW_MODELVIEW;
  1076.          break;
  1077.       case GL_PROJECTION:
  1078.          if (ctx->ProjectionStackDepth==0) {
  1079.             gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  1080.             return;
  1081.          }
  1082.  
  1083.          gl_matrix_copy( &ctx->ProjectionMatrix,
  1084.              &ctx->ProjectionStack[--ctx->ProjectionStackDepth] );
  1085.      ctx->NewState |= NEW_PROJECTION;
  1086.  
  1087.          /* Device driver near/far values */
  1088.          {
  1089.             GLfloat nearVal = ctx->NearFarStack[ctx->ProjectionStackDepth][0];
  1090.             GLfloat farVal  = ctx->NearFarStack[ctx->ProjectionStackDepth][1];
  1091.             if (ctx->Driver.NearFar) {
  1092.                (*ctx->Driver.NearFar)( ctx, nearVal, farVal );
  1093.             }
  1094.          }
  1095.          break;
  1096.       case GL_TEXTURE:
  1097.          {
  1098.             GLuint t = ctx->Texture.CurrentTransformUnit;
  1099.             if (ctx->TextureStackDepth[t]==0) {
  1100.                gl_error( ctx,  GL_STACK_UNDERFLOW, "glPopMatrix");
  1101.                return;
  1102.             }
  1103.         gl_matrix_copy(&ctx->TextureMatrix[t],
  1104.                &ctx->TextureStack[t][--ctx->TextureStackDepth[t]]);
  1105.          }
  1106.          break;
  1107.       default:
  1108.          gl_problem(ctx, "Bad matrix mode in gl_PopMatrix");
  1109.    }
  1110. }
  1111.  
  1112.  
  1113.  
  1114. void gl_LoadIdentity( GLcontext *ctx )
  1115. {
  1116.    GLmatrix *mat = 0;
  1117.    GET_ACTIVE_MATRIX(ctx, mat, ctx->NewState, "glLoadIdentity");
  1118.  
  1119.    MEMCPY( mat->m, Identity, 16*sizeof(GLfloat) );
  1120.  
  1121.    if (mat->inv)
  1122.       MEMCPY( mat->inv, Identity, 16*sizeof(GLfloat) );
  1123.  
  1124.    mat->type = MATRIX_IDENTITY;
  1125.    
  1126.    /* Have to set this to dirty to make sure we recalculate the
  1127.     * combined matrix later.  The update_matrix in this case is a
  1128.     * shortcircuit anyway...
  1129.     */
  1130.    mat->flags = MAT_DIRTY_DEPENDENTS;    
  1131. }
  1132.  
  1133.  
  1134. void gl_LoadMatrixf( GLcontext *ctx, const GLfloat *m )
  1135. {
  1136.    GLmatrix *mat = 0;
  1137.    GET_ACTIVE_MATRIX(ctx, mat, ctx->NewState, "glLoadMatrix");
  1138.  
  1139.    MEMCPY( mat->m, m, 16*sizeof(GLfloat) );
  1140.    mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL_OVER);
  1141.  
  1142.    if (ctx->Transform.MatrixMode == GL_PROJECTION) {
  1143.  
  1144. #define M(row,col)  m[col*4+row]
  1145.       GLfloat c = M(2,2);
  1146.       GLfloat d = M(2,3);
  1147. #undef M
  1148.       GLfloat n = (c ==  1.0 ? 0.0 : d / (c - 1.0));
  1149.       GLfloat f = (c == -1.0 ? 1.0 : d / (c + 1.0));
  1150.  
  1151.       /* Need to keep a stack of near/far values in case the user
  1152.        * push/pops the projection matrix stack so that we can call
  1153.        * Driver.NearFar() after a pop.
  1154.        */
  1155.       ctx->NearFarStack[ctx->ProjectionStackDepth][0] = n;
  1156.       ctx->NearFarStack[ctx->ProjectionStackDepth][1] = f;
  1157.  
  1158.       if (ctx->Driver.NearFar) {
  1159.      (*ctx->Driver.NearFar)( ctx, n, f );
  1160.       }
  1161.    }
  1162. }
  1163.  
  1164.  
  1165.  
  1166. /*
  1167.  * Multiply the active matrix by an arbitary matrix.
  1168.  */
  1169. void gl_MultMatrixf( GLcontext *ctx, const GLfloat *m )
  1170. {
  1171.    GLmatrix *mat = 0;
  1172.    GET_ACTIVE_MATRIX( ctx,  mat, ctx->NewState, "glMultMatrix" );
  1173.    matmul4( mat->m, mat->m, m );
  1174.    mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL_OVER);
  1175. }
  1176.  
  1177.  
  1178. /*
  1179.  * Multiply the active matrix by an arbitary matrix.  
  1180.  */
  1181. void gl_MultMatrixd( GLcontext *ctx, const GLdouble *m )
  1182. {
  1183.    GLmatrix *mat = 0;
  1184.    GET_ACTIVE_MATRIX( ctx,  mat, ctx->NewState, "glMultMatrix" );
  1185.    matmul4fd( mat->m, mat->m, m );
  1186.    mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL_OVER);
  1187. }
  1188.  
  1189.  
  1190.  
  1191.  
  1192. /*
  1193.  * Multiply a matrix by an array of floats with known properties.
  1194.  */
  1195. void gl_mat_mul_floats( GLmatrix *mat, const GLfloat *m, GLuint flags )
  1196. {
  1197.    mat->flags |= (flags |
  1198.           MAT_DIRTY_TYPE | 
  1199.           MAT_DIRTY_INVERSE | 
  1200.           MAT_DIRTY_DEPENDENTS);
  1201.  
  1202.    if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D))
  1203.       matmul34( mat->m, mat->m, m );
  1204.    else 
  1205.       matmul4( mat->m, mat->m, m );      
  1206.  
  1207. }
  1208.  
  1209. /*
  1210.  * Multiply a matrix by an array of floats with known properties.
  1211.  */
  1212. void gl_mat_mul_mat( GLmatrix *mat, const GLmatrix *m )
  1213. {
  1214.    mat->flags |= (m->flags |
  1215.           MAT_DIRTY_TYPE | 
  1216.           MAT_DIRTY_INVERSE | 
  1217.           MAT_DIRTY_DEPENDENTS);
  1218.  
  1219.    if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D))
  1220.       matmul34( mat->m, mat->m, m->m );
  1221.    else 
  1222.       matmul4( mat->m, mat->m, m->m );      
  1223. }
  1224.  
  1225.  
  1226.  
  1227. /*
  1228.  * Execute a glRotate call
  1229.  */
  1230. void gl_Rotatef( GLcontext *ctx,
  1231.                  GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
  1232. {
  1233.    GLfloat m[16];
  1234.    if (angle != 0.0F) {
  1235.       GLmatrix *mat = 0;
  1236.       GET_ACTIVE_MATRIX( ctx,  mat, ctx->NewState, "glRotate" );
  1237.  
  1238.       gl_rotation_matrix( angle, x, y, z, m );
  1239.       gl_mat_mul_floats( mat, m, MAT_FLAG_ROTATION );
  1240.    }
  1241. }
  1242.  
  1243. /*
  1244.  * Execute a glScale call
  1245.  */
  1246. void gl_Scalef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
  1247. {
  1248.    GLmatrix *mat = 0;
  1249.    GLfloat *m;
  1250.    GET_ACTIVE_MATRIX(ctx, mat, ctx->NewState, "glScale");
  1251.  
  1252.    m = mat->m;
  1253.    m[0] *= x;   m[4] *= y;   m[8]  *= z;
  1254.    m[1] *= x;   m[5] *= y;   m[9]  *= z;
  1255.    m[2] *= x;   m[6] *= y;   m[10] *= z;
  1256.    m[3] *= x;   m[7] *= y;   m[11] *= z;
  1257.  
  1258.    if (fabs(x - y) < 1e-8 && fabs(x - z) < 1e-8)
  1259.       mat->flags |= MAT_FLAG_UNIFORM_SCALE;
  1260.    else
  1261.       mat->flags |= MAT_FLAG_GENERAL_SCALE;
  1262.  
  1263.    mat->flags |= (MAT_DIRTY_TYPE | 
  1264.           MAT_DIRTY_INVERSE | 
  1265.           MAT_DIRTY_DEPENDENTS);
  1266. }
  1267.  
  1268. /*
  1269.  * Execute a glTranslate call
  1270.  */
  1271. void gl_Translatef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
  1272. {
  1273.    GLmatrix *mat = 0;
  1274.    GLfloat *m;
  1275.    GET_ACTIVE_MATRIX(ctx, mat, ctx->NewState, "glTranslate");
  1276.    m = mat->m;
  1277.    m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
  1278.    m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
  1279.    m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
  1280.    m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
  1281.  
  1282.    mat->flags |= (MAT_FLAG_TRANSLATION | 
  1283.           MAT_DIRTY_TYPE | 
  1284.           MAT_DIRTY_INVERSE | 
  1285.           MAT_DIRTY_DEPENDENTS);
  1286. }
  1287.  
  1288.  
  1289. /*
  1290.  * Define a new viewport and reallocate auxillary buffers if the size of
  1291.  * the window (color buffer) has changed.
  1292.  */
  1293. void gl_Viewport( GLcontext *ctx,
  1294.                   GLint x, GLint y, GLsizei width, GLsizei height )
  1295. {
  1296.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glViewport");
  1297.  
  1298.    if (width<0 || height<0) {
  1299.       gl_error( ctx,  GL_INVALID_VALUE, "glViewport" );
  1300.       return;
  1301.    }
  1302.  
  1303.    if (MESA_VERBOSE & VERBOSE_API)
  1304.       fprintf(stderr, "glViewport %d %d %d %d\n", x, y, width, height);
  1305.    
  1306.    /* clamp width, and height to implementation dependent range */
  1307.    width  = CLAMP( width,  1, MAX_WIDTH );
  1308.    height = CLAMP( height, 1, MAX_HEIGHT );
  1309.  
  1310.    /* Save viewport */
  1311.    ctx->Viewport.X = x;
  1312.    ctx->Viewport.Width = width;
  1313.    ctx->Viewport.Y = y;
  1314.    ctx->Viewport.Height = height;
  1315.  
  1316.    /* compute scale and bias values */
  1317.    ctx->Viewport.WindowMap.m[MAT_SX] = (GLfloat) width / 2.0F;
  1318.    ctx->Viewport.WindowMap.m[MAT_TX] = ctx->Viewport.WindowMap.m[MAT_SX] + x;
  1319.    ctx->Viewport.WindowMap.m[MAT_SY] = (GLfloat) height / 2.0F;
  1320.    ctx->Viewport.WindowMap.m[MAT_TY] = ctx->Viewport.WindowMap.m[MAT_SY] + y;
  1321.    ctx->Viewport.WindowMap.m[MAT_SZ] = 0.5 * DEPTH_SCALE;
  1322.    ctx->Viewport.WindowMap.m[MAT_TZ] = 0.5 * DEPTH_SCALE;
  1323.  
  1324.    ctx->Viewport.WindowMap.flags = MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION;
  1325.    ctx->Viewport.WindowMap.type = MATRIX_3D_NO_ROT;
  1326.  
  1327.    ctx->ModelProjectWinMatrixUptodate = GL_FALSE;
  1328.    ctx->NewState |= NEW_VIEWPORT;
  1329.  
  1330.    /* Check if window/buffer has been resized and if so, reallocate the
  1331.     * ancillary buffers.
  1332.     */
  1333.    gl_ResizeBuffersMESA(ctx);
  1334.  
  1335.  
  1336.    ctx->RasterMask &= ~WINCLIP_BIT;
  1337.  
  1338.    if (   ctx->Viewport.X<0
  1339.        || ctx->Viewport.X + ctx->Viewport.Width > ctx->Buffer->Width
  1340.        || ctx->Viewport.Y<0
  1341.        || ctx->Viewport.Y + ctx->Viewport.Height > ctx->Buffer->Height) {
  1342.       ctx->RasterMask |= WINCLIP_BIT;
  1343.    }
  1344.  
  1345.  
  1346.    if (ctx->Driver.Viewport) {
  1347.       (*ctx->Driver.Viewport)( ctx, x, y, width, height );
  1348.    }
  1349. }
  1350.  
  1351.  
  1352.  
  1353. void gl_DepthRange( GLcontext *ctx, GLclampd nearval, GLclampd farval )
  1354. {
  1355.    /*
  1356.     * nearval - specifies mapping of the near clipping plane to window
  1357.     *   coordinates, default is 0
  1358.     * farval - specifies mapping of the far clipping plane to window
  1359.     *   coordinates, default is 1
  1360.     *
  1361.     * After clipping and div by w, z coords are in -1.0 to 1.0,
  1362.     * corresponding to near and far clipping planes.  glDepthRange
  1363.     * specifies a linear mapping of the normalized z coords in
  1364.     * this range to window z coords.
  1365.     */
  1366.    GLfloat n, f;
  1367.  
  1368.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDepthRange");
  1369.  
  1370.    if (MESA_VERBOSE&VERBOSE_API)
  1371.       fprintf(stderr, "glDepthRange %f %f\n", nearval, farval); 
  1372.  
  1373.    n = (GLfloat) CLAMP( nearval, 0.0, 1.0 );
  1374.    f = (GLfloat) CLAMP( farval, 0.0, 1.0 );
  1375.  
  1376.    ctx->Viewport.Near = n;
  1377.    ctx->Viewport.Far = f;
  1378.    ctx->Viewport.WindowMap.m[MAT_SZ] = DEPTH_SCALE * ((f - n) / 2.0);
  1379.    ctx->Viewport.WindowMap.m[MAT_TZ] = DEPTH_SCALE * ((f - n) / 2.0 + n);
  1380.  
  1381.    ctx->ModelProjectWinMatrixUptodate = GL_FALSE;
  1382.  
  1383.    if (ctx->Driver.DepthRange) {
  1384.       (*ctx->Driver.DepthRange)( ctx, nearval, farval );
  1385.    }
  1386. }
  1387.  
  1388.  
  1389. void gl_calculate_model_project_matrix( GLcontext *ctx )
  1390. {
  1391.    gl_matrix_mul( &ctx->ModelProjectMatrix,
  1392.           &ctx->ProjectionMatrix,
  1393.           &ctx->ModelView );
  1394.  
  1395.    gl_matrix_analyze( &ctx->ModelProjectMatrix );
  1396. }
  1397.  
  1398.  
  1399. void gl_matrix_ctr( GLmatrix *m )
  1400. {
  1401.    m->inv = 0;
  1402.    MEMCPY( m->m, Identity, sizeof(Identity));
  1403.    m->type = MATRIX_IDENTITY;
  1404.    m->flags = MAT_DIRTY_DEPENDENTS;
  1405. }
  1406.  
  1407. void gl_matrix_dtr( GLmatrix *m )
  1408. {
  1409.    if (m->inv != 0) {
  1410.       FREE(m->inv);
  1411.       m->inv = 0;
  1412.    }
  1413. }
  1414.  
  1415. void gl_matrix_set_identity( GLmatrix *m )
  1416. {
  1417.    MEMCPY( m->m, Identity, sizeof(Identity));
  1418.    m->type = MATRIX_IDENTITY;
  1419.    m->flags = MAT_DIRTY_DEPENDENTS;
  1420. }
  1421.  
  1422.  
  1423. void gl_matrix_alloc_inv( GLmatrix *m )
  1424. {
  1425.    if (m->inv == 0) {
  1426.       m->inv = (GLfloat *)MALLOC(16*sizeof(GLfloat));
  1427.       MEMCPY( m->inv, Identity, 16 * sizeof(GLfloat) );
  1428.    }
  1429. }
  1430.  
  1431. void gl_matrix_copy( GLmatrix *to, const GLmatrix *from )
  1432. {
  1433.    MEMCPY( to->m, from->m, sizeof(Identity));
  1434.    to->flags = from->flags | MAT_DIRTY_DEPENDENTS;
  1435.    to->type = from->type;
  1436.  
  1437.    if (to->inv != 0) {
  1438.       if (from->inv == 0) {
  1439.      gl_matrix_invert( to );
  1440.       } else {
  1441.      MEMCPY(to->inv, from->inv, sizeof(GLfloat)*16);
  1442.       }
  1443.    }
  1444. }
  1445.  
  1446. void gl_matrix_mul( GLmatrix *dest, const GLmatrix *a, const GLmatrix *b )
  1447. {
  1448.    dest->flags = (a->flags |
  1449.           b->flags |
  1450.           MAT_DIRTY_TYPE | 
  1451.           MAT_DIRTY_INVERSE | 
  1452.           MAT_DIRTY_DEPENDENTS);
  1453.  
  1454.    if (TEST_MAT_FLAGS(dest, MAT_FLAGS_3D))
  1455.       matmul34( dest->m, a->m, b->m );
  1456.    else 
  1457.       matmul4( dest->m, a->m, b->m );
  1458. }
  1459.