/** * Fetch a texel with given lod. * Called via machine->FetchTexelLod() */ static void fetch_texel_lod( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda, GLuint unit, GLfloat color[4] ) { const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; if (texObj) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLchan rgba[4]; lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod); /* XXX use a float-valued TextureSample routine here!!! */ swrast->TextureSample[unit](ctx, texObj, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); color[0] = CHAN_TO_FLOAT(rgba[0]); color[1] = CHAN_TO_FLOAT(rgba[1]); color[2] = CHAN_TO_FLOAT(rgba[2]); color[3] = CHAN_TO_FLOAT(rgba[3]); } else { color[0] = color[1] = color[2] = 0.0F; color[3] = 1.0F; } }
static void feedback_vertex( GLcontext *ctx, const SWvertex *v, const SWvertex *pv ) { const GLuint texUnit = 0; /* See section 5.3 of 1.2.1 spec */ GLfloat win[4]; GLfloat color[4]; GLfloat tc[4]; win[0] = v->win[0]; win[1] = v->win[1]; win[2] = v->win[2] / ctx->DepthMaxF; win[3] = 1.0F / v->win[3]; color[0] = CHAN_TO_FLOAT(pv->color[0]); color[1] = CHAN_TO_FLOAT(pv->color[1]); color[2] = CHAN_TO_FLOAT(pv->color[2]); color[3] = CHAN_TO_FLOAT(pv->color[3]); if (v->texcoord[texUnit][3] != 1.0 && v->texcoord[texUnit][3] != 0.0) { GLfloat invq = 1.0F / v->texcoord[texUnit][3]; tc[0] = v->texcoord[texUnit][0] * invq; tc[1] = v->texcoord[texUnit][1] * invq; tc[2] = v->texcoord[texUnit][2] * invq; tc[3] = v->texcoord[texUnit][3]; } else { COPY_4V(tc, v->texcoord[texUnit]); } _mesa_feedback_vertex( ctx, win, color, (GLfloat) v->index, tc ); }
/** * Fetch a texel with the given partial derivatives to compute a level * of detail in the mipmap. */ static void fetch_texel_deriv( GLcontext *ctx, const GLfloat texcoord[4], const GLfloat texdx[4], const GLfloat texdy[4], GLfloat lodBias, GLuint unit, GLfloat color[4] ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; GLfloat lambda; GLchan rgba[4]; if (texObj) { const struct gl_texture_image *texImg = texObj->Image[0][texObj->BaseLevel]; const GLfloat texW = (GLfloat) texImg->WidthScale; const GLfloat texH = (GLfloat) texImg->HeightScale; lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */ texdx[1], texdy[1], /* dt/dx, dt/dy */ texdx[3], texdy[2], /* dq/dx, dq/dy */ texW, texH, texcoord[0], texcoord[1], texcoord[3], 1.0F / texcoord[3]) + lodBias; lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod); } swrast->TextureSample[unit](ctx, texObj, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); color[0] = CHAN_TO_FLOAT(rgba[0]); color[1] = CHAN_TO_FLOAT(rgba[1]); color[2] = CHAN_TO_FLOAT(rgba[2]); color[3] = CHAN_TO_FLOAT(rgba[3]); }
/** * Convert GLchan[n][4] colors to GLfloat[n][4]. * XXX maybe move into image.c */ static void chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4]) { GLuint i; for (i = 0; i < n; i++) { out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]); out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]); out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]); out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]); } }
static void extract_4chan_4f_rgba( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) { GLchan *c = (GLchan *)v; (void) a; out[0] = CHAN_TO_FLOAT(c[0]); out[1] = CHAN_TO_FLOAT(c[1]); out[2] = CHAN_TO_FLOAT(c[2]); out[3] = CHAN_TO_FLOAT(c[3]); }
void _mesa_fetch_texel_2d_f_rgba_dxt5(const struct gl_texture_image *texImage, GLint i, GLint j, GLint k, GLfloat *texel) { /* just sample as GLchan and convert to float here */ GLchan rgba[4]; fetch_texel_2d_rgba_dxt5(texImage, i, j, k, rgba); texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]); texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]); texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]); texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]); }
static void init_machine(GLcontext * ctx, struct atifs_machine *machine, const struct ati_fragment_shader *shader, const struct sw_span *span, GLuint col) { GLint i, j; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) ctx->ATIFragmentShader.Machine.Registers[i][j] = 0.0; } ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_PRIMARY][0] = CHAN_TO_FLOAT(span->array->rgba[col][0]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_PRIMARY][1] = CHAN_TO_FLOAT(span->array->rgba[col][1]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_PRIMARY][2] = CHAN_TO_FLOAT(span->array->rgba[col][2]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_PRIMARY][3] = CHAN_TO_FLOAT(span->array->rgba[col][3]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_SECONDARY][0] = CHAN_TO_FLOAT(span->array->spec[col][0]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_SECONDARY][1] = CHAN_TO_FLOAT(span->array->spec[col][1]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_SECONDARY][2] = CHAN_TO_FLOAT(span->array->spec[col][2]); ctx->ATIFragmentShader.Machine.Inputs[ATI_FS_INPUT_SECONDARY][3] = CHAN_TO_FLOAT(span->array->spec[col][3]); ctx->ATIFragmentShader.Machine.pass = 0; }
static void TEX( void *cc, const float *texcoord, int unit, float *result ) { GLcontext *ctx = (GLcontext *)cc; SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat lambda = 1.0; /* hack */ GLchan rgba[4]; swrast->TextureSample[unit](ctx, unit, ctx->Texture.Unit[unit]._Current, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); result[0] = CHAN_TO_FLOAT(rgba[0]); result[1] = CHAN_TO_FLOAT(rgba[1]); result[2] = CHAN_TO_FLOAT(rgba[2]); result[3] = CHAN_TO_FLOAT(rgba[3]); }
/** * Fetch a texel. */ static void fetch_texel(GLcontext * ctx, const GLfloat texcoord[4], GLfloat lambda, GLuint unit, GLfloat color[4]) { GLchan rgba[4]; SWcontext *swrast = SWRAST_CONTEXT(ctx); /* XXX use a float-valued TextureSample routine here!!! */ swrast->TextureSample[unit] (ctx, unit, ctx->Texture.Unit[unit]._Current, 1, (const GLfloat(*)[4]) texcoord, &lambda, &rgba); color[0] = CHAN_TO_FLOAT(rgba[0]); color[1] = CHAN_TO_FLOAT(rgba[1]); color[2] = CHAN_TO_FLOAT(rgba[2]); color[3] = CHAN_TO_FLOAT(rgba[3]); }
/** * Add specular color to primary color, draw point, restore original * primary color. */ void _swrast_add_spec_terms_point(GLcontext *ctx, const SWvertex *v0) { SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */ GLfloat rSum, gSum, bSum; GLchan cSave[4]; /* save */ COPY_CHAN4(cSave, ncv0->color); /* sum */ rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0]; gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1]; bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2]; UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum); UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum); UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum); /* draw */ SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0); /* restore */ COPY_CHAN4(ncv0->color, cSave); }
void _swrast_add_spec_terms_line(struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1) { SWvertex *ncv0 = (SWvertex *)v0; SWvertex *ncv1 = (SWvertex *)v1; GLfloat rSum, gSum, bSum; GLchan cSave[2][4]; /* save original colors */ COPY_CHAN4(cSave[0], ncv0->color); COPY_CHAN4(cSave[1], ncv1->color); /* sum v0 */ rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0]; gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1]; bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2]; UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum); UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum); UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum); /* sum v1 */ rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0]; gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1]; bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2]; UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum); UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum); UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum); /* draw */ SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 ); /* restore original colors */ COPY_CHAN4( ncv0->attrib[FRAG_ATTRIB_COL0], cSave[0] ); COPY_CHAN4( ncv1->attrib[FRAG_ATTRIB_COL0], cSave[1] ); }
/** * Adaptor for fetching a float texel from a GLchan-valued texture. */ static void fetch_texel_chan_to_float(const struct gl_texture_image *texImage, GLint i, GLint j, GLint k, GLfloat *texelOut) { GLchan temp[4]; GLenum baseFormat = _mesa_get_format_base_format(texImage->TexFormat); ASSERT(texImage->FetchTexelc); texImage->FetchTexelc(texImage, i, j, k, temp); if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL_EXT) { /* just one channel */ texelOut[0] = CHAN_TO_FLOAT(temp[0]); } else { /* four channels */ texelOut[0] = CHAN_TO_FLOAT(temp[0]); texelOut[1] = CHAN_TO_FLOAT(temp[1]); texelOut[2] = CHAN_TO_FLOAT(temp[2]); texelOut[3] = CHAN_TO_FLOAT(temp[3]); } }
static void TXB( void *cc, const float *texcoord, int unit, float *result ) { GLcontext *ctx = (GLcontext *)cc; SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat lambda = 1.0; /* hack */ GLchan rgba[4]; /* texcoord[3] is the bias to add to lambda */ lambda += texcoord[3]; /* Is it necessary to reset texcoord[3] to 1 at this point? */ swrast->TextureSample[unit](ctx, unit, ctx->Texture.Unit[unit]._Current, 1, (const GLfloat (*)[4]) texcoord, &lambda, &rgba); result[0] = CHAN_TO_FLOAT(rgba[0]); result[1] = CHAN_TO_FLOAT(rgba[1]); result[2] = CHAN_TO_FLOAT(rgba[2]); result[3] = CHAN_TO_FLOAT(rgba[3]); }
/* * Convert RGBA values into strq texture coordinates. */ void _mesa_pixeltexgen(GLcontext *ctx, GLuint n, const GLchan rgba[][4], GLfloat s[], GLfloat t[], GLfloat r[], GLfloat q[]) { if (ctx->Pixel.FragmentRgbSource == GL_CURRENT_RASTER_COLOR) { GLuint i; for (i = 0; i < n; i++) { s[i] = ctx->Current.RasterColor[RCOMP]; t[i] = ctx->Current.RasterColor[GCOMP]; r[i] = ctx->Current.RasterColor[BCOMP]; } } else { GLuint i; ASSERT(ctx->Pixel.FragmentRgbSource == GL_PIXEL_GROUP_COLOR_SGIS); for (i = 0; i < n; i++) { s[i] = CHAN_TO_FLOAT(rgba[i][RCOMP]); t[i] = CHAN_TO_FLOAT(rgba[i][GCOMP]); r[i] = CHAN_TO_FLOAT(rgba[i][BCOMP]); } } if (ctx->Pixel.FragmentAlphaSource == GL_CURRENT_RASTER_COLOR) { GLuint i; for (i = 0; i < n; i++) { q[i] = ctx->Current.RasterColor[ACOMP]; } } else { GLuint i; ASSERT(ctx->Pixel.FragmentAlphaSource == GL_PIXEL_GROUP_COLOR_SGIS); for (i = 0; i < n; i++) { q[i] = CHAN_TO_FLOAT(rgba[i][ACOMP]); } } }
/** * Apply texture mapping to a span of fragments. */ void _swrast_texture_span( GLcontext *ctx, SWspan *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat primary_rgba[MAX_WIDTH][4]; GLuint unit; ASSERT(span->end <= MAX_WIDTH); /* * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) */ if (swrast->_TextureCombinePrimary) { GLuint i; for (i = 0; i < span->end; i++) { primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); } } /* First must sample all bump maps */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; float4_array targetcoords = span->array->attribs[FRAG_ATTRIB_TEX0 + ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0]; const struct gl_texture_object *curObj = texUnit->_Current; GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); GLuint i; GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0]; GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1]; GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2]; GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3]; /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + curObj->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = curObj->MinLod; const GLfloat max = curObj->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, texcoords, lambda, texels ); /* manipulate the span values of the bump target not sure this can work correctly even ignoring the problem that channel is unsigned */ for (i = 0; i < span->end; i++) { targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] * rotMatrix01) / targetcoords[i][3]; targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] * rotMatrix11) / targetcoords[i][3]; } } } /* * Must do all texture sampling before combining in order to * accomodate GL_ARB_texture_env_crossbar. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[FRAG_ATTRIB_TEX0 + unit]; const struct gl_texture_object *curObj = texUnit->_Current; GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + curObj->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = curObj->MinLod; const GLfloat max = curObj->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, texUnit->_Current, span->end, texcoords, lambda, texels ); /* GL_SGI_texture_color_table */ if (texUnit->ColorTableEnabled) { _mesa_lookup_rgba_float(&texUnit->ColorTable, span->end, texels); } /* GL_EXT_texture_swizzle */ if (curObj->_Swizzle != SWIZZLE_NOOP) { swizzle_texels(curObj->_Swizzle, span->end, texels); } } } /* * OK, now apply the texture (aka texture combine/blend). * We modify the span->color.rgba values. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { if (ctx->Texture.Unit[unit]._ReallyEnabled) { texture_combine( ctx, unit, span->end, primary_rgba, swrast->TexelBuffer, span->array->rgba ); } } }
/** * 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 texture mapping to a span of fragments. */ void _swrast_texture_span( struct gl_context *ctx, SWspan *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); float4_array primary_rgba; GLuint unit; if (!swrast->TexelBuffer) { #ifdef _OPENMP const GLint maxThreads = omp_get_max_threads(); #else const GLint maxThreads = 1; #endif /* TexelBuffer is also global and normally shared by all SWspan * instances; when running with multiple threads, create one per * thread. */ swrast->TexelBuffer = malloc(ctx->Const.FragmentProgram.MaxTextureImageUnits * maxThreads * SWRAST_MAX_WIDTH * 4 * sizeof(GLfloat)); if (!swrast->TexelBuffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); return; } } primary_rgba = malloc(span->end * 4 * sizeof(GLfloat)); if (!primary_rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span"); return; } ASSERT(span->end <= SWRAST_MAX_WIDTH); /* * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) */ if (swrast->_TextureCombinePrimary) { GLuint i; for (i = 0; i < span->end; i++) { primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); } } /* First must sample all bump maps */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[VARYING_SLOT_TEX0 + unit]; float4_array targetcoords = span->array->attribs[VARYING_SLOT_TEX0 + ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0]; const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); GLuint i; GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0]; GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1]; GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2]; GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3]; /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + samp->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = samp->MinLod; const GLfloat max = samp->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, samp, ctx->Texture.Unit[unit]._Current, span->end, texcoords, lambda, texels ); /* manipulate the span values of the bump target not sure this can work correctly even ignoring the problem that channel is unsigned */ for (i = 0; i < span->end; i++) { targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] * rotMatrix01) / targetcoords[i][3]; targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] * rotMatrix11) / targetcoords[i][3]; } } } /* * Must do all texture sampling before combining in order to * accomodate GL_ARB_texture_env_crossbar. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; if (texUnit->_ReallyEnabled && texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[VARYING_SLOT_TEX0 + unit]; const struct gl_texture_object *curObj = texUnit->_Current; const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit); GLfloat *lambda = span->array->lambda[unit]; float4_array texels = get_texel_array(swrast, unit); /* adjust texture lod (lambda) */ if (span->arrayMask & SPAN_LAMBDA) { if (texUnit->LodBias + samp->LodBias != 0.0F) { /* apply LOD bias, but don't clamp yet */ const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias, -ctx->Const.MaxTextureLodBias, ctx->Const.MaxTextureLodBias); GLuint i; for (i = 0; i < span->end; i++) { lambda[i] += bias; } } if (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0) { /* apply LOD clamping to lambda */ const GLfloat min = samp->MinLod; const GLfloat max = samp->MaxLod; GLuint i; for (i = 0; i < span->end; i++) { GLfloat l = lambda[i]; lambda[i] = CLAMP(l, min, max); } } } else if (samp->MaxAnisotropy > 1.0 && samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) { /* sample_lambda_2d_aniso is beeing used as texture_sample_func, * it requires the current SWspan *span as an additional parameter. * In order to keep the same function signature, the unused lambda * parameter will be modified to actually contain the SWspan pointer. * This is a Hack. To make it right, the texture_sample_func * signature and all implementing functions need to be modified. */ /* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */ lambda = (GLfloat *)span; } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample[unit]( ctx, samp, ctx->Texture.Unit[unit]._Current, span->end, texcoords, lambda, texels ); /* GL_EXT_texture_swizzle */ if (curObj->_Swizzle != SWIZZLE_NOOP) { swizzle_texels(curObj->_Swizzle, span->end, texels); } } } /* * OK, now apply the texture (aka texture combine/blend). * We modify the span->color.rgba values. */ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { if (ctx->Texture.Unit[unit]._ReallyEnabled) texture_combine(ctx, unit, primary_rgba, swrast->TexelBuffer, span); } free(primary_rgba); }
static void pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) { GLuint u; for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { const struct gl_texture_unit *unit = &texAttrib->Unit[u]; GLuint i; _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u); _mesa_set_enable(ctx, GL_TEXTURE_1D, (GLboolean) (unit->Enabled & TEXTURE0_1D ? GL_TRUE : GL_FALSE)); _mesa_set_enable(ctx, GL_TEXTURE_2D, (GLboolean) (unit->Enabled & TEXTURE0_2D ? GL_TRUE : GL_FALSE)); _mesa_set_enable(ctx, GL_TEXTURE_3D, (GLboolean) (unit->Enabled & TEXTURE0_3D ? GL_TRUE : GL_FALSE)); if (ctx->Extensions.ARB_texture_cube_map) { _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, (GLboolean) (unit->Enabled & TEXTURE0_CUBE ? GL_TRUE : GL_FALSE)); } if (ctx->Extensions.NV_texture_rectangle) { _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, (GLboolean) (unit->Enabled & TEXTURE0_RECT ? GL_TRUE : GL_FALSE)); } _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); _mesa_TexGeni(GL_S, GL_TEXTURE_GEN_MODE, unit->GenModeS); _mesa_TexGeni(GL_T, GL_TEXTURE_GEN_MODE, unit->GenModeT); _mesa_TexGeni(GL_R, GL_TEXTURE_GEN_MODE, unit->GenModeR); _mesa_TexGeni(GL_Q, GL_TEXTURE_GEN_MODE, unit->GenModeQ); _mesa_TexGenfv(GL_S, GL_OBJECT_PLANE, unit->ObjectPlaneS); _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->ObjectPlaneT); _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->ObjectPlaneR); _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->ObjectPlaneQ); _mesa_TexGenfv(GL_S, GL_EYE_PLANE, unit->EyePlaneS); _mesa_TexGenfv(GL_T, GL_EYE_PLANE, unit->EyePlaneT); _mesa_TexGenfv(GL_R, GL_EYE_PLANE, unit->EyePlaneR); _mesa_TexGenfv(GL_Q, GL_EYE_PLANE, unit->EyePlaneQ); if (ctx->Extensions.EXT_texture_lod_bias) { _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); } if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, unit->CombineModeRGB); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, unit->CombineModeA); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, unit->CombineSourceRGB[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, unit->CombineSourceRGB[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, unit->CombineSourceRGB[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, unit->CombineSourceA[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, unit->CombineSourceA[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, unit->CombineSourceA[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, unit->CombineOperandRGB[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, unit->CombineOperandRGB[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, unit->CombineOperandRGB[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, unit->CombineOperandA[0]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, unit->CombineOperandA[1]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, unit->CombineOperandA[2]); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1 << unit->CombineScaleShiftRGB); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 << unit->CombineScaleShiftA); } /* Restore texture object state */ for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { GLenum target = 0; const struct gl_texture_object *obj = NULL; GLfloat bordColor[4]; switch (i) { case 0: target = GL_TEXTURE_1D; obj = &unit->Saved1D; break; case 1: target = GL_TEXTURE_2D; obj = &unit->Saved2D; break; case 2: target = GL_TEXTURE_3D; obj = &unit->Saved3D; break; case 3: if (!ctx->Extensions.ARB_texture_cube_map) continue; target = GL_TEXTURE_CUBE_MAP_ARB; obj = &unit->SavedCubeMap; break; case 4: if (!ctx->Extensions.NV_texture_rectangle) continue; target = GL_TEXTURE_RECTANGLE_NV; obj = &unit->SavedRect; break; default: ; /* silence warnings */ } _mesa_BindTexture(target, obj->Name); bordColor[0] = CHAN_TO_FLOAT(obj->BorderColor[0]); bordColor[1] = CHAN_TO_FLOAT(obj->BorderColor[1]); bordColor[2] = CHAN_TO_FLOAT(obj->BorderColor[2]); bordColor[3] = CHAN_TO_FLOAT(obj->BorderColor[3]); _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority); _mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, bordColor); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT); _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR); _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, obj->MinFilter); _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); if (ctx->Extensions.EXT_texture_filter_anisotropic) { _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, obj->MaxAnisotropy); } if (ctx->Extensions.SGIX_shadow) { _mesa_TexParameteri(target, GL_TEXTURE_COMPARE_SGIX, obj->CompareFlag); _mesa_TexParameteri(target, GL_TEXTURE_COMPARE_OPERATOR_SGIX, obj->CompareOperator); } if (ctx->Extensions.SGIX_shadow_ambient) { _mesa_TexParameterf(target, GL_SHADOW_AMBIENT_SGIX, CHAN_TO_FLOAT(obj->ShadowAmbient)); } } } _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texAttrib->CurrentUnit); /* "un-bump" the texture object reference counts. We did that so they * wouldn't inadvertantly get deleted while they were still referenced * inside the attribute state stack. */ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { ctx->Texture.Unit[u].Current1D->RefCount--; ctx->Texture.Unit[u].Current2D->RefCount--; ctx->Texture.Unit[u].Current3D->RefCount--; ctx->Texture.Unit[u].CurrentCubeMap->RefCount--; ctx->Texture.Unit[u].CurrentRect->RefCount--; } }
/* * This function is kind of long just because we have to call a lot * of device driver functions to update device driver state. * * XXX As it is now, most of the pop-code calls immediate-mode Mesa functions * in order to restore GL state. This isn't terribly efficient but it * ensures that dirty flags and any derived state gets updated correctly. * We could at least check if the value to restore equals the current value * and then skip the Mesa call. */ void _mesa_PopAttrib(void) { struct gl_attrib_node *attr, *next; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (ctx->AttribStackDepth == 0) { _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopAttrib" ); return; } ctx->AttribStackDepth--; attr = ctx->AttribStack[ctx->AttribStackDepth]; while (attr) { if (MESA_VERBOSE&VERBOSE_API) { fprintf(stderr, "glPopAttrib %s\n", _mesa_lookup_enum_by_nr(attr->kind)); } switch (attr->kind) { case GL_ACCUM_BUFFER_BIT: { const struct gl_accum_attrib *accum; accum = (const struct gl_accum_attrib *) attr->data; _mesa_ClearAccum(accum->ClearColor[0], accum->ClearColor[1], accum->ClearColor[2], accum->ClearColor[3]); } break; case GL_COLOR_BUFFER_BIT: { const struct gl_colorbuffer_attrib *color; color = (const struct gl_colorbuffer_attrib *) attr->data; _mesa_ClearIndex((GLfloat) color->ClearIndex); _mesa_ClearColor(CHAN_TO_FLOAT(color->ClearColor[0]), CHAN_TO_FLOAT(color->ClearColor[1]), CHAN_TO_FLOAT(color->ClearColor[2]), CHAN_TO_FLOAT(color->ClearColor[3])); _mesa_IndexMask(color->IndexMask); _mesa_ColorMask((GLboolean) (color->ColorMask[0] != 0), (GLboolean) (color->ColorMask[1] != 0), (GLboolean) (color->ColorMask[2] != 0), (GLboolean) (color->ColorMask[3] != 0)); _mesa_DrawBuffer(color->DrawBuffer); _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); _mesa_AlphaFunc(color->AlphaFunc, CHAN_TO_FLOAT(color->AlphaRef)); _mesa_set_enable(ctx, GL_BLEND, color->BlendEnabled); _mesa_BlendFuncSeparateEXT(color->BlendSrcRGB, color->BlendDstRGB, color->BlendSrcA, color->BlendDstA); _mesa_BlendEquation(color->BlendEquation); _mesa_BlendColor(color->BlendColor[0], color->BlendColor[1], color->BlendColor[2], color->BlendColor[3]); _mesa_LogicOp(color->LogicOp); _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, color->ColorLogicOpEnabled); _mesa_set_enable(ctx, GL_INDEX_LOGIC_OP, color->IndexLogicOpEnabled); _mesa_set_enable(ctx, GL_DITHER, color->DitherFlag); } break; case GL_CURRENT_BIT: FLUSH_CURRENT( ctx, 0 ); MEMCPY( &ctx->Current, attr->data, sizeof(struct gl_current_attrib) ); break; case GL_DEPTH_BUFFER_BIT: { const struct gl_depthbuffer_attrib *depth; depth = (const struct gl_depthbuffer_attrib *) attr->data; _mesa_DepthFunc(depth->Func); _mesa_ClearDepth(depth->Clear); _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); _mesa_DepthMask(depth->Mask); if (ctx->Extensions.HP_occlusion_test) _mesa_set_enable(ctx, GL_OCCLUSION_TEST_HP, depth->OcclusionTest); } break; case GL_ENABLE_BIT: { const struct gl_enable_attrib *enable; enable = (const struct gl_enable_attrib *) attr->data; pop_enable_group(ctx, enable); ctx->NewState |= _NEW_ALL; } break; case GL_EVAL_BIT: MEMCPY( &ctx->Eval, attr->data, sizeof(struct gl_eval_attrib) ); ctx->NewState |= _NEW_EVAL; break; case GL_FOG_BIT: { const struct gl_fog_attrib *fog; fog = (const struct gl_fog_attrib *) attr->data; _mesa_set_enable(ctx, GL_FOG, fog->Enabled); _mesa_Fogfv(GL_FOG_COLOR, fog->Color); _mesa_Fogf(GL_FOG_DENSITY, fog->Density); _mesa_Fogf(GL_FOG_START, fog->Start); _mesa_Fogf(GL_FOG_END, fog->End); _mesa_Fogf(GL_FOG_INDEX, fog->Index); _mesa_Fogi(GL_FOG_MODE, fog->Mode); } break; case GL_HINT_BIT: { const struct gl_hint_attrib *hint; hint = (const struct gl_hint_attrib *) attr->data; _mesa_Hint(GL_PERSPECTIVE_CORRECTION_HINT, hint->PerspectiveCorrection ); _mesa_Hint(GL_POINT_SMOOTH_HINT, hint->PointSmooth); _mesa_Hint(GL_LINE_SMOOTH_HINT, hint->LineSmooth); _mesa_Hint(GL_POLYGON_SMOOTH_HINT, hint->PolygonSmooth); _mesa_Hint(GL_FOG_HINT, hint->Fog); _mesa_Hint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, hint->ClipVolumeClipping); if (ctx->Extensions.ARB_texture_compression) _mesa_Hint(GL_TEXTURE_COMPRESSION_HINT_ARB, hint->TextureCompression); } break; case GL_LIGHTING_BIT: { GLuint i; const struct gl_light_attrib *light; light = (const struct gl_light_attrib *) attr->data; /* lighting enable */ _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); /* per-light state */ if (ctx->ModelView.flags & MAT_DIRTY_INVERSE) _math_matrix_analyse( &ctx->ModelView ); for (i = 0; i < MAX_LIGHTS; i++) { GLenum lgt = (GLenum) (GL_LIGHT0 + i); const struct gl_light *l = &light->Light[i]; GLfloat tmp[4]; _mesa_set_enable(ctx, lgt, l->Enabled); _mesa_Lightfv( lgt, GL_AMBIENT, l->Ambient ); _mesa_Lightfv( lgt, GL_DIFFUSE, l->Diffuse ); _mesa_Lightfv( lgt, GL_SPECULAR, l->Specular ); TRANSFORM_POINT( tmp, ctx->ModelView.inv, l->EyePosition ); _mesa_Lightfv( lgt, GL_POSITION, tmp ); TRANSFORM_POINT( tmp, ctx->ModelView.m, l->EyeDirection ); _mesa_Lightfv( lgt, GL_SPOT_DIRECTION, tmp ); _mesa_Lightfv( lgt, GL_SPOT_EXPONENT, &l->SpotExponent ); _mesa_Lightfv( lgt, GL_SPOT_CUTOFF, &l->SpotCutoff ); _mesa_Lightfv( lgt, GL_CONSTANT_ATTENUATION, &l->ConstantAttenuation ); _mesa_Lightfv( lgt, GL_LINEAR_ATTENUATION, &l->LinearAttenuation ); _mesa_Lightfv( lgt, GL_QUADRATIC_ATTENUATION, &l->QuadraticAttenuation ); } /* light model */ _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, light->Model.Ambient); _mesa_LightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, (GLfloat) light->Model.LocalViewer); _mesa_LightModelf(GL_LIGHT_MODEL_TWO_SIDE, (GLfloat) light->Model.TwoSide); _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, (GLfloat) light->Model.ColorControl); /* materials */ MEMCPY(ctx->Light.Material, light->Material, 2 * sizeof(struct gl_material)); /* shade model */ _mesa_ShadeModel(light->ShadeModel); /* color material */ _mesa_ColorMaterial(light->ColorMaterialFace, light->ColorMaterialMode); _mesa_set_enable(ctx, GL_COLOR_MATERIAL, light->ColorMaterialEnabled); } break; case GL_LINE_BIT: { const struct gl_line_attrib *line; line = (const struct gl_line_attrib *) attr->data; _mesa_set_enable(ctx, GL_LINE_SMOOTH, line->SmoothFlag); _mesa_set_enable(ctx, GL_LINE_STIPPLE, line->StippleFlag); _mesa_LineStipple(line->StippleFactor, line->StipplePattern); _mesa_LineWidth(line->Width); } break; case GL_LIST_BIT: MEMCPY( &ctx->List, attr->data, sizeof(struct gl_list_attrib) ); break; case GL_PIXEL_MODE_BIT: MEMCPY( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); ctx->NewState |= _NEW_PIXEL; break; case GL_POINT_BIT: { const struct gl_point_attrib *point; point = (const struct gl_point_attrib *) attr->data; _mesa_PointSize(point->Size); _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); if (ctx->Extensions.EXT_point_parameters) { _mesa_PointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, point->Params); _mesa_PointParameterfEXT(GL_POINT_SIZE_MIN_EXT, point->MinSize); _mesa_PointParameterfEXT(GL_POINT_SIZE_MAX_EXT, point->MaxSize); _mesa_PointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, point->Threshold); } } break; case GL_POLYGON_BIT: { const struct gl_polygon_attrib *polygon; polygon = (const struct gl_polygon_attrib *) attr->data; _mesa_CullFace(polygon->CullFaceMode); _mesa_FrontFace(polygon->FrontFace); _mesa_PolygonMode(GL_FRONT, polygon->FrontMode); _mesa_PolygonMode(GL_BACK, polygon->BackMode); _mesa_PolygonOffset(polygon->OffsetFactor, polygon->OffsetUnits); _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, polygon->SmoothFlag); _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, polygon->StippleFlag); _mesa_set_enable(ctx, GL_CULL_FACE, polygon->CullFlag); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_POINT, polygon->OffsetPoint); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_LINE, polygon->OffsetLine); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, polygon->OffsetFill); } break; case GL_POLYGON_STIPPLE_BIT: MEMCPY( ctx->PolygonStipple, attr->data, 32*sizeof(GLuint) ); ctx->NewState |= _NEW_POLYGONSTIPPLE; if (ctx->Driver.PolygonStipple) ctx->Driver.PolygonStipple( ctx, (const GLubyte *) attr->data ); break; case GL_SCISSOR_BIT: { const struct gl_scissor_attrib *scissor; scissor = (const struct gl_scissor_attrib *) attr->data; _mesa_Scissor(scissor->X, scissor->Y, scissor->Width, scissor->Height); _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissor->Enabled); } break; case GL_STENCIL_BUFFER_BIT: { const struct gl_stencil_attrib *stencil; stencil = (const struct gl_stencil_attrib *) attr->data; _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); _mesa_StencilFunc(stencil->Function, stencil->Ref, stencil->ValueMask); _mesa_StencilMask(stencil->WriteMask); _mesa_StencilOp(stencil->FailFunc, stencil->ZFailFunc, stencil->ZPassFunc); } break; case GL_TRANSFORM_BIT: { GLuint i; const struct gl_transform_attrib *xform; xform = (const struct gl_transform_attrib *) attr->data; _mesa_MatrixMode(xform->MatrixMode); if (ctx->ProjectionMatrix.flags & MAT_DIRTY) _math_matrix_analyse( &ctx->ProjectionMatrix ); /* restore clip planes */ for (i = 0; i < MAX_CLIP_PLANES; i++) { const GLfloat *eyePlane = xform->EyeUserPlane[i]; COPY_4V(ctx->Transform.EyeUserPlane[i], eyePlane); if (xform->ClipEnabled[i]) { _mesa_transform_vector( ctx->Transform._ClipUserPlane[i], eyePlane, ctx->ProjectionMatrix.inv ); _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE ); } else { _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE ); } if (ctx->Driver.ClipPlane) ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, eyePlane ); } /* normalize/rescale */ _mesa_set_enable(ctx, GL_NORMALIZE, ctx->Transform.Normalize); _mesa_set_enable(ctx, GL_RESCALE_NORMAL_EXT, ctx->Transform.RescaleNormals); } break; case GL_TEXTURE_BIT: /* Take care of texture object reference counters */ { const struct gl_texture_attrib *texture; texture = (const struct gl_texture_attrib *) attr->data; pop_texture_group(ctx, texture); ctx->NewState |= _NEW_TEXTURE; } break; case GL_VIEWPORT_BIT: { const struct gl_viewport_attrib *vp; vp = (const struct gl_viewport_attrib *) attr->data; _mesa_Viewport(vp->X, vp->Y, vp->Width, vp->Height); _mesa_DepthRange(vp->Near, vp->Far); } break; case GL_MULTISAMPLE_BIT_ARB: { const struct gl_multisample_attrib *ms; ms = (const struct gl_multisample_attrib *) attr->data; _mesa_SampleCoverageARB(ms->SampleCoverageValue, ms->SampleCoverageInvert); } break; default: _mesa_problem( ctx, "Bad attrib flag in PopAttrib"); break; } next = attr->next; FREE( attr->data ); FREE( attr ); attr = next; } }
/** * Apply texture mapping to a span of fragments. */ void _swrast_texture_span( struct gl_context *ctx, SWspan *span ) { SWcontext *swrast = SWRAST_CONTEXT(ctx); float4_array primary_rgba; if (!swrast->TexelBuffer) { #ifdef _OPENMP const GLint maxThreads = omp_get_max_threads(); #else const GLint maxThreads = 1; #endif /* TexelBuffer is also global and normally shared by all SWspan * instances; when running with multiple threads, create one per * thread. */ swrast->TexelBuffer = (GLfloat *) MALLOC(maxThreads * MAX_WIDTH * 4 * sizeof(GLfloat)); if (!swrast->TexelBuffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine"); return; } } primary_rgba = (float4_array) malloc(span->end * 4 * sizeof(GLfloat)); if (!primary_rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span"); return; } ASSERT(span->end <= MAX_WIDTH); /* * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR) */ if (swrast->_TextureCombinePrimary) { GLuint i; for (i = 0; i < span->end; i++) { primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]); primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]); primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]); primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]); } } /* * Must do all texture sampling before combining in order to * accomodate GL_ARB_texture_env_crossbar. */ { const struct gl_texture_unit *texUnit = &ctx->Texture.Unit; if (texUnit->_ReallyEnabled) { const GLfloat (*texcoords)[4] = (const GLfloat (*)[4]) span->array->attribs[FRAG_ATTRIB_TEX]; const struct gl_texture_object *curObj = texUnit->_Current; GLfloat *lambda = span->array->lambda; float4_array texels = get_texel_array(swrast); if (curObj->Sampler.MaxAnisotropy > 1.0 && curObj->Sampler.MinFilter == GL_LINEAR_MIPMAP_LINEAR) { /* sample_lambda_2d_aniso is beeing used as texture_sample_func, * it requires the current SWspan *span as an additional parameter. * In order to keep the same function signature, the unused lambda * parameter will be modified to actually contain the SWspan pointer. * This is a Hack. To make it right, the texture_sample_func * signature and all implementing functions need to be modified. */ /* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */ lambda = (GLfloat *)span; } /* Sample the texture (span->end = number of fragments) */ swrast->TextureSample( ctx, texUnit->_Current, span->end, texcoords, lambda, texels ); } } /* * OK, now apply the texture (aka texture combine/blend). * We modify the span->color.rgba values. */ if (ctx->Texture.Unit._ReallyEnabled) texture_combine(ctx, primary_rgba, swrast->TexelBuffer, span); free(primary_rgba); }