Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 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>>>>>>>>>>>>=y0>=y2<=y0>=y0>=y1<=y0>=>=y2>=y0<=y2>=>=y1>=y2<=y1>=y1>=y0<=y1>=>=y2>=y1<=y2>=>=> |