1
2/*
3 * Mesa 3-D graphics library
4 * Version:  5.1
5 *
6 * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 */
42static void _XFORMAPI
43TAG(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 = INV_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.0) {
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
109static void _XFORMAPI
110TAG(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 = INV_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
174static void _XFORMAPI
175TAG(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
203static void _XFORMAPI
204TAG(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
235static void _XFORMAPI
236TAG(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
265static void _XFORMAPI
266TAG(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
295static void _XFORMAPI
296TAG(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 = INV_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
341static void _XFORMAPI
342TAG(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
364static void _XFORMAPI
365TAG(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