added missing \'s
[mesa.git] / src / mesa / swrast / s_aatriangle.c
1 /* $Id: s_aatriangle.c,v 1.18 2001/05/29 15:23:15 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 /*
29 * Antialiased Triangle rasterizers
30 */
31
32
33 #include "mem.h"
34 #include "mmath.h"
35 #include "s_aatriangle.h"
36 #include "s_context.h"
37 #include "s_span.h"
38
39
40 /*
41 * Compute coefficients of a plane using the X,Y coords of the v0, v1, v2
42 * vertices and the given Z values.
43 */
44 static INLINE void
45 compute_plane(const GLfloat v0[], const GLfloat v1[], const GLfloat v2[],
46 GLfloat z0, GLfloat z1, GLfloat z2, GLfloat plane[4])
47 {
48 const GLfloat px = v1[0] - v0[0];
49 const GLfloat py = v1[1] - v0[1];
50 const GLfloat pz = z1 - z0;
51
52 const GLfloat qx = v2[0] - v0[0];
53 const GLfloat qy = v2[1] - v0[1];
54 const GLfloat qz = z2 - z0;
55
56 const GLfloat a = py * qz - pz * qy;
57 const GLfloat b = pz * qx - px * qz;
58 const GLfloat c = px * qy - py * qx;
59 const GLfloat d = -(a * v0[0] + b * v0[1] + c * z0);
60
61 plane[0] = a;
62 plane[1] = b;
63 plane[2] = c;
64 plane[3] = d;
65 }
66
67
68 /*
69 * Compute coefficients of a plane with a constant Z value.
70 */
71 static INLINE void
72 constant_plane(GLfloat value, GLfloat plane[4])
73 {
74 plane[0] = 0.0;
75 plane[1] = 0.0;
76 plane[2] = -1.0;
77 plane[3] = value;
78 }
79
80 #define CONSTANT_PLANE(VALUE, PLANE) \
81 do { \
82 PLANE[0] = 0.0F; \
83 PLANE[1] = 0.0F; \
84 PLANE[2] = -1.0F; \
85 PLANE[3] = VALUE; \
86 } while (0)
87
88
89
90 /*
91 * Solve plane equation for Z at (X,Y).
92 */
93 static INLINE GLfloat
94 solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
95 {
96 const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
97 return z;
98 }
99
100
101 #define SOLVE_PLANE(X, Y, PLANE) \
102 ((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
103
104
105 /*
106 * Return 1 / solve_plane().
107 */
108 static INLINE GLfloat
109 solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4])
110 {
111 const GLfloat denom = plane[3] + plane[0] * x + plane[1] * y;
112 if (denom == 0.0F)
113 return 0.0F;
114 else
115 return -plane[2] / denom;
116 }
117
118
119
120 /*
121 * Solve plane and return clamped GLchan value.
122 */
123 static INLINE GLchan
124 solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
125 {
126 GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2] + 0.5F;
127 if (z < 0.0F)
128 return 0;
129 else if (z > CHAN_MAXF)
130 return (GLchan) CHAN_MAXF;
131 return (GLchan) (GLint) z;
132 }
133
134
135
136 /*
137 * Compute how much (area) of the given pixel is inside the triangle.
138 * Vertices MUST be specified in counter-clockwise order.
139 * Return: coverage in [0, 1].
140 */
141 static GLfloat
142 compute_coveragef(const GLfloat v0[3], const GLfloat v1[3],
143 const GLfloat v2[3], GLint winx, GLint winy)
144 {
145 #define B 0.125
146 static const GLfloat samples[16][2] = {
147 /* start with the four corners */
148 { 0.00+B, 0.00+B },
149 { 0.75+B, 0.00+B },
150 { 0.00+B, 0.75+B },
151 { 0.75+B, 0.75+B },
152 /* continue with interior samples */
153 { 0.25+B, 0.00+B },
154 { 0.50+B, 0.00+B },
155 { 0.00+B, 0.25+B },
156 { 0.25+B, 0.25+B },
157 { 0.50+B, 0.25+B },
158 { 0.75+B, 0.25+B },
159 { 0.00+B, 0.50+B },
160 { 0.25+B, 0.50+B },
161 { 0.50+B, 0.50+B },
162 { 0.75+B, 0.50+B },
163 { 0.25+B, 0.75+B },
164 { 0.50+B, 0.75+B }
165 };
166 const GLfloat x = (GLfloat) winx;
167 const GLfloat y = (GLfloat) winy;
168 const GLfloat dx0 = v1[0] - v0[0];
169 const GLfloat dy0 = v1[1] - v0[1];
170 const GLfloat dx1 = v2[0] - v1[0];
171 const GLfloat dy1 = v2[1] - v1[1];
172 const GLfloat dx2 = v0[0] - v2[0];
173 const GLfloat dy2 = v0[1] - v2[1];
174 GLint stop = 4, i;
175 GLfloat insideCount = 16.0F;
176
177 #ifdef DEBUG
178 {
179 const GLfloat area = dx0 * dy1 - dx1 * dy0;
180 assert(area >= 0.0);
181 }
182 #endif
183
184 for (i = 0; i < stop; i++) {
185 const GLfloat sx = x + samples[i][0];
186 const GLfloat sy = y + samples[i][1];
187 const GLfloat fx0 = sx - v0[0];
188 const GLfloat fy0 = sy - v0[1];
189 const GLfloat fx1 = sx - v1[0];
190 const GLfloat fy1 = sy - v1[1];
191 const GLfloat fx2 = sx - v2[0];
192 const GLfloat fy2 = sy - v2[1];
193 /* cross product determines if sample is inside or outside each edge */
194 GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
195 GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
196 GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
197 /* Check if the sample is exactly on an edge. If so, let cross be a
198 * positive or negative value depending on the direction of the edge.
199 */
200 if (cross0 == 0.0F)
201 cross0 = dx0 + dy0;
202 if (cross1 == 0.0F)
203 cross1 = dx1 + dy1;
204 if (cross2 == 0.0F)
205 cross2 = dx2 + dy2;
206 if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
207 /* point is outside triangle */
208 insideCount -= 1.0F;
209 stop = 16;
210 }
211 }
212 if (stop == 4)
213 return 1.0F;
214 else
215 return insideCount * (1.0F / 16.0F);
216 }
217
218
219
220 /*
221 * Compute how much (area) of the given pixel is inside the triangle.
222 * Vertices MUST be specified in counter-clockwise order.
223 * Return: coverage in [0, 15].
224 */
225 static GLint
226 compute_coveragei(const GLfloat v0[3], const GLfloat v1[3],
227 const GLfloat v2[3], GLint winx, GLint winy)
228 {
229 /* NOTE: 15 samples instead of 16.
230 * A better sample distribution could be used.
231 */
232 static const GLfloat samples[15][2] = {
233 /* start with the four corners */
234 { 0.00+B, 0.00+B },
235 { 0.75+B, 0.00+B },
236 { 0.00+B, 0.75+B },
237 { 0.75+B, 0.75+B },
238 /* continue with interior samples */
239 { 0.25+B, 0.00+B },
240 { 0.50+B, 0.00+B },
241 { 0.00+B, 0.25+B },
242 { 0.25+B, 0.25+B },
243 { 0.50+B, 0.25+B },
244 { 0.75+B, 0.25+B },
245 { 0.00+B, 0.50+B },
246 { 0.25+B, 0.50+B },
247 /*{ 0.50, 0.50 },*/
248 { 0.75+B, 0.50+B },
249 { 0.25+B, 0.75+B },
250 { 0.50+B, 0.75+B }
251 };
252 const GLfloat x = (GLfloat) winx;
253 const GLfloat y = (GLfloat) winy;
254 const GLfloat dx0 = v1[0] - v0[0];
255 const GLfloat dy0 = v1[1] - v0[1];
256 const GLfloat dx1 = v2[0] - v1[0];
257 const GLfloat dy1 = v2[1] - v1[1];
258 const GLfloat dx2 = v0[0] - v2[0];
259 const GLfloat dy2 = v0[1] - v2[1];
260 GLint stop = 4, i;
261 GLint insideCount = 15;
262
263 #ifdef DEBUG
264 {
265 const GLfloat area = dx0 * dy1 - dx1 * dy0;
266 assert(area >= 0.0);
267 }
268 #endif
269
270 for (i = 0; i < stop; i++) {
271 const GLfloat sx = x + samples[i][0];
272 const GLfloat sy = y + samples[i][1];
273 const GLfloat fx0 = sx - v0[0];
274 const GLfloat fy0 = sy - v0[1];
275 const GLfloat fx1 = sx - v1[0];
276 const GLfloat fy1 = sy - v1[1];
277 const GLfloat fx2 = sx - v2[0];
278 const GLfloat fy2 = sy - v2[1];
279 /* cross product determines if sample is inside or outside each edge */
280 GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
281 GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
282 GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
283 /* Check if the sample is exactly on an edge. If so, let cross be a
284 * positive or negative value depending on the direction of the edge.
285 */
286 if (cross0 == 0.0F)
287 cross0 = dx0 + dy0;
288 if (cross1 == 0.0F)
289 cross1 = dx1 + dy1;
290 if (cross2 == 0.0F)
291 cross2 = dx2 + dy2;
292 if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
293 /* point is outside triangle */
294 insideCount--;
295 stop = 15;
296 }
297 }
298 if (stop == 4)
299 return 15;
300 else
301 return insideCount;
302 }
303
304
305
306 static void
307 rgba_aa_tri(GLcontext *ctx,
308 const SWvertex *v0,
309 const SWvertex *v1,
310 const SWvertex *v2)
311 {
312 #define DO_Z
313 #define DO_FOG
314 #define DO_RGBA
315 #include "s_aatritemp.h"
316 }
317
318
319 static void
320 index_aa_tri(GLcontext *ctx,
321 const SWvertex *v0,
322 const SWvertex *v1,
323 const SWvertex *v2)
324 {
325 #define DO_Z
326 #define DO_FOG
327 #define DO_INDEX
328 #include "s_aatritemp.h"
329 }
330
331
332 /*
333 * Compute mipmap level of detail.
334 */
335 static INLINE GLfloat
336 compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4],
337 GLfloat invQ, GLfloat width, GLfloat height)
338 {
339 GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width;
340 GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width;
341 GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height;
342 GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height;
343 GLfloat r1 = dudx * dudx + dudy * dudy;
344 GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
345 GLfloat rho2 = r1 + r2;
346 /* return log base 2 of rho */
347 if (rho2 == 0.0F)
348 return 0.0;
349 else
350 return log(rho2) * 1.442695 * 0.5; /* 1.442695 = 1/log(2) */
351 }
352
353
354 static void
355 tex_aa_tri(GLcontext *ctx,
356 const SWvertex *v0,
357 const SWvertex *v1,
358 const SWvertex *v2)
359 {
360 #define DO_Z
361 #define DO_FOG
362 #define DO_RGBA
363 #define DO_TEX
364 #include "s_aatritemp.h"
365 }
366
367
368 static void
369 spec_tex_aa_tri(GLcontext *ctx,
370 const SWvertex *v0,
371 const SWvertex *v1,
372 const SWvertex *v2)
373 {
374 #define DO_Z
375 #define DO_FOG
376 #define DO_RGBA
377 #define DO_TEX
378 #define DO_SPEC
379 #include "s_aatritemp.h"
380 }
381
382
383 static void
384 multitex_aa_tri(GLcontext *ctx,
385 const SWvertex *v0,
386 const SWvertex *v1,
387 const SWvertex *v2)
388 {
389 #define DO_Z
390 #define DO_FOG
391 #define DO_RGBA
392 #define DO_MULTITEX
393 #include "s_aatritemp.h"
394 }
395
396 static void
397 spec_multitex_aa_tri(GLcontext *ctx,
398 const SWvertex *v0,
399 const SWvertex *v1,
400 const SWvertex *v2)
401 {
402 #define DO_Z
403 #define DO_FOG
404 #define DO_RGBA
405 #define DO_MULTITEX
406 #define DO_SPEC
407 #include "s_aatritemp.h"
408 }
409
410
411 /*
412 * Examine GL state and set swrast->Triangle to an
413 * appropriate antialiased triangle rasterizer function.
414 */
415 void
416 _mesa_set_aa_triangle_function(GLcontext *ctx)
417 {
418 ASSERT(ctx->Polygon.SmoothFlag);
419
420 if (ctx->Texture._ReallyEnabled) {
421 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
422 if (ctx->Texture._ReallyEnabled > TEXTURE0_ANY) {
423 SWRAST_CONTEXT(ctx)->Triangle = spec_multitex_aa_tri;
424 }
425 else {
426 SWRAST_CONTEXT(ctx)->Triangle = spec_tex_aa_tri;
427 }
428 }
429 else {
430 if (ctx->Texture._ReallyEnabled > TEXTURE0_ANY) {
431 SWRAST_CONTEXT(ctx)->Triangle = multitex_aa_tri;
432 }
433 else {
434 SWRAST_CONTEXT(ctx)->Triangle = tex_aa_tri;
435 }
436 }
437 }
438 else if (ctx->Visual.rgbMode) {
439 SWRAST_CONTEXT(ctx)->Triangle = rgba_aa_tri;
440 }
441 else {
442 SWRAST_CONTEXT(ctx)->Triangle = index_aa_tri;
443 }
444
445 ASSERT(SWRAST_CONTEXT(ctx)->Triangle);
446 }