diff options
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r-- | src/mesa/tnl/t_context.c | 21 | ||||
-rw-r--r-- | src/mesa/tnl/t_context.h | 18 | ||||
-rw-r--r-- | src/mesa/tnl/t_vb_light.c | 134 | ||||
-rw-r--r-- | src/mesa/tnl/t_vb_lighttmp.h | 12 | ||||
-rw-r--r-- | src/mesa/tnl/tnl.h | 3 |
5 files changed, 179 insertions, 9 deletions
diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c index 1ded44ccffb..ede1d742835 100644 --- a/src/mesa/tnl/t_context.c +++ b/src/mesa/tnl/t_context.c @@ -46,6 +46,7 @@ GLboolean _tnl_CreateContext( struct gl_context *ctx ) { TNLcontext *tnl; + GLuint i; /* Create the TNLcontext structure */ @@ -76,10 +77,21 @@ _tnl_CreateContext( struct gl_context *ctx ) */ tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; - tnl->Driver.NotifyMaterialChange = _mesa_validate_all_lighting_tables; + tnl->Driver.NotifyMaterialChange = _tnl_validate_shine_tables; tnl->nr_blocks = 0; + /* Lighting miscellaneous */ + tnl->_ShineTabList = MALLOC_STRUCT( tnl_shine_tab ); + make_empty_list( tnl->_ShineTabList ); + /* Allocate 10 (arbitrary) shininess lookup tables */ + for (i = 0 ; i < 10 ; i++) { + struct tnl_shine_tab *s = MALLOC_STRUCT( tnl_shine_tab ); + s->shininess = -1; + s->refcount = 0; + insert_at_tail( tnl->_ShineTabList, s ); + } + /* plug in the VBO drawing function */ vbo_set_draw_func(ctx, _tnl_vbo_draw_prims); @@ -93,8 +105,15 @@ _tnl_CreateContext( struct gl_context *ctx ) void _tnl_DestroyContext( struct gl_context *ctx ) { + struct tnl_shine_tab *s, *tmps; TNLcontext *tnl = TNL_CONTEXT(ctx); + /* Free lighting shininess exponentiation table */ + foreach_s( s, tmps, tnl->_ShineTabList ) { + free( s ); + } + free( tnl->_ShineTabList ); + _tnl_destroy_pipeline( ctx ); FREE(tnl); diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h index c5a902082b8..8f18ddeb17a 100644 --- a/src/mesa/tnl/t_context.h +++ b/src/mesa/tnl/t_context.h @@ -384,6 +384,20 @@ struct tnl_clipspace }; +#define SHINE_TABLE_SIZE 256 /**< Material shininess lookup table sizes */ + +/** + * Material shininess lookup table. + */ +struct tnl_shine_tab +{ + struct tnl_shine_tab *next, *prev; + GLfloat tab[SHINE_TABLE_SIZE+1]; + GLfloat shininess; + GLuint refcount; +}; + + struct tnl_device_driver { /*** @@ -518,6 +532,10 @@ typedef struct GLuint nr_blocks; GLuint CurInstance; + + struct tnl_shine_tab *_ShineTable[2]; /**< Active shine tables */ + struct tnl_shine_tab *_ShineTabList; /**< MRU list of inactive shine tables */ + /**@}*/ } TNLcontext; diff --git a/src/mesa/tnl/t_vb_light.c b/src/mesa/tnl/t_vb_light.c index 3acedf6e577..39467fac731 100644 --- a/src/mesa/tnl/t_vb_light.c +++ b/src/mesa/tnl/t_vb_light.c @@ -36,6 +36,7 @@ #include "t_context.h" #include "t_pipeline.h" +#include "tnl.h" #define LIGHT_TWOSIDE 0x1 #define LIGHT_MATERIAL 0x2 @@ -76,6 +77,114 @@ struct light_stage_data { +/**********************************************************************/ +/***** Lighting computation *****/ +/**********************************************************************/ + + +/* + * Notes: + * When two-sided lighting is enabled we compute the color (or index) + * for both the front and back side of the primitive. Then, when the + * orientation of the facet is later learned, we can determine which + * color (or index) to use for rendering. + * + * KW: We now know orientation in advance and only shade for + * the side or sides which are actually required. + * + * Variables: + * n = normal vector + * V = vertex position + * P = light source position + * Pe = (0,0,0,1) + * + * Precomputed: + * IF P[3]==0 THEN + * // light at infinity + * IF local_viewer THEN + * _VP_inf_norm = unit vector from V to P // Precompute + * ELSE + * // eye at infinity + * _h_inf_norm = Normalize( VP + <0,0,1> ) // Precompute + * ENDIF + * ENDIF + * + * Functions: + * Normalize( v ) = normalized vector v + * Magnitude( v ) = length of vector v + */ + + + +static void +validate_shine_table( struct gl_context *ctx, GLuint side, GLfloat shininess ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct tnl_shine_tab *list = tnl->_ShineTabList; + struct tnl_shine_tab *s; + + ASSERT(side < 2); + + foreach(s, list) + if ( s->shininess == shininess ) + break; + + if (s == list) { + GLint j; + GLfloat *m; + + foreach(s, list) + if (s->refcount == 0) + break; + + m = s->tab; + m[0] = 0.0; + if (shininess == 0.0) { + for (j = 1 ; j <= SHINE_TABLE_SIZE ; j++) + m[j] = 1.0; + } + else { + for (j = 1 ; j < SHINE_TABLE_SIZE ; j++) { + GLdouble t, x = j / (GLfloat) (SHINE_TABLE_SIZE - 1); + if (x < 0.005) /* underflow check */ + x = 0.005; + t = pow(x, shininess); + if (t > 1e-20) + m[j] = (GLfloat) t; + else + m[j] = 0.0; + } + m[SHINE_TABLE_SIZE] = 1.0; + } + + s->shininess = shininess; + } + + if (tnl->_ShineTable[side]) + tnl->_ShineTable[side]->refcount--; + + tnl->_ShineTable[side] = s; + move_to_tail( list, s ); + s->refcount++; +} + + +void +_tnl_validate_shine_tables( struct gl_context *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLfloat shininess; + + shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0]; + if (!tnl->_ShineTable[0] || tnl->_ShineTable[0]->shininess != shininess) + validate_shine_table( ctx, 0, shininess ); + + shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0]; + if (!tnl->_ShineTable[1] || tnl->_ShineTable[1]->shininess != shininess) + validate_shine_table( ctx, 1, shininess ); +} + + /** * In the case of colormaterial, the effected material attributes * should already have been bound to point to the incoming color data, @@ -101,7 +210,7 @@ update_materials(struct gl_context *ctx, struct light_stage_data *store) /* XXX we should only call this if we're tracking/changing the specular * exponent. */ - _mesa_validate_all_lighting_tables( ctx ); + _tnl_validate_shine_tables( ctx ); } @@ -149,11 +258,32 @@ prepare_materials(struct gl_context *ctx, /* FIXME: Is this already done? */ _mesa_update_material( ctx, ~0 ); - _mesa_validate_all_lighting_tables( ctx ); + + _tnl_validate_shine_tables( ctx ); return store->mat_count; } +/* + * Compute dp ^ SpecularExponent. + * Lerp between adjacent values in the f(x) lookup table, giving a + * continuous function, with adequate overall accuracy. (Though still + * pretty good compared to a straight lookup). + */ +static inline GLfloat +lookup_shininess(const struct gl_context *ctx, GLuint face, GLfloat dp) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + const struct tnl_shine_tab *tab = tnl->_ShineTable[face]; + float f = dp * (SHINE_TABLE_SIZE - 1); + int k = (int) f; + if (k < 0 /* gcc may cast an overflow float value to negative int value */ + || k > SHINE_TABLE_SIZE - 2) + return powf(dp, tab->shininess); + else + return tab->tab[k] + (f - k) * (tab->tab[k+1] - tab->tab[k]); +} + /* Tables for all the shading functions. */ static light_func _tnl_light_tab[MAX_LIGHT_FUNC]; diff --git a/src/mesa/tnl/t_vb_lighttmp.h b/src/mesa/tnl/t_vb_lighttmp.h index 1041a24e761..1944e5ddc6d 100644 --- a/src/mesa/tnl/t_vb_lighttmp.h +++ b/src/mesa/tnl/t_vb_lighttmp.h @@ -204,7 +204,7 @@ static void TAG(light_rgba_spec)( struct gl_context *ctx, n_dot_h = correction * DOT3(normal, h); if (n_dot_h > 0.0F) { - GLfloat spec_coef = _mesa_lookup_shininess(ctx, side, n_dot_h); + GLfloat spec_coef = lookup_shininess(ctx, side, n_dot_h); if (spec_coef > 1.0e-10) { spec_coef *= attenuation; ACC_SCALE_SCALAR_3V( spec[side], spec_coef, @@ -383,7 +383,7 @@ static void TAG(light_rgba)( struct gl_context *ctx, n_dot_h = correction * DOT3(normal, h); if (n_dot_h > 0.0F) { - GLfloat spec_coef = _mesa_lookup_shininess(ctx, side, n_dot_h); + GLfloat spec_coef = lookup_shininess(ctx, side, n_dot_h); ACC_SCALE_SCALAR_3V( contrib, spec_coef, light->_MatSpecular[side]); } @@ -483,7 +483,7 @@ static void TAG(light_fast_rgba_single)( struct gl_context *ctx, COPY_3V(sum, base[1]); ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]); if (n_dot_h > 0.0F) { - GLfloat spec = _mesa_lookup_shininess(ctx, 1, n_dot_h); + GLfloat spec = lookup_shininess(ctx, 1, n_dot_h); ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]); } COPY_3V(Bcolor[j], sum ); @@ -497,7 +497,7 @@ static void TAG(light_fast_rgba_single)( struct gl_context *ctx, COPY_3V(sum, base[0]); ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]); if (n_dot_h > 0.0F) { - GLfloat spec = _mesa_lookup_shininess(ctx, 0, n_dot_h); + GLfloat spec = lookup_shininess(ctx, 0, n_dot_h); ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]); } COPY_3V(Fcolor[j], sum ); @@ -589,7 +589,7 @@ static void TAG(light_fast_rgba)( struct gl_context *ctx, ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]); n_dot_h = DOT3(normal, light->_h_inf_norm); if (n_dot_h > 0.0F) { - spec = _mesa_lookup_shininess(ctx, 0, n_dot_h); + spec = lookup_shininess(ctx, 0, n_dot_h); ACC_SCALE_SCALAR_3V( sum[0], spec, light->_MatSpecular[0]); } } @@ -598,7 +598,7 @@ static void TAG(light_fast_rgba)( struct gl_context *ctx, ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]); n_dot_h = -DOT3(normal, light->_h_inf_norm); if (n_dot_h > 0.0F) { - spec = _mesa_lookup_shininess(ctx, 1, n_dot_h); + spec = lookup_shininess(ctx, 1, n_dot_h); ACC_SCALE_SCALAR_3V( sum[1], spec, light->_MatSpecular[1]); } } diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h index d3889811e21..434bd7fcd95 100644 --- a/src/mesa/tnl/tnl.h +++ b/src/mesa/tnl/tnl.h @@ -101,4 +101,7 @@ _mesa_load_tracked_matrices(struct gl_context *ctx); extern void _tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]); +extern void +_tnl_validate_shine_tables( struct gl_context *ctx ); + #endif |