/* * Mesa 3-D graphics library * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * Antialiased line template. */ /* * Function to render each fragment in the AA line. * \param ix - integer fragment window X coordiante * \param iy - integer fragment window Y coordiante */ static void NAME(plot)(struct gl_context *ctx, struct LineInfo *line, int ix, int iy) { const SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLfloat fx = (GLfloat) ix; const GLfloat fy = (GLfloat) iy; const GLfloat coverage = compute_coveragef(line, ix, iy); const GLuint i = line->span.end; (void) swrast; if (coverage == 0.0) return; line->span.end++; line->span.array->coverage[i] = coverage; line->span.array->x[i] = ix; line->span.array->y[i] = iy; /* * Compute Z, color, texture coords, fog for the fragment by * solving the plane equations at (ix,iy). */ #ifdef DO_Z line->span.array->z[i] = (GLuint) solve_plane(fx, fy, line->zPlane); #endif line->span.array->rgba[i][RCOMP] = solve_plane_chan(fx, fy, line->rPlane); line->span.array->rgba[i][GCOMP] = solve_plane_chan(fx, fy, line->gPlane); line->span.array->rgba[i][BCOMP] = solve_plane_chan(fx, fy, line->bPlane); line->span.array->rgba[i][ACOMP] = solve_plane_chan(fx, fy, line->aPlane); #if defined(DO_ATTRIBS) ATTRIB_LOOP_BEGIN GLfloat (*attribArray)[4] = line->span.array->attribs[attr]; if (attr >= VARYING_SLOT_TEX0 && attr < VARYING_SLOT_VAR0 && !_swrast_use_fragment_program(ctx)) { /* texcoord w/ divide by Q */ const GLuint unit = attr - VARYING_SLOT_TEX0; const GLfloat invQ = solve_plane_recip(fx, fy, line->attrPlane[attr][3]); GLuint c; for (c = 0; c < 3; c++) { attribArray[i][c] = solve_plane(fx, fy, line->attrPlane[attr][c]) * invQ; } line->span.array->lambda[unit][i] = compute_lambda(line->attrPlane[attr][0], line->attrPlane[attr][1], invQ, line->texWidth[attr], line->texHeight[attr]); } else { /* non-texture attrib */ const GLfloat invW = solve_plane_recip(fx, fy, line->wPlane); GLuint c; for (c = 0; c < 4; c++) { attribArray[i][c] = solve_plane(fx, fy, line->attrPlane[attr][c]) * invW; } } ATTRIB_LOOP_END #endif if (line->span.end == SWRAST_MAX_WIDTH) { _swrast_write_rgba_span(ctx, &(line->span)); line->span.end = 0; /* reset counter */ } } /* * Line setup */ static void NAME(line)(struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1) { SWcontext *swrast = SWRAST_CONTEXT(ctx); GLfloat tStart, tEnd; /* segment start, end along line length */ GLboolean inSegment; GLint iLen, i; /* Init the LineInfo struct */ struct LineInfo line; line.x0 = v0->attrib[VARYING_SLOT_POS][0]; line.y0 = v0->attrib[VARYING_SLOT_POS][1]; line.x1 = v1->attrib[VARYING_SLOT_POS][0]; line.y1 = v1->attrib[VARYING_SLOT_POS][1]; line.dx = line.x1 - line.x0; line.dy = line.y1 - line.y0; line.len = sqrtf(line.dx * line.dx + line.dy * line.dy); line.halfWidth = 0.5F * CLAMP(ctx->Line.Width, ctx->Const.MinLineWidthAA, ctx->Const.MaxLineWidthAA); if (line.len == 0.0 || IS_INF_OR_NAN(line.len)) return; INIT_SPAN(line.span, GL_LINE); line.span.arrayMask = SPAN_XY | SPAN_COVERAGE; line.span.facing = swrast->PointLineFacing; line.xAdj = line.dx / line.len * line.halfWidth; line.yAdj = line.dy / line.len * line.halfWidth; #ifdef DO_Z line.span.arrayMask |= SPAN_Z; compute_plane(line.x0, line.y0, line.x1, line.y1, v0->attrib[VARYING_SLOT_POS][2], v1->attrib[VARYING_SLOT_POS][2], line.zPlane); #endif line.span.arrayMask |= SPAN_RGBA; if (ctx->Light.ShadeModel == GL_SMOOTH) { compute_plane(line.x0, line.y0, line.x1, line.y1, v0->color[RCOMP], v1->color[RCOMP], line.rPlane); compute_plane(line.x0, line.y0, line.x1, line.y1, v0->color[GCOMP], v1->color[GCOMP], line.gPlane); compute_plane(line.x0, line.y0, line.x1, line.y1, v0->color[BCOMP], v1->color[BCOMP], line.bPlane); compute_plane(line.x0, line.y0, line.x1, line.y1, v0->color[ACOMP], v1->color[ACOMP], line.aPlane); } else { constant_plane(v1->color[RCOMP], line.rPlane); constant_plane(v1->color[GCOMP], line.gPlane); constant_plane(v1->color[BCOMP], line.bPlane); constant_plane(v1->color[ACOMP], line.aPlane); } #if defined(DO_ATTRIBS) { const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3]; const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3]; line.span.arrayMask |= SPAN_LAMBDA; compute_plane(line.x0, line.y0, line.x1, line.y1, invW0, invW1, line.wPlane); ATTRIB_LOOP_BEGIN GLuint c; if (swrast->_InterpMode[attr] == GL_FLAT) { for (c = 0; c < 4; c++) { constant_plane(v1->attrib[attr][c], line.attrPlane[attr][c]); } } else { for (c = 0; c < 4; c++) { const GLfloat a0 = v0->attrib[attr][c] * invW0; const GLfloat a1 = v1->attrib[attr][c] * invW1; compute_plane(line.x0, line.y0, line.x1, line.y1, a0, a1, line.attrPlane[attr][c]); } } line.span.arrayAttribs |= BITFIELD64_BIT(attr); if (attr >= VARYING_SLOT_TEX0 && attr < VARYING_SLOT_VAR0) { const GLuint u = attr - VARYING_SLOT_TEX0; const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current; const struct gl_texture_image *texImage = obj->Image[0][obj->BaseLevel]; line.texWidth[attr] = (GLfloat) texImage->Width; line.texHeight[attr] = (GLfloat) texImage->Height; } ATTRIB_LOOP_END } #endif tStart = tEnd = 0.0; inSegment = GL_FALSE; iLen = (GLint) line.len; if (ctx->Line.StippleFlag) { for (i = 0; i < iLen; i++) { const GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf; if ((1 << bit) & ctx->Line.StipplePattern) { /* stipple bit is on */ const GLfloat t = (GLfloat) i / (GLfloat) line.len; if (!inSegment) { /* start new segment */ inSegment = GL_TRUE; tStart = t; } else { /* still in the segment, extend it */ tEnd = t; } } else { /* stipple bit is off */ if (inSegment && (tEnd > tStart)) { /* draw the segment */ segment(ctx, &line, NAME(plot), tStart, tEnd); inSegment = GL_FALSE; } else { /* still between segments, do nothing */ } } swrast->StippleCounter++; } if (inSegment) { /* draw the final segment of the line */ segment(ctx, &line, NAME(plot), tStart, 1.0F); } } else { /* non-stippled */ segment(ctx, &line, NAME(plot), 0.0, 1.0); } _swrast_write_rgba_span(ctx, &(line.span)); } #undef DO_Z #undef DO_ATTRIBS #undef NAME