2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Antialiased Triangle Rasterizer Template
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
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_RGBA - if defined, compute RGBA values
37 * DO_INDEX - if defined, compute color index values
38 * DO_ATTRIBS - if defined, compute texcoords, varying, etc.
41 /*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
43 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
44 const GLfloat
*p0
= v0
->attrib
[FRAG_ATTRIB_WPOS
];
45 const GLfloat
*p1
= v1
->attrib
[FRAG_ATTRIB_WPOS
];
46 const GLfloat
*p2
= v2
->attrib
[FRAG_ATTRIB_WPOS
];
47 const SWvertex
*vMin
, *vMid
, *vMax
;
51 GLfloat majDx
, majDy
; /* major (i.e. long) edge dx and dy */
59 GLfloat rPlane
[4], gPlane
[4], bPlane
[4], aPlane
[4];
64 #if defined(DO_ATTRIBS)
65 GLfloat attrPlane
[FRAG_ATTRIB_MAX
][4][4];
66 GLfloat wPlane
[4]; /* win[3] */
68 GLfloat bf
= SWRAST_CONTEXT(ctx
)->_BackfaceSign
;
72 INIT_SPAN(span
, GL_POLYGON
);
73 span
.arrayMask
= SPAN_COVERAGE
;
75 /* determine bottom to top order of vertices */
77 GLfloat y0
= v0
->attrib
[FRAG_ATTRIB_WPOS
][1];
78 GLfloat y1
= v1
->attrib
[FRAG_ATTRIB_WPOS
][1];
79 GLfloat y2
= v2
->attrib
[FRAG_ATTRIB_WPOS
][1];
82 vMin
= v0
; vMid
= v1
; vMax
= v2
; /* y0<=y1<=y2 */
85 vMin
= v2
; vMid
= v0
; vMax
= v1
; /* y2<=y0<=y1 */
88 vMin
= v0
; vMid
= v2
; vMax
= v1
; bf
= -bf
; /* y0<=y2<=y1 */
93 vMin
= v1
; vMid
= v0
; vMax
= v2
; bf
= -bf
; /* y1<=y0<=y2 */
96 vMin
= v2
; vMid
= v1
; vMax
= v0
; bf
= -bf
; /* y2<=y1<=y0 */
99 vMin
= v1
; vMid
= v2
; vMax
= v0
; /* y1<=y2<=y0 */
104 majDx
= vMax
->attrib
[FRAG_ATTRIB_WPOS
][0] - vMin
->attrib
[FRAG_ATTRIB_WPOS
][0];
105 majDy
= vMax
->attrib
[FRAG_ATTRIB_WPOS
][1] - vMin
->attrib
[FRAG_ATTRIB_WPOS
][1];
108 const GLfloat botDx
= vMid
->attrib
[FRAG_ATTRIB_WPOS
][0] - vMin
->attrib
[FRAG_ATTRIB_WPOS
][0];
109 const GLfloat botDy
= vMid
->attrib
[FRAG_ATTRIB_WPOS
][1] - vMin
->attrib
[FRAG_ATTRIB_WPOS
][1];
110 const GLfloat area
= majDx
* botDy
- botDx
* majDy
;
111 /* Do backface culling */
112 if (area
* bf
< 0 || area
== 0 || IS_INF_OR_NAN(area
))
114 ltor
= (GLboolean
) (area
< 0.0F
);
117 /* Plane equation setup:
118 * We evaluate plane equations at window (x,y) coordinates in order
119 * to compute color, Z, fog, texcoords, etc. This isn't terribly
120 * efficient but it's easy and reliable.
123 compute_plane(p0
, p1
, p2
, p0
[2], p1
[2], p2
[2], zPlane
);
124 span
.arrayMask
|= SPAN_Z
;
127 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
128 compute_plane(p0
, p1
, p2
, v0
->color
[RCOMP
], v1
->color
[RCOMP
], v2
->color
[RCOMP
], rPlane
);
129 compute_plane(p0
, p1
, p2
, v0
->color
[GCOMP
], v1
->color
[GCOMP
], v2
->color
[GCOMP
], gPlane
);
130 compute_plane(p0
, p1
, p2
, v0
->color
[BCOMP
], v1
->color
[BCOMP
], v2
->color
[BCOMP
], bPlane
);
131 compute_plane(p0
, p1
, p2
, v0
->color
[ACOMP
], v1
->color
[ACOMP
], v2
->color
[ACOMP
], aPlane
);
134 constant_plane(v2
->color
[RCOMP
], rPlane
);
135 constant_plane(v2
->color
[GCOMP
], gPlane
);
136 constant_plane(v2
->color
[BCOMP
], bPlane
);
137 constant_plane(v2
->color
[ACOMP
], aPlane
);
139 span
.arrayMask
|= SPAN_RGBA
;
142 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
143 compute_plane(p0
, p1
, p2
, (GLfloat
) v0
->attrib
[FRAG_ATTRIB_CI
][0],
144 v1
->attrib
[FRAG_ATTRIB_CI
][0], v2
->attrib
[FRAG_ATTRIB_CI
][0], iPlane
);
147 constant_plane(v2
->attrib
[FRAG_ATTRIB_CI
][0], iPlane
);
149 span
.arrayMask
|= SPAN_INDEX
;
151 #if defined(DO_ATTRIBS)
153 const GLfloat invW0
= v0
->attrib
[FRAG_ATTRIB_WPOS
][3];
154 const GLfloat invW1
= v1
->attrib
[FRAG_ATTRIB_WPOS
][3];
155 const GLfloat invW2
= v2
->attrib
[FRAG_ATTRIB_WPOS
][3];
156 compute_plane(p0
, p1
, p2
, invW0
, invW1
, invW2
, wPlane
);
157 span
.attrStepX
[FRAG_ATTRIB_WPOS
][3] = plane_dx(wPlane
);
158 span
.attrStepY
[FRAG_ATTRIB_WPOS
][3] = plane_dy(wPlane
);
161 if (swrast
->_InterpMode
[attr
] == GL_FLAT
) {
162 for (c
= 0; c
< 4; c
++) {
163 constant_plane(v2
->attrib
[attr
][c
] * invW2
, attrPlane
[attr
][c
]);
167 for (c
= 0; c
< 4; c
++) {
168 const GLfloat a0
= v0
->attrib
[attr
][c
] * invW0
;
169 const GLfloat a1
= v1
->attrib
[attr
][c
] * invW1
;
170 const GLfloat a2
= v2
->attrib
[attr
][c
] * invW2
;
171 compute_plane(p0
, p1
, p2
, a0
, a1
, a2
, attrPlane
[attr
][c
]);
174 for (c
= 0; c
< 4; c
++) {
175 span
.attrStepX
[attr
][c
] = plane_dx(attrPlane
[attr
][c
]);
176 span
.attrStepY
[attr
][c
] = plane_dy(attrPlane
[attr
][c
]);
182 /* Begin bottom-to-top scan over the triangle.
183 * The long edge will either be on the left or right side of the
184 * triangle. We always scan from the long edge toward the shorter
185 * edges, stopping when we find that coverage = 0. If the long edge
186 * is on the left we scan left-to-right. Else, we scan right-to-left.
188 yMin
= vMin
->attrib
[FRAG_ATTRIB_WPOS
][1];
189 yMax
= vMax
->attrib
[FRAG_ATTRIB_WPOS
][1];
190 iyMin
= (GLint
) yMin
;
191 iyMax
= (GLint
) yMax
+ 1;
194 /* scan left to right */
195 const GLfloat
*pMin
= vMin
->attrib
[FRAG_ATTRIB_WPOS
];
196 const GLfloat
*pMid
= vMid
->attrib
[FRAG_ATTRIB_WPOS
];
197 const GLfloat
*pMax
= vMax
->attrib
[FRAG_ATTRIB_WPOS
];
198 const GLfloat dxdy
= majDx
/ majDy
;
199 const GLfloat xAdj
= dxdy
< 0.0F
? -dxdy
: 0.0F
;
200 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
202 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
203 GLint ix
, startX
= (GLint
) (x
- xAdj
);
205 GLfloat coverage
= 0.0F
;
207 /* skip over fragments with zero coverage */
208 while (startX
< MAX_WIDTH
) {
209 coverage
= compute_coveragef(pMin
, pMid
, pMax
, startX
, iy
);
215 /* enter interior of triangle */
218 #if defined(DO_ATTRIBS)
219 /* compute attributes at left-most fragment */
220 span
.attrStart
[FRAG_ATTRIB_WPOS
][3] = solve_plane(ix
+ 0.5, iy
+ 0.5, wPlane
);
223 for (c
= 0; c
< 4; c
++) {
224 span
.attrStart
[attr
][c
] = solve_plane(ix
+ 0.5, iy
+ 0.5, attrPlane
[attr
][c
]);
230 while (coverage
> 0.0F
) {
231 /* (cx,cy) = center of fragment */
232 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
233 SWspanarrays
*array
= span
.array
;
235 array
->coverage
[count
] = (GLfloat
) compute_coveragei(pMin
, pMid
, pMax
, ix
, iy
);
237 array
->coverage
[count
] = coverage
;
240 array
->z
[count
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
243 array
->rgba
[count
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
244 array
->rgba
[count
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
245 array
->rgba
[count
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
246 array
->rgba
[count
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
249 array
->index
[count
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
253 coverage
= compute_coveragef(pMin
, pMid
, pMax
, ix
, iy
);
261 span
.end
= (GLuint
) ix
- (GLuint
) startX
;
263 _swrast_write_rgba_span(ctx
, &span
);
265 _swrast_write_index_span(ctx
, &span
);
270 /* scan right to left */
271 const GLfloat
*pMin
= vMin
->attrib
[FRAG_ATTRIB_WPOS
];
272 const GLfloat
*pMid
= vMid
->attrib
[FRAG_ATTRIB_WPOS
];
273 const GLfloat
*pMax
= vMax
->attrib
[FRAG_ATTRIB_WPOS
];
274 const GLfloat dxdy
= majDx
/ majDy
;
275 const GLfloat xAdj
= dxdy
> 0 ? dxdy
: 0.0F
;
276 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
278 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
279 GLint ix
, left
, startX
= (GLint
) (x
+ xAdj
);
281 GLfloat coverage
= 0.0F
;
283 /* make sure we're not past the window edge */
284 if (startX
>= ctx
->DrawBuffer
->_Xmax
) {
285 startX
= ctx
->DrawBuffer
->_Xmax
- 1;
288 /* skip fragments with zero coverage */
289 while (startX
>= 0) {
290 coverage
= compute_coveragef(pMin
, pMax
, pMid
, startX
, iy
);
296 /* enter interior of triangle */
299 while (coverage
> 0.0F
) {
300 /* (cx,cy) = center of fragment */
301 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
302 SWspanarrays
*array
= span
.array
;
304 array
->coverage
[ix
] = (GLfloat
) compute_coveragei(pMin
, pMax
, pMid
, ix
, iy
);
306 array
->coverage
[ix
] = coverage
;
309 array
->z
[ix
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
312 array
->rgba
[ix
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
313 array
->rgba
[ix
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
314 array
->rgba
[ix
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
315 array
->rgba
[ix
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
318 array
->index
[ix
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
322 coverage
= compute_coveragef(pMin
, pMax
, pMid
, ix
, iy
);
325 #if defined(DO_ATTRIBS)
326 /* compute attributes at left-most fragment */
327 span
.attrStart
[FRAG_ATTRIB_WPOS
][3] = solve_plane(ix
+ 1.5, iy
+ 0.5, wPlane
);
330 for (c
= 0; c
< 4; c
++) {
331 span
.attrStart
[attr
][c
] = solve_plane(ix
+ 1.5, iy
+ 0.5, attrPlane
[attr
][c
]);
339 n
= (GLuint
) startX
- (GLuint
) ix
;
343 /* shift all values to the left */
344 /* XXX this is temporary */
346 SWspanarrays
*array
= span
.array
;
348 for (j
= 0; j
< (GLint
) n
; j
++) {
349 array
->coverage
[j
] = array
->coverage
[j
+ left
];
351 COPY_CHAN4(array
->rgba
[j
], array
->rgba
[j
+ left
]);
354 array
->index
[j
] = array
->index
[j
+ left
];
357 array
->z
[j
] = array
->z
[j
+ left
];
366 _swrast_write_rgba_span(ctx
, &span
);
368 _swrast_write_index_span(ctx
, &span
);
379 #undef DO_OCCLUSION_TEST