📄 light.c
字号:
if (ctx->_ShineTable[side])
ctx->_ShineTable[side]->refcount--;
ctx->_ShineTable[side] = NULL;
}
static void
validate_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 < MAX_LIGHTS ; 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 = 0;
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);
}
}
}
/* _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 void
compute_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) {
COPY_4FV( light->_Position, light->EyePosition );
}
else {
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;
}
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 void
update_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 uptodate 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 = 0;
if (ctx->_ForceEyeCoords ||
(ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD) ||
ctx->Point._Attenuated ||
ctx->Light._NeedEyeCoords)
ctx->_NeedEyeCoords = 1;
if (ctx->Light.Enabled &&
!_math_matrix_is_length_preserving(ctx->ModelviewMatrixStack.Top))
ctx->_NeedEyeCoords = 1;
/* 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 void
init_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->_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 void
init_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 void
init_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 );
}
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;
/* 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 = 0;
ctx->_NeedEyeCoords = 0;
ctx->_ModelViewInvScale = 1.0;
}
void
_mesa_free_lighting_data( GLcontext *ctx )
{
struct gl_shine_tab *s, *tmps;
/* Free lighting shininess exponentiation table */
foreach_s( s, tmps, ctx->_ShineTabList ) {
FREE( s );
}
FREE( ctx->_ShineTabList );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -