• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 /*
27  * Antialiased Triangle Rasterizer Template
28  *
29  * This file is #include'd to generate custom AA triangle rasterizers.
30  * NOTE: this code hasn't been optimized yet.  That'll come after it
31  * works correctly.
32  *
33  * The following macros may be defined to indicate what auxillary information
34  * must be copmuted across the triangle:
35  *    DO_Z         - if defined, compute Z values
36  *    DO_ATTRIBS   - if defined, compute texcoords, varying, etc.
37  */
38 
39 /*void triangle( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
40 {
41    const SWcontext *swrast = SWRAST_CONTEXT(ctx);
42    const GLfloat *p0 = v0->attrib[VARYING_SLOT_POS];
43    const GLfloat *p1 = v1->attrib[VARYING_SLOT_POS];
44    const GLfloat *p2 = v2->attrib[VARYING_SLOT_POS];
45    const SWvertex *vMin, *vMid, *vMax;
46    GLint iyMin, iyMax;
47    GLfloat yMin, yMax;
48    GLboolean ltor;
49    GLfloat majDx, majDy;  /* major (i.e. long) edge dx and dy */
50 
51    SWspan span;
52 
53 #ifdef DO_Z
54    GLfloat zPlane[4];
55 #endif
56    GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
57 #if defined(DO_ATTRIBS)
58    GLfloat attrPlane[VARYING_SLOT_MAX][4][4];
59    GLfloat wPlane[4];  /* win[3] */
60 #endif
61    GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceCullSign;
62 
63    (void) swrast;
64 
65    INIT_SPAN(span, GL_POLYGON);
66    span.arrayMask = SPAN_COVERAGE;
67 
68    /* determine bottom to top order of vertices */
69    {
70       GLfloat y0 = v0->attrib[VARYING_SLOT_POS][1];
71       GLfloat y1 = v1->attrib[VARYING_SLOT_POS][1];
72       GLfloat y2 = v2->attrib[VARYING_SLOT_POS][1];
73       if (y0 <= y1) {
74 	 if (y1 <= y2) {
75 	    vMin = v0;   vMid = v1;   vMax = v2;   /* y0<=y1<=y2 */
76 	 }
77 	 else if (y2 <= y0) {
78 	    vMin = v2;   vMid = v0;   vMax = v1;   /* y2<=y0<=y1 */
79 	 }
80 	 else {
81 	    vMin = v0;   vMid = v2;   vMax = v1;  bf = -bf; /* y0<=y2<=y1 */
82 	 }
83       }
84       else {
85 	 if (y0 <= y2) {
86 	    vMin = v1;   vMid = v0;   vMax = v2;  bf = -bf; /* y1<=y0<=y2 */
87 	 }
88 	 else if (y2 <= y1) {
89 	    vMin = v2;   vMid = v1;   vMax = v0;  bf = -bf; /* y2<=y1<=y0 */
90 	 }
91 	 else {
92 	    vMin = v1;   vMid = v2;   vMax = v0;   /* y1<=y2<=y0 */
93 	 }
94       }
95    }
96 
97    majDx = vMax->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
98    majDy = vMax->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
99 
100    /* front/back-face determination and cullling */
101    {
102       const GLfloat botDx = vMid->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
103       const GLfloat botDy = vMid->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
104       const GLfloat area = majDx * botDy - botDx * majDy;
105       /* Do backface culling */
106       if (area * bf < 0 || area == 0 || IS_INF_OR_NAN(area))
107 	 return;
108       ltor = (GLboolean) (area < 0.0F);
109 
110       span.facing = area * swrast->_BackfaceSign > 0.0F;
111    }
112 
113    /* Plane equation setup:
114     * We evaluate plane equations at window (x,y) coordinates in order
115     * to compute color, Z, fog, texcoords, etc.  This isn't terribly
116     * efficient but it's easy and reliable.
117     */
118 #ifdef DO_Z
119    compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
120    span.arrayMask |= SPAN_Z;
121 #endif
122    if (ctx->Light.ShadeModel == GL_SMOOTH) {
123       compute_plane(p0, p1, p2, v0->color[RCOMP], v1->color[RCOMP], v2->color[RCOMP], rPlane);
124       compute_plane(p0, p1, p2, v0->color[GCOMP], v1->color[GCOMP], v2->color[GCOMP], gPlane);
125       compute_plane(p0, p1, p2, v0->color[BCOMP], v1->color[BCOMP], v2->color[BCOMP], bPlane);
126       compute_plane(p0, p1, p2, v0->color[ACOMP], v1->color[ACOMP], v2->color[ACOMP], aPlane);
127    }
128    else {
129       constant_plane(v2->color[RCOMP], rPlane);
130       constant_plane(v2->color[GCOMP], gPlane);
131       constant_plane(v2->color[BCOMP], bPlane);
132       constant_plane(v2->color[ACOMP], aPlane);
133    }
134    span.arrayMask |= SPAN_RGBA;
135 #if defined(DO_ATTRIBS)
136    {
137       const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3];
138       const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3];
139       const GLfloat invW2 = v2->attrib[VARYING_SLOT_POS][3];
140       compute_plane(p0, p1, p2, invW0, invW1, invW2, wPlane);
141       span.attrStepX[VARYING_SLOT_POS][3] = plane_dx(wPlane);
142       span.attrStepY[VARYING_SLOT_POS][3] = plane_dy(wPlane);
143       ATTRIB_LOOP_BEGIN
144          GLuint c;
145          if (swrast->_InterpMode[attr] == GL_FLAT) {
146             for (c = 0; c < 4; c++) {
147                constant_plane(v2->attrib[attr][c] * invW2, attrPlane[attr][c]);
148             }
149          }
150          else {
151             for (c = 0; c < 4; c++) {
152                const GLfloat a0 = v0->attrib[attr][c] * invW0;
153                const GLfloat a1 = v1->attrib[attr][c] * invW1;
154                const GLfloat a2 = v2->attrib[attr][c] * invW2;
155                compute_plane(p0, p1, p2, a0, a1, a2, attrPlane[attr][c]);
156             }
157          }
158          for (c = 0; c < 4; c++) {
159             span.attrStepX[attr][c] = plane_dx(attrPlane[attr][c]);
160             span.attrStepY[attr][c] = plane_dy(attrPlane[attr][c]);
161          }
162       ATTRIB_LOOP_END
163    }
164 #endif
165 
166    /* Begin bottom-to-top scan over the triangle.
167     * The long edge will either be on the left or right side of the
168     * triangle.  We always scan from the long edge toward the shorter
169     * edges, stopping when we find that coverage = 0.  If the long edge
170     * is on the left we scan left-to-right.  Else, we scan right-to-left.
171     */
172    yMin = vMin->attrib[VARYING_SLOT_POS][1];
173    yMax = vMax->attrib[VARYING_SLOT_POS][1];
174    iyMin = (GLint) yMin;
175    iyMax = (GLint) yMax + 1;
176 
177    if (ltor) {
178       /* scan left to right */
179       const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
180       const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
181       const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
182       const GLfloat dxdy = majDx / majDy;
183       const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
184       GLint iy;
185 #ifdef _OPENMP
186 #pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
187 #endif
188       for (iy = iyMin; iy < iyMax; iy++) {
189          GLfloat x = pMin[0] - (yMin - iy) * dxdy;
190          GLint ix, startX = (GLint) (x - xAdj);
191          GLuint count;
192          GLfloat coverage = 0.0F;
193 
194 #ifdef _OPENMP
195          /* each thread needs to use a different (global) SpanArrays variable */
196          span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
197 #endif
198          /* skip over fragments with zero coverage */
199          while (startX < SWRAST_MAX_WIDTH) {
200             coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
201             if (coverage > 0.0F)
202                break;
203             startX++;
204          }
205 
206          /* enter interior of triangle */
207          ix = startX;
208 
209 #if defined(DO_ATTRIBS)
210          /* compute attributes at left-most fragment */
211          span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 0.5F, iy + 0.5F, wPlane);
212          ATTRIB_LOOP_BEGIN
213             GLuint c;
214             for (c = 0; c < 4; c++) {
215                span.attrStart[attr][c] = solve_plane(ix + 0.5F, iy + 0.5F, attrPlane[attr][c]);
216             }
217          ATTRIB_LOOP_END
218 #endif
219 
220          count = 0;
221          while (coverage > 0.0F) {
222             /* (cx,cy) = center of fragment */
223             const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
224             SWspanarrays *array = span.array;
225             array->coverage[count] = coverage;
226 #ifdef DO_Z
227             array->z[count] = (GLuint) solve_plane(cx, cy, zPlane);
228 #endif
229             array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane);
230             array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane);
231             array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane);
232             array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane);
233             ix++;
234             count++;
235             coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
236          }
237 
238          if (ix > startX) {
239             span.x = startX;
240             span.y = iy;
241             span.end = (GLuint) ix - (GLuint) startX;
242             _swrast_write_rgba_span(ctx, &span);
243          }
244       }
245    }
246    else {
247       /* scan right to left */
248       const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
249       const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
250       const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
251       const GLfloat dxdy = majDx / majDy;
252       const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
253       GLint iy;
254 #ifdef _OPENMP
255 #pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
256 #endif
257       for (iy = iyMin; iy < iyMax; iy++) {
258          GLfloat x = pMin[0] - (yMin - iy) * dxdy;
259          GLint ix, left, startX = (GLint) (x + xAdj);
260          GLuint count, n;
261          GLfloat coverage = 0.0F;
262 
263 #ifdef _OPENMP
264          /* each thread needs to use a different (global) SpanArrays variable */
265          span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
266 #endif
267          /* make sure we're not past the window edge */
268          if (startX >= ctx->DrawBuffer->_Xmax) {
269             startX = ctx->DrawBuffer->_Xmax - 1;
270          }
271 
272          /* skip fragments with zero coverage */
273          while (startX > 0) {
274             coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
275             if (coverage > 0.0F)
276                break;
277             startX--;
278          }
279 
280          /* enter interior of triangle */
281          ix = startX;
282          count = 0;
283          while (coverage > 0.0F) {
284             /* (cx,cy) = center of fragment */
285             const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
286             SWspanarrays *array = span.array;
287             assert(ix >= 0);
288             array->coverage[ix] = coverage;
289 #ifdef DO_Z
290             array->z[ix] = (GLuint) solve_plane(cx, cy, zPlane);
291 #endif
292             array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane);
293             array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane);
294             array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane);
295             array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane);
296             ix--;
297             count++;
298             coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
299          }
300 
301 #if defined(DO_ATTRIBS)
302          /* compute attributes at left-most fragment */
303          span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 1.5F, iy + 0.5F, wPlane);
304          ATTRIB_LOOP_BEGIN
305             GLuint c;
306             for (c = 0; c < 4; c++) {
307                span.attrStart[attr][c] = solve_plane(ix + 1.5F, iy + 0.5F, attrPlane[attr][c]);
308             }
309          ATTRIB_LOOP_END
310 #endif
311 
312          if (startX > ix) {
313             n = (GLuint) startX - (GLuint) ix;
314 
315             left = ix + 1;
316 
317             /* shift all values to the left */
318             /* XXX this is temporary */
319             {
320                SWspanarrays *array = span.array;
321                GLint j;
322                for (j = 0; j < (GLint) n; j++) {
323                   array->coverage[j] = array->coverage[j + left];
324                   COPY_CHAN4(array->rgba[j], array->rgba[j + left]);
325 #ifdef DO_Z
326                   array->z[j] = array->z[j + left];
327 #endif
328                }
329             }
330 
331             span.x = left;
332             span.y = iy;
333             span.end = n;
334             _swrast_write_rgba_span(ctx, &span);
335          }
336       }
337    }
338 }
339 
340 
341 #undef DO_Z
342 #undef DO_ATTRIBS
343 #undef DO_OCCLUSION_TEST
344