2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 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_TEX - if defined, compute unit 0 STRQ texcoords
40 * DO_MULTITEX - if defined, compute all unit's STRQ texcoords
43 /*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
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];
74 GLfloat sPlane
[4], tPlane
[4], uPlane
[4], vPlane
[4];
75 GLfloat texWidth
, texHeight
;
76 #elif defined(DO_MULTITEX)
77 GLfloat sPlane
[MAX_TEXTURE_COORD_UNITS
][4]; /* texture S */
78 GLfloat tPlane
[MAX_TEXTURE_COORD_UNITS
][4]; /* texture T */
79 GLfloat uPlane
[MAX_TEXTURE_COORD_UNITS
][4]; /* texture R */
80 GLfloat vPlane
[MAX_TEXTURE_COORD_UNITS
][4]; /* texture Q */
81 GLfloat texWidth
[MAX_TEXTURE_COORD_UNITS
];
82 GLfloat texHeight
[MAX_TEXTURE_COORD_UNITS
];
84 GLfloat bf
= SWRAST_CONTEXT(ctx
)->_BackfaceSign
;
87 INIT_SPAN(span
, GL_POLYGON
, 0, 0, SPAN_COVERAGE
);
89 /* determine bottom to top order of vertices */
91 GLfloat y0
= v0
->win
[1];
92 GLfloat y1
= v1
->win
[1];
93 GLfloat y2
= v2
->win
[1];
96 vMin
= v0
; vMid
= v1
; vMax
= v2
; /* y0<=y1<=y2 */
99 vMin
= v2
; vMid
= v0
; vMax
= v1
; /* y2<=y0<=y1 */
102 vMin
= v0
; vMid
= v2
; vMax
= v1
; bf
= -bf
; /* y0<=y2<=y1 */
107 vMin
= v1
; vMid
= v0
; vMax
= v2
; bf
= -bf
; /* y1<=y0<=y2 */
110 vMin
= v2
; vMid
= v1
; vMax
= v0
; bf
= -bf
; /* y2<=y1<=y0 */
113 vMin
= v1
; vMid
= v2
; vMax
= v0
; /* y1<=y2<=y0 */
118 majDx
= vMax
->win
[0] - vMin
->win
[0];
119 majDy
= vMax
->win
[1] - vMin
->win
[1];
122 const GLfloat botDx
= vMid
->win
[0] - vMin
->win
[0];
123 const GLfloat botDy
= vMid
->win
[1] - vMin
->win
[1];
124 const GLfloat area
= majDx
* botDy
- botDx
* majDy
;
125 /* Do backface culling */
126 if (area
* bf
< 0 || area
== 0 || IS_INF_OR_NAN(area
))
128 ltor
= (GLboolean
) (area
< 0.0F
);
131 /* Plane equation setup:
132 * We evaluate plane equations at window (x,y) coordinates in order
133 * to compute color, Z, fog, texcoords, etc. This isn't terribly
134 * efficient but it's easy and reliable.
137 compute_plane(p0
, p1
, p2
, p0
[2], p1
[2], p2
[2], zPlane
);
138 span
.arrayMask
|= SPAN_Z
;
141 compute_plane(p0
, p1
, p2
, v0
->fog
, v1
->fog
, v2
->fog
, fogPlane
);
142 span
.arrayMask
|= SPAN_FOG
;
145 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
146 compute_plane(p0
, p1
, p2
, v0
->color
[RCOMP
], v1
->color
[RCOMP
], v2
->color
[RCOMP
], rPlane
);
147 compute_plane(p0
, p1
, p2
, v0
->color
[GCOMP
], v1
->color
[GCOMP
], v2
->color
[GCOMP
], gPlane
);
148 compute_plane(p0
, p1
, p2
, v0
->color
[BCOMP
], v1
->color
[BCOMP
], v2
->color
[BCOMP
], bPlane
);
149 compute_plane(p0
, p1
, p2
, v0
->color
[ACOMP
], v1
->color
[ACOMP
], v2
->color
[ACOMP
], aPlane
);
152 constant_plane(v2
->color
[RCOMP
], rPlane
);
153 constant_plane(v2
->color
[GCOMP
], gPlane
);
154 constant_plane(v2
->color
[BCOMP
], bPlane
);
155 constant_plane(v2
->color
[ACOMP
], aPlane
);
157 span
.arrayMask
|= SPAN_RGBA
;
160 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
161 compute_plane(p0
, p1
, p2
, (GLfloat
) v0
->index
,
162 v1
->index
, v2
->index
, iPlane
);
165 constant_plane(v2
->index
, iPlane
);
167 span
.arrayMask
|= SPAN_INDEX
;
170 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
171 compute_plane(p0
, p1
, p2
, v0
->specular
[RCOMP
], v1
->specular
[RCOMP
], v2
->specular
[RCOMP
], srPlane
);
172 compute_plane(p0
, p1
, p2
, v0
->specular
[GCOMP
], v1
->specular
[GCOMP
], v2
->specular
[GCOMP
], sgPlane
);
173 compute_plane(p0
, p1
, p2
, v0
->specular
[BCOMP
], v1
->specular
[BCOMP
], v2
->specular
[BCOMP
], sbPlane
);
176 constant_plane(v2
->specular
[RCOMP
], srPlane
);
177 constant_plane(v2
->specular
[GCOMP
], sgPlane
);
178 constant_plane(v2
->specular
[BCOMP
], sbPlane
);
180 span
.arrayMask
|= SPAN_SPEC
;
184 const struct gl_texture_object
*obj
= ctx
->Texture
.Unit
[0]._Current
;
185 const struct gl_texture_image
*texImage
= obj
->Image
[0][obj
->BaseLevel
];
186 const GLfloat invW0
= v0
->win
[3];
187 const GLfloat invW1
= v1
->win
[3];
188 const GLfloat invW2
= v2
->win
[3];
189 const GLfloat s0
= v0
->texcoord
[0][0] * invW0
;
190 const GLfloat s1
= v1
->texcoord
[0][0] * invW1
;
191 const GLfloat s2
= v2
->texcoord
[0][0] * invW2
;
192 const GLfloat t0
= v0
->texcoord
[0][1] * invW0
;
193 const GLfloat t1
= v1
->texcoord
[0][1] * invW1
;
194 const GLfloat t2
= v2
->texcoord
[0][1] * invW2
;
195 const GLfloat r0
= v0
->texcoord
[0][2] * invW0
;
196 const GLfloat r1
= v1
->texcoord
[0][2] * invW1
;
197 const GLfloat r2
= v2
->texcoord
[0][2] * invW2
;
198 const GLfloat q0
= v0
->texcoord
[0][3] * invW0
;
199 const GLfloat q1
= v1
->texcoord
[0][3] * invW1
;
200 const GLfloat q2
= v2
->texcoord
[0][3] * invW2
;
201 compute_plane(p0
, p1
, p2
, s0
, s1
, s2
, sPlane
);
202 compute_plane(p0
, p1
, p2
, t0
, t1
, t2
, tPlane
);
203 compute_plane(p0
, p1
, p2
, r0
, r1
, r2
, uPlane
);
204 compute_plane(p0
, p1
, p2
, q0
, q1
, q2
, vPlane
);
205 texWidth
= (GLfloat
) texImage
->Width
;
206 texHeight
= (GLfloat
) texImage
->Height
;
208 span
.arrayMask
|= (SPAN_TEXTURE
| SPAN_LAMBDA
);
209 #elif defined(DO_MULTITEX)
212 for (u
= 0; u
< ctx
->Const
.MaxTextureUnits
; u
++) {
213 if (ctx
->Texture
.Unit
[u
]._ReallyEnabled
) {
214 const struct gl_texture_object
*obj
= ctx
->Texture
.Unit
[u
]._Current
;
215 const struct gl_texture_image
*texImage
= obj
->Image
[0][obj
->BaseLevel
];
216 const GLfloat invW0
= v0
->win
[3];
217 const GLfloat invW1
= v1
->win
[3];
218 const GLfloat invW2
= v2
->win
[3];
219 const GLfloat s0
= v0
->texcoord
[u
][0] * invW0
;
220 const GLfloat s1
= v1
->texcoord
[u
][0] * invW1
;
221 const GLfloat s2
= v2
->texcoord
[u
][0] * invW2
;
222 const GLfloat t0
= v0
->texcoord
[u
][1] * invW0
;
223 const GLfloat t1
= v1
->texcoord
[u
][1] * invW1
;
224 const GLfloat t2
= v2
->texcoord
[u
][1] * invW2
;
225 const GLfloat r0
= v0
->texcoord
[u
][2] * invW0
;
226 const GLfloat r1
= v1
->texcoord
[u
][2] * invW1
;
227 const GLfloat r2
= v2
->texcoord
[u
][2] * invW2
;
228 const GLfloat q0
= v0
->texcoord
[u
][3] * invW0
;
229 const GLfloat q1
= v1
->texcoord
[u
][3] * invW1
;
230 const GLfloat q2
= v2
->texcoord
[u
][3] * invW2
;
231 compute_plane(p0
, p1
, p2
, s0
, s1
, s2
, sPlane
[u
]);
232 compute_plane(p0
, p1
, p2
, t0
, t1
, t2
, tPlane
[u
]);
233 compute_plane(p0
, p1
, p2
, r0
, r1
, r2
, uPlane
[u
]);
234 compute_plane(p0
, p1
, p2
, q0
, q1
, q2
, vPlane
[u
]);
235 texWidth
[u
] = (GLfloat
) texImage
->Width
;
236 texHeight
[u
] = (GLfloat
) texImage
->Height
;
240 span
.arrayMask
|= (SPAN_TEXTURE
| SPAN_LAMBDA
);
243 /* Begin bottom-to-top scan over the triangle.
244 * The long edge will either be on the left or right side of the
245 * triangle. We always scan from the long edge toward the shorter
246 * edges, stopping when we find that coverage = 0. If the long edge
247 * is on the left we scan left-to-right. Else, we scan right-to-left.
251 iyMin
= (GLint
) yMin
;
252 iyMax
= (GLint
) yMax
+ 1;
255 /* scan left to right */
256 const GLfloat
*pMin
= vMin
->win
;
257 const GLfloat
*pMid
= vMid
->win
;
258 const GLfloat
*pMax
= vMax
->win
;
259 const GLfloat dxdy
= majDx
/ majDy
;
260 const GLfloat xAdj
= dxdy
< 0.0F
? -dxdy
: 0.0F
;
261 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
263 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
264 GLint ix
, startX
= (GLint
) (x
- xAdj
);
266 GLfloat coverage
= 0.0F
;
268 /* skip over fragments with zero coverage */
269 while (startX
< MAX_WIDTH
) {
270 coverage
= compute_coveragef(pMin
, pMid
, pMax
, startX
, iy
);
276 /* enter interior of triangle */
279 while (coverage
> 0.0F
) {
280 /* (cx,cy) = center of fragment */
281 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
282 SWspanarrays
*array
= span
.array
;
284 array
->coverage
[count
] = (GLfloat
) compute_coveragei(pMin
, pMid
, pMax
, ix
, iy
);
286 array
->coverage
[count
] = coverage
;
289 array
->z
[count
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
292 array
->fog
[count
] = solve_plane(cx
, cy
, fogPlane
);
295 array
->rgba
[count
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
296 array
->rgba
[count
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
297 array
->rgba
[count
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
298 array
->rgba
[count
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
301 array
->index
[count
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
304 array
->spec
[count
][RCOMP
] = solve_plane_chan(cx
, cy
, srPlane
);
305 array
->spec
[count
][GCOMP
] = solve_plane_chan(cx
, cy
, sgPlane
);
306 array
->spec
[count
][BCOMP
] = solve_plane_chan(cx
, cy
, sbPlane
);
310 const GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
);
311 array
->texcoords
[0][count
][0] = solve_plane(cx
, cy
, sPlane
) * invQ
;
312 array
->texcoords
[0][count
][1] = solve_plane(cx
, cy
, tPlane
) * invQ
;
313 array
->texcoords
[0][count
][2] = solve_plane(cx
, cy
, uPlane
) * invQ
;
314 array
->lambda
[0][count
] = compute_lambda(sPlane
, tPlane
, vPlane
,
316 texWidth
, texHeight
);
318 #elif defined(DO_MULTITEX)
321 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
322 if (ctx
->Texture
.Unit
[unit
]._ReallyEnabled
) {
323 GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
[unit
]);
324 array
->texcoords
[unit
][count
][0] = solve_plane(cx
, cy
, sPlane
[unit
]) * invQ
;
325 array
->texcoords
[unit
][count
][1] = solve_plane(cx
, cy
, tPlane
[unit
]) * invQ
;
326 array
->texcoords
[unit
][count
][2] = solve_plane(cx
, cy
, uPlane
[unit
]) * invQ
;
327 array
->lambda
[unit
][count
] = compute_lambda(sPlane
[unit
],
328 tPlane
[unit
], vPlane
[unit
], cx
, cy
, invQ
,
329 texWidth
[unit
], texHeight
[unit
]);
336 coverage
= compute_coveragef(pMin
, pMid
, pMax
, ix
, iy
);
344 span
.end
= (GLuint
) ix
- (GLuint
) startX
;
345 ASSERT(span
.interpMask
== 0);
347 _swrast_write_rgba_span(ctx
, &span
);
349 _swrast_write_index_span(ctx
, &span
);
354 /* scan right to left */
355 const GLfloat
*pMin
= vMin
->win
;
356 const GLfloat
*pMid
= vMid
->win
;
357 const GLfloat
*pMax
= vMax
->win
;
358 const GLfloat dxdy
= majDx
/ majDy
;
359 const GLfloat xAdj
= dxdy
> 0 ? dxdy
: 0.0F
;
360 GLfloat x
= pMin
[0] - (yMin
- iyMin
) * dxdy
;
362 for (iy
= iyMin
; iy
< iyMax
; iy
++, x
+= dxdy
) {
363 GLint ix
, left
, startX
= (GLint
) (x
+ xAdj
);
365 GLfloat coverage
= 0.0F
;
367 /* make sure we're not past the window edge */
368 if (startX
>= ctx
->DrawBuffer
->_Xmax
) {
369 startX
= ctx
->DrawBuffer
->_Xmax
- 1;
372 /* skip fragments with zero coverage */
373 while (startX
>= 0) {
374 coverage
= compute_coveragef(pMin
, pMax
, pMid
, startX
, iy
);
380 /* enter interior of triangle */
383 while (coverage
> 0.0F
) {
384 /* (cx,cy) = center of fragment */
385 const GLfloat cx
= ix
+ 0.5F
, cy
= iy
+ 0.5F
;
386 SWspanarrays
*array
= span
.array
;
388 array
->coverage
[ix
] = (GLfloat
) compute_coveragei(pMin
, pMax
, pMid
, ix
, iy
);
390 array
->coverage
[ix
] = coverage
;
393 array
->z
[ix
] = (GLuint
) solve_plane(cx
, cy
, zPlane
);
396 array
->fog
[ix
] = solve_plane(cx
, cy
, fogPlane
);
399 array
->rgba
[ix
][RCOMP
] = solve_plane_chan(cx
, cy
, rPlane
);
400 array
->rgba
[ix
][GCOMP
] = solve_plane_chan(cx
, cy
, gPlane
);
401 array
->rgba
[ix
][BCOMP
] = solve_plane_chan(cx
, cy
, bPlane
);
402 array
->rgba
[ix
][ACOMP
] = solve_plane_chan(cx
, cy
, aPlane
);
405 array
->index
[ix
] = (GLint
) solve_plane(cx
, cy
, iPlane
);
408 array
->spec
[ix
][RCOMP
] = solve_plane_chan(cx
, cy
, srPlane
);
409 array
->spec
[ix
][GCOMP
] = solve_plane_chan(cx
, cy
, sgPlane
);
410 array
->spec
[ix
][BCOMP
] = solve_plane_chan(cx
, cy
, sbPlane
);
414 const GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
);
415 array
->texcoords
[0][ix
][0] = solve_plane(cx
, cy
, sPlane
) * invQ
;
416 array
->texcoords
[0][ix
][1] = solve_plane(cx
, cy
, tPlane
) * invQ
;
417 array
->texcoords
[0][ix
][2] = solve_plane(cx
, cy
, uPlane
) * invQ
;
418 array
->lambda
[0][ix
] = compute_lambda(sPlane
, tPlane
, vPlane
,
419 cx
, cy
, invQ
, texWidth
, texHeight
);
421 #elif defined(DO_MULTITEX)
424 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
425 if (ctx
->Texture
.Unit
[unit
]._ReallyEnabled
) {
426 GLfloat invQ
= solve_plane_recip(cx
, cy
, vPlane
[unit
]);
427 array
->texcoords
[unit
][ix
][0] = solve_plane(cx
, cy
, sPlane
[unit
]) * invQ
;
428 array
->texcoords
[unit
][ix
][1] = solve_plane(cx
, cy
, tPlane
[unit
]) * invQ
;
429 array
->texcoords
[unit
][ix
][2] = solve_plane(cx
, cy
, uPlane
[unit
]) * invQ
;
430 array
->lambda
[unit
][ix
] = compute_lambda(sPlane
[unit
],
442 coverage
= compute_coveragef(pMin
, pMax
, pMid
, ix
, iy
);
448 n
= (GLuint
) startX
- (GLuint
) ix
;
452 /* shift all values to the left */
453 /* XXX this is temporary */
455 SWspanarrays
*array
= span
.array
;
457 for (j
= 0; j
< (GLint
) n
; j
++) {
459 COPY_CHAN4(array
->rgba
[j
], array
->rgba
[j
+ left
]);
462 COPY_CHAN4(array
->spec
[j
], array
->spec
[j
+ left
]);
465 array
->index
[j
] = array
->index
[j
+ left
];
468 array
->z
[j
] = array
->z
[j
+ left
];
471 array
->fog
[j
] = array
->fog
[j
+ left
];
474 COPY_4V(array
->texcoords
[0][j
], array
->texcoords
[0][j
+ left
]);
476 #if defined(DO_MULTITEX) || defined(DO_TEX)
477 array
->lambda
[0][j
] = array
->lambda
[0][j
+ left
];
479 array
->coverage
[j
] = array
->coverage
[j
+ left
];
483 /* shift texcoords */
485 SWspanarrays
*array
= span
.array
;
487 for (unit
= 0; unit
< ctx
->Const
.MaxTextureUnits
; unit
++) {
488 if (ctx
->Texture
.Unit
[unit
]._ReallyEnabled
) {
490 for (j
= 0; j
< (GLint
) n
; j
++) {
491 array
->texcoords
[unit
][j
][0] = array
->texcoords
[unit
][j
+ left
][0];
492 array
->texcoords
[unit
][j
][1] = array
->texcoords
[unit
][j
+ left
][1];
493 array
->texcoords
[unit
][j
][2] = array
->texcoords
[unit
][j
+ left
][2];
494 array
->lambda
[unit
][j
] = array
->lambda
[unit
][j
+ left
];
504 ASSERT(span
.interpMask
== 0);
506 _swrast_write_rgba_span(ctx
, &span
);
508 _swrast_write_index_span(ctx
, &span
);
543 #ifdef DO_OCCLUSION_TEST
544 #undef DO_OCCLUSION_TEST