1 /* $Id: xform.c,v 1.10 1997/10/30 06:00:06 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.5
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: xform.c,v $
26 * Revision 1.10 1997/10/30 06:00:06 brianp
27 * added Intel X86 assembly optimzations (Josh Vanderhoof)
28 *
29 * Revision 1.9 1997/07/24 01:25:54 brianp
30 * changed precompiled header symbol from PCH to PC_HEADER
31 *
32 * Revision 1.8 1997/05/28 03:27:03 brianp
33 * added precompiled header (PCH) support
34 *
35 * Revision 1.7 1997/05/01 01:40:51 brianp
36 * replaced sqrt() with GL_SQRT()
37 *
38 * Revision 1.6 1997/04/02 03:15:02 brianp
39 * removed gl_xform_texcoords_4fv()
40 *
41 * Revision 1.5 1997/01/03 23:54:17 brianp
42 * changed length threshold in gl_xform_normals_3fv() to 1E-30 per Jeroen
43 *
44 * Revision 1.4 1996/11/09 01:50:49 brianp
45 * relaxed the minimum normal threshold in gl_xform_normals_3fv()
46 *
47 * Revision 1.3 1996/11/08 02:20:39 brianp
48 * added gl_xform_texcoords_4fv()
49 *
50 * Revision 1.2 1996/11/05 01:38:50 brianp
51 * fixed some comments
52 *
53 * Revision 1.1 1996/09/13 01:38:16 brianp
54 * Initial revision
55 *
56 */
57
58
59 /*
60 * Matrix/vertex/vector transformation stuff
61 *
62 *
63 * NOTES:
64 * 1. 4x4 transformation matrices are stored in memory in column major order.
65 * 2. Points/vertices are to be thought of as column vectors.
66 * 3. Transformation of a point p by a matrix M is: p' = M * p
67 *
68 */
69
70
71 #ifdef PC_HEADER
72 #include "all.h"
73 #else
74 #include <math.h>
75 #include "mmath.h"
76 #include "types.h"
77 #include "xform.h"
78 #endif
79
80
81
82 /*
83 * Apply a transformation matrix to an array of [X Y Z W] coordinates:
84 * for i in 0 to n-1 do q[i] = m * p[i]
85 * where p[i] and q[i] are 4-element column vectors and m is a 16-element
86 * transformation matrix.
87 */
gl_xform_points_4fv(GLuint n,GLfloat q[][4],const GLfloat m[16],GLfloat p[][4])88 void gl_xform_points_4fv( GLuint n, GLfloat q[][4], const GLfloat m[16],
89 GLfloat p[][4] )
90 {
91 /* This function has been carefully crafted to maximize register usage
92 * and use loop unrolling with IRIX 5.3's cc. Hopefully other compilers
93 * will like this code too.
94 */
95 {
96 GLuint i;
97 GLfloat m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
98 GLfloat m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
99 if (m12==0.0F && m13==0.0F) {
100 /* common case */
101 for (i=0;i<n;i++) {
102 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
103 q[i][0] = m0 * p0 + m4 * p1 + m8 * p2;
104 q[i][1] = m1 * p0 + m5 * p1 + m9 * p2;
105 }
106 }
107 else {
108 /* general case */
109 for (i=0;i<n;i++) {
110 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2], p3 = p[i][3];
111 q[i][0] = m0 * p0 + m4 * p1 + m8 * p2 + m12 * p3;
112 q[i][1] = m1 * p0 + m5 * p1 + m9 * p2 + m13 * p3;
113 }
114 }
115 }
116 {
117 GLuint i;
118 GLfloat m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
119 GLfloat m3 = m[3], m7 = m[7], m11 = m[11], m15 = m[15];
120 if (m3==0.0F && m7==0.0F && m11==0.0F && m15==1.0F) {
121 /* common case */
122 for (i=0;i<n;i++) {
123 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2], p3 = p[i][3];
124 q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14 * p3;
125 q[i][3] = p3;
126 }
127 }
128 else {
129 /* general case */
130 for (i=0;i<n;i++) {
131 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2], p3 = p[i][3];
132 q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14 * p3;
133 q[i][3] = m3 * p0 + m7 * p1 + m11 * p2 + m15 * p3;
134 }
135 }
136 }
137 }
138
139
140
141 /*
142 * Apply a transformation matrix to an array of [X Y Z] coordinates:
143 * for i in 0 to n-1 do q[i] = m * p[i]
144 */
gl_xform_points_3fv(GLuint n,GLfloat q[][4],const GLfloat m[16],GLfloat p[][3])145 void gl_xform_points_3fv( GLuint n, GLfloat q[][4], const GLfloat m[16],
146 GLfloat p[][3] )
147 {
148 /* This function has been carefully crafted to maximize register usage
149 * and use loop unrolling with IRIX 5.3's cc. Hopefully other compilers
150 * will like this code too.
151 */
152 {
153 GLuint i;
154 GLfloat m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
155 GLfloat m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
156 for (i=0;i<n;i++) {
157 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
158 q[i][0] = m0 * p0 + m4 * p1 + m8 * p2 + m12;
159 q[i][1] = m1 * p0 + m5 * p1 + m9 * p2 + m13;
160 }
161 }
162 {
163 GLuint i;
164 GLfloat m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
165 GLfloat m3 = m[3], m7 = m[7], m11 = m[11], m15 = m[15];
166 if (m3==0.0F && m7==0.0F && m11==0.0F && m15==1.0F) {
167 /* common case */
168 for (i=0;i<n;i++) {
169 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
170 q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14;
171 q[i][3] = 1.0F;
172 }
173 }
174 else {
175 /* general case */
176 for (i=0;i<n;i++) {
177 GLfloat p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
178 q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14;
179 q[i][3] = m3 * p0 + m7 * p1 + m11 * p2 + m15;
180 }
181 }
182 }
183 }
184
185
186
187 #ifndef USE_ASM
188 /*
189 * Apply a transformation matrix to an array of normal vectors:
190 * for i in 0 to n-1 do v[i] = u[i] * m
191 * where u[i] and v[i] are 3-element row vectors and m is a 16-element
192 * transformation matrix.
193 * If the normalize flag is true the normals will be scaled to length 1.
194 */
gl_xform_normals_3fv(GLuint n,GLfloat v[][3],const GLfloat m[16],GLfloat u[][3],GLboolean normalize)195 void gl_xform_normals_3fv( GLuint n, GLfloat v[][3], const GLfloat m[16],
196 GLfloat u[][3], GLboolean normalize )
197 {
198 if (normalize) {
199 /* Transform normals and scale to unit length */
200 GLuint i;
201 GLfloat m0 = m[0], m4 = m[4], m8 = m[8];
202 GLfloat m1 = m[1], m5 = m[5], m9 = m[9];
203 GLfloat m2 = m[2], m6 = m[6], m10 = m[10];
204 for (i=0;i<n;i++) {
205 GLdouble tx, ty, tz;
206 {
207 GLfloat ux = u[i][0], uy = u[i][1], uz = u[i][2];
208 tx = ux * m0 + uy * m1 + uz * m2;
209 ty = ux * m4 + uy * m5 + uz * m6;
210 tz = ux * m8 + uy * m9 + uz * m10;
211 }
212 {
213 GLdouble len, scale;
214 len = GL_SQRT( tx*tx + ty*ty + tz*tz );
215 scale = (len>1E-30) ? (1.0 / len) : 1.0;
216 v[i][0] = tx * scale;
217 v[i][1] = ty * scale;
218 v[i][2] = tz * scale;
219 }
220 }
221 }
222 else {
223 /* Just transform normals, don't scale */
224 GLuint i;
225 GLfloat m0 = m[0], m4 = m[4], m8 = m[8];
226 GLfloat m1 = m[1], m5 = m[5], m9 = m[9];
227 GLfloat m2 = m[2], m6 = m[6], m10 = m[10];
228 for (i=0;i<n;i++) {
229 GLfloat ux = u[i][0], uy = u[i][1], uz = u[i][2];
230 v[i][0] = ux * m0 + uy * m1 + uz * m2;
231 v[i][1] = ux * m4 + uy * m5 + uz * m6;
232 v[i][2] = ux * m8 + uy * m9 + uz * m10;
233 }
234 }
235 }
236 #endif
237
238
239 /*
240 * Transform a 4-element row vector (1x4 matrix) by a 4x4 matrix. This
241 * function is used for transforming clipping plane equations and spotlight
242 * directions.
243 * Mathematically, u = v * m.
244 * Input: v - input vector
245 * m - transformation matrix
246 * Output: u - transformed vector
247 */
gl_transform_vector(GLfloat u[4],const GLfloat v[4],const GLfloat m[16])248 void gl_transform_vector( GLfloat u[4], const GLfloat v[4], const GLfloat m[16] )
249 {
250 GLfloat v0=v[0], v1=v[1], v2=v[2], v3=v[3];
251 #define M(row,col) m[col*4+row]
252 u[0] = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + v3 * M(3,0);
253 u[1] = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + v3 * M(3,1);
254 u[2] = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + v3 * M(3,2);
255 u[3] = v0 * M(0,3) + v1 * M(1,3) + v2 * M(2,3) + v3 * M(3,3);
256 #undef M
257 }
258
259