Home | History | Annotate | Download | only in test
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  6.3
      4  *
      5  * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 
     26 /**
     27  * \file m_matrix.c
     28  * Matrix operations.
     29  *
     30  * \note
     31  * -# 4x4 transformation matrices are stored in memory in column major order.
     32  * -# Points/vertices are to be thought of as column vectors.
     33  * -# Transformation of a point p by a matrix M is: p' = M * p
     34  */
     35 
     36 #include <GLES2/gl2.h>
     37 #include <stdio.h>
     38 #include <math.h>
     39 #include <assert.h>
     40 #include <string.h>
     41 
     42 #include "../src/mesa/main/macros.h"
     43 
     44 #include "m_matrix.h"
     45 
     46 #define _mesa_debug(...)
     47 /**
     48  * \defgroup MatFlags MAT_FLAG_XXX-flags
     49  *
     50  * Bitmasks to indicate different kinds of 4x4 matrices in GLmatrix::flags
     51  * It would be nice to make all these flags private to m_matrix.c
     52  */
     53 /*@{*/
     54 #define MAT_FLAG_IDENTITY       0     /**< is an identity matrix flag.
     55 *   (Not actually used - the identity
     56 *   matrix is identified by the absense
     57 *   of all other flags.)
     58 */
     59 #define MAT_FLAG_GENERAL        0x1   /**< is a general matrix flag */
     60 #define MAT_FLAG_ROTATION       0x2   /**< is a rotation matrix flag */
     61 #define MAT_FLAG_TRANSLATION    0x4   /**< is a translation matrix flag */
     62 #define MAT_FLAG_UNIFORM_SCALE  0x8   /**< is an uniform scaling matrix flag */
     63 #define MAT_FLAG_GENERAL_SCALE  0x10  /**< is a general scaling matrix flag */
     64 #define MAT_FLAG_GENERAL_3D     0x20  /**< general 3D matrix flag */
     65 #define MAT_FLAG_PERSPECTIVE    0x40  /**< is a perspective proj matrix flag */
     66 #define MAT_FLAG_SINGULAR       0x80  /**< is a singular matrix flag */
     67 #define MAT_DIRTY_TYPE          0x100  /**< matrix type is dirty */
     68 #define MAT_DIRTY_FLAGS         0x200  /**< matrix flags are dirty */
     69 #define MAT_DIRTY_INVERSE       0x400  /**< matrix inverse is dirty */
     70 
     71 /** angle preserving matrix flags mask */
     72 #define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \
     73 MAT_FLAG_TRANSLATION | \
     74 MAT_FLAG_UNIFORM_SCALE)
     75 
     76 /** geometry related matrix flags mask */
     77 #define MAT_FLAGS_GEOMETRY (MAT_FLAG_GENERAL | \
     78 MAT_FLAG_ROTATION | \
     79 MAT_FLAG_TRANSLATION | \
     80 MAT_FLAG_UNIFORM_SCALE | \
     81 MAT_FLAG_GENERAL_SCALE | \
     82 MAT_FLAG_GENERAL_3D | \
     83 MAT_FLAG_PERSPECTIVE | \
     84 MAT_FLAG_SINGULAR)
     85 
     86 /** length preserving matrix flags mask */
     87 #define MAT_FLAGS_LENGTH_PRESERVING (MAT_FLAG_ROTATION | \
     88 MAT_FLAG_TRANSLATION)
     89 
     90 
     91 /** 3D (non-perspective) matrix flags mask */
     92 #define MAT_FLAGS_3D (MAT_FLAG_ROTATION | \
     93 MAT_FLAG_TRANSLATION | \
     94 MAT_FLAG_UNIFORM_SCALE | \
     95 MAT_FLAG_GENERAL_SCALE | \
     96 MAT_FLAG_GENERAL_3D)
     97 
     98 /** dirty matrix flags mask */
     99 #define MAT_DIRTY          (MAT_DIRTY_TYPE | \
    100 MAT_DIRTY_FLAGS | \
    101 MAT_DIRTY_INVERSE)
    102 
    103 /*@}*/
    104 
    105 
    106 /**
    107  * Test geometry related matrix flags.
    108  *
    109  * \param mat a pointer to a GLmatrix structure.
    110  * \param a flags mask.
    111  *
    112  * \returns non-zero if all geometry related matrix flags are contained within
    113  * the mask, or zero otherwise.
    114  */
    115 #define TEST_MAT_FLAGS(mat, a)  \
    116 ((MAT_FLAGS_GEOMETRY & (~(a)) & ((mat)->flags) ) == 0)
    117 
    118 
    119 
    120 /**
    121  * Names of the corresponding GLmatrixtype values.
    122  */
    123 static const char *types[] = {
    124 "MATRIX_GENERAL",
    125 "MATRIX_IDENTITY",
    126 "MATRIX_3D_NO_ROT",
    127 "MATRIX_PERSPECTIVE",
    128 "MATRIX_2D",
    129 "MATRIX_2D_NO_ROT",
    130 "MATRIX_3D"
    131 };
    132 
    133 
    134 /**
    135  * Identity matrix.
    136  */
    137 static GLfloat Identity[16] = {
    138 1.0, 0.0, 0.0, 0.0,
    139 0.0, 1.0, 0.0, 0.0,
    140 0.0, 0.0, 1.0, 0.0,
    141 0.0, 0.0, 0.0, 1.0
    142 };
    143 
    144 
    145 
    146 /**********************************************************************/
    147 /** \name Matrix multiplication */
    148 /*@{*/
    149 
    150 #define A(row,col)  a[(col<<2)+row]
    151 #define B(row,col)  b[(col<<2)+row]
    152 #define P(row,col)  product[(col<<2)+row]
    153 
    154 /**
    155  * Perform a full 4x4 matrix multiplication.
    156  *
    157  * \param a matrix.
    158  * \param b matrix.
    159  * \param product will receive the product of \p a and \p b.
    160  *
    161  * \warning Is assumed that \p product != \p b. \p product == \p a is allowed.
    162  *
    163  * \note KW: 4*16 = 64 multiplications
    164  *
    165  * \author This \c matmul was contributed by Thomas Malik
    166  */
    167 static void matmul4( GLfloat *product, const GLfloat *a, const GLfloat *b )
    168 {
    169     assert(product != b);
    170     GLint i;
    171     for (i = 0; i < 4; i++) {
    172         const GLfloat ai0=A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
    173         P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
    174         P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
    175         P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
    176         P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
    177     }
    178 }
    179 
    180 /**
    181  * Multiply two matrices known to occupy only the top three rows, such
    182  * as typical model matrices, and orthogonal matrices.
    183  *
    184  * \param a matrix.
    185  * \param b matrix.
    186  * \param product will receive the product of \p a and \p b.
    187  */
    188 static void matmul34( GLfloat *product, const GLfloat *a, const GLfloat *b )
    189 {
    190     GLint i;
    191     for (i = 0; i < 3; i++) {
    192         const GLfloat ai0=A(i,0),  ai1=A(i,1),  ai2=A(i,2),  ai3=A(i,3);
    193         P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0);
    194         P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1);
    195         P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2);
    196         P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3;
    197     }
    198     P(3,0) = 0;
    199     P(3,1) = 0;
    200     P(3,2) = 0;
    201     P(3,3) = 1;
    202 }
    203 
    204 #undef A
    205 #undef B
    206 #undef P
    207 
    208 /**
    209  * Multiply a matrix by an array of floats with known properties.
    210  *
    211  * \param mat pointer to a GLmatrix structure containing the left multiplication
    212  * matrix, and that will receive the product result.
    213  * \param m right multiplication matrix array.
    214  * \param flags flags of the matrix \p m.
    215  *
    216  * Joins both flags and marks the type and inverse as dirty.  Calls matmul34()
    217  * if both matrices are 3D, or matmul4() otherwise.
    218  */
    219 static void matrix_multf( GLmatrix *mat, const GLfloat *m, GLuint flags )
    220 {
    221     mat->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
    222 
    223     if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D))
    224         matmul34( mat->m, mat->m, m );
    225     else
    226         matmul4( mat->m, mat->m, m );
    227 }
    228 
    229 /**
    230  * Matrix multiplication.
    231  *
    232  * \param dest destination matrix.
    233  * \param a left matrix.
    234  * \param b right matrix.
    235  *
    236  * Joins both flags and marks the type and inverse as dirty.  Calls matmul34()
    237  * if both matrices are 3D, or matmul4() otherwise.
    238  */
    239 void
    240 _math_matrix_mul_matrix( GLmatrix *dest, const GLmatrix *a, const GLmatrix *b )
    241 {
    242     dest->flags = (a->flags |
    243                    b->flags |
    244                    MAT_DIRTY_TYPE |
    245                    MAT_DIRTY_INVERSE);
    246 
    247     if (TEST_MAT_FLAGS(dest, MAT_FLAGS_3D))
    248         matmul34( dest->m, a->m, b->m );
    249     else
    250         matmul4( dest->m, a->m, b->m );
    251 }
    252 
    253 /**
    254  * Matrix multiplication.
    255  *
    256  * \param dest left and destination matrix.
    257  * \param m right matrix array.
    258  *
    259  * Marks the matrix flags with general flag, and type and inverse dirty flags.
    260  * Calls matmul4() for the multiplication.
    261  */
    262 void
    263 _math_matrix_mul_floats( GLmatrix *dest, const GLfloat *m )
    264 {
    265     dest->flags |= (MAT_FLAG_GENERAL |
    266                     MAT_DIRTY_TYPE |
    267                     MAT_DIRTY_INVERSE |
    268                     MAT_DIRTY_FLAGS);
    269 
    270     matmul4( dest->m, dest->m, m );
    271 }
    272 
    273 /*@}*/
    274 
    275 
    276 /**********************************************************************/
    277 /** \name Matrix output */
    278 /*@{*/
    279 
    280 /**
    281  * Print a matrix array.
    282  *
    283  * \param m matrix array.
    284  *
    285  * Called by _math_matrix_print() to print a matrix or its inverse.
    286  */
    287 static void print_matrix_floats( const GLfloat m[16] )
    288 {
    289     int i;
    290     for (i=0;i<4;i++) {
    291         _mesa_debug(NULL,"\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
    292     }
    293 }
    294 
    295 /**
    296  * Dumps the contents of a GLmatrix structure.
    297  *
    298  * \param m pointer to the GLmatrix structure.
    299  */
    300 void
    301 _math_matrix_print( const GLmatrix *m )
    302 {
    303     _mesa_debug(NULL, "Matrix type: %s, flags: %x\n", types[m->type], m->flags);
    304     print_matrix_floats(m->m);
    305     _mesa_debug(NULL, "Inverse: \n");
    306     if (m->inv) {
    307         GLfloat prod[16];
    308         print_matrix_floats(m->inv);
    309         matmul4(prod, m->m, m->inv);
    310         _mesa_debug(NULL, "Mat * Inverse:\n");
    311         print_matrix_floats(prod);
    312     }
    313     else {
    314         _mesa_debug(NULL, "  - not available\n");
    315     }
    316 }
    317 
    318 /*@}*/
    319 
    320 
    321 /**
    322  * References an element of 4x4 matrix.
    323  *
    324  * \param m matrix array.
    325  * \param c column of the desired element.
    326  * \param r row of the desired element.
    327  *
    328  * \return value of the desired element.
    329  *
    330  * Calculate the linear storage index of the element and references it.
    331  */
    332 #define MAT(m,r,c) (m)[(c)*4+(r)]
    333 
    334 
    335 /**********************************************************************/
    336 /** \name Matrix inversion */
    337 /*@{*/
    338 
    339 /**
    340  * Swaps the values of two floating pointer variables.
    341  *
    342  * Used by invert_matrix_general() to swap the row pointers.
    343  */
    344 #define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
    345 
    346 /**
    347  * Compute inverse of 4x4 transformation matrix.
    348  *
    349  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    350  * stored in the GLmatrix::inv attribute.
    351  *
    352  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    353  *
    354  * \author
    355  * Code contributed by Jacques Leroy jle (at) star.be
    356  *
    357  * Calculates the inverse matrix by performing the gaussian matrix reduction
    358  * with partial pivoting followed by back/substitution with the loops manually
    359  * unrolled.
    360  */
    361 static GLboolean invert_matrix_general( GLmatrix *mat )
    362 {
    363     const GLfloat *m = mat->m;
    364     GLfloat *out = mat->inv;
    365     GLfloat wtmp[4][8];
    366     GLfloat m0, m1, m2, m3, s;
    367     GLfloat *r0, *r1, *r2, *r3;
    368 
    369     r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
    370 
    371     r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
    372     r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
    373     r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
    374 
    375     r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
    376     r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
    377     r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
    378 
    379     r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
    380     r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
    381     r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
    382 
    383     r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
    384     r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
    385     r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
    386 
    387     /* choose pivot - or die */
    388     if (FABSF(r3[0])>FABSF(r2[0])) SWAP_ROWS(r3, r2);
    389     if (FABSF(r2[0])>FABSF(r1[0])) SWAP_ROWS(r2, r1);
    390     if (FABSF(r1[0])>FABSF(r0[0])) SWAP_ROWS(r1, r0);
    391     if (0.0 == r0[0])  return GL_FALSE;
    392 
    393     /* eliminate first variable     */
    394     m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
    395     s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
    396     s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
    397     s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
    398     s = r0[4];
    399     if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
    400     s = r0[5];
    401     if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
    402     s = r0[6];
    403     if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
    404     s = r0[7];
    405     if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
    406 
    407     /* choose pivot - or die */
    408     if (FABSF(r3[1])>FABSF(r2[1])) SWAP_ROWS(r3, r2);
    409     if (FABSF(r2[1])>FABSF(r1[1])) SWAP_ROWS(r2, r1);
    410     if (0.0 == r1[1])  return GL_FALSE;
    411 
    412     /* eliminate second variable */
    413     m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
    414     r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
    415     r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
    416     s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
    417     s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
    418     s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
    419     s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
    420 
    421     /* choose pivot - or die */
    422     if (FABSF(r3[2])>FABSF(r2[2])) SWAP_ROWS(r3, r2);
    423     if (0.0 == r2[2])  return GL_FALSE;
    424 
    425     /* eliminate third variable */
    426     m3 = r3[2]/r2[2];
    427     r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
    428     r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
    429     r3[7] -= m3 * r2[7];
    430 
    431     /* last check */
    432     if (0.0 == r3[3]) return GL_FALSE;
    433 
    434     s = 1.0F/r3[3];             /* now back substitute row 3 */
    435     r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
    436 
    437     m2 = r2[3];                 /* now back substitute row 2 */
    438     s  = 1.0F/r2[2];
    439     r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
    440     r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
    441     m1 = r1[3];
    442     r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
    443     r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
    444     m0 = r0[3];
    445     r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
    446     r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
    447 
    448     m1 = r1[2];                 /* now back substitute row 1 */
    449     s  = 1.0F/r1[1];
    450     r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
    451     r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
    452     m0 = r0[2];
    453     r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
    454     r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
    455 
    456     m0 = r0[1];                 /* now back substitute row 0 */
    457     s  = 1.0F/r0[0];
    458     r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
    459     r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
    460 
    461     MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
    462     MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
    463     MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
    464     MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
    465     MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
    466     MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
    467     MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
    468     MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
    469 
    470     return GL_TRUE;
    471 }
    472 #undef SWAP_ROWS
    473 
    474 /**
    475  * Compute inverse of a general 3d transformation matrix.
    476  *
    477  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    478  * stored in the GLmatrix::inv attribute.
    479  *
    480  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    481  *
    482  * \author Adapted from graphics gems II.
    483  *
    484  * Calculates the inverse of the upper left by first calculating its
    485  * determinant and multiplying it to the symmetric adjust matrix of each
    486  * element. Finally deals with the translation part by transforming the
    487  * original translation vector using by the calculated submatrix inverse.
    488  */
    489 static GLboolean invert_matrix_3d_general( GLmatrix *mat )
    490 {
    491     const GLfloat *in = mat->m;
    492     GLfloat *out = mat->inv;
    493     GLfloat pos, neg, t;
    494     GLfloat det;
    495 
    496     /* Calculate the determinant of upper left 3x3 submatrix and
    497      * determine if the matrix is singular.
    498      */
    499     pos = neg = 0.0;
    500     t =  MAT(in,0,0) * MAT(in,1,1) * MAT(in,2,2);
    501     if (t >= 0.0) pos += t; else neg += t;
    502 
    503     t =  MAT(in,1,0) * MAT(in,2,1) * MAT(in,0,2);
    504     if (t >= 0.0) pos += t; else neg += t;
    505 
    506     t =  MAT(in,2,0) * MAT(in,0,1) * MAT(in,1,2);
    507     if (t >= 0.0) pos += t; else neg += t;
    508 
    509     t = -MAT(in,2,0) * MAT(in,1,1) * MAT(in,0,2);
    510     if (t >= 0.0) pos += t; else neg += t;
    511 
    512     t = -MAT(in,1,0) * MAT(in,0,1) * MAT(in,2,2);
    513     if (t >= 0.0) pos += t; else neg += t;
    514 
    515     t = -MAT(in,0,0) * MAT(in,2,1) * MAT(in,1,2);
    516     if (t >= 0.0) pos += t; else neg += t;
    517 
    518     det = pos + neg;
    519 
    520     if (det*det < 1e-25)
    521         return GL_FALSE;
    522 
    523     det = 1.0F / det;
    524     MAT(out,0,0) = (  (MAT(in,1,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,1,2) )*det);
    525     MAT(out,0,1) = (- (MAT(in,0,1)*MAT(in,2,2) - MAT(in,2,1)*MAT(in,0,2) )*det);
    526     MAT(out,0,2) = (  (MAT(in,0,1)*MAT(in,1,2) - MAT(in,1,1)*MAT(in,0,2) )*det);
    527     MAT(out,1,0) = (- (MAT(in,1,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,1,2) )*det);
    528     MAT(out,1,1) = (  (MAT(in,0,0)*MAT(in,2,2) - MAT(in,2,0)*MAT(in,0,2) )*det);
    529     MAT(out,1,2) = (- (MAT(in,0,0)*MAT(in,1,2) - MAT(in,1,0)*MAT(in,0,2) )*det);
    530     MAT(out,2,0) = (  (MAT(in,1,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,1,1) )*det);
    531     MAT(out,2,1) = (- (MAT(in,0,0)*MAT(in,2,1) - MAT(in,2,0)*MAT(in,0,1) )*det);
    532     MAT(out,2,2) = (  (MAT(in,0,0)*MAT(in,1,1) - MAT(in,1,0)*MAT(in,0,1) )*det);
    533 
    534     /* Do the translation part */
    535     MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
    536                       MAT(in,1,3) * MAT(out,0,1) +
    537                       MAT(in,2,3) * MAT(out,0,2) );
    538     MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
    539                       MAT(in,1,3) * MAT(out,1,1) +
    540                       MAT(in,2,3) * MAT(out,1,2) );
    541     MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
    542                       MAT(in,1,3) * MAT(out,2,1) +
    543                       MAT(in,2,3) * MAT(out,2,2) );
    544 
    545     return GL_TRUE;
    546 }
    547 
    548 /**
    549  * Compute inverse of a 3d transformation matrix.
    550  *
    551  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    552  * stored in the GLmatrix::inv attribute.
    553  *
    554  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    555  *
    556  * If the matrix is not an angle preserving matrix then calls
    557  * invert_matrix_3d_general for the actual calculation. Otherwise calculates
    558  * the inverse matrix analyzing and inverting each of the scaling, rotation and
    559  * translation parts.
    560  */
    561 static GLboolean invert_matrix_3d( GLmatrix *mat )
    562 {
    563     const GLfloat *in = mat->m;
    564     GLfloat *out = mat->inv;
    565 
    566     if (!TEST_MAT_FLAGS(mat, MAT_FLAGS_ANGLE_PRESERVING)) {
    567         return invert_matrix_3d_general( mat );
    568     }
    569 
    570     if (mat->flags & MAT_FLAG_UNIFORM_SCALE) {
    571         GLfloat scale = (MAT(in,0,0) * MAT(in,0,0) +
    572                          MAT(in,0,1) * MAT(in,0,1) +
    573                          MAT(in,0,2) * MAT(in,0,2));
    574 
    575         if (scale == 0.0)
    576             return GL_FALSE;
    577 
    578         scale = 1.0F / scale;
    579 
    580         /* Transpose and scale the 3 by 3 upper-left submatrix. */
    581         MAT(out,0,0) = scale * MAT(in,0,0);
    582         MAT(out,1,0) = scale * MAT(in,0,1);
    583         MAT(out,2,0) = scale * MAT(in,0,2);
    584         MAT(out,0,1) = scale * MAT(in,1,0);
    585         MAT(out,1,1) = scale * MAT(in,1,1);
    586         MAT(out,2,1) = scale * MAT(in,1,2);
    587         MAT(out,0,2) = scale * MAT(in,2,0);
    588         MAT(out,1,2) = scale * MAT(in,2,1);
    589         MAT(out,2,2) = scale * MAT(in,2,2);
    590     }
    591     else if (mat->flags & MAT_FLAG_ROTATION) {
    592         /* Transpose the 3 by 3 upper-left submatrix. */
    593         MAT(out,0,0) = MAT(in,0,0);
    594         MAT(out,1,0) = MAT(in,0,1);
    595         MAT(out,2,0) = MAT(in,0,2);
    596         MAT(out,0,1) = MAT(in,1,0);
    597         MAT(out,1,1) = MAT(in,1,1);
    598         MAT(out,2,1) = MAT(in,1,2);
    599         MAT(out,0,2) = MAT(in,2,0);
    600         MAT(out,1,2) = MAT(in,2,1);
    601         MAT(out,2,2) = MAT(in,2,2);
    602     }
    603     else {
    604         /* pure translation */
    605         memcpy( out, Identity, sizeof(Identity) );
    606         MAT(out,0,3) = - MAT(in,0,3);
    607         MAT(out,1,3) = - MAT(in,1,3);
    608         MAT(out,2,3) = - MAT(in,2,3);
    609         return GL_TRUE;
    610     }
    611 
    612     if (mat->flags & MAT_FLAG_TRANSLATION) {
    613         /* Do the translation part */
    614         MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0) +
    615                           MAT(in,1,3) * MAT(out,0,1) +
    616                           MAT(in,2,3) * MAT(out,0,2) );
    617         MAT(out,1,3) = - (MAT(in,0,3) * MAT(out,1,0) +
    618                           MAT(in,1,3) * MAT(out,1,1) +
    619                           MAT(in,2,3) * MAT(out,1,2) );
    620         MAT(out,2,3) = - (MAT(in,0,3) * MAT(out,2,0) +
    621                           MAT(in,1,3) * MAT(out,2,1) +
    622                           MAT(in,2,3) * MAT(out,2,2) );
    623     }
    624     else {
    625         MAT(out,0,3) = MAT(out,1,3) = MAT(out,2,3) = 0.0;
    626     }
    627 
    628     return GL_TRUE;
    629 }
    630 
    631 /**
    632  * Compute inverse of an identity transformation matrix.
    633  *
    634  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    635  * stored in the GLmatrix::inv attribute.
    636  *
    637  * \return always GL_TRUE.
    638  *
    639  * Simply copies Identity into GLmatrix::inv.
    640  */
    641 static GLboolean invert_matrix_identity( GLmatrix *mat )
    642 {
    643     memcpy( mat->inv, Identity, sizeof(Identity) );
    644     return GL_TRUE;
    645 }
    646 
    647 /**
    648  * Compute inverse of a no-rotation 3d transformation matrix.
    649  *
    650  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    651  * stored in the GLmatrix::inv attribute.
    652  *
    653  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    654  *
    655  * Calculates the
    656  */
    657 static GLboolean invert_matrix_3d_no_rot( GLmatrix *mat )
    658 {
    659     const GLfloat *in = mat->m;
    660     GLfloat *out = mat->inv;
    661 
    662     if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0 || MAT(in,2,2) == 0 )
    663         return GL_FALSE;
    664 
    665     memcpy( out, Identity, 16 * sizeof(GLfloat) );
    666     MAT(out,0,0) = 1.0F / MAT(in,0,0);
    667     MAT(out,1,1) = 1.0F / MAT(in,1,1);
    668     MAT(out,2,2) = 1.0F / MAT(in,2,2);
    669 
    670     if (mat->flags & MAT_FLAG_TRANSLATION) {
    671         MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
    672         MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
    673         MAT(out,2,3) = - (MAT(in,2,3) * MAT(out,2,2));
    674     }
    675 
    676     return GL_TRUE;
    677 }
    678 
    679 /**
    680  * Compute inverse of a no-rotation 2d transformation matrix.
    681  *
    682  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    683  * stored in the GLmatrix::inv attribute.
    684  *
    685  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    686  *
    687  * Calculates the inverse matrix by applying the inverse scaling and
    688  * translation to the identity matrix.
    689  */
    690 static GLboolean invert_matrix_2d_no_rot( GLmatrix *mat )
    691 {
    692     const GLfloat *in = mat->m;
    693     GLfloat *out = mat->inv;
    694 
    695     if (MAT(in,0,0) == 0 || MAT(in,1,1) == 0)
    696         return GL_FALSE;
    697 
    698     memcpy( out, Identity, 16 * sizeof(GLfloat) );
    699     MAT(out,0,0) = 1.0F / MAT(in,0,0);
    700     MAT(out,1,1) = 1.0F / MAT(in,1,1);
    701 
    702     if (mat->flags & MAT_FLAG_TRANSLATION) {
    703         MAT(out,0,3) = - (MAT(in,0,3) * MAT(out,0,0));
    704         MAT(out,1,3) = - (MAT(in,1,3) * MAT(out,1,1));
    705     }
    706 
    707     return GL_TRUE;
    708 }
    709 
    710 #if 0
    711 /* broken */
    712 static GLboolean invert_matrix_perspective( GLmatrix *mat )
    713 {
    714     const GLfloat *in = mat->m;
    715     GLfloat *out = mat->inv;
    716 
    717     if (MAT(in,2,3) == 0)
    718         return GL_FALSE;
    719 
    720     memcpy( out, Identity, 16 * sizeof(GLfloat) );
    721 
    722     MAT(out,0,0) = 1.0F / MAT(in,0,0);
    723     MAT(out,1,1) = 1.0F / MAT(in,1,1);
    724 
    725     MAT(out,0,3) = MAT(in,0,2);
    726     MAT(out,1,3) = MAT(in,1,2);
    727 
    728     MAT(out,2,2) = 0;
    729     MAT(out,2,3) = -1;
    730 
    731     MAT(out,3,2) = 1.0F / MAT(in,2,3);
    732     MAT(out,3,3) = MAT(in,2,2) * MAT(out,3,2);
    733 
    734     return GL_TRUE;
    735 }
    736 #endif
    737 
    738 /**
    739  * Matrix inversion function pointer type.
    740  */
    741 typedef GLboolean (*inv_mat_func)( GLmatrix *mat );
    742 
    743 /**
    744  * Table of the matrix inversion functions according to the matrix type.
    745  */
    746 static inv_mat_func inv_mat_tab[7] = {
    747 invert_matrix_general,
    748 invert_matrix_identity,
    749 invert_matrix_3d_no_rot,
    750 #if 0
    751 /* Don't use this function for now - it fails when the projection matrix
    752  * is premultiplied by a translation (ala Chromium's tilesort SPU).
    753  */
    754 invert_matrix_perspective,
    755 #else
    756 invert_matrix_general,
    757 #endif
    758 invert_matrix_3d,		/* lazy! */
    759 invert_matrix_2d_no_rot,
    760 invert_matrix_3d
    761 };
    762 
    763 /**
    764  * Compute inverse of a transformation matrix.
    765  *
    766  * \param mat pointer to a GLmatrix structure. The matrix inverse will be
    767  * stored in the GLmatrix::inv attribute.
    768  *
    769  * \return GL_TRUE for success, GL_FALSE for failure (\p singular matrix).
    770  *
    771  * Calls the matrix inversion function in inv_mat_tab corresponding to the
    772  * given matrix type.  In case of failure, updates the MAT_FLAG_SINGULAR flag,
    773  * and copies the identity matrix into GLmatrix::inv.
    774  */
    775 static GLboolean matrix_invert( GLmatrix *mat )
    776 {
    777     if (inv_mat_tab[mat->type](mat)) {
    778         mat->flags &= ~MAT_FLAG_SINGULAR;
    779         return GL_TRUE;
    780     } else {
    781         mat->flags |= MAT_FLAG_SINGULAR;
    782         memcpy( mat->inv, Identity, sizeof(Identity) );
    783         return GL_FALSE;
    784     }
    785 }
    786 
    787 /*@}*/
    788 
    789 
    790 /**********************************************************************/
    791 /** \name Matrix generation */
    792 /*@{*/
    793 
    794 /**
    795  * Generate a 4x4 transformation matrix from glRotate parameters, and
    796  * post-multiply the input matrix by it.
    797  *
    798  * \author
    799  * This function was contributed by Erich Boleyn (erich (at) uruk.org).
    800  * Optimizations contributed by Rudolf Opalla (rudi (at) khm.de).
    801  */
    802 void
    803 _math_matrix_rotate( GLmatrix *mat,
    804                     GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
    805 {
    806     GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
    807     GLfloat m[16];
    808     GLboolean optimized;
    809 
    810     s = (GLfloat) sinf( angle * (M_PI / 180.0f) );
    811     c = (GLfloat) cosf( angle * (M_PI / 180.0f) );
    812 
    813     memcpy(m, Identity, sizeof(GLfloat)*16);
    814     optimized = GL_FALSE;
    815 
    816 #define M(row,col)  m[col*4+row]
    817 
    818     if (x == 0.0F) {
    819         if (y == 0.0F) {
    820             if (z != 0.0F) {
    821                 optimized = GL_TRUE;
    822                 /* rotate only around z-axis */
    823                 M(0,0) = c;
    824                 M(1,1) = c;
    825                 if (z < 0.0F) {
    826                     M(0,1) = s;
    827                     M(1,0) = -s;
    828                 }
    829                 else {
    830                     M(0,1) = -s;
    831                     M(1,0) = s;
    832                 }
    833             }
    834         }
    835         else if (z == 0.0F) {
    836             optimized = GL_TRUE;
    837             /* rotate only around y-axis */
    838             M(0,0) = c;
    839             M(2,2) = c;
    840             if (y < 0.0F) {
    841                 M(0,2) = -s;
    842                 M(2,0) = s;
    843             }
    844             else {
    845                 M(0,2) = s;
    846                 M(2,0) = -s;
    847             }
    848         }
    849     }
    850     else if (y == 0.0F) {
    851         if (z == 0.0F) {
    852             optimized = GL_TRUE;
    853             /* rotate only around x-axis */
    854             M(1,1) = c;
    855             M(2,2) = c;
    856             if (x < 0.0F) {
    857                 M(1,2) = s;
    858                 M(2,1) = -s;
    859             }
    860             else {
    861                 M(1,2) = -s;
    862                 M(2,1) = s;
    863             }
    864         }
    865     }
    866 
    867     if (!optimized) {
    868         const GLfloat mag = SQRTF(x * x + y * y + z * z);
    869 
    870         if (mag <= 1.0e-4) {
    871             /* no rotation, leave mat as-is */
    872             return;
    873         }
    874 
    875         x /= mag;
    876         y /= mag;
    877         z /= mag;
    878 
    879 
    880         /*
    881          *     Arbitrary axis rotation matrix.
    882          *
    883          *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
    884          *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
    885          *  (which is about the X-axis), and the two composite transforms
    886          *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
    887          *  from the arbitrary axis to the X-axis then back.  They are
    888          *  all elementary rotations.
    889          *
    890          *  Rz' is a rotation about the Z-axis, to bring the axis vector
    891          *  into the x-z plane.  Then Ry' is applied, rotating about the
    892          *  Y-axis to bring the axis vector parallel with the X-axis.  The
    893          *  rotation about the X-axis is then performed.  Ry and Rz are
    894          *  simply the respective inverse transforms to bring the arbitrary
    895          *  axis back to it's original orientation.  The first transforms
    896          *  Rz' and Ry' are considered inverses, since the data from the
    897          *  arbitrary axis gives you info on how to get to it, not how
    898          *  to get away from it, and an inverse must be applied.
    899          *
    900          *  The basic calculation used is to recognize that the arbitrary
    901          *  axis vector (x, y, z), since it is of unit length, actually
    902          *  represents the sines and cosines of the angles to rotate the
    903          *  X-axis to the same orientation, with theta being the angle about
    904          *  Z and phi the angle about Y (in the order described above)
    905          *  as follows:
    906          *
    907          *  cos ( theta ) = x / sqrt ( 1 - z^2 )
    908          *  sin ( theta ) = y / sqrt ( 1 - z^2 )
    909          *
    910          *  cos ( phi ) = sqrt ( 1 - z^2 )
    911          *  sin ( phi ) = z
    912          *
    913          *  Note that cos ( phi ) can further be inserted to the above
    914          *  formulas:
    915          *
    916          *  cos ( theta ) = x / cos ( phi )
    917          *  sin ( theta ) = y / sin ( phi )
    918          *
    919          *  ...etc.  Because of those relations and the standard trigonometric
    920          *  relations, it is pssible to reduce the transforms down to what
    921          *  is used below.  It may be that any primary axis chosen will give the
    922          *  same results (modulo a sign convention) using thie method.
    923          *
    924          *  Particularly nice is to notice that all divisions that might
    925          *  have caused trouble when parallel to certain planes or
    926          *  axis go away with care paid to reducing the expressions.
    927          *  After checking, it does perform correctly under all cases, since
    928          *  in all the cases of division where the denominator would have
    929          *  been zero, the numerator would have been zero as well, giving
    930          *  the expected result.
    931          */
    932 
    933         xx = x * x;
    934         yy = y * y;
    935         zz = z * z;
    936         xy = x * y;
    937         yz = y * z;
    938         zx = z * x;
    939         xs = x * s;
    940         ys = y * s;
    941         zs = z * s;
    942         one_c = 1.0F - c;
    943 
    944         /* We already hold the identity-matrix so we can skip some statements */
    945         M(0,0) = (one_c * xx) + c;
    946         M(0,1) = (one_c * xy) - zs;
    947         M(0,2) = (one_c * zx) + ys;
    948         /*    M(0,3) = 0.0F; */
    949 
    950         M(1,0) = (one_c * xy) + zs;
    951         M(1,1) = (one_c * yy) + c;
    952         M(1,2) = (one_c * yz) - xs;
    953         /*    M(1,3) = 0.0F; */
    954 
    955         M(2,0) = (one_c * zx) - ys;
    956         M(2,1) = (one_c * yz) + xs;
    957         M(2,2) = (one_c * zz) + c;
    958         /*    M(2,3) = 0.0F; */
    959 
    960         /*
    961          M(3,0) = 0.0F;
    962          M(3,1) = 0.0F;
    963          M(3,2) = 0.0F;
    964          M(3,3) = 1.0F;
    965          */
    966     }
    967 #undef M
    968 
    969     matrix_multf( mat, m, MAT_FLAG_ROTATION );
    970 }
    971 
    972 /**
    973  * Apply a perspective projection matrix.
    974  *
    975  * \param mat matrix to apply the projection.
    976  * \param left left clipping plane coordinate.
    977  * \param right right clipping plane coordinate.
    978  * \param bottom bottom clipping plane coordinate.
    979  * \param top top clipping plane coordinate.
    980  * \param nearval distance to the near clipping plane.
    981  * \param farval distance to the far clipping plane.
    982  *
    983  * Creates the projection matrix and multiplies it with \p mat, marking the
    984  * MAT_FLAG_PERSPECTIVE flag.
    985  */
    986 void
    987 _math_matrix_frustum( GLmatrix *mat,
    988                      GLfloat left, GLfloat right,
    989                      GLfloat bottom, GLfloat top,
    990                      GLfloat nearval, GLfloat farval )
    991 {
    992     GLfloat x, y, a, b, c, d;
    993     GLfloat m[16];
    994 
    995     x = (2.0F*nearval) / (right-left);
    996     y = (2.0F*nearval) / (top-bottom);
    997     a = (right+left) / (right-left);
    998     b = (top+bottom) / (top-bottom);
    999     c = -(farval+nearval) / ( farval-nearval);
   1000     d = -(2.0F*farval*nearval) / (farval-nearval);  /* error? */
   1001 
   1002     if (0)
   1003     {
   1004         c /= farval; // linearize z in vs by gl_Position.z *= gl_Position.w
   1005         d /= farval;
   1006     }
   1007 
   1008 #define M(row,col)  m[col*4+row]
   1009     M(0,0) = x;     M(0,1) = 0.0F;  M(0,2) = a;      M(0,3) = 0.0F;
   1010     M(1,0) = 0.0F;  M(1,1) = y;     M(1,2) = b;      M(1,3) = 0.0F;
   1011     M(2,0) = 0.0F;  M(2,1) = 0.0F;  M(2,2) = c;      M(2,3) = d;
   1012     M(3,0) = 0.0F;  M(3,1) = 0.0F;  M(3,2) = -1.0F;  M(3,3) = 0.0F;
   1013 #undef M
   1014 
   1015     matrix_multf( mat, m, MAT_FLAG_PERSPECTIVE );
   1016 }
   1017 
   1018 /**
   1019  * Apply an orthographic projection matrix.
   1020  *
   1021  * \param mat matrix to apply the projection.
   1022  * \param left left clipping plane coordinate.
   1023  * \param right right clipping plane coordinate.
   1024  * \param bottom bottom clipping plane coordinate.
   1025  * \param top top clipping plane coordinate.
   1026  * \param nearval distance to the near clipping plane.
   1027  * \param farval distance to the far clipping plane.
   1028  *
   1029  * Creates the projection matrix and multiplies it with \p mat, marking the
   1030  * MAT_FLAG_GENERAL_SCALE and MAT_FLAG_TRANSLATION flags.
   1031  */
   1032 void
   1033 _math_matrix_ortho( GLmatrix *mat,
   1034                    GLfloat left, GLfloat right,
   1035                    GLfloat bottom, GLfloat top,
   1036                    GLfloat nearval, GLfloat farval )
   1037 {
   1038     GLfloat m[16];
   1039 
   1040 #define M(row,col)  m[col*4+row]
   1041     M(0,0) = 2.0F / (right-left);
   1042     M(0,1) = 0.0F;
   1043     M(0,2) = 0.0F;
   1044     M(0,3) = -(right+left) / (right-left);
   1045 
   1046     M(1,0) = 0.0F;
   1047     M(1,1) = 2.0F / (top-bottom);
   1048     M(1,2) = 0.0F;
   1049     M(1,3) = -(top+bottom) / (top-bottom);
   1050 
   1051     M(2,0) = 0.0F;
   1052     M(2,1) = 0.0F;
   1053     M(2,2) = -2.0F / (farval-nearval);
   1054     M(2,3) = -(farval+nearval) / (farval-nearval);
   1055 
   1056     M(3,0) = 0.0F;
   1057     M(3,1) = 0.0F;
   1058     M(3,2) = 0.0F;
   1059     M(3,3) = 1.0F;
   1060 #undef M
   1061 
   1062     matrix_multf( mat, m, (MAT_FLAG_GENERAL_SCALE|MAT_FLAG_TRANSLATION));
   1063 }
   1064 
   1065 // multiplies mat by a perspective transform matrix
   1066 void _math_matrix_perspective(GLmatrix * mat, GLfloat fovy, GLfloat aspect,
   1067                               GLfloat zNear, GLfloat zFar)
   1068 {
   1069     GLfloat xmin, xmax, ymin, ymax;
   1070 
   1071     ymax = zNear * tan(fovy * M_PI / 360.0);
   1072     ymin = -ymax;
   1073     xmin = ymin * aspect;
   1074     xmax = ymax * aspect;
   1075 
   1076     _math_matrix_frustum(mat, xmin, xmax, ymin, ymax, zNear, zFar);
   1077 }
   1078 
   1079 // multiplies mat by a look at matrix
   1080 void _math_matrix_lookat(GLmatrix * mat, GLfloat eyex, GLfloat eyey, GLfloat eyez,
   1081           GLfloat centerx, GLfloat centery, GLfloat centerz,
   1082           GLfloat upx, GLfloat upy, GLfloat upz)
   1083 {
   1084     GLfloat m[16];
   1085     GLfloat x[3], y[3], z[3];
   1086     GLfloat mag;
   1087 
   1088     /* Make rotation matrix */
   1089 
   1090     /* Z vector */
   1091     z[0] = eyex - centerx;
   1092     z[1] = eyey - centery;
   1093     z[2] = eyez - centerz;
   1094     mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
   1095     if (mag) {			/* mpichler, 19950515 */
   1096         z[0] /= mag;
   1097         z[1] /= mag;
   1098         z[2] /= mag;
   1099     }
   1100 
   1101     /* Y vector */
   1102     y[0] = upx;
   1103     y[1] = upy;
   1104     y[2] = upz;
   1105 
   1106     /* X vector = Y cross Z */
   1107     x[0] = y[1] * z[2] - y[2] * z[1];
   1108     x[1] = -y[0] * z[2] + y[2] * z[0];
   1109     x[2] = y[0] * z[1] - y[1] * z[0];
   1110 
   1111     /* Recompute Y = Z cross X */
   1112     y[0] = z[1] * x[2] - z[2] * x[1];
   1113     y[1] = -z[0] * x[2] + z[2] * x[0];
   1114     y[2] = z[0] * x[1] - z[1] * x[0];
   1115 
   1116     /* mpichler, 19950515 */
   1117     /* cross product gives area of parallelogram, which is < 1.0 for
   1118      * non-perpendicular unit-length vectors; so normalize x, y here
   1119      */
   1120 
   1121     mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
   1122     if (mag) {
   1123         x[0] /= mag;
   1124         x[1] /= mag;
   1125         x[2] /= mag;
   1126     }
   1127 
   1128     mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
   1129     if (mag) {
   1130         y[0] /= mag;
   1131         y[1] /= mag;
   1132         y[2] /= mag;
   1133     }
   1134 
   1135 #define M(row,col)  m[col*4+row]
   1136     M(0, 0) = x[0];
   1137     M(0, 1) = x[1];
   1138     M(0, 2) = x[2];
   1139     M(0, 3) = 0.0;
   1140     M(1, 0) = y[0];
   1141     M(1, 1) = y[1];
   1142     M(1, 2) = y[2];
   1143     M(1, 3) = 0.0;
   1144     M(2, 0) = z[0];
   1145     M(2, 1) = z[1];
   1146     M(2, 2) = z[2];
   1147     M(2, 3) = 0.0;
   1148     M(3, 0) = 0.0;
   1149     M(3, 1) = 0.0;
   1150     M(3, 2) = 0.0;
   1151     M(3, 3) = 1.0;
   1152 #undef M
   1153 
   1154     GLfloat translate[16] =
   1155     {
   1156         1, 0, 0, 0,
   1157         0, 1, 0, 0,
   1158         0, 0, 1, 0,
   1159         -eyex, -eyey, -eyez, 1,
   1160     };
   1161 
   1162     _math_matrix_mul_floats(mat, m);
   1163 
   1164     _math_matrix_mul_floats(mat, translate);
   1165 
   1166     /* Translate Eye to Origin */
   1167    // glTranslated(-eyex, -eyey, -eyez);
   1168 
   1169 }
   1170 
   1171 /**
   1172  * Multiply a matrix with a general scaling matrix.
   1173  *
   1174  * \param mat matrix.
   1175  * \param x x axis scale factor.
   1176  * \param y y axis scale factor.
   1177  * \param z z axis scale factor.
   1178  *
   1179  * Multiplies in-place the elements of \p mat by the scale factors. Checks if
   1180  * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE
   1181  * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and
   1182  * MAT_DIRTY_INVERSE dirty flags.
   1183  */
   1184 void
   1185 _math_matrix_scale( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
   1186 {
   1187     GLfloat *m = mat->m;
   1188     m[0] *= x;   m[4] *= y;   m[8]  *= z;
   1189     m[1] *= x;   m[5] *= y;   m[9]  *= z;
   1190     m[2] *= x;   m[6] *= y;   m[10] *= z;
   1191     m[3] *= x;   m[7] *= y;   m[11] *= z;
   1192 
   1193     if (FABSF(x - y) < 1e-8 && FABSF(x - z) < 1e-8)
   1194         mat->flags |= MAT_FLAG_UNIFORM_SCALE;
   1195     else
   1196         mat->flags |= MAT_FLAG_GENERAL_SCALE;
   1197 
   1198     mat->flags |= (MAT_DIRTY_TYPE |
   1199                    MAT_DIRTY_INVERSE);
   1200 }
   1201 
   1202 /**
   1203  * Multiply a matrix with a translation matrix.
   1204  *
   1205  * \param mat matrix.
   1206  * \param x translation vector x coordinate.
   1207  * \param y translation vector y coordinate.
   1208  * \param z translation vector z coordinate.
   1209  *
   1210  * Adds the translation coordinates to the elements of \p mat in-place.  Marks
   1211  * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE
   1212  * dirty flags.
   1213  */
   1214 void
   1215 _math_matrix_translate( GLmatrix *mat, GLfloat x, GLfloat y, GLfloat z )
   1216 {
   1217     GLfloat *m = mat->m;
   1218     m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
   1219     m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
   1220     m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
   1221     m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
   1222 
   1223     mat->flags |= (MAT_FLAG_TRANSLATION |
   1224                    MAT_DIRTY_TYPE |
   1225                    MAT_DIRTY_INVERSE);
   1226 }
   1227 
   1228 
   1229 /**
   1230  * Set matrix to do viewport and depthrange mapping.
   1231  * Transforms Normalized Device Coords to window/Z values.
   1232  */
   1233 void
   1234 _math_matrix_viewport(GLmatrix *m, GLint x, GLint y, GLint width, GLint height,
   1235                       GLfloat zNear, GLfloat zFar, GLfloat depthMax)
   1236 {
   1237     m->m[MAT_SX] = (GLfloat) width / 2.0F;
   1238     m->m[MAT_TX] = m->m[MAT_SX] + x;
   1239     m->m[MAT_SY] = (GLfloat) height / 2.0F;
   1240     m->m[MAT_TY] = m->m[MAT_SY] + y;
   1241     m->m[MAT_SZ] = depthMax * ((zFar - zNear) / 2.0F);
   1242     m->m[MAT_TZ] = depthMax * ((zFar - zNear) / 2.0F + zNear);
   1243     m->flags = MAT_FLAG_GENERAL_SCALE | MAT_FLAG_TRANSLATION;
   1244     m->type = MATRIX_3D_NO_ROT;
   1245 }
   1246 
   1247 
   1248 /**
   1249  * Set a matrix to the identity matrix.
   1250  *
   1251  * \param mat matrix.
   1252  *
   1253  * Copies ::Identity into \p GLmatrix::m, and into GLmatrix::inv if not NULL.
   1254  * Sets the matrix type to identity, and clear the dirty flags.
   1255  */
   1256 void
   1257 _math_matrix_set_identity( GLmatrix *mat )
   1258 {
   1259     memcpy( mat->m, Identity, 16*sizeof(GLfloat) );
   1260 
   1261     if (mat->inv)
   1262         memcpy( mat->inv, Identity, 16*sizeof(GLfloat) );
   1263 
   1264     mat->type = MATRIX_IDENTITY;
   1265     mat->flags &= ~(MAT_DIRTY_FLAGS|
   1266                     MAT_DIRTY_TYPE|
   1267                     MAT_DIRTY_INVERSE);
   1268 }
   1269 
   1270 /*@}*/
   1271 
   1272 
   1273 /**********************************************************************/
   1274 /** \name Matrix analysis */
   1275 /*@{*/
   1276 
   1277 #define ZERO(x) (1<<x)
   1278 #define ONE(x)  (1<<(x+16))
   1279 
   1280 #define MASK_NO_TRX      (ZERO(12) | ZERO(13) | ZERO(14))
   1281 #define MASK_NO_2D_SCALE ( ONE(0)  | ONE(5))
   1282 
   1283 #define MASK_IDENTITY    ( ONE(0)  | ZERO(4)  | ZERO(8)  | ZERO(12) |\
   1284 ZERO(1)  |  ONE(5)  | ZERO(9)  | ZERO(13) |\
   1285 ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
   1286 ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
   1287 
   1288 #define MASK_2D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
   1289 ZERO(1)  |            ZERO(9)  |           \
   1290 ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
   1291 ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
   1292 
   1293 #define MASK_2D          (                      ZERO(8)  |           \
   1294 ZERO(9)  |           \
   1295 ZERO(2)  | ZERO(6)  |  ONE(10) | ZERO(14) |\
   1296 ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
   1297 
   1298 
   1299 #define MASK_3D_NO_ROT   (           ZERO(4)  | ZERO(8)  |           \
   1300 ZERO(1)  |            ZERO(9)  |           \
   1301 ZERO(2)  | ZERO(6)  |                      \
   1302 ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
   1303 
   1304 #define MASK_3D          (                                           \
   1305 \
   1306 \
   1307 ZERO(3)  | ZERO(7)  | ZERO(11) |  ONE(15) )
   1308 
   1309 
   1310 #define MASK_PERSPECTIVE (           ZERO(4)  |            ZERO(12) |\
   1311 ZERO(1)  |                       ZERO(13) |\
   1312 ZERO(2)  | ZERO(6)  |                      \
   1313 ZERO(3)  | ZERO(7)  |            ZERO(15) )
   1314 
   1315 #define SQ(x) ((x)*(x))
   1316 
   1317 /**
   1318  * Determine type and flags from scratch.
   1319  *
   1320  * \param mat matrix.
   1321  *
   1322  * This is expensive enough to only want to do it once.
   1323  */
   1324 static void analyse_from_scratch( GLmatrix *mat )
   1325 {
   1326     const GLfloat *m = mat->m;
   1327     GLuint mask = 0;
   1328     GLuint i;
   1329 
   1330     for (i = 0 ; i < 16 ; i++) {
   1331         if (m[i] == 0.0) mask |= (1<<i);
   1332     }
   1333 
   1334     if (m[0] == 1.0F) mask |= (1<<16);
   1335     if (m[5] == 1.0F) mask |= (1<<21);
   1336     if (m[10] == 1.0F) mask |= (1<<26);
   1337     if (m[15] == 1.0F) mask |= (1<<31);
   1338 
   1339     mat->flags &= ~MAT_FLAGS_GEOMETRY;
   1340 
   1341     /* Check for translation - no-one really cares
   1342      */
   1343     if ((mask & MASK_NO_TRX) != MASK_NO_TRX)
   1344         mat->flags |= MAT_FLAG_TRANSLATION;
   1345 
   1346     /* Do the real work
   1347      */
   1348     if (mask == (GLuint) MASK_IDENTITY) {
   1349         mat->type = MATRIX_IDENTITY;
   1350     }
   1351     else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) {
   1352         mat->type = MATRIX_2D_NO_ROT;
   1353 
   1354         if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE)
   1355             mat->flags |= MAT_FLAG_GENERAL_SCALE;
   1356     }
   1357     else if ((mask & MASK_2D) == (GLuint) MASK_2D) {
   1358         GLfloat mm = DOT2(m, m);
   1359         GLfloat m4m4 = DOT2(m+4,m+4);
   1360         GLfloat mm4 = DOT2(m,m+4);
   1361 
   1362         mat->type = MATRIX_2D;
   1363 
   1364         /* Check for scale */
   1365         if (SQ(mm-1) > SQ(1e-6) ||
   1366             SQ(m4m4-1) > SQ(1e-6))
   1367             mat->flags |= MAT_FLAG_GENERAL_SCALE;
   1368 
   1369         /* Check for rotation */
   1370         if (SQ(mm4) > SQ(1e-6))
   1371             mat->flags |= MAT_FLAG_GENERAL_3D;
   1372         else
   1373             mat->flags |= MAT_FLAG_ROTATION;
   1374 
   1375     }
   1376     else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) {
   1377         mat->type = MATRIX_3D_NO_ROT;
   1378 
   1379         /* Check for scale */
   1380         if (SQ(m[0]-m[5]) < SQ(1e-6) &&
   1381             SQ(m[0]-m[10]) < SQ(1e-6)) {
   1382             if (SQ(m[0]-1.0) > SQ(1e-6)) {
   1383                 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
   1384             }
   1385         }
   1386         else {
   1387             mat->flags |= MAT_FLAG_GENERAL_SCALE;
   1388         }
   1389     }
   1390     else if ((mask & MASK_3D) == (GLuint) MASK_3D) {
   1391         GLfloat c1 = DOT3(m,m);
   1392         GLfloat c2 = DOT3(m+4,m+4);
   1393         GLfloat c3 = DOT3(m+8,m+8);
   1394         GLfloat d1 = DOT3(m, m+4);
   1395         GLfloat cp[3];
   1396 
   1397         mat->type = MATRIX_3D;
   1398 
   1399         /* Check for scale */
   1400         if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) {
   1401             if (SQ(c1-1.0) > SQ(1e-6))
   1402                 mat->flags |= MAT_FLAG_UNIFORM_SCALE;
   1403             /* else no scale at all */
   1404         }
   1405         else {
   1406             mat->flags |= MAT_FLAG_GENERAL_SCALE;
   1407         }
   1408 
   1409         /* Check for rotation */
   1410         if (SQ(d1) < SQ(1e-6)) {
   1411             CROSS3( cp, m, m+4 );
   1412             SUB_3V( cp, cp, (m+8) );
   1413             if (LEN_SQUARED_3FV(cp) < SQ(1e-6))
   1414                 mat->flags |= MAT_FLAG_ROTATION;
   1415             else
   1416                 mat->flags |= MAT_FLAG_GENERAL_3D;
   1417         }
   1418         else {
   1419             mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */
   1420         }
   1421     }
   1422     else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) {
   1423         mat->type = MATRIX_PERSPECTIVE;
   1424         mat->flags |= MAT_FLAG_GENERAL;
   1425     }
   1426     else {
   1427         mat->type = MATRIX_GENERAL;
   1428         mat->flags |= MAT_FLAG_GENERAL;
   1429     }
   1430 }
   1431 
   1432 /**
   1433  * Analyze a matrix given that its flags are accurate.
   1434  *
   1435  * This is the more common operation, hopefully.
   1436  */
   1437 static void analyse_from_flags( GLmatrix *mat )
   1438 {
   1439     const GLfloat *m = mat->m;
   1440 
   1441     if (TEST_MAT_FLAGS(mat, 0)) {
   1442         mat->type = MATRIX_IDENTITY;
   1443     }
   1444     else if (TEST_MAT_FLAGS(mat, (MAT_FLAG_TRANSLATION |
   1445                                   MAT_FLAG_UNIFORM_SCALE |
   1446                                   MAT_FLAG_GENERAL_SCALE))) {
   1447         if ( m[10]==1.0F && m[14]==0.0F ) {
   1448             mat->type = MATRIX_2D_NO_ROT;
   1449         }
   1450         else {
   1451             mat->type = MATRIX_3D_NO_ROT;
   1452         }
   1453     }
   1454     else if (TEST_MAT_FLAGS(mat, MAT_FLAGS_3D)) {
   1455         if (                                 m[ 8]==0.0F
   1456             &&                             m[ 9]==0.0F
   1457             && m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F) {
   1458             mat->type = MATRIX_2D;
   1459         }
   1460         else {
   1461             mat->type = MATRIX_3D;
   1462         }
   1463     }
   1464     else if (                 m[4]==0.0F                 && m[12]==0.0F
   1465              && m[1]==0.0F                               && m[13]==0.0F
   1466              && m[2]==0.0F && m[6]==0.0F
   1467              && m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
   1468         mat->type = MATRIX_PERSPECTIVE;
   1469     }
   1470     else {
   1471         mat->type = MATRIX_GENERAL;
   1472     }
   1473 }
   1474 
   1475 /**
   1476  * Analyze and update a matrix.
   1477  *
   1478  * \param mat matrix.
   1479  *
   1480  * If the matrix type is dirty then calls either analyse_from_scratch() or
   1481  * analyse_from_flags() to determine its type, according to whether the flags
   1482  * are dirty or not, respectively. If the matrix has an inverse and it's dirty
   1483  * then calls matrix_invert(). Finally clears the dirty flags.
   1484  */
   1485 void
   1486 _math_matrix_analyse( GLmatrix *mat )
   1487 {
   1488     if (mat->flags & MAT_DIRTY_TYPE) {
   1489         if (mat->flags & MAT_DIRTY_FLAGS)
   1490             analyse_from_scratch( mat );
   1491         else
   1492             analyse_from_flags( mat );
   1493     }
   1494 
   1495     if (mat->inv && (mat->flags & MAT_DIRTY_INVERSE)) {
   1496         matrix_invert( mat );
   1497         mat->flags &= ~MAT_DIRTY_INVERSE;
   1498     }
   1499 
   1500     mat->flags &= ~(MAT_DIRTY_FLAGS | MAT_DIRTY_TYPE);
   1501 }
   1502 
   1503 /*@}*/
   1504 
   1505 
   1506 /**
   1507  * Test if the given matrix preserves vector lengths.
   1508  */
   1509 GLboolean
   1510 _math_matrix_is_length_preserving( const GLmatrix *m )
   1511 {
   1512     return TEST_MAT_FLAGS( m, MAT_FLAGS_LENGTH_PRESERVING);
   1513 }
   1514 
   1515 
   1516 /**
   1517  * Test if the given matrix does any rotation.
   1518  * (or perhaps if the upper-left 3x3 is non-identity)
   1519  */
   1520 GLboolean
   1521 _math_matrix_has_rotation( const GLmatrix *m )
   1522 {
   1523     if (m->flags & (MAT_FLAG_GENERAL |
   1524                     MAT_FLAG_ROTATION |
   1525                     MAT_FLAG_GENERAL_3D |
   1526                     MAT_FLAG_PERSPECTIVE))
   1527         return GL_TRUE;
   1528     else
   1529         return GL_FALSE;
   1530 }
   1531 
   1532 
   1533 GLboolean
   1534 _math_matrix_is_general_scale( const GLmatrix *m )
   1535 {
   1536     return (m->flags & MAT_FLAG_GENERAL_SCALE) ? GL_TRUE : GL_FALSE;
   1537 }
   1538 
   1539 
   1540 GLboolean
   1541 _math_matrix_is_dirty( const GLmatrix *m )
   1542 {
   1543     return (m->flags & MAT_DIRTY) ? GL_TRUE : GL_FALSE;
   1544 }
   1545 
   1546 
   1547 /**********************************************************************/
   1548 /** \name Matrix setup */
   1549 /*@{*/
   1550 
   1551 /**
   1552  * Copy a matrix.
   1553  *
   1554  * \param to destination matrix.
   1555  * \param from source matrix.
   1556  *
   1557  * Copies all fields in GLmatrix, creating an inverse array if necessary.
   1558  */
   1559 void
   1560 _math_matrix_copy( GLmatrix *to, const GLmatrix *from )
   1561 {
   1562     memcpy( to->m, from->m, sizeof(Identity) );
   1563     to->flags = from->flags;
   1564     to->type = from->type;
   1565 
   1566     if (to->inv != 0) {
   1567         if (from->inv == 0) {
   1568             matrix_invert( to );
   1569         }
   1570         else {
   1571             memcpy(to->inv, from->inv, sizeof(GLfloat)*16);
   1572         }
   1573     }
   1574 }
   1575 
   1576 /**
   1577  * Loads a matrix array into GLmatrix.
   1578  *
   1579  * \param m matrix array.
   1580  * \param mat matrix.
   1581  *
   1582  * Copies \p m into GLmatrix::m and marks the MAT_FLAG_GENERAL and MAT_DIRTY
   1583  * flags.
   1584  */
   1585 void
   1586 _math_matrix_loadf( GLmatrix *mat, const GLfloat *m )
   1587 {
   1588     memcpy( mat->m, m, 16*sizeof(GLfloat) );
   1589     mat->flags = (MAT_FLAG_GENERAL | MAT_DIRTY);
   1590 }
   1591 
   1592 /**
   1593  * Matrix constructor.
   1594  *
   1595  * \param m matrix.
   1596  *
   1597  * Initialize the GLmatrix fields.
   1598  */
   1599 void
   1600 _math_matrix_ctr( GLmatrix *m )
   1601 {
   1602     //m->m = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 );
   1603     if (m->m)
   1604         memcpy( m->m, Identity, sizeof(Identity) );
   1605     m->inv = NULL;
   1606     m->type = MATRIX_IDENTITY;
   1607     m->flags = 0;
   1608 }
   1609 
   1610 /**
   1611  * Matrix destructor.
   1612  *
   1613  * \param m matrix.
   1614  *
   1615  * Frees the data in a GLmatrix.
   1616  */
   1617 void
   1618 _math_matrix_dtr( GLmatrix *m )
   1619 {
   1620     if (m->m) {
   1621         //ALIGN_FREE( m->m );
   1622         //m->m = NULL;
   1623     }
   1624     if (m->inv) {
   1625         free( m->inv );
   1626         m->inv = NULL;
   1627     }
   1628 }
   1629 
   1630 /**
   1631  * Allocate a matrix inverse.
   1632  *
   1633  * \param m matrix.
   1634  *
   1635  * Allocates the matrix inverse, GLmatrix::inv, and sets it to Identity.
   1636  */
   1637 void
   1638 _math_matrix_alloc_inv( GLmatrix *m )
   1639 {
   1640     if (!m->inv) {
   1641         m->inv = (GLfloat *) malloc( 16 * sizeof(GLfloat));
   1642         if (m->inv)
   1643             memcpy( m->inv, Identity, 16 * sizeof(GLfloat) );
   1644     }
   1645 }
   1646 
   1647 /*@}*/
   1648 
   1649 
   1650 /**********************************************************************/
   1651 /** \name Matrix transpose */
   1652 /*@{*/
   1653 
   1654 /**
   1655  * Transpose a GLfloat matrix.
   1656  *
   1657  * \param to destination array.
   1658  * \param from source array.
   1659  */
   1660 void
   1661 _math_transposef( GLfloat to[16], const GLfloat from[16] )
   1662 {
   1663     to[0] = from[0];
   1664     to[1] = from[4];
   1665     to[2] = from[8];
   1666     to[3] = from[12];
   1667     to[4] = from[1];
   1668     to[5] = from[5];
   1669     to[6] = from[9];
   1670     to[7] = from[13];
   1671     to[8] = from[2];
   1672     to[9] = from[6];
   1673     to[10] = from[10];
   1674     to[11] = from[14];
   1675     to[12] = from[3];
   1676     to[13] = from[7];
   1677     to[14] = from[11];
   1678     to[15] = from[15];
   1679 }
   1680 
   1681 
   1682 /**
   1683  * Transform a 4-element row vector (1x4 matrix) by a 4x4 matrix.  This
   1684  * function is used for transforming clipping plane equations and spotlight
   1685  * directions.
   1686  * Mathematically,  u = v * m.
   1687  * Input:  v - input vector
   1688  *         m - transformation matrix
   1689  * Output:  u - transformed vector
   1690  */
   1691 void
   1692 _mesa_transform_vector( GLfloat u[4], const GLfloat v[4], const GLfloat m[16] )
   1693 {
   1694     const GLfloat v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
   1695 #define M(row,col)  m[row + col*4]
   1696     u[0] = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + v3 * M(3,0);
   1697     u[1] = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + v3 * M(3,1);
   1698     u[2] = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + v3 * M(3,2);
   1699     u[3] = v0 * M(0,3) + v1 * M(1,3) + v2 * M(2,3) + v3 * M(3,3);
   1700 #undef M
   1701 }
   1702