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