s_aaline.c revision 8afe7de8deaf3c9613fd68b344de8c52b02b1879
1/* $Id: s_aaline.c,v 1.15 2002/06/15 03:03:10 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 4.1 6 * 7 * Copyright (C) 1999-2002 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#include "glheader.h" 29#include "swrast/s_aaline.h" 30#include "swrast/s_context.h" 31#include "swrast/s_span.h" 32#include "swrast/swrast.h" 33#include "mtypes.h" 34#include "mmath.h" 35 36 37#define SUB_PIXEL 4 38 39 40/* 41 * Info about the AA line we're rendering 42 */ 43struct LineInfo 44{ 45 GLfloat x0, y0; /* start */ 46 GLfloat x1, y1; /* end */ 47 GLfloat dx, dy; /* direction vector */ 48 GLfloat len; /* length */ 49 GLfloat halfWidth; /* half of line width */ 50 GLfloat xAdj, yAdj; /* X and Y adjustment for quad corners around line */ 51 /* for coverage computation */ 52 GLfloat qx0, qy0; /* quad vertices */ 53 GLfloat qx1, qy1; 54 GLfloat qx2, qy2; 55 GLfloat qx3, qy3; 56 GLfloat ex0, ey0; /* quad edge vectors */ 57 GLfloat ex1, ey1; 58 GLfloat ex2, ey2; 59 GLfloat ex3, ey3; 60 61 /* DO_Z */ 62 GLfloat zPlane[4]; 63 /* DO_FOG */ 64 GLfloat fPlane[4]; 65 /* DO_RGBA */ 66 GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4]; 67 /* DO_INDEX */ 68 GLfloat iPlane[4]; 69 /* DO_SPEC */ 70 GLfloat srPlane[4], sgPlane[4], sbPlane[4]; 71 /* DO_TEX or DO_MULTITEX */ 72 GLfloat sPlane[MAX_TEXTURE_UNITS][4]; 73 GLfloat tPlane[MAX_TEXTURE_UNITS][4]; 74 GLfloat uPlane[MAX_TEXTURE_UNITS][4]; 75 GLfloat vPlane[MAX_TEXTURE_UNITS][4]; 76 GLfloat lambda[MAX_TEXTURE_UNITS]; 77 GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS]; 78 79 struct sw_span *span; 80}; 81 82 83 84/* 85 * Compute the equation of a plane used to interpolate line fragment data 86 * such as color, Z, texture coords, etc. 87 * Input: (x0, y0) and (x1,y1) are the endpoints of the line. 88 * z0, and z1 are the end point values to interpolate. 89 * Output: plane - the plane equation. 90 * 91 * Note: we don't really have enough parameters to specify a plane. 92 * We take the endpoints of the line and compute a plane such that 93 * the cross product of the line vector and the plane normal is 94 * parallel to the projection plane. 95 */ 96static void 97compute_plane(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, 98 GLfloat z0, GLfloat z1, GLfloat plane[4]) 99{ 100#if 0 101 /* original */ 102 const GLfloat px = x1 - x0; 103 const GLfloat py = y1 - y0; 104 const GLfloat pz = z1 - z0; 105 const GLfloat qx = -py; 106 const GLfloat qy = px; 107 const GLfloat qz = 0; 108 const GLfloat a = py * qz - pz * qy; 109 const GLfloat b = pz * qx - px * qz; 110 const GLfloat c = px * qy - py * qx; 111 const GLfloat d = -(a * x0 + b * y0 + c * z0); 112 plane[0] = a; 113 plane[1] = b; 114 plane[2] = c; 115 plane[3] = d; 116#else 117 /* simplified */ 118 const GLfloat px = x1 - x0; 119 const GLfloat py = y1 - y0; 120 const GLfloat pz = z0 - z1; 121 const GLfloat a = pz * px; 122 const GLfloat b = pz * py; 123 const GLfloat c = px * px + py * py; 124 const GLfloat d = -(a * x0 + b * y0 + c * z0); 125 if (a == 0.0 && b == 0.0 && c == 0.0 && d == 0.0) { 126 plane[0] = 0.0; 127 plane[1] = 0.0; 128 plane[2] = 1.0; 129 plane[3] = 0.0; 130 } 131 else { 132 plane[0] = a; 133 plane[1] = b; 134 plane[2] = c; 135 plane[3] = d; 136 } 137#endif 138} 139 140 141static INLINE void 142constant_plane(GLfloat value, GLfloat plane[4]) 143{ 144 plane[0] = 0.0; 145 plane[1] = 0.0; 146 plane[2] = -1.0; 147 plane[3] = value; 148} 149 150 151static INLINE GLfloat 152solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4]) 153{ 154 const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2]; 155 return z; 156} 157 158#define SOLVE_PLANE(X, Y, PLANE) \ 159 ((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2]) 160 161 162/* 163 * Return 1 / solve_plane(). 164 */ 165static INLINE GLfloat 166solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4]) 167{ 168 const GLfloat denom = plane[3] + plane[0] * x + plane[1] * y; 169 if (denom == 0.0) 170 return 0.0; 171 else 172 return -plane[2] / denom; 173} 174 175 176/* 177 * Solve plane and return clamped GLchan value. 178 */ 179static INLINE GLchan 180solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4]) 181{ 182 GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2] + 0.5F; 183 if (z < 0.0F) 184 return 0; 185 else if (z > CHAN_MAXF) 186 return (GLchan) CHAN_MAXF; 187 return (GLchan) (GLint) z; 188} 189 190 191/* 192 * Compute mipmap level of detail. 193 */ 194static INLINE GLfloat 195compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4], 196 GLfloat invQ, GLfloat width, GLfloat height) 197{ 198 GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width; 199 GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width; 200 GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height; 201 GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height; 202 GLfloat r1 = dudx * dudx + dudy * dudy; 203 GLfloat r2 = dvdx * dvdx + dvdy * dvdy; 204 GLfloat rho2 = r1 + r2; 205 /* return log base 2 of rho */ 206 if (rho2 == 0.0F) 207 return 0.0; 208 else 209 return (GLfloat) (log(rho2) * 1.442695 * 0.5);/* 1.442695 = 1/log(2) */ 210} 211 212 213 214 215/* 216 * Fill in the samples[] array with the (x,y) subpixel positions of 217 * xSamples * ySamples sample positions. 218 * Note that the four corner samples are put into the first four 219 * positions of the array. This allows us to optimize for the common 220 * case of all samples being inside the polygon. 221 */ 222static void 223make_sample_table(GLint xSamples, GLint ySamples, GLfloat samples[][2]) 224{ 225 const GLfloat dx = 1.0F / (GLfloat) xSamples; 226 const GLfloat dy = 1.0F / (GLfloat) ySamples; 227 GLint x, y; 228 GLint i; 229 230 i = 4; 231 for (x = 0; x < xSamples; x++) { 232 for (y = 0; y < ySamples; y++) { 233 GLint j; 234 if (x == 0 && y == 0) { 235 /* lower left */ 236 j = 0; 237 } 238 else if (x == xSamples - 1 && y == 0) { 239 /* lower right */ 240 j = 1; 241 } 242 else if (x == 0 && y == ySamples - 1) { 243 /* upper left */ 244 j = 2; 245 } 246 else if (x == xSamples - 1 && y == ySamples - 1) { 247 /* upper right */ 248 j = 3; 249 } 250 else { 251 j = i++; 252 } 253 samples[j][0] = x * dx + 0.5F * dx; 254 samples[j][1] = y * dy + 0.5F * dy; 255 } 256 } 257} 258 259 260 261/* 262 * Compute how much of the given pixel's area is inside the rectangle 263 * defined by vertices v0, v1, v2, v3. 264 * Vertices MUST be specified in counter-clockwise order. 265 * Return: coverage in [0, 1]. 266 */ 267static GLfloat 268compute_coveragef(const struct LineInfo *info, 269 GLint winx, GLint winy) 270{ 271 static GLfloat samples[SUB_PIXEL * SUB_PIXEL][2]; 272 static GLboolean haveSamples = GL_FALSE; 273 const GLfloat x = (GLfloat) winx; 274 const GLfloat y = (GLfloat) winy; 275 GLint stop = 4, i; 276 GLfloat insideCount = SUB_PIXEL * SUB_PIXEL; 277 278 if (!haveSamples) { 279 make_sample_table(SUB_PIXEL, SUB_PIXEL, samples); 280 haveSamples = GL_TRUE; 281 } 282 283#if 0 /*DEBUG*/ 284 { 285 const GLfloat area = dx0 * dy1 - dx1 * dy0; 286 assert(area >= 0.0); 287 } 288#endif 289 290 for (i = 0; i < stop; i++) { 291 const GLfloat sx = x + samples[i][0]; 292 const GLfloat sy = y + samples[i][1]; 293 const GLfloat fx0 = sx - info->qx0; 294 const GLfloat fy0 = sy - info->qy0; 295 const GLfloat fx1 = sx - info->qx1; 296 const GLfloat fy1 = sy - info->qy1; 297 const GLfloat fx2 = sx - info->qx2; 298 const GLfloat fy2 = sy - info->qy2; 299 const GLfloat fx3 = sx - info->qx3; 300 const GLfloat fy3 = sy - info->qy3; 301 /* cross product determines if sample is inside or outside each edge */ 302 GLfloat cross0 = (info->ex0 * fy0 - info->ey0 * fx0); 303 GLfloat cross1 = (info->ex1 * fy1 - info->ey1 * fx1); 304 GLfloat cross2 = (info->ex2 * fy2 - info->ey2 * fx2); 305 GLfloat cross3 = (info->ex3 * fy3 - info->ey3 * fx3); 306 /* Check if the sample is exactly on an edge. If so, let cross be a 307 * positive or negative value depending on the direction of the edge. 308 */ 309 if (cross0 == 0.0F) 310 cross0 = info->ex0 + info->ey0; 311 if (cross1 == 0.0F) 312 cross1 = info->ex1 + info->ey1; 313 if (cross2 == 0.0F) 314 cross2 = info->ex2 + info->ey2; 315 if (cross3 == 0.0F) 316 cross3 = info->ex3 + info->ey3; 317 if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F || cross3 < 0.0F) { 318 /* point is outside quadrilateral */ 319 insideCount -= 1.0F; 320 stop = SUB_PIXEL * SUB_PIXEL; 321 } 322 } 323 if (stop == 4) 324 return 1.0F; 325 else 326 return insideCount * (1.0F / (SUB_PIXEL * SUB_PIXEL)); 327} 328 329 330 331typedef void (*plot_func)(GLcontext *ctx, struct LineInfo *line, 332 int ix, int iy); 333 334 335 336/* 337 * Draw an AA line segment (called many times per line when stippling) 338 */ 339static void 340segment(GLcontext *ctx, 341 struct LineInfo *line, 342 plot_func plot, 343 GLfloat t0, GLfloat t1) 344{ 345 const GLfloat absDx = (line->dx < 0.0F) ? -line->dx : line->dx; 346 const GLfloat absDy = (line->dy < 0.0F) ? -line->dy : line->dy; 347 /* compute the actual segment's endpoints */ 348 const GLfloat x0 = line->x0 + t0 * line->dx; 349 const GLfloat y0 = line->y0 + t0 * line->dy; 350 const GLfloat x1 = line->x0 + t1 * line->dx; 351 const GLfloat y1 = line->y0 + t1 * line->dy; 352 353 /* compute vertices of the line-aligned quadrilateral */ 354 line->qx0 = x0 - line->yAdj; 355 line->qy0 = y0 + line->xAdj; 356 line->qx1 = x0 + line->yAdj; 357 line->qy1 = y0 - line->xAdj; 358 line->qx2 = x1 + line->yAdj; 359 line->qy2 = y1 - line->xAdj; 360 line->qx3 = x1 - line->yAdj; 361 line->qy3 = y1 + line->xAdj; 362 /* compute the quad's edge vectors (for coverage calc) */ 363 line->ex0 = line->qx1 - line->qx0; 364 line->ey0 = line->qy1 - line->qy0; 365 line->ex1 = line->qx2 - line->qx1; 366 line->ey1 = line->qy2 - line->qy1; 367 line->ex2 = line->qx3 - line->qx2; 368 line->ey2 = line->qy3 - line->qy2; 369 line->ex3 = line->qx0 - line->qx3; 370 line->ey3 = line->qy0 - line->qy3; 371 372 if (absDx > absDy) { 373 /* X-major line */ 374 GLfloat dydx = line->dy / line->dx; 375 GLfloat xLeft, xRight, yBot, yTop; 376 GLint ix, ixRight; 377 if (x0 < x1) { 378 xLeft = x0 - line->halfWidth; 379 xRight = x1 + line->halfWidth; 380 if (line->dy >= 0.0) { 381 yBot = y0 - 3.0F * line->halfWidth; 382 yTop = y0 + line->halfWidth; 383 } 384 else { 385 yBot = y0 - line->halfWidth; 386 yTop = y0 + 3.0F * line->halfWidth; 387 } 388 } 389 else { 390 xLeft = x1 - line->halfWidth; 391 xRight = x0 + line->halfWidth; 392 if (line->dy <= 0.0) { 393 yBot = y1 - 3.0F * line->halfWidth; 394 yTop = y1 + line->halfWidth; 395 } 396 else { 397 yBot = y1 - line->halfWidth; 398 yTop = y1 + 3.0F * line->halfWidth; 399 } 400 } 401 402 /* scan along the line, left-to-right */ 403 ixRight = (GLint) (xRight + 1.0F); 404 405 /*printf("avg span height: %g\n", yTop - yBot);*/ 406 for (ix = (GLint) xLeft; ix < ixRight; ix++) { 407 const GLint iyBot = (GLint) yBot; 408 const GLint iyTop = (GLint) (yTop + 1.0F); 409 GLint iy; 410 /* scan across the line, bottom-to-top */ 411 for (iy = iyBot; iy < iyTop; iy++) { 412 (*plot)(ctx, line, ix, iy); 413 } 414 yBot += dydx; 415 yTop += dydx; 416 } 417 } 418 else { 419 /* Y-major line */ 420 GLfloat dxdy = line->dx / line->dy; 421 GLfloat yBot, yTop, xLeft, xRight; 422 GLint iy, iyTop; 423 if (y0 < y1) { 424 yBot = y0 - line->halfWidth; 425 yTop = y1 + line->halfWidth; 426 if (line->dx >= 0.0) { 427 xLeft = x0 - 3.0F * line->halfWidth; 428 xRight = x0 + line->halfWidth; 429 } 430 else { 431 xLeft = x0 - line->halfWidth; 432 xRight = x0 + 3.0F * line->halfWidth; 433 } 434 } 435 else { 436 yBot = y1 - line->halfWidth; 437 yTop = y0 + line->halfWidth; 438 if (line->dx <= 0.0) { 439 xLeft = x1 - 3.0F * line->halfWidth; 440 xRight = x1 + line->halfWidth; 441 } 442 else { 443 xLeft = x1 - line->halfWidth; 444 xRight = x1 + 3.0F * line->halfWidth; 445 } 446 } 447 448 /* scan along the line, bottom-to-top */ 449 iyTop = (GLint) (yTop + 1.0F); 450 451 /*printf("avg span width: %g\n", xRight - xLeft);*/ 452 for (iy = (GLint) yBot; iy < iyTop; iy++) { 453 const GLint ixLeft = (GLint) xLeft; 454 const GLint ixRight = (GLint) (xRight + 1.0F); 455 GLint ix; 456 /* scan across the line, left-to-right */ 457 for (ix = ixLeft; ix < ixRight; ix++) { 458 (*plot)(ctx, line, ix, iy); 459 } 460 xLeft += dxdy; 461 xRight += dxdy; 462 } 463 } 464} 465 466 467#define NAME(x) aa_ci_##x 468#define DO_Z 469#define DO_FOG 470#define DO_INDEX 471#include "s_aalinetemp.h" 472 473 474#define NAME(x) aa_rgba_##x 475#define DO_Z 476#define DO_FOG 477#define DO_RGBA 478#include "s_aalinetemp.h" 479 480 481#define NAME(x) aa_tex_rgba_##x 482#define DO_Z 483#define DO_FOG 484#define DO_RGBA 485#define DO_TEX 486#include "s_aalinetemp.h" 487 488 489#define NAME(x) aa_multitex_rgba_##x 490#define DO_Z 491#define DO_FOG 492#define DO_RGBA 493#define DO_MULTITEX 494#include "s_aalinetemp.h" 495 496 497#define NAME(x) aa_multitex_spec_##x 498#define DO_Z 499#define DO_FOG 500#define DO_RGBA 501#define DO_MULTITEX 502#define DO_SPEC 503#include "s_aalinetemp.h" 504 505 506 507void 508_swrast_choose_aa_line_function(GLcontext *ctx) 509{ 510 SWcontext *swrast = SWRAST_CONTEXT(ctx); 511 512 ASSERT(ctx->Line.SmoothFlag); 513 514 if (ctx->Visual.rgbMode) { 515 /* RGBA */ 516 if (ctx->Texture._EnabledUnits != 0) { 517 if (ctx->Texture._EnabledUnits > 1) { 518 /* Multitextured! */ 519 if (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR || 520 ctx->Fog.ColorSumEnabled) 521 swrast->Line = aa_multitex_spec_line; 522 else 523 swrast->Line = aa_multitex_rgba_line; 524 } 525 else { 526 swrast->Line = aa_tex_rgba_line; 527 } 528 } 529 else { 530 swrast->Line = aa_rgba_line; 531 } 532 } 533 else { 534 /* Color Index */ 535 swrast->Line = aa_ci_line; 536 } 537} 538