Home | History | Annotate | Download | only in tnl
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 
     26 #include "c99_math.h"
     27 #include "main/glheader.h"
     28 #include "main/light.h"
     29 #include "main/macros.h"
     30 #include "main/imports.h"
     31 #include "util/simple_list.h"
     32 #include "main/mtypes.h"
     33 
     34 #include "math/m_translate.h"
     35 
     36 #include "util/bitscan.h"
     37 
     38 #include "t_context.h"
     39 #include "t_pipeline.h"
     40 #include "tnl.h"
     41 
     42 #define LIGHT_TWOSIDE       0x1
     43 #define LIGHT_MATERIAL      0x2
     44 #define MAX_LIGHT_FUNC      0x4
     45 
     46 typedef void (*light_func)( struct gl_context *ctx,
     47 			    struct vertex_buffer *VB,
     48 			    struct tnl_pipeline_stage *stage,
     49 			    GLvector4f *input );
     50 
     51 /**
     52  * Information for updating current material attributes from vertex color,
     53  * for GL_COLOR_MATERIAL.
     54  */
     55 struct material_cursor {
     56    const GLfloat *ptr;    /* points to src vertex color (in VB array) */
     57    GLuint stride;         /* stride to next vertex color (bytes) */
     58    GLfloat *current;      /* points to material attribute to update */
     59    GLuint size;           /* vertex/color size: 1, 2, 3 or 4 */
     60 };
     61 
     62 /**
     63  * Data private to this pipeline stage.
     64  */
     65 struct light_stage_data {
     66    GLvector4f Input;
     67    GLvector4f LitColor[2];
     68    GLvector4f LitSecondary[2];
     69    light_func *light_func_tab;
     70 
     71    struct material_cursor mat[MAT_ATTRIB_MAX];
     72    GLuint mat_count;
     73    GLuint mat_bitmask;
     74 };
     75 
     76 
     77 #define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
     78 
     79 
     80 
     81 /**********************************************************************/
     82 /*****                  Lighting computation                      *****/
     83 /**********************************************************************/
     84 
     85 
     86 /*
     87  * Notes:
     88  *   When two-sided lighting is enabled we compute the color (or index)
     89  *   for both the front and back side of the primitive.  Then, when the
     90  *   orientation of the facet is later learned, we can determine which
     91  *   color (or index) to use for rendering.
     92  *
     93  *   KW: We now know orientation in advance and only shade for
     94  *       the side or sides which are actually required.
     95  *
     96  * Variables:
     97  *   n = normal vector
     98  *   V = vertex position
     99  *   P = light source position
    100  *   Pe = (0,0,0,1)
    101  *
    102  * Precomputed:
    103  *   IF P[3]==0 THEN
    104  *       // light at infinity
    105  *       IF local_viewer THEN
    106  *           _VP_inf_norm = unit vector from V to P      // Precompute
    107  *       ELSE
    108  *           // eye at infinity
    109  *           _h_inf_norm = Normalize( VP + <0,0,1> )     // Precompute
    110  *       ENDIF
    111  *   ENDIF
    112  *
    113  * Functions:
    114  *   Normalize( v ) = normalized vector v
    115  *   Magnitude( v ) = length of vector v
    116  */
    117 
    118 
    119 
    120 static void
    121 validate_shine_table( struct gl_context *ctx, GLuint side, GLfloat shininess )
    122 {
    123    TNLcontext *tnl = TNL_CONTEXT(ctx);
    124    struct tnl_shine_tab *list = tnl->_ShineTabList;
    125    struct tnl_shine_tab *s;
    126 
    127    assert(side < 2);
    128 
    129    foreach(s, list)
    130       if ( s->shininess == shininess )
    131 	 break;
    132 
    133    if (s == list) {
    134       GLint j;
    135       GLfloat *m;
    136 
    137       foreach(s, list)
    138 	 if (s->refcount == 0)
    139 	    break;
    140 
    141       m = s->tab;
    142       m[0] = 0.0F;
    143       if (shininess == 0.0F) {
    144 	 for (j = 1 ; j <= SHINE_TABLE_SIZE ; j++)
    145 	    m[j] = 1.0F;
    146       }
    147       else {
    148 	 for (j = 1 ; j < SHINE_TABLE_SIZE ; j++) {
    149             GLfloat t, x = j / (GLfloat) (SHINE_TABLE_SIZE - 1);
    150             if (x < 0.005F) /* underflow check */
    151                x = 0.005F;
    152             t = powf(x, shininess);
    153 	    if (t > 1e-20F)
    154 	       m[j] = t;
    155 	    else
    156 	       m[j] = 0.0F;
    157 	 }
    158 	 m[SHINE_TABLE_SIZE] = 1.0F;
    159       }
    160 
    161       s->shininess = shininess;
    162    }
    163 
    164    if (tnl->_ShineTable[side])
    165       tnl->_ShineTable[side]->refcount--;
    166 
    167    tnl->_ShineTable[side] = s;
    168    move_to_tail( list, s );
    169    s->refcount++;
    170 }
    171 
    172 
    173 void
    174 _tnl_validate_shine_tables( struct gl_context *ctx )
    175 {
    176    TNLcontext *tnl = TNL_CONTEXT(ctx);
    177    GLfloat shininess;
    178 
    179    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
    180    if (!tnl->_ShineTable[0] || tnl->_ShineTable[0]->shininess != shininess)
    181       validate_shine_table( ctx, 0, shininess );
    182 
    183    shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0];
    184    if (!tnl->_ShineTable[1] || tnl->_ShineTable[1]->shininess != shininess)
    185       validate_shine_table( ctx, 1, shininess );
    186 }
    187 
    188 
    189 /**
    190  * In the case of colormaterial, the effected material attributes
    191  * should already have been bound to point to the incoming color data,
    192  * prior to running the pipeline.
    193  * This function copies the vertex's color to the material attributes
    194  * which are tracking glColor.
    195  * It's called per-vertex in the lighting loop.
    196  */
    197 static void
    198 update_materials(struct gl_context *ctx, struct light_stage_data *store)
    199 {
    200    GLuint i;
    201 
    202    for (i = 0 ; i < store->mat_count ; i++) {
    203       /* update the material */
    204       COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr);
    205       /* increment src vertex color pointer */
    206       STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
    207    }
    208 
    209    /* recompute derived light/material values */
    210    _mesa_update_material( ctx, store->mat_bitmask );
    211    /* XXX we should only call this if we're tracking/changing the specular
    212     * exponent.
    213     */
    214    _tnl_validate_shine_tables( ctx );
    215 }
    216 
    217 
    218 /**
    219  * Prepare things prior to running the lighting stage.
    220  * Return number of material attributes which will track vertex color.
    221  */
    222 static GLuint
    223 prepare_materials(struct gl_context *ctx,
    224                   struct vertex_buffer *VB, struct light_stage_data *store)
    225 {
    226    GLuint i;
    227 
    228    store->mat_count = 0;
    229    store->mat_bitmask = 0;
    230 
    231    /* Examine the _ColorMaterialBitmask to determine which materials
    232     * track vertex color.  Override the material attribute's pointer
    233     * with the color pointer for each one.
    234     */
    235    if (ctx->Light.ColorMaterialEnabled) {
    236       GLbitfield bitmask = ctx->Light._ColorMaterialBitmask;
    237       while (bitmask) {
    238          const int i = u_bit_scan(&bitmask);
    239          VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
    240             VB->AttribPtr[_TNL_ATTRIB_COLOR0];
    241       }
    242    }
    243 
    244    /* Now, for each material attribute that's tracking vertex color, save
    245     * some values (ptr, stride, size, current) that we'll need in
    246     * update_materials(), above, that'll actually copy the vertex color to
    247     * the material attribute(s).
    248     */
    249    for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
    250       if (VB->AttribPtr[i]->stride) {
    251 	 const GLuint j = store->mat_count++;
    252 	 const GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
    253 	 store->mat[j].ptr    = VB->AttribPtr[i]->start;
    254 	 store->mat[j].stride = VB->AttribPtr[i]->stride;
    255 	 store->mat[j].size   = VB->AttribPtr[i]->size;
    256 	 store->mat[j].current = ctx->Light.Material.Attrib[attr];
    257 	 store->mat_bitmask |= (1<<attr);
    258       }
    259    }
    260 
    261    /* FIXME: Is this already done?
    262     */
    263    _mesa_update_material( ctx, ~0 );
    264 
    265    _tnl_validate_shine_tables( ctx );
    266 
    267    return store->mat_count;
    268 }
    269 
    270 /*
    271  * Compute dp ^ SpecularExponent.
    272  * Lerp between adjacent values in the f(x) lookup table, giving a
    273  * continuous function, with adequate overall accuracy.  (Though still
    274  * pretty good compared to a straight lookup).
    275  */
    276 static inline GLfloat
    277 lookup_shininess(const struct gl_context *ctx, GLuint face, GLfloat dp)
    278 {
    279    TNLcontext *tnl = TNL_CONTEXT(ctx);
    280    const struct tnl_shine_tab *tab = tnl->_ShineTable[face];
    281    float f = dp * (SHINE_TABLE_SIZE - 1);
    282    int k = (int) f;
    283    if (k < 0 /* gcc may cast an overflow float value to negative int value */
    284 	|| k > SHINE_TABLE_SIZE - 2)
    285       return powf(dp, tab->shininess);
    286    else
    287       return tab->tab[k] + (f - k) * (tab->tab[k+1] - tab->tab[k]);
    288 }
    289 
    290 /* Tables for all the shading functions.
    291  */
    292 static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
    293 static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
    294 static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
    295 static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
    296 
    297 #define TAG(x)           x
    298 #define IDX              (0)
    299 #include "t_vb_lighttmp.h"
    300 
    301 #define TAG(x)           x##_twoside
    302 #define IDX              (LIGHT_TWOSIDE)
    303 #include "t_vb_lighttmp.h"
    304 
    305 #define TAG(x)           x##_material
    306 #define IDX              (LIGHT_MATERIAL)
    307 #include "t_vb_lighttmp.h"
    308 
    309 #define TAG(x)           x##_twoside_material
    310 #define IDX              (LIGHT_TWOSIDE|LIGHT_MATERIAL)
    311 #include "t_vb_lighttmp.h"
    312 
    313 
    314 static void init_lighting_tables( void )
    315 {
    316    static int done;
    317 
    318    if (!done) {
    319       init_light_tab();
    320       init_light_tab_twoside();
    321       init_light_tab_material();
    322       init_light_tab_twoside_material();
    323       done = 1;
    324    }
    325 }
    326 
    327 
    328 static GLboolean run_lighting( struct gl_context *ctx,
    329 			       struct tnl_pipeline_stage *stage )
    330 {
    331    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
    332    TNLcontext *tnl = TNL_CONTEXT(ctx);
    333    struct vertex_buffer *VB = &tnl->vb;
    334    GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->AttribPtr[_TNL_ATTRIB_POS];
    335    GLuint idx;
    336 
    337    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
    338       return GL_TRUE;
    339 
    340    /* Make sure we can talk about position x,y and z:
    341     */
    342    if (input->size <= 2 && input == VB->AttribPtr[_TNL_ATTRIB_POS]) {
    343 
    344       _math_trans_4f( store->Input.data,
    345 		      VB->AttribPtr[_TNL_ATTRIB_POS]->data,
    346 		      VB->AttribPtr[_TNL_ATTRIB_POS]->stride,
    347 		      GL_FLOAT,
    348 		      VB->AttribPtr[_TNL_ATTRIB_POS]->size,
    349 		      0,
    350 		      VB->Count );
    351 
    352       if (input->size <= 2) {
    353 	 /* Clean z.
    354 	  */
    355 	 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2);
    356       }
    357 
    358       if (input->size <= 1) {
    359 	 /* Clean y.
    360 	  */
    361 	 _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1);
    362       }
    363 
    364       input = &store->Input;
    365    }
    366 
    367    idx = 0;
    368 
    369    if (prepare_materials( ctx, VB, store ))
    370       idx |= LIGHT_MATERIAL;
    371 
    372    if (ctx->Light.Model.TwoSide)
    373       idx |= LIGHT_TWOSIDE;
    374 
    375    /* The individual functions know about replaying side-effects
    376     * vs. full re-execution.
    377     */
    378    store->light_func_tab[idx]( ctx, VB, stage, input );
    379 
    380    return GL_TRUE;
    381 }
    382 
    383 
    384 /* Called in place of do_lighting when the light table may have changed.
    385  */
    386 static void validate_lighting( struct gl_context *ctx,
    387 					struct tnl_pipeline_stage *stage )
    388 {
    389    light_func *tab;
    390 
    391    if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
    392       return;
    393 
    394    if (ctx->Light._NeedVertices) {
    395       if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
    396 	 tab = _tnl_light_spec_tab;
    397       else
    398 	 tab = _tnl_light_tab;
    399    }
    400    else {
    401       /* Power of two means only a single active light. */
    402       if (_mesa_is_pow_two(ctx->Light._EnabledLights))
    403 	 tab = _tnl_light_fast_single_tab;
    404       else
    405 	 tab = _tnl_light_fast_tab;
    406    }
    407 
    408 
    409    LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
    410 
    411    /* This and the above should only be done on _NEW_LIGHT:
    412     */
    413    TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
    414 }
    415 
    416 
    417 
    418 /* Called the first time stage->run is called.  In effect, don't
    419  * allocate data until the first time the stage is run.
    420  */
    421 static GLboolean init_lighting( struct gl_context *ctx,
    422 				struct tnl_pipeline_stage *stage )
    423 {
    424    TNLcontext *tnl = TNL_CONTEXT(ctx);
    425    struct light_stage_data *store;
    426    GLuint size = tnl->vb.Size;
    427 
    428    stage->privatePtr = malloc(sizeof(*store));
    429    store = LIGHT_STAGE_DATA(stage);
    430    if (!store)
    431       return GL_FALSE;
    432 
    433    /* Do onetime init.
    434     */
    435    init_lighting_tables();
    436 
    437    _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
    438    _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
    439    _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
    440    _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
    441    _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
    442 
    443    store->LitColor[0].size = 4;
    444    store->LitColor[1].size = 4;
    445    store->LitSecondary[0].size = 3;
    446    store->LitSecondary[1].size = 3;
    447 
    448    return GL_TRUE;
    449 }
    450 
    451 
    452 
    453 
    454 static void dtr( struct tnl_pipeline_stage *stage )
    455 {
    456    struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
    457 
    458    if (store) {
    459       _mesa_vector4f_free( &store->Input );
    460       _mesa_vector4f_free( &store->LitColor[0] );
    461       _mesa_vector4f_free( &store->LitColor[1] );
    462       _mesa_vector4f_free( &store->LitSecondary[0] );
    463       _mesa_vector4f_free( &store->LitSecondary[1] );
    464       free( store );
    465       stage->privatePtr = NULL;
    466    }
    467 }
    468 
    469 const struct tnl_pipeline_stage _tnl_lighting_stage =
    470 {
    471    "lighting",			/* name */
    472    NULL,			/* private_data */
    473    init_lighting,
    474    dtr,				/* destroy */
    475    validate_lighting,
    476    run_lighting
    477 };
    478