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_SPEC - if defined, compute specular RGB values
39 * DO_TEXVAR - if defined, compute texcoords, varying
42 /*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
44 const SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
45 const GLfloat
*p0
= v0
->win
;
46 const GLfloat
*p1
= v1
->win
;
47 const GLfloat
*p2
= v2
->win
;
48 const SWvertex
*vMin
, *vMid
, *vMax
;
52 GLfloat majDx
, majDy
; /* major (i.e. long) edge dx and dy */
65 GLfloat rPlane
[4], gPlane
[4], bPlane
[4], aPlane
[4];
71 GLfloat srPlane
[4], sgPlane
[4], sbPlane
[4];
73 #if defined(DO_TEXVAR)
74 GLfloat sPlane
[FRAG_ATTRIB_MAX
][4]; /* texture S */
75 GLfloat tPlane
[FRAG_ATTRIB_MAX
][4]; /* texture T */
76 GLfloat uPlane
[FRAG_ATTRIB_MAX
][4]; /* texture R */
77 GLfloat vPlane
[FRAG_ATTRIB_MAX
][4]; /* texture Q */
78 GLfloat texWidth
[FRAG_ATTRIB_MAX
];
79 GLfloat texHeight
[FRAG_ATTRIB_MAX
];
81 GLfloat bf
= SWRAST_CONTEXT(ctx
)->_BackfaceSign
;
85 INIT_SPAN(span
, GL_POLYGON
, 0, 0, SPAN_COVERAGE
);
87 /* determine bottom to top order of vertices */
89 GLfloat y0
= v0
->win
[1];
90 GLfloat y1
= v1
->win
[1];
91 GLfloat y2
= v2
->win
[1];
94 vMin
= v0
; vMid
= v1
; vMax
= v2
; /* y0<=y1<=y2 */
97 vMin
= v2
; vMid
= v0
; vMax
= v1
; /* y2<=y0<=y1 */
100 vMin
= v0
; vMid
= v2
; vMax
= v1
; bf
= -bf
; /* y0<=y2<=y1 */
105 vMin
= v1
; vMid
= v0
; vMax
= v2
; bf
= -bf
; /* y1<=y0<=y2 */
108 vMin
= v2
; vMid
= v1
; vMax
= v0
; bf
= -bf
; /* y2<=y1<=y0 */
111 vMin
= v1
; vMid
= v2
; vMax
= v0
; /* y1<=y2<=y0 */
116 majDx
= vMax
->win
[0] - vMin
->win
[0];
117 majDy
= vMax
->win
[1] - vMin
->win
[1];
120 const GLfloat botDx
= vMid
->win
[0] - vMin
->win
[0];
121 const GLfloat botDy
= vMid
->win
[1] - vMin
->win
[1];
122 const GLfloat area
= majDx
* botDy
- botDx
* majDy
;
123 /* Do backface culling */
124 if (area
* bf
< 0 || area
== 0 || IS_INF_OR_NAN(area
))
126 ltor
= (GLboolean
) (area
< 0.0F
);
129 /* Plane equation setup:
130 * We evaluate plane equations at window (x,y) coordinates in order
131 * to compute color, Z, fog, texcoords, etc. This isn't terribly
132 * efficient but it's easy and reliable.
135 compute_plane(p0
, p1
, p2
, p0
[2], p1
[2], p2
[2], zPlane
);
136 span
.arrayMask
|= SPAN_Z
;
139 compute_plane(p0
, p1
, p2
, v0
->fog
, v1
->fog
, v2
->fog
, fogPlane
);
140 span
.arrayMask
|= SPAN_FOG
;
143 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
144 compute_plane(p0
, p1
, p2
, v0
->color
[RCOMP
], v1
->color
[RCOMP
], v2
->color
[RCOMP
], rPlane
);
145 compute_plane(p0
, p1
, p2
, v0
->color
[GCOMP
], v1
->color
[GCOMP
], v2
->color
[GCOMP
], gPlane
);
146 compute_plane(p0
, p1
, p2
, v0
->color
[BCOMP
], v1
->color
[BCOMP
], v2
->color
[BCOMP
], bPlane
);
147 compute_plane(p0
, p1
, p2
, v0
->color
[ACOMP
], v1
->color
[ACOMP
], v2
->color
[ACOMP
], aPlane
);
150 constant_plane(v2
->color
[RCOMP
], rPlane
);
151 constant_plane(v2
->color
[GCOMP
], gPlane
);
152 constant_plane(v2
->color
[BCOMP
], bPlane
);
153 constant_plane(v2
->color
[ACOMP
], aPlane
);
155 span
.arrayMask
|= SPAN_RGBA
;
158 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
159 compute_plane(p0
, p1
, p2
, (GLfloat
) v0
->index
,
160 v1
->index
, v2
->index
, iPlane
);
163 constant_plane(v2
->index
, iPlane
);
165 span
.arrayMask
|= SPAN_INDEX
;
168 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
169 compute_plane(p0
, p1
, p2
, v0
->specular
[RCOMP
], v1
->specular
[RCOMP
], v2
->specular
[RCOMP
], srPlane
);
170 compute_plane(p0
, p1
, p2
, v0
->specular
[GCOMP
], v1
->specular
[GCOMP
], v2
->specular
[GCOMP
], sgPlane
);
171 compute_plane(p0
, p1
, p2
, v0
->specular
[BCOMP
], v1
->specular
[BCOMP
], v2
->specular
[BCOMP
], sbPlane
);
174 constant_plane(v2
->specular
[RCOMP
], srPlane
);
175 constant_plane(v2
->specular
[GCOMP
], sgPlane
);
176 constant_plane(v2
->specular
[BCOMP
], sbPlane
);
178 span
.arrayMask
|= SPAN_SPEC
;
180 #if defined(DO_TEXVAR)
183 const GLfloat invW0
= v0
->win
[3];
184 const GLfloat invW1
= v1
->win
[3];
185 const GLfloat invW2
= v2
->win
[3];
186 for (attr
= swrast
->_MinFragmentAttrib
; attr
< swrast
->_MaxFragmentAttrib
; attr
++) {
187 if (swrast
->_FragmentAttribs
& (1 << attr
)) {
188 const GLfloat s0
= v0
->attrib
[attr
][0] * invW0
;
189 const GLfloat s1
= v1
->attrib
[attr
][0] * invW1
;
190 const GLfloat s2
= v2
->attrib
[attr
][0] * invW2
;
191 const GLfloat t0
= v0
->attrib
[attr
][1] * invW0
;
192 const GLfloat t1
= v1
->attrib
[attr
][1] * invW1
;
193 const GLfloat t2
= v2
->attrib
[attr
][1] * invW2
;
194 const GLfloat r0
= v0
->attrib
[attr
][2] * invW0
;
195 const GLfloat r1
= v1
->attrib
[attr
][2] * invW1
;
196 const GLfloat r2
= v2
->attrib
[attr
][2] * invW2
;
197 const GLfloat q0
= v0
->attrib
[attr
][3] * invW0
;
198 const GLfloat q1
= v1
->attrib
[attr
][3] * invW1
;
199 const GLfloat q2
= v2
->attrib
[attr
][3] * invW2
;
200 compute_plane(p0
, p1
, p2
, s0
, s1
, s2
, sPlane
[attr
]);
201 compute_plane(p0
, p1
, p2
, t0
, t1
, t2
, tPlane
[attr
]);
202 compute_plane(p0
, p1
, p2
, r0
, r1
, r2
, uPlane
[attr
]);
203 compute_plane(p0
, p1
, p2
, q0
, q1
, q2
, vPlane
[attr
]);
204 if (attr
< FRAG_ATTRIB_VAR0
) {
205 const GLuint u
= attr
- FRAG_ATTRIB_TEX0
;
206 const struct gl_texture_object
*obj
= ctx
->Texture
.Unit
[u
]._Current
;
207 const struct gl_texture_image
*texImage
= obj
->Image
[0][obj
->BaseLevel
];
208 texWidth
[attr
] = (GLfloat
) texImage
->Width
;
209 texHeight
[attr
] = (GLfloat
) texImage
->Height
;
212 texWidth
[attr
] = texHeight
[attr
] = 1.0;
217 span
.arrayMask
|= (SPAN_TEXTURE
| SPAN_LAMBDA
| SPAN_VARYING
);
220 /* Begin bottom-to-top scan over the triangle.
221 * The long edge will either be on the left or right side of the
222 * triangle. We always scan from the long edge toward the shorter
223 * edges, stopping when we find that coverage = 0. If the long edge
224 * is on the left we scan left-to-right. Else, we scan right-to-left.
228 iyMin
= (GLint
) yMin
;
229 iyMax
= (GLint
) yMax
+ 1;
232 /* scan left to right */
233 const GLfloat
*pMin
= vMin
->win
;
234 const GLfloat
*pMid
= vMid
->win
;
235 const GLfloat
*pMax
= vMax
->win
;
236 const GLfloat dxdy
= majDx
/ majDy
;
237 const GLfloat xAdj
= dxdy
< 0.0F
? -dxdy
: 0.0F
;
238 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
240 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
241 GLint ix
, startX
= (GLint
) (x
- xAdj
);
243 GLfloat coverage
= 0.0F
;
245 /* skip over fragments with zero coverage */
246 while (startX
< MAX_WIDTH
) {
247 coverage
= compute_coveragef(pMin
, pMid
, pMax
, startX
, iy
);
253 /* enter interior of triangle */
256 while (coverage
> 0.0F
) {
257 /* (cx,cy) = center of fragment */
258 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
259 SWspanarrays
*array
= span
.array
;
261 array
->coverage
[count
] = (GLfloat
) compute_coveragei(pMin
, pMid
, pMax
, ix
, iy
);
263 array
->coverage
[count
] = coverage
;
266 array
->z
[count
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
269 array
->attribs
[FRAG_ATTRIB_FOGC
][count
][0] = solve_plane(cx
, cy
, fogPlane
);
272 array
->rgba
[count
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
273 array
->rgba
[count
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
274 array
->rgba
[count
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
275 array
->rgba
[count
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
278 array
->index
[count
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
281 array
->spec
[count
][RCOMP
] = solve_plane_chan(cx
, cy
, srPlane
);
282 array
->spec
[count
][GCOMP
] = solve_plane_chan(cx
, cy
, sgPlane
);
283 array
->spec
[count
][BCOMP
] = solve_plane_chan(cx
, cy
, sbPlane
);
285 #if defined(DO_TEXVAR)
288 for (attr
= swrast
->_MinFragmentAttrib
; attr
< swrast
->_MaxFragmentAttrib
; attr
++) {
289 if (swrast
->_FragmentAttribs
& (1 << attr
)) {
290 GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
[attr
]);
291 array
->attribs
[attr
][count
][0] = solve_plane(cx
, cy
, sPlane
[attr
]) * invQ
;
292 array
->attribs
[attr
][count
][1] = solve_plane(cx
, cy
, tPlane
[attr
]) * invQ
;
293 array
->attribs
[attr
][count
][2] = solve_plane(cx
, cy
, uPlane
[attr
]) * invQ
;
294 if (attr
< FRAG_ATTRIB_VAR0
) {
295 const GLuint unit
= attr
- FRAG_ATTRIB_TEX0
;
296 array
->lambda
[unit
][count
] = compute_lambda(sPlane
[attr
], tPlane
[attr
],
297 vPlane
[attr
], cx
, cy
, invQ
,
298 texWidth
[attr
], texHeight
[attr
]);
306 coverage
= compute_coveragef(pMin
, pMid
, pMax
, ix
, iy
);
314 span
.end
= (GLuint
) ix
- (GLuint
) startX
;
315 ASSERT(span
.interpMask
== 0);
317 _swrast_write_rgba_span(ctx
, &span
);
319 _swrast_write_index_span(ctx
, &span
);
324 /* scan right to left */
325 const GLfloat
*pMin
= vMin
->win
;
326 const GLfloat
*pMid
= vMid
->win
;
327 const GLfloat
*pMax
= vMax
->win
;
328 const GLfloat dxdy
= majDx
/ majDy
;
329 const GLfloat xAdj
= dxdy
> 0 ? dxdy
: 0.0F
;
330 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
332 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
333 GLint ix
, left
, startX
= (GLint
) (x
+ xAdj
);
335 GLfloat coverage
= 0.0F
;
337 /* make sure we're not past the window edge */
338 if (startX
>= ctx
->DrawBuffer
->_Xmax
) {
339 startX
= ctx
->DrawBuffer
->_Xmax
- 1;
342 /* skip fragments with zero coverage */
343 while (startX
>= 0) {
344 coverage
= compute_coveragef(pMin
, pMax
, pMid
, startX
, iy
);
350 /* enter interior of triangle */
353 while (coverage
> 0.0F
) {
354 /* (cx,cy) = center of fragment */
355 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
356 SWspanarrays
*array
= span
.array
;
358 array
->coverage
[ix
] = (GLfloat
) compute_coveragei(pMin
, pMax
, pMid
, ix
, iy
);
360 array
->coverage
[ix
] = coverage
;
363 array
->z
[ix
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
366 array
->attribs
[FRAG_ATTRIB_FOGC
][ix
][0] = solve_plane(cx
, cy
, fogPlane
);
369 array
->rgba
[ix
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
370 array
->rgba
[ix
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
371 array
->rgba
[ix
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
372 array
->rgba
[ix
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
375 array
->index
[ix
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
378 array
->spec
[ix
][RCOMP
] = solve_plane_chan(cx
, cy
, srPlane
);
379 array
->spec
[ix
][GCOMP
] = solve_plane_chan(cx
, cy
, sgPlane
);
380 array
->spec
[ix
][BCOMP
] = solve_plane_chan(cx
, cy
, sbPlane
);
382 #if defined(DO_TEXVAR)
385 for (attr
= swrast
->_MinFragmentAttrib
; attr
< swrast
->_MaxFragmentAttrib
; attr
++) {
386 if (swrast
->_FragmentAttribs
& (1 << attr
)) {
387 GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
[attr
]);
388 array
->attribs
[attr
][ix
][0] = solve_plane(cx
, cy
, sPlane
[attr
]) * invQ
;
389 array
->attribs
[attr
][ix
][1] = solve_plane(cx
, cy
, tPlane
[attr
]) * invQ
;
390 array
->attribs
[attr
][ix
][2] = solve_plane(cx
, cy
, uPlane
[attr
]) * invQ
;
391 if (attr
< FRAG_ATTRIB_VAR0
) {
392 const GLuint unit
= attr
- FRAG_ATTRIB_TEX0
;
393 array
->lambda
[unit
][ix
] = compute_lambda(sPlane
[attr
],
406 coverage
= compute_coveragef(pMin
, pMax
, pMid
, ix
, iy
);
412 n
= (GLuint
) startX
- (GLuint
) ix
;
416 /* shift all values to the left */
417 /* XXX this is temporary */
419 SWspanarrays
*array
= span
.array
;
421 for (j
= 0; j
< (GLint
) n
; j
++) {
423 COPY_CHAN4(array
->rgba
[j
], array
->rgba
[j
+ left
]);
426 COPY_CHAN4(array
->spec
[j
], array
->spec
[j
+ left
]);
429 array
->index
[j
] = array
->index
[j
+ left
];
432 array
->z
[j
] = array
->z
[j
+ left
];
435 array
->attribs
[FRAG_ATTRIB_FOGC
][j
][0]
436 = array
->attribs
[FRAG_ATTRIB_FOGC
][j
+ left
][0];
438 #if defined(DO_TEXVAR)
439 array
->lambda
[0][j
] = array
->lambda
[0][j
+ left
];
441 array
->coverage
[j
] = array
->coverage
[j
+ left
];
445 /* shift texcoords, varying */
447 SWspanarrays
*array
= span
.array
;
449 for (attr
= swrast
->_MinFragmentAttrib
; attr
< swrast
->_MaxFragmentAttrib
; attr
++) {
450 if (swrast
->_FragmentAttribs
& (1 << attr
)) {
452 for (j
= 0; j
< (GLint
) n
; j
++) {
453 array
->attribs
[attr
][j
][0] = array
->attribs
[attr
][j
+ left
][0];
454 array
->attribs
[attr
][j
][1] = array
->attribs
[attr
][j
+ left
][1];
455 array
->attribs
[attr
][j
][2] = array
->attribs
[attr
][j
+ left
][2];
456 /*array->lambda[unit][j] = array->lambda[unit][j + left];*/
466 ASSERT(span
.interpMask
== 0);
468 _swrast_write_rgba_span(ctx
, &span
);
470 _swrast_write_index_span(ctx
, &span
);
501 #ifdef DO_OCCLUSION_TEST
502 #undef DO_OCCLUSION_TEST