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