📄 light.c
字号:
* lighting, and the cost of doing it early may be partially offset * by keeping a MRU cache of shine tables for various shine values. */void_mesa_invalidate_shine_table( GLcontext *ctx, GLuint side ){ ASSERT(side < 2); if (ctx->_ShineTable[side]) ctx->_ShineTable[side]->refcount--; ctx->_ShineTable[side] = NULL;}static voidvalidate_shine_table( GLcontext *ctx, GLuint side, GLfloat shininess ){ struct gl_shine_tab *list = ctx->_ShineTabList; struct gl_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 = _mesa_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 (ctx->_ShineTable[side]) ctx->_ShineTable[side]->refcount--; ctx->_ShineTable[side] = s; move_to_tail( list, s ); s->refcount++;}void_mesa_validate_all_lighting_tables( GLcontext *ctx ){ GLuint i; GLfloat shininess; shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0]; if (!ctx->_ShineTable[0] || ctx->_ShineTable[0]->shininess != shininess) validate_shine_table( ctx, 0, shininess ); shininess = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_SHININESS][0]; if (!ctx->_ShineTable[1] || ctx->_ShineTable[1]->shininess != shininess) validate_shine_table( ctx, 1, shininess ); for (i = 0; i < ctx->Const.MaxLights; i++) if (ctx->Light.Light[i]._SpotExpTable[0][0] == -1) validate_spot_exp_table( &ctx->Light.Light[i] );}/** * Examine current lighting parameters to determine if the optimized lighting * function can be used. * Also, precompute some lighting values such as the products of light * source and material ambient, diffuse and specular coefficients. */void_mesa_update_lighting( GLcontext *ctx ){ struct gl_light *light; ctx->Light._NeedEyeCoords = GL_FALSE; ctx->Light._Flags = 0; if (!ctx->Light.Enabled) return; foreach(light, &ctx->Light.EnabledList) { ctx->Light._Flags |= light->_Flags; } ctx->Light._NeedVertices = ((ctx->Light._Flags & (LIGHT_POSITIONAL|LIGHT_SPOT)) || ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR || ctx->Light.Model.LocalViewer); ctx->Light._NeedEyeCoords = ((ctx->Light._Flags & LIGHT_POSITIONAL) || ctx->Light.Model.LocalViewer); /* XXX: This test is overkill & needs to be fixed both for software and * hardware t&l drivers. The above should be sufficient & should * be tested to verify this. */ if (ctx->Light._NeedVertices) ctx->Light._NeedEyeCoords = GL_TRUE; /* Precompute some shading values. Although we reference * Light.Material here, we can get away without flushing * FLUSH_UPDATE_CURRENT, as when any outstanding material changes * are flushed, they will update the derived state at that time. */ if (ctx->Visual.rgbMode) { if (ctx->Light.Model.TwoSide) _mesa_update_material( ctx, MAT_BIT_FRONT_EMISSION | MAT_BIT_FRONT_AMBIENT | MAT_BIT_FRONT_DIFFUSE | MAT_BIT_FRONT_SPECULAR | MAT_BIT_BACK_EMISSION | MAT_BIT_BACK_AMBIENT | MAT_BIT_BACK_DIFFUSE | MAT_BIT_BACK_SPECULAR); else _mesa_update_material( ctx, MAT_BIT_FRONT_EMISSION | MAT_BIT_FRONT_AMBIENT | MAT_BIT_FRONT_DIFFUSE | MAT_BIT_FRONT_SPECULAR); } else { static const GLfloat ci[3] = { .30F, .59F, .11F }; foreach(light, &ctx->Light.EnabledList) { light->_dli = DOT3(ci, light->Diffuse); light->_sli = DOT3(ci, light->Specular); } }}/** * Update state derived from light position, spot direction. * Called upon: * _NEW_MODELVIEW * _NEW_LIGHT * _TNL_NEW_NEED_EYE_COORDS * * Update on (_NEW_MODELVIEW | _NEW_LIGHT) when lighting is enabled. * Also update on lighting space changes. */static voidcompute_light_positions( GLcontext *ctx ){ struct gl_light *light; static const GLfloat eye_z[3] = { 0, 0, 1 }; if (!ctx->Light.Enabled) return; if (ctx->_NeedEyeCoords) { COPY_3V( ctx->_EyeZDir, eye_z ); } else { TRANSFORM_NORMAL( ctx->_EyeZDir, eye_z, ctx->ModelviewMatrixStack.Top->m ); } foreach (light, &ctx->Light.EnabledList) { if (ctx->_NeedEyeCoords) { /* _Position is in eye coordinate space */ COPY_4FV( light->_Position, light->EyePosition ); } else { /* _Position is in object coordinate space */ TRANSFORM_POINT( light->_Position, ctx->ModelviewMatrixStack.Top->inv, light->EyePosition ); } if (!(light->_Flags & LIGHT_POSITIONAL)) { /* VP (VP) = Normalize( Position ) */ COPY_3V( light->_VP_inf_norm, light->_Position ); NORMALIZE_3FV( light->_VP_inf_norm ); if (!ctx->Light.Model.LocalViewer) { /* _h_inf_norm = Normalize( V_to_P + <0,0,1> ) */ ADD_3V( light->_h_inf_norm, light->_VP_inf_norm, ctx->_EyeZDir); NORMALIZE_3FV( light->_h_inf_norm ); } light->_VP_inf_spot_attenuation = 1.0; } else { /* positional light w/ homogeneous coordinate, divide by W */ GLfloat wInv = 1.0 / light->_Position[3]; light->_Position[0] *= wInv; light->_Position[1] *= wInv; light->_Position[2] *= wInv; } if (light->_Flags & LIGHT_SPOT) { if (ctx->_NeedEyeCoords) { COPY_3V( light->_NormDirection, light->EyeDirection ); } else { TRANSFORM_NORMAL( light->_NormDirection, light->EyeDirection, ctx->ModelviewMatrixStack.Top->m); } NORMALIZE_3FV( light->_NormDirection ); if (!(light->_Flags & LIGHT_POSITIONAL)) { GLfloat PV_dot_dir = - DOT3(light->_VP_inf_norm, light->_NormDirection); if (PV_dot_dir > light->_CosCutoff) { double x = PV_dot_dir * (EXP_TABLE_SIZE-1); int k = (int) x; light->_VP_inf_spot_attenuation = (GLfloat) (light->_SpotExpTable[k][0] + (x-k)*light->_SpotExpTable[k][1]); } else { light->_VP_inf_spot_attenuation = 0; } } } }}static voidupdate_modelview_scale( GLcontext *ctx ){ ctx->_ModelViewInvScale = 1.0F; if (!_math_matrix_is_length_preserving(ctx->ModelviewMatrixStack.Top)) { const GLfloat *m = ctx->ModelviewMatrixStack.Top->inv; GLfloat f = m[2] * m[2] + m[6] * m[6] + m[10] * m[10]; if (f < 1e-12) f = 1.0; if (ctx->_NeedEyeCoords) ctx->_ModelViewInvScale = (GLfloat) INV_SQRTF(f); else ctx->_ModelViewInvScale = (GLfloat) SQRTF(f); }}/** * Bring up to date any state that relies on _NeedEyeCoords. */void_mesa_update_tnl_spaces( GLcontext *ctx, GLuint new_state ){ const GLuint oldneedeyecoords = ctx->_NeedEyeCoords; (void) new_state; ctx->_NeedEyeCoords = GL_FALSE; if (ctx->_ForceEyeCoords || (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD) || ctx->Point._Attenuated || ctx->Light._NeedEyeCoords) ctx->_NeedEyeCoords = GL_TRUE; if (ctx->Light.Enabled && !_math_matrix_is_length_preserving(ctx->ModelviewMatrixStack.Top)) ctx->_NeedEyeCoords = GL_TRUE; /* Check if the truth-value interpretations of the bitfields have * changed: */ if (oldneedeyecoords != ctx->_NeedEyeCoords) { /* Recalculate all state that depends on _NeedEyeCoords. */ update_modelview_scale(ctx); compute_light_positions( ctx ); if (ctx->Driver.LightingSpaceChange) ctx->Driver.LightingSpaceChange( ctx ); } else { GLuint new_state = ctx->NewState; /* Recalculate that same state only if it has been invalidated * by other statechanges. */ if (new_state & _NEW_MODELVIEW) update_modelview_scale(ctx); if (new_state & (_NEW_LIGHT|_NEW_MODELVIEW)) compute_light_positions( ctx ); }}/** * Drivers may need this if the hardware tnl unit doesn't support the * light-in-modelspace optimization. It's also useful for debugging. */void_mesa_allow_light_in_model( GLcontext *ctx, GLboolean flag ){ ctx->_ForceEyeCoords = !flag; ctx->NewState |= _NEW_POINT; /* one of the bits from * _MESA_NEW_NEED_EYE_COORDS. */}/**********************************************************************//***** Initialization *****//**********************************************************************//** * Initialize the n-th light data structure. * * \param l pointer to the gl_light structure to be initialized. * \param n number of the light. * \note The defaults for light 0 are different than the other lights. */static voidinit_light( struct gl_light *l, GLuint n ){ make_empty_list( l ); ASSIGN_4V( l->Ambient, 0.0, 0.0, 0.0, 1.0 ); if (n==0) { ASSIGN_4V( l->Diffuse, 1.0, 1.0, 1.0, 1.0 ); ASSIGN_4V( l->Specular, 1.0, 1.0, 1.0, 1.0 ); } else { ASSIGN_4V( l->Diffuse, 0.0, 0.0, 0.0, 1.0 ); ASSIGN_4V( l->Specular, 0.0, 0.0, 0.0, 1.0 ); } ASSIGN_4V( l->EyePosition, 0.0, 0.0, 1.0, 0.0 ); ASSIGN_3V( l->EyeDirection, 0.0, 0.0, -1.0 ); l->SpotExponent = 0.0; _mesa_invalidate_spot_exp_table( l ); l->SpotCutoff = 180.0; l->_CosCutoffNeg = -1.0f; l->_CosCutoff = 0.0; /* KW: -ve values not admitted */ l->ConstantAttenuation = 1.0; l->LinearAttenuation = 0.0; l->QuadraticAttenuation = 0.0; l->Enabled = GL_FALSE;}/** * Initialize the light model data structure. * * \param lm pointer to the gl_lightmodel structure to be initialized. */static voidinit_lightmodel( struct gl_lightmodel *lm ){ ASSIGN_4V( lm->Ambient, 0.2F, 0.2F, 0.2F, 1.0F ); lm->LocalViewer = GL_FALSE; lm->TwoSide = GL_FALSE; lm->ColorControl = GL_SINGLE_COLOR;}/** * Initialize the material data structure. * * \param m pointer to the gl_material structure to be initialized. */static voidinit_material( struct gl_material *m ){ ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_AMBIENT], 0.2F, 0.2F, 0.2F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_DIFFUSE], 0.8F, 0.8F, 0.8F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_SPECULAR], 0.0F, 0.0F, 0.0F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_EMISSION], 0.0F, 0.0F, 0.0F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_SHININESS], 0.0F, 0.0F, 0.0F, 0.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_FRONT_INDEXES], 0.0F, 1.0F, 1.0F, 0.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_AMBIENT], 0.2F, 0.2F, 0.2F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_DIFFUSE], 0.8F, 0.8F, 0.8F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_SPECULAR], 0.0F, 0.0F, 0.0F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_EMISSION], 0.0F, 0.0F, 0.0F, 1.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_SHININESS], 0.0F, 0.0F, 0.0F, 0.0F ); ASSIGN_4V( m->Attrib[MAT_ATTRIB_BACK_INDEXES], 0.0F, 1.0F, 1.0F, 0.0F );}/** * Initialize all lighting state for the given context. */void_mesa_init_lighting( GLcontext *ctx ){ GLuint i; /* Lighting group */ for (i = 0; i < MAX_LIGHTS; i++) { init_light( &ctx->Light.Light[i], i ); } make_empty_list( &ctx->Light.EnabledList ); init_lightmodel( &ctx->Light.Model ); init_material( &ctx->Light.Material ); ctx->Light.ShadeModel = GL_SMOOTH; ctx->Light.Enabled = GL_FALSE; ctx->Light.ColorMaterialFace = GL_FRONT_AND_BACK; ctx->Light.ColorMaterialMode = GL_AMBIENT_AND_DIFFUSE; ctx->Light.ColorMaterialBitmask = _mesa_material_bitmask( ctx, GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ~0, NULL ); ctx->Light.ColorMaterialEnabled = GL_FALSE; ctx->Light.ClampVertexColor = GL_TRUE; /* Lighting miscellaneous */ ctx->_ShineTabList = MALLOC_STRUCT( gl_shine_tab ); make_empty_list( ctx->_ShineTabList ); /* Allocate 10 (arbitrary) shininess lookup tables */ for (i = 0 ; i < 10 ; i++) { struct gl_shine_tab *s = MALLOC_STRUCT( gl_shine_tab ); s->shininess = -1; s->refcount = 0; insert_at_tail( ctx->_ShineTabList, s ); } /* Miscellaneous */ ctx->Light._NeedEyeCoords = GL_FALSE; ctx->_NeedEyeCoords = GL_FALSE; ctx->_ModelViewInvScale = 1.0;}/** * Deallocate malloc'd lighting state attached to given context. */void_mesa_free_lighting_data( GLcontext *ctx ){ struct gl_shine_tab *s, *tmps; /* Free lighting shininess exponentiation table */ foreach_s( s, tmps, ctx->_ShineTabList ) { _mesa_free( s ); } _mesa_free( ctx->_ShineTabList );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -