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