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