Home | History | Annotate | Download | only in math
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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