1 
2 /*
3  * Mesa 3-D graphics library
4  *
5  * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 /*
27  * New (3.1) transformation code written by Keith Whitwell.
28  */
29 
30 /* Functions to tranform a vector of normals.  This includes applying
31  * the transformation matrix, rescaling and normalization.
32  */
33 
34 /*
35  * mat - the 4x4 transformation matrix
36  * scale - uniform scale factor of the transformation matrix (not always used)
37  * in - the source vector of normals
38  * lengths - length of each incoming normal (may be NULL) (a display list
39  *           optimization)
40  * dest - the destination vector of normals
41  */
42 static void
TAG(transform_normalize_normals)43 TAG(transform_normalize_normals)( const GLmatrix *mat,
44                                   GLfloat scale,
45                                   const GLvector4f *in,
46                                   const GLfloat *lengths,
47                                   GLvector4f *dest )
48 {
49    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
50    const GLfloat *from = in->start;
51    const GLuint stride = in->stride;
52    const GLuint count = in->count;
53    const GLfloat *m = mat->inv;
54    GLfloat m0 = m[0],  m4 = m[4],  m8 = m[8];
55    GLfloat m1 = m[1],  m5 = m[5],  m9 = m[9];
56    GLfloat m2 = m[2],  m6 = m[6],  m10 = m[10];
57    GLuint i;
58 
59    if (!lengths) {
60       STRIDE_LOOP {
61 	 GLfloat tx, ty, tz;
62 	 {
63 	    const GLfloat ux = from[0],  uy = from[1],  uz = from[2];
64 	    tx = ux * m0 + uy * m1 + uz * m2;
65 	    ty = ux * m4 + uy * m5 + uz * m6;
66 	    tz = ux * m8 + uy * m9 + uz * m10;
67 	 }
68 	 {
69 	    GLdouble len = tx*tx + ty*ty + tz*tz;
70 	    if (len > 1e-20) {
71 	       GLfloat scale = 1.0f / sqrtf(len);
72 	       out[i][0] = tx * scale;
73 	       out[i][1] = ty * scale;
74 	       out[i][2] = tz * scale;
75 	    }
76 	    else {
77 	       out[i][0] = out[i][1] = out[i][2] = 0;
78 	    }
79 	 }
80       }
81    }
82    else {
83       if (scale != 1.0f) {
84 	 m0 *= scale,  m4 *= scale,  m8 *= scale;
85 	 m1 *= scale,  m5 *= scale,  m9 *= scale;
86 	 m2 *= scale,  m6 *= scale,  m10 *= scale;
87       }
88 
89       STRIDE_LOOP {
90 	 GLfloat tx, ty, tz;
91 	 {
92 	    const GLfloat ux = from[0],  uy = from[1],  uz = from[2];
93 	    tx = ux * m0 + uy * m1 + uz * m2;
94 	    ty = ux * m4 + uy * m5 + uz * m6;
95 	    tz = ux * m8 + uy * m9 + uz * m10;
96 	 }
97 	 {
98 	    GLfloat len = lengths[i];
99 	    out[i][0] = tx * len;
100 	    out[i][1] = ty * len;
101 	    out[i][2] = tz * len;
102 	 }
103       }
104    }
105    dest->count = in->count;
106 }
107 
108 
109 static void
TAG(transform_normalize_normals_no_rot)110 TAG(transform_normalize_normals_no_rot)( const GLmatrix *mat,
111                                          GLfloat scale,
112                                          const GLvector4f *in,
113                                          const GLfloat *lengths,
114                                          GLvector4f *dest )
115 {
116    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
117    const GLfloat *from = in->start;
118    const GLuint stride = in->stride;
119    const GLuint count = in->count;
120    const GLfloat *m = mat->inv;
121    GLfloat m0 = m[0];
122    GLfloat m5 = m[5];
123    GLfloat m10 = m[10];
124    GLuint i;
125 
126    if (!lengths) {
127       STRIDE_LOOP {
128 	 GLfloat tx, ty, tz;
129 	 {
130 	    const GLfloat ux = from[0],  uy = from[1],  uz = from[2];
131 	    tx = ux * m0                    ;
132 	    ty =           uy * m5          ;
133 	    tz =                     uz * m10;
134 	 }
135 	 {
136 	    GLdouble len = tx*tx + ty*ty + tz*tz;
137 	    if (len > 1e-20) {
138 	       GLfloat scale = 1.0f / sqrtf(len);
139 	       out[i][0] = tx * scale;
140 	       out[i][1] = ty * scale;
141 	       out[i][2] = tz * scale;
142 	    }
143 	    else {
144 	       out[i][0] = out[i][1] = out[i][2] = 0;
145 	    }
146 	 }
147       }
148    }
149    else {
150       m0 *= scale;
151       m5 *= scale;
152       m10 *= scale;
153 
154       STRIDE_LOOP {
155 	 GLfloat tx, ty, tz;
156 	 {
157 	    const GLfloat ux = from[0],  uy = from[1],  uz = from[2];
158 	    tx = ux * m0                    ;
159 	    ty =           uy * m5          ;
160 	    tz =                     uz * m10;
161 	 }
162 	 {
163 	    GLfloat len = lengths[i];
164 	    out[i][0] = tx * len;
165 	    out[i][1] = ty * len;
166 	    out[i][2] = tz * len;
167 	 }
168       }
169    }
170    dest->count = in->count;
171 }
172 
173 
174 static void
TAG(transform_rescale_normals_no_rot)175 TAG(transform_rescale_normals_no_rot)( const GLmatrix *mat,
176                                        GLfloat scale,
177                                        const GLvector4f *in,
178                                        const GLfloat *lengths,
179                                        GLvector4f *dest )
180 {
181    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
182    const GLfloat *from = in->start;
183    const GLuint stride = in->stride;
184    const GLuint count = in->count;
185    const GLfloat *m = mat->inv;
186    const GLfloat m0 = scale*m[0];
187    const GLfloat m5 = scale*m[5];
188    const GLfloat m10 = scale*m[10];
189    GLuint i;
190 
191    (void) lengths;
192 
193    STRIDE_LOOP {
194       GLfloat ux = from[0],  uy = from[1],  uz = from[2];
195       out[i][0] = ux * m0;
196       out[i][1] =           uy * m5;
197       out[i][2] =                     uz * m10;
198    }
199    dest->count = in->count;
200 }
201 
202 
203 static void
TAG(transform_rescale_normals)204 TAG(transform_rescale_normals)( const GLmatrix *mat,
205                                 GLfloat scale,
206                                 const GLvector4f *in,
207                                 const GLfloat *lengths,
208                                 GLvector4f *dest )
209 {
210    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
211    const GLfloat *from = in->start;
212    const GLuint stride = in->stride;
213    const GLuint count = in->count;
214    /* Since we are unlikely to have < 3 vertices in the buffer,
215     * it makes sense to pre-multiply by scale.
216     */
217    const GLfloat *m = mat->inv;
218    const GLfloat m0 = scale*m[0],  m4 = scale*m[4],  m8 = scale*m[8];
219    const GLfloat m1 = scale*m[1],  m5 = scale*m[5],  m9 = scale*m[9];
220    const GLfloat m2 = scale*m[2],  m6 = scale*m[6],  m10 = scale*m[10];
221    GLuint i;
222 
223    (void) lengths;
224 
225    STRIDE_LOOP {
226       GLfloat ux = from[0],  uy = from[1],  uz = from[2];
227       out[i][0] = ux * m0 + uy * m1 + uz * m2;
228       out[i][1] = ux * m4 + uy * m5 + uz * m6;
229       out[i][2] = ux * m8 + uy * m9 + uz * m10;
230    }
231    dest->count = in->count;
232 }
233 
234 
235 static void
TAG(transform_normals_no_rot)236 TAG(transform_normals_no_rot)( const GLmatrix *mat,
237 			       GLfloat scale,
238 			       const GLvector4f *in,
239 			       const GLfloat *lengths,
240 			       GLvector4f *dest )
241 {
242    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
243    const GLfloat *from = in->start;
244    const GLuint stride = in->stride;
245    const GLuint count = in->count;
246    const GLfloat *m = mat->inv;
247    const GLfloat m0 = m[0];
248    const GLfloat m5 = m[5];
249    const GLfloat m10 = m[10];
250    GLuint i;
251 
252    (void) scale;
253    (void) lengths;
254 
255    STRIDE_LOOP {
256       GLfloat ux = from[0],  uy = from[1],  uz = from[2];
257       out[i][0] = ux * m0;
258       out[i][1] =           uy * m5;
259       out[i][2] =                     uz * m10;
260    }
261    dest->count = in->count;
262 }
263 
264 
265 static void
TAG(transform_normals)266 TAG(transform_normals)( const GLmatrix *mat,
267                         GLfloat scale,
268                         const GLvector4f *in,
269                         const GLfloat *lengths,
270                         GLvector4f *dest )
271 {
272    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
273    const GLfloat *from = in->start;
274    const GLuint stride = in->stride;
275    const GLuint count = in->count;
276    const GLfloat *m = mat->inv;
277    const GLfloat m0 = m[0],  m4 = m[4],  m8 = m[8];
278    const GLfloat m1 = m[1],  m5 = m[5],  m9 = m[9];
279    const GLfloat m2 = m[2],  m6 = m[6],  m10 = m[10];
280    GLuint i;
281 
282    (void) scale;
283    (void) lengths;
284 
285    STRIDE_LOOP {
286       GLfloat ux = from[0],  uy = from[1],  uz = from[2];
287       out[i][0] = ux * m0 + uy * m1 + uz * m2;
288       out[i][1] = ux * m4 + uy * m5 + uz * m6;
289       out[i][2] = ux * m8 + uy * m9 + uz * m10;
290    }
291    dest->count = in->count;
292 }
293 
294 
295 static void
TAG(normalize_normals)296 TAG(normalize_normals)( const GLmatrix *mat,
297                         GLfloat scale,
298                         const GLvector4f *in,
299                         const GLfloat *lengths,
300                         GLvector4f *dest )
301 {
302    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
303    const GLfloat *from = in->start;
304    const GLuint stride = in->stride;
305    const GLuint count = in->count;
306    GLuint i;
307 
308    (void) mat;
309    (void) scale;
310 
311    if (lengths) {
312       STRIDE_LOOP {
313 	 const GLfloat x = from[0], y = from[1], z = from[2];
314 	 GLfloat invlen = lengths[i];
315 	 out[i][0] = x * invlen;
316 	 out[i][1] = y * invlen;
317 	 out[i][2] = z * invlen;
318       }
319    }
320    else {
321       STRIDE_LOOP {
322 	 const GLfloat x = from[0], y = from[1], z = from[2];
323 	 GLdouble len = x * x + y * y + z * z;
324 	 if (len > 1e-50) {
325 	    len = 1.0f / sqrtf(len);
326 	    out[i][0] = (GLfloat)(x * len);
327 	    out[i][1] = (GLfloat)(y * len);
328 	    out[i][2] = (GLfloat)(z * len);
329 	 }
330 	 else {
331 	    out[i][0] = x;
332 	    out[i][1] = y;
333 	    out[i][2] = z;
334 	 }
335       }
336    }
337    dest->count = in->count;
338 }
339 
340 
341 static void
TAG(rescale_normals)342 TAG(rescale_normals)( const GLmatrix *mat,
343                       GLfloat scale,
344                       const GLvector4f *in,
345                       const GLfloat *lengths,
346                       GLvector4f *dest )
347 {
348    GLfloat (*out)[4] = (GLfloat (*)[4])dest->start;
349    const GLfloat *from = in->start;
350    const GLuint stride = in->stride;
351    const GLuint count = in->count;
352    GLuint i;
353 
354    (void) mat;
355    (void) lengths;
356 
357    STRIDE_LOOP {
358       SCALE_SCALAR_3V( out[i], scale, from );
359    }
360    dest->count = in->count;
361 }
362 
363 
364 static void
TAG(init_c_norm_transform)365 TAG(init_c_norm_transform)( void )
366 {
367    _mesa_normal_tab[NORM_TRANSFORM_NO_ROT] =
368       TAG(transform_normals_no_rot);
369 
370    _mesa_normal_tab[NORM_TRANSFORM_NO_ROT | NORM_RESCALE] =
371       TAG(transform_rescale_normals_no_rot);
372 
373    _mesa_normal_tab[NORM_TRANSFORM_NO_ROT | NORM_NORMALIZE] =
374       TAG(transform_normalize_normals_no_rot);
375 
376    _mesa_normal_tab[NORM_TRANSFORM] =
377       TAG(transform_normals);
378 
379    _mesa_normal_tab[NORM_TRANSFORM | NORM_RESCALE] =
380       TAG(transform_rescale_normals);
381 
382    _mesa_normal_tab[NORM_TRANSFORM | NORM_NORMALIZE] =
383       TAG(transform_normalize_normals);
384 
385    _mesa_normal_tab[NORM_RESCALE] =
386       TAG(rescale_normals);
387 
388    _mesa_normal_tab[NORM_NORMALIZE] =
389       TAG(normalize_normals);
390 }
391