1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg/* 27848b8605Smrg * Antialiased Triangle Rasterizer Template 28848b8605Smrg * 29848b8605Smrg * This file is #include'd to generate custom AA triangle rasterizers. 30848b8605Smrg * NOTE: this code hasn't been optimized yet. That'll come after it 31848b8605Smrg * works correctly. 32848b8605Smrg * 33848b8605Smrg * The following macros may be defined to indicate what auxillary information 34848b8605Smrg * must be copmuted across the triangle: 35848b8605Smrg * DO_Z - if defined, compute Z values 36848b8605Smrg * DO_ATTRIBS - if defined, compute texcoords, varying, etc. 37848b8605Smrg */ 38848b8605Smrg 39848b8605Smrg/*void triangle( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/ 40848b8605Smrg{ 41848b8605Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 42848b8605Smrg const GLfloat *p0 = v0->attrib[VARYING_SLOT_POS]; 43848b8605Smrg const GLfloat *p1 = v1->attrib[VARYING_SLOT_POS]; 44848b8605Smrg const GLfloat *p2 = v2->attrib[VARYING_SLOT_POS]; 45848b8605Smrg const SWvertex *vMin, *vMid, *vMax; 46848b8605Smrg GLint iyMin, iyMax; 47848b8605Smrg GLfloat yMin, yMax; 48848b8605Smrg GLboolean ltor; 49848b8605Smrg GLfloat majDx, majDy; /* major (i.e. long) edge dx and dy */ 50848b8605Smrg 51848b8605Smrg SWspan span; 52848b8605Smrg 53848b8605Smrg#ifdef DO_Z 54848b8605Smrg GLfloat zPlane[4]; 55848b8605Smrg#endif 56848b8605Smrg GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4]; 57848b8605Smrg#if defined(DO_ATTRIBS) 58848b8605Smrg GLfloat attrPlane[VARYING_SLOT_MAX][4][4]; 59848b8605Smrg GLfloat wPlane[4]; /* win[3] */ 60848b8605Smrg#endif 61848b8605Smrg GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceCullSign; 62848b8605Smrg 63848b8605Smrg (void) swrast; 64848b8605Smrg 65848b8605Smrg INIT_SPAN(span, GL_POLYGON); 66848b8605Smrg span.arrayMask = SPAN_COVERAGE; 67848b8605Smrg 68848b8605Smrg /* determine bottom to top order of vertices */ 69848b8605Smrg { 70848b8605Smrg GLfloat y0 = v0->attrib[VARYING_SLOT_POS][1]; 71848b8605Smrg GLfloat y1 = v1->attrib[VARYING_SLOT_POS][1]; 72848b8605Smrg GLfloat y2 = v2->attrib[VARYING_SLOT_POS][1]; 73848b8605Smrg if (y0 <= y1) { 74848b8605Smrg if (y1 <= y2) { 75848b8605Smrg vMin = v0; vMid = v1; vMax = v2; /* y0<=y1<=y2 */ 76848b8605Smrg } 77848b8605Smrg else if (y2 <= y0) { 78848b8605Smrg vMin = v2; vMid = v0; vMax = v1; /* y2<=y0<=y1 */ 79848b8605Smrg } 80848b8605Smrg else { 81848b8605Smrg vMin = v0; vMid = v2; vMax = v1; bf = -bf; /* y0<=y2<=y1 */ 82848b8605Smrg } 83848b8605Smrg } 84848b8605Smrg else { 85848b8605Smrg if (y0 <= y2) { 86848b8605Smrg vMin = v1; vMid = v0; vMax = v2; bf = -bf; /* y1<=y0<=y2 */ 87848b8605Smrg } 88848b8605Smrg else if (y2 <= y1) { 89848b8605Smrg vMin = v2; vMid = v1; vMax = v0; bf = -bf; /* y2<=y1<=y0 */ 90848b8605Smrg } 91848b8605Smrg else { 92848b8605Smrg vMin = v1; vMid = v2; vMax = v0; /* y1<=y2<=y0 */ 93848b8605Smrg } 94848b8605Smrg } 95848b8605Smrg } 96848b8605Smrg 97848b8605Smrg majDx = vMax->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0]; 98848b8605Smrg majDy = vMax->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1]; 99848b8605Smrg 100848b8605Smrg /* front/back-face determination and cullling */ 101848b8605Smrg { 102848b8605Smrg const GLfloat botDx = vMid->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0]; 103848b8605Smrg const GLfloat botDy = vMid->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1]; 104848b8605Smrg const GLfloat area = majDx * botDy - botDx * majDy; 105848b8605Smrg /* Do backface culling */ 106848b8605Smrg if (area * bf < 0 || area == 0 || IS_INF_OR_NAN(area)) 107848b8605Smrg return; 108848b8605Smrg ltor = (GLboolean) (area < 0.0F); 109848b8605Smrg 110848b8605Smrg span.facing = area * swrast->_BackfaceSign > 0.0F; 111848b8605Smrg } 112848b8605Smrg 113848b8605Smrg /* Plane equation setup: 114848b8605Smrg * We evaluate plane equations at window (x,y) coordinates in order 115848b8605Smrg * to compute color, Z, fog, texcoords, etc. This isn't terribly 116848b8605Smrg * efficient but it's easy and reliable. 117848b8605Smrg */ 118848b8605Smrg#ifdef DO_Z 119848b8605Smrg compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane); 120848b8605Smrg span.arrayMask |= SPAN_Z; 121848b8605Smrg#endif 122848b8605Smrg if (ctx->Light.ShadeModel == GL_SMOOTH) { 123848b8605Smrg compute_plane(p0, p1, p2, v0->color[RCOMP], v1->color[RCOMP], v2->color[RCOMP], rPlane); 124848b8605Smrg compute_plane(p0, p1, p2, v0->color[GCOMP], v1->color[GCOMP], v2->color[GCOMP], gPlane); 125848b8605Smrg compute_plane(p0, p1, p2, v0->color[BCOMP], v1->color[BCOMP], v2->color[BCOMP], bPlane); 126848b8605Smrg compute_plane(p0, p1, p2, v0->color[ACOMP], v1->color[ACOMP], v2->color[ACOMP], aPlane); 127848b8605Smrg } 128848b8605Smrg else { 129848b8605Smrg constant_plane(v2->color[RCOMP], rPlane); 130848b8605Smrg constant_plane(v2->color[GCOMP], gPlane); 131848b8605Smrg constant_plane(v2->color[BCOMP], bPlane); 132848b8605Smrg constant_plane(v2->color[ACOMP], aPlane); 133848b8605Smrg } 134848b8605Smrg span.arrayMask |= SPAN_RGBA; 135848b8605Smrg#if defined(DO_ATTRIBS) 136848b8605Smrg { 137848b8605Smrg const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3]; 138848b8605Smrg const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3]; 139848b8605Smrg const GLfloat invW2 = v2->attrib[VARYING_SLOT_POS][3]; 140848b8605Smrg compute_plane(p0, p1, p2, invW0, invW1, invW2, wPlane); 141848b8605Smrg span.attrStepX[VARYING_SLOT_POS][3] = plane_dx(wPlane); 142848b8605Smrg span.attrStepY[VARYING_SLOT_POS][3] = plane_dy(wPlane); 143848b8605Smrg ATTRIB_LOOP_BEGIN 144848b8605Smrg GLuint c; 145848b8605Smrg if (swrast->_InterpMode[attr] == GL_FLAT) { 146848b8605Smrg for (c = 0; c < 4; c++) { 147848b8605Smrg constant_plane(v2->attrib[attr][c] * invW2, attrPlane[attr][c]); 148848b8605Smrg } 149848b8605Smrg } 150848b8605Smrg else { 151848b8605Smrg for (c = 0; c < 4; c++) { 152848b8605Smrg const GLfloat a0 = v0->attrib[attr][c] * invW0; 153848b8605Smrg const GLfloat a1 = v1->attrib[attr][c] * invW1; 154848b8605Smrg const GLfloat a2 = v2->attrib[attr][c] * invW2; 155848b8605Smrg compute_plane(p0, p1, p2, a0, a1, a2, attrPlane[attr][c]); 156848b8605Smrg } 157848b8605Smrg } 158848b8605Smrg for (c = 0; c < 4; c++) { 159848b8605Smrg span.attrStepX[attr][c] = plane_dx(attrPlane[attr][c]); 160848b8605Smrg span.attrStepY[attr][c] = plane_dy(attrPlane[attr][c]); 161848b8605Smrg } 162848b8605Smrg ATTRIB_LOOP_END 163848b8605Smrg } 164848b8605Smrg#endif 165848b8605Smrg 166848b8605Smrg /* Begin bottom-to-top scan over the triangle. 167848b8605Smrg * The long edge will either be on the left or right side of the 168848b8605Smrg * triangle. We always scan from the long edge toward the shorter 169848b8605Smrg * edges, stopping when we find that coverage = 0. If the long edge 170848b8605Smrg * is on the left we scan left-to-right. Else, we scan right-to-left. 171848b8605Smrg */ 172848b8605Smrg yMin = vMin->attrib[VARYING_SLOT_POS][1]; 173848b8605Smrg yMax = vMax->attrib[VARYING_SLOT_POS][1]; 174848b8605Smrg iyMin = (GLint) yMin; 175848b8605Smrg iyMax = (GLint) yMax + 1; 176848b8605Smrg 177848b8605Smrg if (ltor) { 178848b8605Smrg /* scan left to right */ 179848b8605Smrg const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS]; 180848b8605Smrg const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS]; 181848b8605Smrg const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS]; 182848b8605Smrg const GLfloat dxdy = majDx / majDy; 183848b8605Smrg const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F; 184848b8605Smrg GLint iy; 185848b8605Smrg#ifdef _OPENMP 186848b8605Smrg#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span) 187848b8605Smrg#endif 188848b8605Smrg for (iy = iyMin; iy < iyMax; iy++) { 189848b8605Smrg GLfloat x = pMin[0] - (yMin - iy) * dxdy; 190848b8605Smrg GLint ix, startX = (GLint) (x - xAdj); 191848b8605Smrg GLuint count; 192848b8605Smrg GLfloat coverage = 0.0F; 193848b8605Smrg 194848b8605Smrg#ifdef _OPENMP 195848b8605Smrg /* each thread needs to use a different (global) SpanArrays variable */ 196848b8605Smrg span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num(); 197848b8605Smrg#endif 198848b8605Smrg /* skip over fragments with zero coverage */ 199848b8605Smrg while (startX < SWRAST_MAX_WIDTH) { 200848b8605Smrg coverage = compute_coveragef(pMin, pMid, pMax, startX, iy); 201848b8605Smrg if (coverage > 0.0F) 202848b8605Smrg break; 203848b8605Smrg startX++; 204848b8605Smrg } 205848b8605Smrg 206848b8605Smrg /* enter interior of triangle */ 207848b8605Smrg ix = startX; 208848b8605Smrg 209848b8605Smrg#if defined(DO_ATTRIBS) 210848b8605Smrg /* compute attributes at left-most fragment */ 211848b8605Smrg span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 0.5F, iy + 0.5F, wPlane); 212848b8605Smrg ATTRIB_LOOP_BEGIN 213848b8605Smrg GLuint c; 214848b8605Smrg for (c = 0; c < 4; c++) { 215848b8605Smrg span.attrStart[attr][c] = solve_plane(ix + 0.5F, iy + 0.5F, attrPlane[attr][c]); 216848b8605Smrg } 217848b8605Smrg ATTRIB_LOOP_END 218848b8605Smrg#endif 219848b8605Smrg 220848b8605Smrg count = 0; 221848b8605Smrg while (coverage > 0.0F) { 222848b8605Smrg /* (cx,cy) = center of fragment */ 223848b8605Smrg const GLfloat cx = ix + 0.5F, cy = iy + 0.5F; 224848b8605Smrg SWspanarrays *array = span.array; 225848b8605Smrg array->coverage[count] = coverage; 226848b8605Smrg#ifdef DO_Z 227848b8605Smrg array->z[count] = (GLuint) solve_plane(cx, cy, zPlane); 228848b8605Smrg#endif 229848b8605Smrg array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane); 230848b8605Smrg array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane); 231848b8605Smrg array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane); 232848b8605Smrg array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane); 233848b8605Smrg ix++; 234848b8605Smrg count++; 235848b8605Smrg coverage = compute_coveragef(pMin, pMid, pMax, ix, iy); 236848b8605Smrg } 237848b8605Smrg 238848b8605Smrg if (ix > startX) { 239848b8605Smrg span.x = startX; 240848b8605Smrg span.y = iy; 241848b8605Smrg span.end = (GLuint) ix - (GLuint) startX; 242848b8605Smrg _swrast_write_rgba_span(ctx, &span); 243848b8605Smrg } 244848b8605Smrg } 245848b8605Smrg } 246848b8605Smrg else { 247848b8605Smrg /* scan right to left */ 248848b8605Smrg const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS]; 249848b8605Smrg const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS]; 250848b8605Smrg const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS]; 251848b8605Smrg const GLfloat dxdy = majDx / majDy; 252848b8605Smrg const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F; 253848b8605Smrg GLint iy; 254848b8605Smrg#ifdef _OPENMP 255848b8605Smrg#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span) 256848b8605Smrg#endif 257848b8605Smrg for (iy = iyMin; iy < iyMax; iy++) { 258848b8605Smrg GLfloat x = pMin[0] - (yMin - iy) * dxdy; 259848b8605Smrg GLint ix, left, startX = (GLint) (x + xAdj); 260848b8605Smrg GLuint count, n; 261848b8605Smrg GLfloat coverage = 0.0F; 262848b8605Smrg 263848b8605Smrg#ifdef _OPENMP 264848b8605Smrg /* each thread needs to use a different (global) SpanArrays variable */ 265848b8605Smrg span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num(); 266848b8605Smrg#endif 267848b8605Smrg /* make sure we're not past the window edge */ 268848b8605Smrg if (startX >= ctx->DrawBuffer->_Xmax) { 269848b8605Smrg startX = ctx->DrawBuffer->_Xmax - 1; 270848b8605Smrg } 271848b8605Smrg 272848b8605Smrg /* skip fragments with zero coverage */ 273848b8605Smrg while (startX > 0) { 274848b8605Smrg coverage = compute_coveragef(pMin, pMax, pMid, startX, iy); 275848b8605Smrg if (coverage > 0.0F) 276848b8605Smrg break; 277848b8605Smrg startX--; 278848b8605Smrg } 279848b8605Smrg 280848b8605Smrg /* enter interior of triangle */ 281848b8605Smrg ix = startX; 282848b8605Smrg count = 0; 283848b8605Smrg while (coverage > 0.0F) { 284848b8605Smrg /* (cx,cy) = center of fragment */ 285848b8605Smrg const GLfloat cx = ix + 0.5F, cy = iy + 0.5F; 286848b8605Smrg SWspanarrays *array = span.array; 287b8e80941Smrg assert(ix >= 0); 288848b8605Smrg array->coverage[ix] = coverage; 289848b8605Smrg#ifdef DO_Z 290848b8605Smrg array->z[ix] = (GLuint) solve_plane(cx, cy, zPlane); 291848b8605Smrg#endif 292848b8605Smrg array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane); 293848b8605Smrg array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane); 294848b8605Smrg array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane); 295848b8605Smrg array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane); 296848b8605Smrg ix--; 297848b8605Smrg count++; 298848b8605Smrg coverage = compute_coveragef(pMin, pMax, pMid, ix, iy); 299848b8605Smrg } 300848b8605Smrg 301848b8605Smrg#if defined(DO_ATTRIBS) 302848b8605Smrg /* compute attributes at left-most fragment */ 303848b8605Smrg span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 1.5F, iy + 0.5F, wPlane); 304848b8605Smrg ATTRIB_LOOP_BEGIN 305848b8605Smrg GLuint c; 306848b8605Smrg for (c = 0; c < 4; c++) { 307848b8605Smrg span.attrStart[attr][c] = solve_plane(ix + 1.5F, iy + 0.5F, attrPlane[attr][c]); 308848b8605Smrg } 309848b8605Smrg ATTRIB_LOOP_END 310848b8605Smrg#endif 311848b8605Smrg 312848b8605Smrg if (startX > ix) { 313848b8605Smrg n = (GLuint) startX - (GLuint) ix; 314848b8605Smrg 315848b8605Smrg left = ix + 1; 316848b8605Smrg 317848b8605Smrg /* shift all values to the left */ 318848b8605Smrg /* XXX this is temporary */ 319848b8605Smrg { 320848b8605Smrg SWspanarrays *array = span.array; 321848b8605Smrg GLint j; 322848b8605Smrg for (j = 0; j < (GLint) n; j++) { 323848b8605Smrg array->coverage[j] = array->coverage[j + left]; 324848b8605Smrg COPY_CHAN4(array->rgba[j], array->rgba[j + left]); 325848b8605Smrg#ifdef DO_Z 326848b8605Smrg array->z[j] = array->z[j + left]; 327848b8605Smrg#endif 328848b8605Smrg } 329848b8605Smrg } 330848b8605Smrg 331848b8605Smrg span.x = left; 332848b8605Smrg span.y = iy; 333848b8605Smrg span.end = n; 334848b8605Smrg _swrast_write_rgba_span(ctx, &span); 335848b8605Smrg } 336848b8605Smrg } 337848b8605Smrg } 338848b8605Smrg} 339848b8605Smrg 340848b8605Smrg 341848b8605Smrg#undef DO_Z 342848b8605Smrg#undef DO_ATTRIBS 343848b8605Smrg#undef DO_OCCLUSION_TEST 344