/** * Do texture application for: * GL_EXT_texture_env_combine * GL_ARB_texture_env_combine * GL_EXT_texture_env_dot3 * GL_ARB_texture_env_dot3 * GL_ATI_texture_env_combine3 * GL_NV_texture_env_combine4 * conventional GL texture env modes * * \param ctx rendering context * \param unit the texture combiner unit * \param primary_rgba incoming fragment color array * \param texelBuffer pointer to texel colors for all texture units * * \param span two fields are used in this function: * span->end: number of fragments to process * span->array->rgba: incoming/result fragment colors */ static void texture_combine( struct gl_context *ctx, GLuint unit, const float4_array primary_rgba, const GLfloat *texelBuffer, SWspan *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]); const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine; float4_array argRGB[MAX_COMBINER_TERMS]; float4_array argA[MAX_COMBINER_TERMS]; const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB); const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA); const GLuint numArgsRGB = combine->_NumArgsRGB; const GLuint numArgsA = combine->_NumArgsA; float4_array ccolor[4], rgba; GLuint i, term; GLuint n = span->end; GLchan (*rgbaChan)[4] = span->array->rgba; /* alloc temp pixel buffers */ rgba = malloc(4 * n * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); return; } for (i = 0; i < numArgsRGB || i < numArgsA; i++) { ccolor[i] = malloc(4 * n * sizeof(GLfloat)); if (!ccolor[i]) { while (i) { free(ccolor[i]); i--; } _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); free(rgba); return; } } for (i = 0; i < n; i++) { rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]); rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]); rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]); rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]); } /* printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n", combine->ModeRGB, combine->ModeA, combine->SourceRGB[0], combine->SourceA[0], combine->SourceRGB[1], combine->SourceA[1]); */ /* * Do operand setup for up to 4 operands. Loop over the terms. */ for (term = 0; term < numArgsRGB; term++) { const GLenum srcRGB = combine->SourceRGB[term]; const GLenum operandRGB = combine->OperandRGB[term]; switch (srcRGB) { case GL_TEXTURE: argRGB[term] = get_texel_array(swrast, unit); break; case GL_PRIMARY_COLOR: argRGB[term] = primary_rgba; break; case GL_PREVIOUS: argRGB[term] = rgba; break; case GL_CONSTANT: { float4_array c = ccolor[term]; GLfloat red = textureUnit->EnvColor[0]; GLfloat green = textureUnit->EnvColor[1]; GLfloat blue = textureUnit->EnvColor[2]; GLfloat alpha = textureUnit->EnvColor[3]; for (i = 0; i < n; i++) { ASSIGN_4V(c[i], red, green, blue, alpha); } argRGB[term] = ccolor[term]; } break; /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. */ case GL_ZERO: { float4_array c = ccolor[term]; for (i = 0; i < n; i++) { ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F); } argRGB[term] = ccolor[term]; } break; case GL_ONE: { float4_array c = ccolor[term]; for (i = 0; i < n; i++) { ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F); } argRGB[term] = ccolor[term]; } break; default: /* ARB_texture_env_crossbar source */ { const GLuint srcUnit = srcRGB - GL_TEXTURE0; ASSERT(srcUnit < ctx->Const.MaxTextureUnits); if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) goto end; argRGB[term] = get_texel_array(swrast, srcUnit); } } if (operandRGB != GL_SRC_COLOR) { float4_array src = argRGB[term]; float4_array dst = ccolor[term]; /* point to new arg[term] storage */ argRGB[term] = ccolor[term]; switch (operandRGB) { case GL_ONE_MINUS_SRC_COLOR: for (i = 0; i < n; i++) { dst[i][RCOMP] = 1.0F - src[i][RCOMP]; dst[i][GCOMP] = 1.0F - src[i][GCOMP]; dst[i][BCOMP] = 1.0F - src[i][BCOMP]; } break; case GL_SRC_ALPHA: for (i = 0; i < n; i++) { dst[i][RCOMP] = dst[i][GCOMP] = dst[i][BCOMP] = src[i][ACOMP]; } break; case GL_ONE_MINUS_SRC_ALPHA: for (i = 0; i < n; i++) { dst[i][RCOMP] = dst[i][GCOMP] = dst[i][BCOMP] = 1.0F - src[i][ACOMP]; } break; default: _mesa_problem(ctx, "Bad operandRGB"); } } } /* * Set up the argA[term] pointers */ for (term = 0; term < numArgsA; term++) { const GLenum srcA = combine->SourceA[term]; const GLenum operandA = combine->OperandA[term]; switch (srcA) { case GL_TEXTURE: argA[term] = get_texel_array(swrast, unit); break; case GL_PRIMARY_COLOR: argA[term] = primary_rgba; break; case GL_PREVIOUS: argA[term] = rgba; break; case GL_CONSTANT: { float4_array c = ccolor[term]; GLfloat alpha = textureUnit->EnvColor[3]; for (i = 0; i < n; i++) c[i][ACOMP] = alpha; argA[term] = ccolor[term]; } break; /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources. */ case GL_ZERO: { float4_array c = ccolor[term]; for (i = 0; i < n; i++) c[i][ACOMP] = 0.0F; argA[term] = ccolor[term]; } break; case GL_ONE: { float4_array c = ccolor[term]; for (i = 0; i < n; i++) c[i][ACOMP] = 1.0F; argA[term] = ccolor[term]; } break; default: /* ARB_texture_env_crossbar source */ { const GLuint srcUnit = srcA - GL_TEXTURE0; ASSERT(srcUnit < ctx->Const.MaxTextureUnits); if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled) goto end; argA[term] = get_texel_array(swrast, srcUnit); } } if (operandA == GL_ONE_MINUS_SRC_ALPHA) { float4_array src = argA[term]; float4_array dst = ccolor[term]; argA[term] = ccolor[term]; for (i = 0; i < n; i++) { dst[i][ACOMP] = 1.0F - src[i][ACOMP]; } } } /* RGB channel combine */ { float4_array arg0 = argRGB[0]; float4_array arg1 = argRGB[1]; float4_array arg2 = argRGB[2]; float4_array arg3 = argRGB[3]; switch (combine->ModeRGB) { case GL_REPLACE: for (i = 0; i < n; i++) { rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB; rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB; rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB; } break; case GL_MODULATE: for (i = 0; i < n; i++) { rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB; rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB; rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB; } break; case GL_ADD: if (textureUnit->EnvMode == GL_COMBINE4_NV) { /* (a * b) + (c * d) */ for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB; } } else { /* 2-term addition */ for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB; } } break; case GL_ADD_SIGNED: if (textureUnit->EnvMode == GL_COMBINE4_NV) { /* (a * b) + (c * d) - 0.5 */ for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] + arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] + arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] + arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB; } } else { for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB; } } break; case GL_INTERPOLATE: for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] + arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] + arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] + arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB; } break; case GL_SUBTRACT: for (i = 0; i < n; i++) { rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB; rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB; rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB; } break; case GL_DOT3_RGB_EXT: case GL_DOT3_RGBA_EXT: /* Do not scale the result by 1 2 or 4 */ for (i = 0; i < n; i++) { GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) * 4.0F; dot = CLAMP(dot, 0.0F, 1.0F); rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; } break; case GL_DOT3_RGB: case GL_DOT3_RGBA: /* DO scale the result by 1 2 or 4 */ for (i = 0; i < n; i++) { GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) + (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) + (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F)) * 4.0F * scaleRGB; dot = CLAMP(dot, 0.0F, 1.0F); rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot; } break; case GL_MODULATE_ADD_ATI: for (i = 0; i < n; i++) { rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP]) * scaleRGB; rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP]) * scaleRGB; rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP]) * scaleRGB; } break; case GL_MODULATE_SIGNED_ADD_ATI: for (i = 0; i < n; i++) { rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP] - 0.5F) * scaleRGB; rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP] - 0.5F) * scaleRGB; rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP] - 0.5F) * scaleRGB; } break; case GL_MODULATE_SUBTRACT_ATI: for (i = 0; i < n; i++) { rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) - arg1[i][RCOMP]) * scaleRGB; rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) - arg1[i][GCOMP]) * scaleRGB; rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) - arg1[i][BCOMP]) * scaleRGB; } break; case GL_BUMP_ENVMAP_ATI: /* this produces a fixed rgba color, and the coord calc is done elsewhere */ for (i = 0; i < n; i++) { /* rgba result is 0,0,0,1 */ rgba[i][RCOMP] = 0.0; rgba[i][GCOMP] = 0.0; rgba[i][BCOMP] = 0.0; rgba[i][ACOMP] = 1.0; } goto end; /* no alpha processing */ default: _mesa_problem(ctx, "invalid combine mode"); } } /* Alpha channel combine */ { float4_array arg0 = argA[0]; float4_array arg1 = argA[1]; float4_array arg2 = argA[2]; float4_array arg3 = argA[3]; switch (combine->ModeA) { case GL_REPLACE: for (i = 0; i < n; i++) { rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA; } break; case GL_MODULATE: for (i = 0; i < n; i++) { rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA; } break; case GL_ADD: if (textureUnit->EnvMode == GL_COMBINE4_NV) { /* (a * b) + (c * d) */ for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA; } } else { /* two-term add */ for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA; } } break; case GL_ADD_SIGNED: if (textureUnit->EnvMode == GL_COMBINE4_NV) { /* (a * b) + (c * d) - 0.5 */ for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] + arg2[i][ACOMP] * arg3[i][ACOMP] - 0.5F) * scaleA; } } else { /* a + b - 0.5 */ for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA; } } break; case GL_INTERPOLATE: for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] + arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP])) * scaleA; } break; case GL_SUBTRACT: for (i = 0; i < n; i++) { rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA; } break; case GL_MODULATE_ADD_ATI: for (i = 0; i < n; i++) { rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP]) * scaleA; } break; case GL_MODULATE_SIGNED_ADD_ATI: for (i = 0; i < n; i++) { rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP] - 0.5F) * scaleA; } break; case GL_MODULATE_SUBTRACT_ATI: for (i = 0; i < n; i++) { rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) - arg1[i][ACOMP]) * scaleA; } break; default: _mesa_problem(ctx, "invalid combine mode"); } } /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining. * This is kind of a kludge. It would have been better if the spec * were written such that the GL_COMBINE_ALPHA value could be set to * GL_DOT3. */ if (combine->ModeRGB == GL_DOT3_RGBA_EXT || combine->ModeRGB == GL_DOT3_RGBA) { for (i = 0; i < n; i++) { rgba[i][ACOMP] = rgba[i][RCOMP]; } } for (i = 0; i < n; i++) { UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]); UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]); UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]); UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]); } /* The span->array->rgba values are of CHAN type so set * span->array->ChanType field accordingly. */ span->array->ChanType = CHAN_TYPE; end: for (i = 0; i < numArgsRGB || i < numArgsA; i++) { free(ccolor[i]); } free(rgba); }
/** * Apply fog to a span of RGBA pixels. * The fog value are either in the span->array->fog array or interpolated from * the fog/fogStep values. * They fog values are either fog coordinates (Z) or fog blend factors. * _PreferPixelFog should be in sync with that state! */ void _swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span ) { const SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLchan rFog = swrast->_FogColor[RCOMP]; const GLchan gFog = swrast->_FogColor[GCOMP]; const GLchan bFog = swrast->_FogColor[BCOMP]; const GLuint haveW = (span->interpMask & SPAN_W); GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba; ASSERT(swrast->_FogEnabled); ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG); ASSERT(span->arrayMask & SPAN_RGBA); /* NOTE: if haveW is true, that means the fog start/step values are * perspective-corrected and we have to divide each fog coord by W. */ /* we need to compute fog blend factors */ if (swrast->_PreferPixelFog) { /* The span's fog values are fog coordinates, now compute blend factors * and blend the fragment colors with the fog color. */ switch (swrast->_FogMode) { case GL_LINEAR: { const GLfloat fogEnd = ctx->Fog.End; const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End) ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start); const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f, oneMinusF; f = (fogEnd - fogCoord / w) * fogScale; f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; case GL_EXP: { const GLfloat density = -ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f, oneMinusF; f = (GLfloat) exp(density * fogCoord / w); f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; case GL_EXP2: { const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { const GLfloat coord = fogCoord / w; GLfloat tmp = negDensitySquared * coord * coord; GLfloat f, oneMinusF; #if defined(__alpha__) || defined(__alpha) /* XXX this underflow check may be needed for other systems*/ if (tmp < FLT_MIN_10_EXP) tmp = FLT_MIN_10_EXP; #endif f = (GLfloat) exp(tmp); f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; default: _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span"); return; } } else if (span->arrayMask & SPAN_FOG) { /* The span's fog array values are blend factors. * They were previously computed per-vertex. */ GLuint i; for (i = 0; i < span->end; i++) { const GLfloat f = span->array->fog[i]; const GLfloat oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); } } else { /* The span's fog start/step values are blend factors. * They were previously computed per-vertex. */ const GLfloat fogStep = span->fogStep; GLfloat fog = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; ASSERT(span->interpMask & SPAN_FOG); for (i = 0; i < span->end; i++) { const GLfloat fact = fog / w; const GLfloat oneMinusF = 1.0F - fact; rgba[i][RCOMP] = (GLchan) (fact * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (fact * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (fact * rgba[i][BCOMP] + oneMinusF * bFog); fog += fogStep; w += wStep; } } }