static void build_f2( GLfloat *f, GLuint fstride, const GLvector4f *normal, const GLvector4f *eye ) { GLuint stride = eye->stride; GLfloat *coord = eye->start; GLuint count = eye->count; GLfloat *norm = normal->start; GLuint i; for (i=0;i<count;i++) { GLfloat u[3], two_nu; COPY_2V( u, coord ); u[2] = 0; NORMALIZE_3FV( u ); two_nu = 2.0F * DOT3(norm,u); f[0] = u[0] - norm[0] * two_nu; f[1] = u[1] - norm[1] * two_nu; f[2] = u[2] - norm[2] * two_nu; STRIDE_F(coord,stride); STRIDE_F(f,fstride); STRIDE_F(norm, normal->stride); } }
static void build_m2( GLfloat f[][3], GLfloat m[], const GLvector4f *normal, const GLvector4f *eye ) { GLuint stride = eye->stride; GLfloat *coord = eye->start; GLuint count = eye->count; GLfloat *norm = normal->start; GLuint i; for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->stride)) { GLfloat u[3], two_nu, fx, fy, fz; COPY_2V( u, coord ); u[2] = 0; NORMALIZE_3FV( u ); two_nu = 2.0F * DOT3(norm,u); fx = f[i][0] = u[0] - norm[0] * two_nu; fy = f[i][1] = u[1] - norm[1] * two_nu; fz = f[i][2] = u[2] - norm[2] * two_nu; m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); if (m[i] != 0.0F) { m[i] = 0.5F * (1.0f / sqrtf(m[i])); } } }
/** * For debugging */ void _mesa_vector4f_print( const GLvector4f *v, const GLubyte *cullmask, GLboolean culling ) { static const GLfloat c[4] = { 0, 0, 0, 1 }; static const char *templates[5] = { "%d:\t0, 0, 0, 1\n", "%d:\t%f, 0, 0, 1\n", "%d:\t%f, %f, 0, 1\n", "%d:\t%f, %f, %f, 1\n", "%d:\t%f, %f, %f, %f\n" }; const char *t = templates[v->size]; GLfloat *d = (GLfloat *)v->data; GLuint j, i = 0, count; printf("data-start\n"); for (; d != v->start; STRIDE_F(d, v->stride), i++) printf(t, i, d[0], d[1], d[2], d[3]); printf("start-count(%u)\n", v->count); count = i + v->count; if (culling) { for (; i < count; STRIDE_F(d, v->stride), i++) if (cullmask[i]) printf(t, i, d[0], d[1], d[2], d[3]); } else { for (; i < count; STRIDE_F(d, v->stride), i++) printf(t, i, d[0], d[1], d[2], d[3]); } for (j = v->size; j < 4; j++) { if ((v->flags & (1<<j)) == 0) { printf("checking col %u is clean as advertised ", j); for (i = 0, d = (GLfloat *) v->data; i < count && d[j] == c[j]; i++, STRIDE_F(d, v->stride)) { /* no-op */ } if (i == count) printf(" --> ok\n"); else printf(" --> Failed at %u ******\n", i); } } }
static GLvector4f * ref_cliptest_points2( GLvector4f *clip_vec, GLvector4f *proj_vec, GLubyte clipMask[], GLubyte *orMask, GLubyte *andMask, GLboolean viewport_z_clip ) { const GLuint stride = clip_vec->stride; const GLuint count = clip_vec->count; const GLfloat *from = (GLfloat *)clip_vec->start; GLubyte tmpOrMask = *orMask; GLubyte tmpAndMask = *andMask; GLuint i; (void) viewport_z_clip; for ( i = 0 ; i < count ; i++, STRIDE_F(from, stride) ) { const GLfloat cx = from[0], cy = from[1]; GLubyte mask = 0; if ( cx > 1.0 ) mask |= CLIP_RIGHT_BIT; else if ( cx < -1.0 ) mask |= CLIP_LEFT_BIT; if ( cy > 1.0 ) mask |= CLIP_TOP_BIT; else if ( cy < -1.0 ) mask |= CLIP_BOTTOM_BIT; clipMask[i] = mask; tmpOrMask |= mask; tmpAndMask &= mask; } *orMask = tmpOrMask; *andMask = tmpAndMask; return clip_vec; }
static void texgen_normal_map_nv( struct gl_context *ctx, struct texgen_stage_data *store, GLuint unit ) { struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; GLvector4f *out = &store->texcoord[unit]; GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start; GLuint count = VB->Count; GLuint i; const GLfloat *norm = normal->start; for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { texcoord[i][0] = norm[0]; texcoord[i][1] = norm[1]; texcoord[i][2] = norm[2]; } out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; out->count = count; out->size = MAX2(in->size, 3); if (in->size == 4) _mesa_copy_tab[0x8]( out, in ); }
/** * Compute per-vertex fog blend factors from fog coordinates by * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function. * Fog coordinates are distances from the eye (typically between the * near and far clip plane distances). * Note that fogcoords may be negative, if eye z is source absolute * value must be taken earlier. * Fog blend factors are in the range [0,1]. */ static void compute_fog_blend_factors(struct gl_context *ctx, GLvector4f *out, const GLvector4f *in) { GLfloat end = ctx->Fog.End; GLfloat *v = in->start; GLuint stride = in->stride; GLuint n = in->count; GLfloat (*data)[4] = out->data; GLfloat d; GLuint i; out->count = in->count; switch (ctx->Fog.Mode) { case GL_LINEAR: if (ctx->Fog.Start == ctx->Fog.End) d = 1.0F; else d = 1.0F / (ctx->Fog.End - ctx->Fog.Start); for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { const GLfloat z = *v; GLfloat f = (end - z) * d; data[i][0] = CLAMP(f, 0.0F, 1.0F); } break; case GL_EXP: d = ctx->Fog.Density; for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) { const GLfloat z = *v; NEG_EXP( data[i][0], d * z ); } break; case GL_EXP2: d = ctx->Fog.Density*ctx->Fog.Density; for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { const GLfloat z = *v; NEG_EXP( data[i][0], d * z * z ); } break; default: _mesa_problem(ctx, "Bad fog mode in make_fog_coord"); return; } }
static GLvector4f *ref_cliptest_points4( GLvector4f *clip_vec, GLvector4f *proj_vec, GLubyte clipMask[], GLubyte *orMask, GLubyte *andMask, GLboolean viewport_z_clip ) { const GLuint stride = clip_vec->stride; const GLuint count = clip_vec->count; const GLfloat *from = (GLfloat *)clip_vec->start; GLuint c = 0; GLfloat (*vProj)[4] = (GLfloat (*)[4])proj_vec->start; GLubyte tmpAndMask = *andMask; GLubyte tmpOrMask = *orMask; GLuint i; for ( i = 0 ; i < count ; i++, STRIDE_F(from, stride) ) { const GLfloat cx = from[0]; const GLfloat cy = from[1]; const GLfloat cz = from[2]; const GLfloat cw = from[3]; GLubyte mask = 0; if ( -cx + cw < 0 ) mask |= CLIP_RIGHT_BIT; if ( cx + cw < 0 ) mask |= CLIP_LEFT_BIT; if ( -cy + cw < 0 ) mask |= CLIP_TOP_BIT; if ( cy + cw < 0 ) mask |= CLIP_BOTTOM_BIT; if (viewport_z_clip) { if ( -cz + cw < 0 ) mask |= CLIP_FAR_BIT; if ( cz + cw < 0 ) mask |= CLIP_NEAR_BIT; } clipMask[i] = mask; if ( mask ) { c++; tmpAndMask &= mask; tmpOrMask |= mask; vProj[i][0] = 0; vProj[i][1] = 0; vProj[i][2] = 0; vProj[i][3] = 1; } else { GLfloat oow = 1.0F / cw; vProj[i][0] = cx * oow; vProj[i][1] = cy * oow; vProj[i][2] = cz * oow; vProj[i][3] = oow; } } *orMask = tmpOrMask; *andMask = (GLubyte) (c < count ? 0 : tmpAndMask); proj_vec->flags |= VEC_SIZE_4; proj_vec->size = 4; proj_vec->count = clip_vec->count; return proj_vec; }
static void userclip( struct gl_context *ctx, GLvector4f *clip, GLubyte *clipmask, GLubyte *clipormask, GLubyte *clipandmask ) { GLuint p; for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { GLuint nr, i; const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; GLfloat *coord = (GLfloat *)clip->data; GLuint stride = clip->stride; GLuint count = clip->count; for (nr = 0, i = 0 ; i < count ; i++) { GLfloat dp = (coord[0] * a + coord[1] * b + coord[2] * c + coord[3] * d); if (dp < 0) { nr++; clipmask[i] |= CLIP_USER_BIT; } STRIDE_F(coord, stride); } if (nr > 0) { *clipormask |= CLIP_USER_BIT; if (nr == count) { *clipandmask |= CLIP_USER_BIT; return; } } } } }
/* EXT_vertex_cull. Not really a big win, but probably depends on * your application. This stage not included in the default pipeline. */ static GLboolean run_cull_stage( GLcontext *ctx, struct tnl_pipeline_stage *stage ) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; const GLfloat a = ctx->Transform.CullObjPos[0]; const GLfloat b = ctx->Transform.CullObjPos[1]; const GLfloat c = ctx->Transform.CullObjPos[2]; GLfloat *norm = (GLfloat *)VB->NormalPtr->data; GLuint stride = VB->NormalPtr->stride; GLuint count = VB->Count; GLuint i; if (ctx->ShaderObjects._VertexShaderPresent) return GL_TRUE; if (ctx->VertexProgram._Enabled || !ctx->Transform.CullVertexFlag) return GL_TRUE; VB->ClipOrMask &= ~CLIP_CULL_BIT; VB->ClipAndMask |= CLIP_CULL_BIT; for (i = 0 ; i < count ; i++) { GLfloat dp = (norm[0] * a + norm[1] * b + norm[2] * c); if (dp < 0) { VB->ClipMask[i] |= CLIP_CULL_BIT; VB->ClipOrMask |= CLIP_CULL_BIT; } else { VB->ClipMask[i] &= ~CLIP_CULL_BIT; VB->ClipAndMask &= ~CLIP_CULL_BIT; } STRIDE_F(norm, stride); } return !(VB->ClipAndMask & CLIP_CULL_BIT); }
/** * In the case of colormaterial, the effected material attributes * should already have been bound to point to the incoming color data, * prior to running the pipeline. * This function copies the vertex's color to the material attributes * which are tracking glColor. * It's called per-vertex in the lighting loop. */ static void update_materials(GLcontext *ctx, struct light_stage_data *store) { GLuint i; for (i = 0 ; i < store->mat_count ; i++) { /* update the material */ COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr); /* increment src vertex color pointer */ STRIDE_F(store->mat[i].ptr, store->mat[i].stride); } /* recompute derived light/material values */ _mesa_update_material( ctx, store->mat_bitmask ); /* XXX we should only call this if we're tracking/changing the specular * exponent. */ _mesa_validate_all_lighting_tables( ctx ); }
GLvector4f *_mesa_project_points( GLvector4f *proj_vec, const GLvector4f *clip_vec ) { const GLuint stride = clip_vec->stride; const GLfloat *from = (GLfloat *)clip_vec->start; const GLuint count = clip_vec->count; GLfloat (*vProj)[4] = (GLfloat (*)[4])proj_vec->start; GLuint i; for (i = 0 ; i < count ; i++, STRIDE_F(from, stride)) { GLfloat oow = 1.0F / from[3]; vProj[i][3] = oow; vProj[i][0] = from[0] * oow; vProj[i][1] = from[1] * oow; vProj[i][2] = from[2] * oow; } proj_vec->flags |= VEC_SIZE_4; proj_vec->size = 3; proj_vec->count = clip_vec->count; return proj_vec; }
static int test_cliptest_function( clip_func func, int np, int psize, long *cycles ) { GLvector4f source[1], dest[1], ref[1]; GLubyte dm[TEST_COUNT], dco, dca; GLubyte rm[TEST_COUNT], rco, rca; int i, j; #ifdef RUN_DEBUG_BENCHMARK int cycle_i; /* the counter for the benchmarks we run */ #endif GLboolean viewport_z_clip = GL_TRUE; (void) cycles; if ( psize > 4 ) { _mesa_problem( NULL, "test_cliptest_function called with psize > 4\n" ); return 0; } for ( i = 0 ; i < TEST_COUNT ; i++) { ASSIGN_4V( d[i], 0.0, 0.0, 0.0, 1.0 ); ASSIGN_4V( s[i], 0.0, 0.0, 0.0, 1.0 ); for ( j = 0 ; j < psize ; j++ ) s[i][j] = rnd(); } source->data = (GLfloat(*)[4])s; source->start = (GLfloat *)s; source->count = TEST_COUNT; source->stride = sizeof(s[0]); source->size = 4; source->flags = 0; dest->data = (GLfloat(*)[4])d; dest->start = (GLfloat *)d; dest->count = TEST_COUNT; dest->stride = sizeof(float[4]); dest->size = 0; dest->flags = 0; ref->data = (GLfloat(*)[4])r; ref->start = (GLfloat *)r; ref->count = TEST_COUNT; ref->stride = sizeof(float[4]); ref->size = 0; ref->flags = 0; dco = rco = 0; dca = rca = CLIP_FRUSTUM_BITS; ref_cliptest[psize]( source, ref, rm, &rco, &rca, viewport_z_clip ); if ( mesa_profile ) { BEGIN_RACE( *cycles ); func( source, dest, dm, &dco, &dca, viewport_z_clip ); END_RACE( *cycles ); } else { func( source, dest, dm, &dco, &dca, viewport_z_clip ); } if ( dco != rco ) { printf( "\n-----------------------------\n" ); printf( "dco = 0x%02x rco = 0x%02x\n", dco, rco ); return 0; } if ( dca != rca ) { printf( "\n-----------------------------\n" ); printf( "dca = 0x%02x rca = 0x%02x\n", dca, rca ); return 0; } for ( i = 0 ; i < TEST_COUNT ; i++ ) { if ( dm[i] != rm[i] ) { GLfloat *c = source->start; STRIDE_F(c, source->stride * i); if (psize == 4 && xyz_close_to_w(c)) { /* The coordinate is very close to the clip plane. The clipmask * may vary depending on code path, but that's OK. */ continue; } printf( "\n-----------------------------\n" ); printf( "mask[%d] = 0x%02x ref mask[%d] = 0x%02x\n", i, dm[i], i,rm[i] ); printf(" coord = %f, %f, %f, %f\n", c[0], c[1], c[2], c[3]); return 0; } } /* Only verify output on projected points4 case. FIXME: Do we need * to test other cases? */ if ( np || psize < 4 ) return 1; for ( i = 0 ; i < TEST_COUNT ; i++ ) { for ( j = 0 ; j < 4 ; j++ ) { if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) { printf( "\n-----------------------------\n" ); printf( "(i = %i, j = %i) dm = 0x%02x rm = 0x%02x\n", i, j, dm[i], rm[i] ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][0], r[i][0], r[i][0]-d[i][0], MAX_PRECISION - significand_match( d[i][0], r[i][0] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][1], r[i][1], r[i][1]-d[i][1], MAX_PRECISION - significand_match( d[i][1], r[i][1] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][2], r[i][2], r[i][2]-d[i][2], MAX_PRECISION - significand_match( d[i][2], r[i][2] ) ); printf( "%f \t %f \t [diff = %e - %i bit missed]\n", d[i][3], r[i][3], r[i][3]-d[i][3], MAX_PRECISION - significand_match( d[i][3], r[i][3] ) ); return 0; } } } return 1; }
static void texgen( struct gl_context *ctx, struct texgen_stage_data *store, GLuint unit ) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; GLvector4f *out = &store->texcoord[unit]; const struct gl_fixedfunc_texture_unit *texUnit = &ctx->Texture.FixedFuncUnit[unit]; const GLvector4f *obj = VB->AttribPtr[_TNL_ATTRIB_POS]; const GLvector4f *eye = VB->EyePtr; const GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; const GLfloat *m = store->tmp_m; const GLuint count = VB->Count; GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data; GLfloat (*f)[3] = store->tmp_f; GLuint copy; if (texUnit->_GenFlags & TEXGEN_NEED_M) { build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye ); } else if (texUnit->_GenFlags & TEXGEN_NEED_F) { build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye ); } out->size = MAX2(in->size, store->TexgenSize[unit]); out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; out->count = count; copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); if (copy) _mesa_copy_tab[copy]( out, in ); if (texUnit->TexGenEnabled & S_BIT) { GLuint i; switch (texUnit->GenS.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( (GLfloat *)out->data, sizeof(out->data[0]), obj, texUnit->GenS.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data, sizeof(out->data[0]), eye, texUnit->GenS.EyePlane ); break; case GL_SPHERE_MAP: for (i = 0; i < count; i++) texcoord[i][0] = f[i][0] * m[i] + 0.5F; break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][0] = f[i][0]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { texcoord[i][0] = norm[0]; } break; } default: _mesa_problem(ctx, "Bad S texgen"); } } if (texUnit->TexGenEnabled & T_BIT) { GLuint i; switch (texUnit->GenT.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][1]), sizeof(out->data[0]), obj, texUnit->GenT.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][1]), sizeof(out->data[0]), eye, texUnit->GenT.EyePlane ); break; case GL_SPHERE_MAP: for (i = 0; i < count; i++) texcoord[i][1] = f[i][1] * m[i] + 0.5F; break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][1] = f[i][1]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { texcoord[i][1] = norm[1]; } break; } default: _mesa_problem(ctx, "Bad T texgen"); } } if (texUnit->TexGenEnabled & R_BIT) { GLuint i; switch (texUnit->GenR.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][2]), sizeof(out->data[0]), obj, texUnit->GenR.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][2]), sizeof(out->data[0]), eye, texUnit->GenR.EyePlane ); break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][2] = f[i][2]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) { texcoord[i][2] = norm[2]; } break; } default: _mesa_problem(ctx, "Bad R texgen"); } } if (texUnit->TexGenEnabled & Q_BIT) { switch (texUnit->GenQ.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][3]), sizeof(out->data[0]), obj, texUnit->GenQ.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][3]), sizeof(out->data[0]), eye, texUnit->GenQ.EyePlane ); break; default: _mesa_problem(ctx, "Bad Q texgen"); } } }
static GLboolean run_fog_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; struct fog_stage_data *store = FOG_STAGE_DATA(stage); GLvector4f *input; if (!ctx->Fog.Enabled) return GL_TRUE; if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT && !ctx->VertexProgram._Current) { GLuint i; GLfloat *coord; /* Fog is computed from vertex or fragment Z values */ /* source = VB->AttribPtr[_TNL_ATTRIB_POS] or VB->EyePtr coords */ /* dest = VB->AttribPtr[_TNL_ATTRIB_FOG] = fog stage private storage */ VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord; if (!ctx->_NeedEyeCoords) { /* compute fog coords from object coords */ const GLfloat *m = ctx->ModelviewMatrixStack.Top->m; GLfloat plane[4]; /* Use this to store calculated eye z values: */ input = &store->fogcoord; plane[0] = m[2]; plane[1] = m[6]; plane[2] = m[10]; plane[3] = m[14]; /* Full eye coords weren't required, just calculate the * eye Z values. */ _mesa_dotprod_tab[VB->AttribPtr[_TNL_ATTRIB_POS]->size] ( (GLfloat *) input->data, 4 * sizeof(GLfloat), VB->AttribPtr[_TNL_ATTRIB_POS], plane ); input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count; /* make sure coords are really positive NOTE should avoid going through array twice */ coord = input->start; for (i = 0; i < input->count; i++) { *coord = fabsf(*coord); STRIDE_F(coord, input->stride); } } else { /* fog coordinates = eye Z coordinates - need to copy for ABS */ input = &store->fogcoord; if (VB->EyePtr->size < 2) _mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 ); input->stride = 4 * sizeof(GLfloat); input->count = VB->EyePtr->count; coord = VB->EyePtr->start; for (i = 0 ; i < VB->EyePtr->count; i++) { input->data[i][0] = fabsf(coord[2]); STRIDE_F(coord, VB->EyePtr->stride); } } } else { /* use glFogCoord() coordinates */ input = VB->AttribPtr[_TNL_ATTRIB_FOG]; /* source data */ /* input->count may be one if glFogCoord was only called once * before glBegin. But we need to compute fog for all vertices. */ input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count; VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord; /* dest data */ } if (tnl->_DoVertexFog) { /* compute blend factors from fog coordinates */ compute_fog_blend_factors( ctx, VB->AttribPtr[_TNL_ATTRIB_FOG], input ); } else { /* results = incoming fog coords (compute fog per-fragment later) */ VB->AttribPtr[_TNL_ATTRIB_FOG] = input; } return GL_TRUE; }