0,0 → 1,242 |
/* |
* 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 |