17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 47117f1b4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 267117f1b4Smrg/* 277117f1b4Smrg * Antialiased Triangle Rasterizer Template 287117f1b4Smrg * 297117f1b4Smrg * This file is #include'd to generate custom AA triangle rasterizers. 307117f1b4Smrg * NOTE: this code hasn't been optimized yet. That'll come after it 317117f1b4Smrg * works correctly. 327117f1b4Smrg * 337117f1b4Smrg * The following macros may be defined to indicate what auxillary information 347117f1b4Smrg * must be copmuted across the triangle: 357117f1b4Smrg * DO_Z - if defined, compute Z values 367117f1b4Smrg * DO_ATTRIBS - if defined, compute texcoords, varying, etc. 377117f1b4Smrg */ 387117f1b4Smrg 393464ebd5Sriastradh/*void triangle( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/ 407117f1b4Smrg{ 417117f1b4Smrg const SWcontext *swrast = SWRAST_CONTEXT(ctx); 42af69d88dSmrg const GLfloat *p0 = v0->attrib[VARYING_SLOT_POS]; 43af69d88dSmrg const GLfloat *p1 = v1->attrib[VARYING_SLOT_POS]; 44af69d88dSmrg const GLfloat *p2 = v2->attrib[VARYING_SLOT_POS]; 457117f1b4Smrg const SWvertex *vMin, *vMid, *vMax; 467117f1b4Smrg GLint iyMin, iyMax; 477117f1b4Smrg GLfloat yMin, yMax; 487117f1b4Smrg GLboolean ltor; 497117f1b4Smrg GLfloat majDx, majDy; /* major (i.e. long) edge dx and dy */ 507117f1b4Smrg 517117f1b4Smrg SWspan span; 527117f1b4Smrg 537117f1b4Smrg#ifdef DO_Z 547117f1b4Smrg GLfloat zPlane[4]; 557117f1b4Smrg#endif 567117f1b4Smrg GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4]; 577117f1b4Smrg#if defined(DO_ATTRIBS) 58af69d88dSmrg GLfloat attrPlane[VARYING_SLOT_MAX][4][4]; 59c1f859d4Smrg GLfloat wPlane[4]; /* win[3] */ 607117f1b4Smrg#endif 617117f1b4Smrg GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceCullSign; 627117f1b4Smrg 637117f1b4Smrg (void) swrast; 647117f1b4Smrg 65c1f859d4Smrg INIT_SPAN(span, GL_POLYGON); 66c1f859d4Smrg span.arrayMask = SPAN_COVERAGE; 677117f1b4Smrg 687117f1b4Smrg /* determine bottom to top order of vertices */ 697117f1b4Smrg { 70af69d88dSmrg GLfloat y0 = v0->attrib[VARYING_SLOT_POS][1]; 71af69d88dSmrg GLfloat y1 = v1->attrib[VARYING_SLOT_POS][1]; 72af69d88dSmrg GLfloat y2 = v2->attrib[VARYING_SLOT_POS][1]; 737117f1b4Smrg if (y0 <= y1) { 747117f1b4Smrg if (y1 <= y2) { 757117f1b4Smrg vMin = v0; vMid = v1; vMax = v2; /* y0<=y1<=y2 */ 767117f1b4Smrg } 777117f1b4Smrg else if (y2 <= y0) { 787117f1b4Smrg vMin = v2; vMid = v0; vMax = v1; /* y2<=y0<=y1 */ 797117f1b4Smrg } 807117f1b4Smrg else { 817117f1b4Smrg vMin = v0; vMid = v2; vMax = v1; bf = -bf; /* y0<=y2<=y1 */ 827117f1b4Smrg } 837117f1b4Smrg } 847117f1b4Smrg else { 857117f1b4Smrg if (y0 <= y2) { 867117f1b4Smrg vMin = v1; vMid = v0; vMax = v2; bf = -bf; /* y1<=y0<=y2 */ 877117f1b4Smrg } 887117f1b4Smrg else if (y2 <= y1) { 897117f1b4Smrg vMin = v2; vMid = v1; vMax = v0; bf = -bf; /* y2<=y1<=y0 */ 907117f1b4Smrg } 917117f1b4Smrg else { 927117f1b4Smrg vMin = v1; vMid = v2; vMax = v0; /* y1<=y2<=y0 */ 937117f1b4Smrg } 947117f1b4Smrg } 957117f1b4Smrg } 967117f1b4Smrg 97af69d88dSmrg majDx = vMax->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0]; 98af69d88dSmrg majDy = vMax->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1]; 997117f1b4Smrg 1007117f1b4Smrg /* front/back-face determination and cullling */ 1017117f1b4Smrg { 102af69d88dSmrg const GLfloat botDx = vMid->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0]; 103af69d88dSmrg const GLfloat botDy = vMid->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1]; 1047117f1b4Smrg const GLfloat area = majDx * botDy - botDx * majDy; 1057117f1b4Smrg /* Do backface culling */ 1067ec681f3Smrg if (area * bf < 0 || area == 0 || util_is_inf_or_nan(area)) 1077117f1b4Smrg return; 1087117f1b4Smrg ltor = (GLboolean) (area < 0.0F); 1097117f1b4Smrg 1107117f1b4Smrg span.facing = area * swrast->_BackfaceSign > 0.0F; 1117117f1b4Smrg } 1127117f1b4Smrg 1137117f1b4Smrg /* Plane equation setup: 1147117f1b4Smrg * We evaluate plane equations at window (x,y) coordinates in order 1157117f1b4Smrg * to compute color, Z, fog, texcoords, etc. This isn't terribly 1167117f1b4Smrg * efficient but it's easy and reliable. 1177117f1b4Smrg */ 1187117f1b4Smrg#ifdef DO_Z 1197117f1b4Smrg compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane); 1207117f1b4Smrg span.arrayMask |= SPAN_Z; 1217117f1b4Smrg#endif 1227117f1b4Smrg if (ctx->Light.ShadeModel == GL_SMOOTH) { 1237117f1b4Smrg compute_plane(p0, p1, p2, v0->color[RCOMP], v1->color[RCOMP], v2->color[RCOMP], rPlane); 1247117f1b4Smrg compute_plane(p0, p1, p2, v0->color[GCOMP], v1->color[GCOMP], v2->color[GCOMP], gPlane); 1257117f1b4Smrg compute_plane(p0, p1, p2, v0->color[BCOMP], v1->color[BCOMP], v2->color[BCOMP], bPlane); 1267117f1b4Smrg compute_plane(p0, p1, p2, v0->color[ACOMP], v1->color[ACOMP], v2->color[ACOMP], aPlane); 1277117f1b4Smrg } 1287117f1b4Smrg else { 1297117f1b4Smrg constant_plane(v2->color[RCOMP], rPlane); 1307117f1b4Smrg constant_plane(v2->color[GCOMP], gPlane); 1317117f1b4Smrg constant_plane(v2->color[BCOMP], bPlane); 1327117f1b4Smrg constant_plane(v2->color[ACOMP], aPlane); 1337117f1b4Smrg } 1347117f1b4Smrg span.arrayMask |= SPAN_RGBA; 1357117f1b4Smrg#if defined(DO_ATTRIBS) 1367117f1b4Smrg { 137af69d88dSmrg const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3]; 138af69d88dSmrg const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3]; 139af69d88dSmrg const GLfloat invW2 = v2->attrib[VARYING_SLOT_POS][3]; 140c1f859d4Smrg compute_plane(p0, p1, p2, invW0, invW1, invW2, wPlane); 141af69d88dSmrg span.attrStepX[VARYING_SLOT_POS][3] = plane_dx(wPlane); 142af69d88dSmrg span.attrStepY[VARYING_SLOT_POS][3] = plane_dy(wPlane); 1437117f1b4Smrg ATTRIB_LOOP_BEGIN 144c1f859d4Smrg GLuint c; 145c1f859d4Smrg if (swrast->_InterpMode[attr] == GL_FLAT) { 146c1f859d4Smrg for (c = 0; c < 4; c++) { 147c1f859d4Smrg constant_plane(v2->attrib[attr][c] * invW2, attrPlane[attr][c]); 148c1f859d4Smrg } 1497117f1b4Smrg } 1507117f1b4Smrg else { 151c1f859d4Smrg for (c = 0; c < 4; c++) { 152c1f859d4Smrg const GLfloat a0 = v0->attrib[attr][c] * invW0; 153c1f859d4Smrg const GLfloat a1 = v1->attrib[attr][c] * invW1; 154c1f859d4Smrg const GLfloat a2 = v2->attrib[attr][c] * invW2; 155c1f859d4Smrg compute_plane(p0, p1, p2, a0, a1, a2, attrPlane[attr][c]); 156c1f859d4Smrg } 157c1f859d4Smrg } 158c1f859d4Smrg for (c = 0; c < 4; c++) { 159c1f859d4Smrg span.attrStepX[attr][c] = plane_dx(attrPlane[attr][c]); 160c1f859d4Smrg span.attrStepY[attr][c] = plane_dy(attrPlane[attr][c]); 1617117f1b4Smrg } 1627117f1b4Smrg ATTRIB_LOOP_END 1637117f1b4Smrg } 1647117f1b4Smrg#endif 1657117f1b4Smrg 1667117f1b4Smrg /* Begin bottom-to-top scan over the triangle. 1677117f1b4Smrg * The long edge will either be on the left or right side of the 1687117f1b4Smrg * triangle. We always scan from the long edge toward the shorter 1697117f1b4Smrg * edges, stopping when we find that coverage = 0. If the long edge 1707117f1b4Smrg * is on the left we scan left-to-right. Else, we scan right-to-left. 1717117f1b4Smrg */ 172af69d88dSmrg yMin = vMin->attrib[VARYING_SLOT_POS][1]; 173af69d88dSmrg yMax = vMax->attrib[VARYING_SLOT_POS][1]; 1747117f1b4Smrg iyMin = (GLint) yMin; 1757117f1b4Smrg iyMax = (GLint) yMax + 1; 1767117f1b4Smrg 1777117f1b4Smrg if (ltor) { 1787117f1b4Smrg /* scan left to right */ 179af69d88dSmrg const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS]; 180af69d88dSmrg const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS]; 181af69d88dSmrg const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS]; 1827117f1b4Smrg const GLfloat dxdy = majDx / majDy; 1837117f1b4Smrg const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F; 1847117f1b4Smrg GLint iy; 185af69d88dSmrg#ifdef _OPENMP 186af69d88dSmrg#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span) 187af69d88dSmrg#endif 188af69d88dSmrg for (iy = iyMin; iy < iyMax; iy++) { 189af69d88dSmrg GLfloat x = pMin[0] - (yMin - iy) * dxdy; 1907117f1b4Smrg GLint ix, startX = (GLint) (x - xAdj); 1917117f1b4Smrg GLuint count; 1927117f1b4Smrg GLfloat coverage = 0.0F; 1937117f1b4Smrg 194af69d88dSmrg#ifdef _OPENMP 195af69d88dSmrg /* each thread needs to use a different (global) SpanArrays variable */ 196af69d88dSmrg span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num(); 197af69d88dSmrg#endif 1987117f1b4Smrg /* skip over fragments with zero coverage */ 199af69d88dSmrg while (startX < SWRAST_MAX_WIDTH) { 2007117f1b4Smrg coverage = compute_coveragef(pMin, pMid, pMax, startX, iy); 2017117f1b4Smrg if (coverage > 0.0F) 2027117f1b4Smrg break; 2037117f1b4Smrg startX++; 2047117f1b4Smrg } 2057117f1b4Smrg 2067117f1b4Smrg /* enter interior of triangle */ 2077117f1b4Smrg ix = startX; 208c1f859d4Smrg 209c1f859d4Smrg#if defined(DO_ATTRIBS) 210c1f859d4Smrg /* compute attributes at left-most fragment */ 211af69d88dSmrg span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 0.5F, iy + 0.5F, wPlane); 212c1f859d4Smrg ATTRIB_LOOP_BEGIN 213c1f859d4Smrg GLuint c; 214c1f859d4Smrg for (c = 0; c < 4; c++) { 215cdc920a0Smrg span.attrStart[attr][c] = solve_plane(ix + 0.5F, iy + 0.5F, attrPlane[attr][c]); 216c1f859d4Smrg } 217c1f859d4Smrg ATTRIB_LOOP_END 218c1f859d4Smrg#endif 219c1f859d4Smrg 2207117f1b4Smrg count = 0; 2217117f1b4Smrg while (coverage > 0.0F) { 2227117f1b4Smrg /* (cx,cy) = center of fragment */ 2237117f1b4Smrg const GLfloat cx = ix + 0.5F, cy = iy + 0.5F; 2247117f1b4Smrg SWspanarrays *array = span.array; 2257117f1b4Smrg array->coverage[count] = coverage; 2267117f1b4Smrg#ifdef DO_Z 2277117f1b4Smrg array->z[count] = (GLuint) solve_plane(cx, cy, zPlane); 2287117f1b4Smrg#endif 2297117f1b4Smrg array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane); 2307117f1b4Smrg array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane); 2317117f1b4Smrg array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane); 2327117f1b4Smrg array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane); 2337117f1b4Smrg ix++; 2347117f1b4Smrg count++; 2357117f1b4Smrg coverage = compute_coveragef(pMin, pMid, pMax, ix, iy); 2367117f1b4Smrg } 2377117f1b4Smrg 238af69d88dSmrg if (ix > startX) { 239af69d88dSmrg span.x = startX; 240af69d88dSmrg span.y = iy; 241af69d88dSmrg span.end = (GLuint) ix - (GLuint) startX; 242af69d88dSmrg _swrast_write_rgba_span(ctx, &span); 243af69d88dSmrg } 2447117f1b4Smrg } 2457117f1b4Smrg } 2467117f1b4Smrg else { 2477117f1b4Smrg /* scan right to left */ 248af69d88dSmrg const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS]; 249af69d88dSmrg const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS]; 250af69d88dSmrg const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS]; 2517117f1b4Smrg const GLfloat dxdy = majDx / majDy; 2527117f1b4Smrg const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F; 2537117f1b4Smrg GLint iy; 254af69d88dSmrg#ifdef _OPENMP 255af69d88dSmrg#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span) 256af69d88dSmrg#endif 257af69d88dSmrg for (iy = iyMin; iy < iyMax; iy++) { 258af69d88dSmrg GLfloat x = pMin[0] - (yMin - iy) * dxdy; 2597117f1b4Smrg GLint ix, left, startX = (GLint) (x + xAdj); 2607117f1b4Smrg GLuint count, n; 2617117f1b4Smrg GLfloat coverage = 0.0F; 2627117f1b4Smrg 263af69d88dSmrg#ifdef _OPENMP 264af69d88dSmrg /* each thread needs to use a different (global) SpanArrays variable */ 265af69d88dSmrg span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num(); 266af69d88dSmrg#endif 2677117f1b4Smrg /* make sure we're not past the window edge */ 2687117f1b4Smrg if (startX >= ctx->DrawBuffer->_Xmax) { 2697117f1b4Smrg startX = ctx->DrawBuffer->_Xmax - 1; 2707117f1b4Smrg } 2717117f1b4Smrg 2727117f1b4Smrg /* skip fragments with zero coverage */ 2737117f1b4Smrg while (startX > 0) { 2747117f1b4Smrg coverage = compute_coveragef(pMin, pMax, pMid, startX, iy); 2757117f1b4Smrg if (coverage > 0.0F) 2767117f1b4Smrg break; 2777117f1b4Smrg startX--; 2787117f1b4Smrg } 2797117f1b4Smrg 2807117f1b4Smrg /* enter interior of triangle */ 2817117f1b4Smrg ix = startX; 2827117f1b4Smrg count = 0; 2837117f1b4Smrg while (coverage > 0.0F) { 2847117f1b4Smrg /* (cx,cy) = center of fragment */ 2857117f1b4Smrg const GLfloat cx = ix + 0.5F, cy = iy + 0.5F; 2867117f1b4Smrg SWspanarrays *array = span.array; 28701e04c3fSmrg assert(ix >= 0); 2887117f1b4Smrg array->coverage[ix] = coverage; 2897117f1b4Smrg#ifdef DO_Z 2907117f1b4Smrg array->z[ix] = (GLuint) solve_plane(cx, cy, zPlane); 2917117f1b4Smrg#endif 2927117f1b4Smrg array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane); 2937117f1b4Smrg array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane); 2947117f1b4Smrg array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane); 2957117f1b4Smrg array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane); 2967117f1b4Smrg ix--; 2977117f1b4Smrg count++; 2987117f1b4Smrg coverage = compute_coveragef(pMin, pMax, pMid, ix, iy); 2997117f1b4Smrg } 3007117f1b4Smrg 301c1f859d4Smrg#if defined(DO_ATTRIBS) 302c1f859d4Smrg /* compute attributes at left-most fragment */ 303af69d88dSmrg span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 1.5F, iy + 0.5F, wPlane); 304c1f859d4Smrg ATTRIB_LOOP_BEGIN 305c1f859d4Smrg GLuint c; 306c1f859d4Smrg for (c = 0; c < 4; c++) { 307cdc920a0Smrg span.attrStart[attr][c] = solve_plane(ix + 1.5F, iy + 0.5F, attrPlane[attr][c]); 308c1f859d4Smrg } 309c1f859d4Smrg ATTRIB_LOOP_END 310c1f859d4Smrg#endif 311c1f859d4Smrg 312af69d88dSmrg if (startX > ix) { 313af69d88dSmrg n = (GLuint) startX - (GLuint) ix; 3147117f1b4Smrg 315af69d88dSmrg left = ix + 1; 3167117f1b4Smrg 317af69d88dSmrg /* shift all values to the left */ 318af69d88dSmrg /* XXX this is temporary */ 319af69d88dSmrg { 320af69d88dSmrg SWspanarrays *array = span.array; 321af69d88dSmrg GLint j; 322af69d88dSmrg for (j = 0; j < (GLint) n; j++) { 323af69d88dSmrg array->coverage[j] = array->coverage[j + left]; 324af69d88dSmrg COPY_CHAN4(array->rgba[j], array->rgba[j + left]); 3257117f1b4Smrg#ifdef DO_Z 326af69d88dSmrg array->z[j] = array->z[j + left]; 3277117f1b4Smrg#endif 328af69d88dSmrg } 3297117f1b4Smrg } 3307117f1b4Smrg 331af69d88dSmrg span.x = left; 332af69d88dSmrg span.y = iy; 333af69d88dSmrg span.end = n; 334af69d88dSmrg _swrast_write_rgba_span(ctx, &span); 335af69d88dSmrg } 3367117f1b4Smrg } 3377117f1b4Smrg } 3387117f1b4Smrg} 3397117f1b4Smrg 3407117f1b4Smrg 3417117f1b4Smrg#undef DO_Z 3427117f1b4Smrg#undef DO_ATTRIBS 3437117f1b4Smrg#undef DO_OCCLUSION_TEST 344