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