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