s_aaline.c revision eca456b63d41700617987ba45a09e8f2168b9577
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.3 4 * 5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 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. 23 */ 24 25 26#include "glheader.h" 27#include "imports.h" 28#include "macros.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 35 36#define SUB_PIXEL 4 37 38 39/* 40 * Info about the AA line we're rendering 41 */ 42struct LineInfo 43{ 44 GLfloat x0, y0; /* start */ 45 GLfloat x1, y1; /* end */ 46 GLfloat dx, dy; /* direction vector */ 47 GLfloat len; /* length */ 48 GLfloat halfWidth; /* half of line width */ 49 GLfloat xAdj, yAdj; /* X and Y adjustment for quad corners around line */ 50 /* for coverage computation */ 51 GLfloat qx0, qy0; /* quad vertices */ 52 GLfloat qx1, qy1; 53 GLfloat qx2, qy2; 54 GLfloat qx3, qy3; 55 GLfloat ex0, ey0; /* quad edge vectors */ 56 GLfloat ex1, ey1; 57 GLfloat ex2, ey2; 58 GLfloat ex3, ey3; 59 60 /* DO_Z */ 61 GLfloat zPlane[4]; 62 /* DO_FOG */ 63 GLfloat fPlane[4]; 64 /* DO_RGBA */ 65 GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4]; 66 /* DO_INDEX */ 67 GLfloat iPlane[4]; 68 /* DO_SPEC */ 69 GLfloat srPlane[4], sgPlane[4], sbPlane[4]; 70 /* DO_ATTRIBS */ 71 GLfloat sPlane[FRAG_ATTRIB_MAX][4]; 72 GLfloat tPlane[FRAG_ATTRIB_MAX][4]; 73 GLfloat uPlane[FRAG_ATTRIB_MAX][4]; 74 GLfloat vPlane[FRAG_ATTRIB_MAX][4]; 75 GLfloat lambda[FRAG_ATTRIB_MAX]; 76 GLfloat texWidth[FRAG_ATTRIB_MAX]; 77 GLfloat texHeight[FRAG_ATTRIB_MAX]; 78 79 SWspan 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 const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2]; 183#if CHAN_TYPE == GL_FLOAT 184 return CLAMP(z, 0.0F, CHAN_MAXF); 185#else 186 if (z < 0) 187 return 0; 188 else if (z > CHAN_MAX) 189 return CHAN_MAX; 190 return (GLchan) IROUND_POS(z); 191#endif 192} 193 194 195/* 196 * Compute mipmap level of detail. 197 */ 198static INLINE GLfloat 199compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4], 200 GLfloat invQ, GLfloat width, GLfloat height) 201{ 202 GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width; 203 GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width; 204 GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height; 205 GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height; 206 GLfloat r1 = dudx * dudx + dudy * dudy; 207 GLfloat r2 = dvdx * dvdx + dvdy * dvdy; 208 GLfloat rho2 = r1 + r2; 209 /* return log base 2 of rho */ 210 if (rho2 == 0.0F) 211 return 0.0; 212 else 213 return (GLfloat) (LOGF(rho2) * 1.442695 * 0.5);/* 1.442695 = 1/log(2) */ 214} 215 216 217 218 219/* 220 * Fill in the samples[] array with the (x,y) subpixel positions of 221 * xSamples * ySamples sample positions. 222 * Note that the four corner samples are put into the first four 223 * positions of the array. This allows us to optimize for the common 224 * case of all samples being inside the polygon. 225 */ 226static void 227make_sample_table(GLint xSamples, GLint ySamples, GLfloat samples[][2]) 228{ 229 const GLfloat dx = 1.0F / (GLfloat) xSamples; 230 const GLfloat dy = 1.0F / (GLfloat) ySamples; 231 GLint x, y; 232 GLint i; 233 234 i = 4; 235 for (x = 0; x < xSamples; x++) { 236 for (y = 0; y < ySamples; y++) { 237 GLint j; 238 if (x == 0 && y == 0) { 239 /* lower left */ 240 j = 0; 241 } 242 else if (x == xSamples - 1 && y == 0) { 243 /* lower right */ 244 j = 1; 245 } 246 else if (x == 0 && y == ySamples - 1) { 247 /* upper left */ 248 j = 2; 249 } 250 else if (x == xSamples - 1 && y == ySamples - 1) { 251 /* upper right */ 252 j = 3; 253 } 254 else { 255 j = i++; 256 } 257 samples[j][0] = x * dx + 0.5F * dx; 258 samples[j][1] = y * dy + 0.5F * dy; 259 } 260 } 261} 262 263 264 265/* 266 * Compute how much of the given pixel's area is inside the rectangle 267 * defined by vertices v0, v1, v2, v3. 268 * Vertices MUST be specified in counter-clockwise order. 269 * Return: coverage in [0, 1]. 270 */ 271static GLfloat 272compute_coveragef(const struct LineInfo *info, 273 GLint winx, GLint winy) 274{ 275 static GLfloat samples[SUB_PIXEL * SUB_PIXEL][2]; 276 static GLboolean haveSamples = GL_FALSE; 277 const GLfloat x = (GLfloat) winx; 278 const GLfloat y = (GLfloat) winy; 279 GLint stop = 4, i; 280 GLfloat insideCount = SUB_PIXEL * SUB_PIXEL; 281 282 if (!haveSamples) { 283 make_sample_table(SUB_PIXEL, SUB_PIXEL, samples); 284 haveSamples = GL_TRUE; 285 } 286 287#if 0 /*DEBUG*/ 288 { 289 const GLfloat area = dx0 * dy1 - dx1 * dy0; 290 assert(area >= 0.0); 291 } 292#endif 293 294 for (i = 0; i < stop; i++) { 295 const GLfloat sx = x + samples[i][0]; 296 const GLfloat sy = y + samples[i][1]; 297 const GLfloat fx0 = sx - info->qx0; 298 const GLfloat fy0 = sy - info->qy0; 299 const GLfloat fx1 = sx - info->qx1; 300 const GLfloat fy1 = sy - info->qy1; 301 const GLfloat fx2 = sx - info->qx2; 302 const GLfloat fy2 = sy - info->qy2; 303 const GLfloat fx3 = sx - info->qx3; 304 const GLfloat fy3 = sy - info->qy3; 305 /* cross product determines if sample is inside or outside each edge */ 306 GLfloat cross0 = (info->ex0 * fy0 - info->ey0 * fx0); 307 GLfloat cross1 = (info->ex1 * fy1 - info->ey1 * fx1); 308 GLfloat cross2 = (info->ex2 * fy2 - info->ey2 * fx2); 309 GLfloat cross3 = (info->ex3 * fy3 - info->ey3 * fx3); 310 /* Check if the sample is exactly on an edge. If so, let cross be a 311 * positive or negative value depending on the direction of the edge. 312 */ 313 if (cross0 == 0.0F) 314 cross0 = info->ex0 + info->ey0; 315 if (cross1 == 0.0F) 316 cross1 = info->ex1 + info->ey1; 317 if (cross2 == 0.0F) 318 cross2 = info->ex2 + info->ey2; 319 if (cross3 == 0.0F) 320 cross3 = info->ex3 + info->ey3; 321 if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F || cross3 < 0.0F) { 322 /* point is outside quadrilateral */ 323 insideCount -= 1.0F; 324 stop = SUB_PIXEL * SUB_PIXEL; 325 } 326 } 327 if (stop == 4) 328 return 1.0F; 329 else 330 return insideCount * (1.0F / (SUB_PIXEL * SUB_PIXEL)); 331} 332 333 334/** 335 * Compute coverage value for color index mode. 336 * XXX this may not be quite correct. 337 * \return coverage in [0,15]. 338 */ 339static GLfloat 340compute_coveragei(const struct LineInfo *info, 341 GLint winx, GLint winy) 342{ 343 return compute_coveragef(info, winx, winy) * 15.0F; 344} 345 346 347 348typedef void (*plot_func)(GLcontext *ctx, struct LineInfo *line, 349 int ix, int iy); 350 351 352 353/* 354 * Draw an AA line segment (called many times per line when stippling) 355 */ 356static void 357segment(GLcontext *ctx, 358 struct LineInfo *line, 359 plot_func plot, 360 GLfloat t0, GLfloat t1) 361{ 362 const GLfloat absDx = (line->dx < 0.0F) ? -line->dx : line->dx; 363 const GLfloat absDy = (line->dy < 0.0F) ? -line->dy : line->dy; 364 /* compute the actual segment's endpoints */ 365 const GLfloat x0 = line->x0 + t0 * line->dx; 366 const GLfloat y0 = line->y0 + t0 * line->dy; 367 const GLfloat x1 = line->x0 + t1 * line->dx; 368 const GLfloat y1 = line->y0 + t1 * line->dy; 369 370 /* compute vertices of the line-aligned quadrilateral */ 371 line->qx0 = x0 - line->yAdj; 372 line->qy0 = y0 + line->xAdj; 373 line->qx1 = x0 + line->yAdj; 374 line->qy1 = y0 - line->xAdj; 375 line->qx2 = x1 + line->yAdj; 376 line->qy2 = y1 - line->xAdj; 377 line->qx3 = x1 - line->yAdj; 378 line->qy3 = y1 + line->xAdj; 379 /* compute the quad's edge vectors (for coverage calc) */ 380 line->ex0 = line->qx1 - line->qx0; 381 line->ey0 = line->qy1 - line->qy0; 382 line->ex1 = line->qx2 - line->qx1; 383 line->ey1 = line->qy2 - line->qy1; 384 line->ex2 = line->qx3 - line->qx2; 385 line->ey2 = line->qy3 - line->qy2; 386 line->ex3 = line->qx0 - line->qx3; 387 line->ey3 = line->qy0 - line->qy3; 388 389 if (absDx > absDy) { 390 /* X-major line */ 391 GLfloat dydx = line->dy / line->dx; 392 GLfloat xLeft, xRight, yBot, yTop; 393 GLint ix, ixRight; 394 if (x0 < x1) { 395 xLeft = x0 - line->halfWidth; 396 xRight = x1 + line->halfWidth; 397 if (line->dy >= 0.0) { 398 yBot = y0 - 3.0F * line->halfWidth; 399 yTop = y0 + line->halfWidth; 400 } 401 else { 402 yBot = y0 - line->halfWidth; 403 yTop = y0 + 3.0F * line->halfWidth; 404 } 405 } 406 else { 407 xLeft = x1 - line->halfWidth; 408 xRight = x0 + line->halfWidth; 409 if (line->dy <= 0.0) { 410 yBot = y1 - 3.0F * line->halfWidth; 411 yTop = y1 + line->halfWidth; 412 } 413 else { 414 yBot = y1 - line->halfWidth; 415 yTop = y1 + 3.0F * line->halfWidth; 416 } 417 } 418 419 /* scan along the line, left-to-right */ 420 ixRight = (GLint) (xRight + 1.0F); 421 422 /*printf("avg span height: %g\n", yTop - yBot);*/ 423 for (ix = (GLint) xLeft; ix < ixRight; ix++) { 424 const GLint iyBot = (GLint) yBot; 425 const GLint iyTop = (GLint) (yTop + 1.0F); 426 GLint iy; 427 /* scan across the line, bottom-to-top */ 428 for (iy = iyBot; iy < iyTop; iy++) { 429 (*plot)(ctx, line, ix, iy); 430 } 431 yBot += dydx; 432 yTop += dydx; 433 } 434 } 435 else { 436 /* Y-major line */ 437 GLfloat dxdy = line->dx / line->dy; 438 GLfloat yBot, yTop, xLeft, xRight; 439 GLint iy, iyTop; 440 if (y0 < y1) { 441 yBot = y0 - line->halfWidth; 442 yTop = y1 + line->halfWidth; 443 if (line->dx >= 0.0) { 444 xLeft = x0 - 3.0F * line->halfWidth; 445 xRight = x0 + line->halfWidth; 446 } 447 else { 448 xLeft = x0 - line->halfWidth; 449 xRight = x0 + 3.0F * line->halfWidth; 450 } 451 } 452 else { 453 yBot = y1 - line->halfWidth; 454 yTop = y0 + line->halfWidth; 455 if (line->dx <= 0.0) { 456 xLeft = x1 - 3.0F * line->halfWidth; 457 xRight = x1 + line->halfWidth; 458 } 459 else { 460 xLeft = x1 - line->halfWidth; 461 xRight = x1 + 3.0F * line->halfWidth; 462 } 463 } 464 465 /* scan along the line, bottom-to-top */ 466 iyTop = (GLint) (yTop + 1.0F); 467 468 /*printf("avg span width: %g\n", xRight - xLeft);*/ 469 for (iy = (GLint) yBot; iy < iyTop; iy++) { 470 const GLint ixLeft = (GLint) xLeft; 471 const GLint ixRight = (GLint) (xRight + 1.0F); 472 GLint ix; 473 /* scan across the line, left-to-right */ 474 for (ix = ixLeft; ix < ixRight; ix++) { 475 (*plot)(ctx, line, ix, iy); 476 } 477 xLeft += dxdy; 478 xRight += dxdy; 479 } 480 } 481} 482 483 484#define NAME(x) aa_ci_##x 485#define DO_Z 486#define DO_FOG 487#define DO_INDEX 488#include "s_aalinetemp.h" 489 490 491#define NAME(x) aa_rgba_##x 492#define DO_Z 493#define DO_FOG 494#define DO_RGBA 495#include "s_aalinetemp.h" 496 497 498#define NAME(x) aa_tex_rgba_##x 499#define DO_Z 500#define DO_FOG 501#define DO_RGBA 502#define DO_ATTRIBS 503#include "s_aalinetemp.h" 504 505 506#define NAME(x) aa_multitex_spec_##x 507#define DO_Z 508#define DO_FOG 509#define DO_RGBA 510#define DO_ATTRIBS 511#define DO_SPEC 512#include "s_aalinetemp.h" 513 514 515 516void 517_swrast_choose_aa_line_function(GLcontext *ctx) 518{ 519 SWcontext *swrast = SWRAST_CONTEXT(ctx); 520 521 ASSERT(ctx->Line.SmoothFlag); 522 523 if (ctx->Visual.rgbMode) { 524 /* RGBA */ 525 if (ctx->Texture._EnabledCoordUnits != 0 526 || ctx->FragmentProgram._Current) { 527 528 if (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR || 529 ctx->Fog.ColorSumEnabled) 530 swrast->Line = aa_multitex_spec_line; 531 else 532 swrast->Line = aa_tex_rgba_line; 533 534 } 535 else { 536 swrast->Line = aa_rgba_line; 537 } 538 } 539 else { 540 /* Color Index */ 541 swrast->Line = aa_ci_line; 542 } 543} 544