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