1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 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/colormac.h" 28#include "main/macros.h" 29#include "s_context.h" 30#include "s_feedback.h" 31#include "s_points.h" 32#include "s_span.h" 33 34 35/** 36 * Used to cull points with invalid coords 37 */ 38#define CULL_INVALID(V) \ 39 do { \ 40 float tmp = (V)->attrib[FRAG_ATTRIB_WPOS][0] \ 41 + (V)->attrib[FRAG_ATTRIB_WPOS][1]; \ 42 if (IS_INF_OR_NAN(tmp)) \ 43 return; \ 44 } while(0) 45 46 47 48/** 49 * Get/compute the point size. 50 * The size may come from a vertex shader, or computed with attentuation 51 * or just the glPointSize value. 52 * Must also clamp to user-defined range and implmentation limits. 53 */ 54static inline GLfloat 55get_size(const struct gl_context *ctx, const SWvertex *vert, GLboolean smoothed) 56{ 57 GLfloat size; 58 59 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) { 60 /* use vertex's point size */ 61 size = vert->pointSize; 62 } 63 else { 64 /* use constant point size */ 65 size = ctx->Point.Size; 66 } 67 /* always clamp to user-specified limits */ 68 size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize); 69 /* clamp to implementation limits */ 70 if (smoothed) 71 size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA); 72 else 73 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize); 74 75 return size; 76} 77 78 79/** 80 * Draw a point sprite 81 */ 82static void 83sprite_point(struct gl_context *ctx, const SWvertex *vert) 84{ 85 SWcontext *swrast = SWRAST_CONTEXT(ctx); 86 SWspan span; 87 GLfloat size; 88 GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1]; 89 GLuint numTcoords = 0; 90 GLfloat t0, dtdy; 91 92 CULL_INVALID(vert); 93 94 /* z coord */ 95 if (ctx->DrawBuffer->Visual.depthBits <= 16) 96 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 97 else 98 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 99 span.zStep = 0; 100 101 size = get_size(ctx, vert, GL_FALSE); 102 103 /* span init */ 104 INIT_SPAN(span, GL_POINT); 105 span.interpMask = SPAN_Z | SPAN_RGBA; 106 107 span.facing = swrast->PointLineFacing; 108 109 span.red = ChanToFixed(vert->color[0]); 110 span.green = ChanToFixed(vert->color[1]); 111 span.blue = ChanToFixed(vert->color[2]); 112 span.alpha = ChanToFixed(vert->color[3]); 113 span.redStep = 0; 114 span.greenStep = 0; 115 span.blueStep = 0; 116 span.alphaStep = 0; 117 118 /* need these for fragment programs */ 119 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; 120 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; 121 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; 122 123 { 124 GLfloat s, r, dsdx; 125 126 /* texcoord / pointcoord interpolants */ 127 s = 0.0F; 128 dsdx = 1.0F / size; 129 if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) { 130 dtdy = 1.0F / size; 131 t0 = 0.5F * dtdy; 132 } 133 else { 134 /* GL_UPPER_LEFT */ 135 dtdy = -1.0F / size; 136 t0 = 1.0F + 0.5F * dtdy; 137 } 138 139 ATTRIB_LOOP_BEGIN 140 if (attr >= FRAG_ATTRIB_TEX0 && attr <= FRAG_ATTRIB_TEX7) { 141 /* a texcoord attribute */ 142 const GLuint u = attr - FRAG_ATTRIB_TEX0; 143 ASSERT(u < Elements(ctx->Point.CoordReplace)); 144 if (ctx->Point.CoordReplace[u]) { 145 tCoords[numTcoords++] = attr; 146 147 if (ctx->Point.SpriteRMode == GL_ZERO) 148 r = 0.0F; 149 else if (ctx->Point.SpriteRMode == GL_S) 150 r = vert->attrib[attr][0]; 151 else /* GL_R */ 152 r = vert->attrib[attr][2]; 153 154 span.attrStart[attr][0] = s; 155 span.attrStart[attr][1] = 0.0; /* overwritten below */ 156 span.attrStart[attr][2] = r; 157 span.attrStart[attr][3] = 1.0; 158 159 span.attrStepX[attr][0] = dsdx; 160 span.attrStepX[attr][1] = 0.0; 161 span.attrStepX[attr][2] = 0.0; 162 span.attrStepX[attr][3] = 0.0; 163 164 span.attrStepY[attr][0] = 0.0; 165 span.attrStepY[attr][1] = dtdy; 166 span.attrStepY[attr][2] = 0.0; 167 span.attrStepY[attr][3] = 0.0; 168 169 continue; 170 } 171 } 172 else if (attr == FRAG_ATTRIB_PNTC) { 173 /* GLSL gl_PointCoord.xy (.zw undefined) */ 174 span.attrStart[FRAG_ATTRIB_PNTC][0] = 0.0; 175 span.attrStart[FRAG_ATTRIB_PNTC][1] = 0.0; /* t0 set below */ 176 span.attrStepX[FRAG_ATTRIB_PNTC][0] = dsdx; 177 span.attrStepX[FRAG_ATTRIB_PNTC][1] = 0.0; 178 span.attrStepY[FRAG_ATTRIB_PNTC][0] = 0.0; 179 span.attrStepY[FRAG_ATTRIB_PNTC][1] = dtdy; 180 tCoords[numTcoords++] = FRAG_ATTRIB_PNTC; 181 continue; 182 } 183 /* use vertex's texcoord/attrib */ 184 COPY_4V(span.attrStart[attr], vert->attrib[attr]); 185 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); 186 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); 187 ATTRIB_LOOP_END; 188 } 189 190 /* compute pos, bounds and render */ 191 { 192 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; 193 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; 194 GLint iSize = (GLint) (size + 0.5F); 195 GLint xmin, xmax, ymin, ymax, iy; 196 GLint iRadius; 197 GLfloat tcoord = t0; 198 199 iSize = MAX2(1, iSize); 200 iRadius = iSize / 2; 201 202 if (iSize & 1) { 203 /* odd size */ 204 xmin = (GLint) (x - iRadius); 205 xmax = (GLint) (x + iRadius); 206 ymin = (GLint) (y - iRadius); 207 ymax = (GLint) (y + iRadius); 208 } 209 else { 210 /* even size */ 211 /* 0.501 factor allows conformance to pass */ 212 xmin = (GLint) (x + 0.501) - iRadius; 213 xmax = xmin + iSize - 1; 214 ymin = (GLint) (y + 0.501) - iRadius; 215 ymax = ymin + iSize - 1; 216 } 217 218 /* render spans */ 219 for (iy = ymin; iy <= ymax; iy++) { 220 GLuint i; 221 /* setup texcoord T for this row */ 222 for (i = 0; i < numTcoords; i++) { 223 span.attrStart[tCoords[i]][1] = tcoord; 224 } 225 226 /* these might get changed by span clipping */ 227 span.x = xmin; 228 span.y = iy; 229 span.end = xmax - xmin + 1; 230 231 _swrast_write_rgba_span(ctx, &span); 232 233 tcoord += dtdy; 234 } 235 } 236} 237 238 239/** 240 * Draw smooth/antialiased point. RGB or CI mode. 241 */ 242static void 243smooth_point(struct gl_context *ctx, const SWvertex *vert) 244{ 245 SWcontext *swrast = SWRAST_CONTEXT(ctx); 246 SWspan span; 247 GLfloat size, alphaAtten; 248 249 CULL_INVALID(vert); 250 251 /* z coord */ 252 if (ctx->DrawBuffer->Visual.depthBits <= 16) 253 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 254 else 255 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 256 span.zStep = 0; 257 258 size = get_size(ctx, vert, GL_TRUE); 259 260 /* alpha attenuation / fade factor */ 261 if (ctx->Multisample._Enabled) { 262 if (vert->pointSize >= ctx->Point.Threshold) { 263 alphaAtten = 1.0F; 264 } 265 else { 266 GLfloat dsize = vert->pointSize / ctx->Point.Threshold; 267 alphaAtten = dsize * dsize; 268 } 269 } 270 else { 271 alphaAtten = 1.0; 272 } 273 (void) alphaAtten; /* not used */ 274 275 /* span init */ 276 INIT_SPAN(span, GL_POINT); 277 span.interpMask = SPAN_Z | SPAN_RGBA; 278 span.arrayMask = SPAN_COVERAGE | SPAN_MASK; 279 280 span.facing = swrast->PointLineFacing; 281 282 span.red = ChanToFixed(vert->color[0]); 283 span.green = ChanToFixed(vert->color[1]); 284 span.blue = ChanToFixed(vert->color[2]); 285 span.alpha = ChanToFixed(vert->color[3]); 286 span.redStep = 0; 287 span.greenStep = 0; 288 span.blueStep = 0; 289 span.alphaStep = 0; 290 291 /* need these for fragment programs */ 292 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; 293 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; 294 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; 295 296 ATTRIB_LOOP_BEGIN 297 COPY_4V(span.attrStart[attr], vert->attrib[attr]); 298 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); 299 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); 300 ATTRIB_LOOP_END 301 302 /* compute pos, bounds and render */ 303 { 304 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; 305 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; 306 const GLfloat radius = 0.5F * size; 307 const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */ 308 const GLfloat rmax = radius + 0.7071F; 309 const GLfloat rmin2 = MAX2(0.0F, rmin * rmin); 310 const GLfloat rmax2 = rmax * rmax; 311 const GLfloat cscale = 1.0F / (rmax2 - rmin2); 312 const GLint xmin = (GLint) (x - radius); 313 const GLint xmax = (GLint) (x + radius); 314 const GLint ymin = (GLint) (y - radius); 315 const GLint ymax = (GLint) (y + radius); 316 GLint ix, iy; 317 318 for (iy = ymin; iy <= ymax; iy++) { 319 320 /* these might get changed by span clipping */ 321 span.x = xmin; 322 span.y = iy; 323 span.end = xmax - xmin + 1; 324 325 /* compute coverage for each pixel in span */ 326 for (ix = xmin; ix <= xmax; ix++) { 327 const GLfloat dx = ix - x + 0.5F; 328 const GLfloat dy = iy - y + 0.5F; 329 const GLfloat dist2 = dx * dx + dy * dy; 330 GLfloat coverage; 331 332 if (dist2 < rmax2) { 333 if (dist2 >= rmin2) { 334 /* compute partial coverage */ 335 coverage = 1.0F - (dist2 - rmin2) * cscale; 336 } 337 else { 338 /* full coverage */ 339 coverage = 1.0F; 340 } 341 span.array->mask[ix - xmin] = 1; 342 } 343 else { 344 /* zero coverage - fragment outside the radius */ 345 coverage = 0.0; 346 span.array->mask[ix - xmin] = 0; 347 } 348 span.array->coverage[ix - xmin] = coverage; 349 } 350 351 /* render span */ 352 _swrast_write_rgba_span(ctx, &span); 353 354 } 355 } 356} 357 358 359/** 360 * Draw large (size >= 1) non-AA point. RGB or CI mode. 361 */ 362static void 363large_point(struct gl_context *ctx, const SWvertex *vert) 364{ 365 SWcontext *swrast = SWRAST_CONTEXT(ctx); 366 SWspan span; 367 GLfloat size; 368 369 CULL_INVALID(vert); 370 371 /* z coord */ 372 if (ctx->DrawBuffer->Visual.depthBits <= 16) 373 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 374 else 375 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 376 span.zStep = 0; 377 378 size = get_size(ctx, vert, GL_FALSE); 379 380 /* span init */ 381 INIT_SPAN(span, GL_POINT); 382 span.arrayMask = SPAN_XY; 383 span.facing = swrast->PointLineFacing; 384 385 span.interpMask = SPAN_Z | SPAN_RGBA; 386 span.red = ChanToFixed(vert->color[0]); 387 span.green = ChanToFixed(vert->color[1]); 388 span.blue = ChanToFixed(vert->color[2]); 389 span.alpha = ChanToFixed(vert->color[3]); 390 span.redStep = 0; 391 span.greenStep = 0; 392 span.blueStep = 0; 393 span.alphaStep = 0; 394 395 /* need these for fragment programs */ 396 span.attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; 397 span.attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; 398 span.attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; 399 400 ATTRIB_LOOP_BEGIN 401 COPY_4V(span.attrStart[attr], vert->attrib[attr]); 402 ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0); 403 ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0); 404 ATTRIB_LOOP_END 405 406 /* compute pos, bounds and render */ 407 { 408 const GLfloat x = vert->attrib[FRAG_ATTRIB_WPOS][0]; 409 const GLfloat y = vert->attrib[FRAG_ATTRIB_WPOS][1]; 410 GLint iSize = (GLint) (size + 0.5F); 411 GLint xmin, xmax, ymin, ymax, ix, iy; 412 GLint iRadius; 413 414 iSize = MAX2(1, iSize); 415 iRadius = iSize / 2; 416 417 if (iSize & 1) { 418 /* odd size */ 419 xmin = (GLint) (x - iRadius); 420 xmax = (GLint) (x + iRadius); 421 ymin = (GLint) (y - iRadius); 422 ymax = (GLint) (y + iRadius); 423 } 424 else { 425 /* even size */ 426 /* 0.501 factor allows conformance to pass */ 427 xmin = (GLint) (x + 0.501) - iRadius; 428 xmax = xmin + iSize - 1; 429 ymin = (GLint) (y + 0.501) - iRadius; 430 ymax = ymin + iSize - 1; 431 } 432 433 /* generate fragments */ 434 span.end = 0; 435 for (iy = ymin; iy <= ymax; iy++) { 436 for (ix = xmin; ix <= xmax; ix++) { 437 span.array->x[span.end] = ix; 438 span.array->y[span.end] = iy; 439 span.end++; 440 } 441 } 442 assert(span.end <= SWRAST_MAX_WIDTH); 443 _swrast_write_rgba_span(ctx, &span); 444 } 445} 446 447 448/** 449 * Draw size=1, single-pixel point 450 */ 451static void 452pixel_point(struct gl_context *ctx, const SWvertex *vert) 453{ 454 SWcontext *swrast = SWRAST_CONTEXT(ctx); 455 /* 456 * Note that unlike the other functions, we put single-pixel points 457 * into a special span array in order to render as many points as 458 * possible with a single _swrast_write_rgba_span() call. 459 */ 460 SWspan *span = &(swrast->PointSpan); 461 GLuint count; 462 463 CULL_INVALID(vert); 464 465 /* Span init */ 466 span->interpMask = 0; 467 span->arrayMask = SPAN_XY | SPAN_Z; 468 span->arrayMask |= SPAN_RGBA; 469 /*span->arrayMask |= SPAN_LAMBDA;*/ 470 span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */ 471 472 /* need these for fragment programs */ 473 span->attrStart[FRAG_ATTRIB_WPOS][3] = 1.0F; 474 span->attrStepX[FRAG_ATTRIB_WPOS][3] = 0.0F; 475 span->attrStepY[FRAG_ATTRIB_WPOS][3] = 0.0F; 476 477 /* check if we need to flush */ 478 if (span->end >= SWRAST_MAX_WIDTH || 479 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) || 480 span->facing != swrast->PointLineFacing) { 481 if (span->end > 0) { 482 _swrast_write_rgba_span(ctx, span); 483 span->end = 0; 484 } 485 } 486 487 count = span->end; 488 489 span->facing = swrast->PointLineFacing; 490 491 /* fragment attributes */ 492 span->array->rgba[count][RCOMP] = vert->color[0]; 493 span->array->rgba[count][GCOMP] = vert->color[1]; 494 span->array->rgba[count][BCOMP] = vert->color[2]; 495 span->array->rgba[count][ACOMP] = vert->color[3]; 496 497 ATTRIB_LOOP_BEGIN 498 COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]); 499 ATTRIB_LOOP_END 500 501 /* fragment position */ 502 span->array->x[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][0]; 503 span->array->y[count] = (GLint) vert->attrib[FRAG_ATTRIB_WPOS][1]; 504 span->array->z[count] = (GLint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F); 505 506 span->end = count + 1; 507 ASSERT(span->end <= SWRAST_MAX_WIDTH); 508} 509 510 511/** 512 * Add specular color to primary color, draw point, restore original 513 * primary color. 514 */ 515void 516_swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0) 517{ 518 SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */ 519 GLfloat rSum, gSum, bSum; 520 GLchan cSave[4]; 521 522 /* save */ 523 COPY_CHAN4(cSave, ncv0->color); 524 /* sum */ 525 rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0]; 526 gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1]; 527 bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2]; 528 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum); 529 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum); 530 UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum); 531 /* draw */ 532 SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0); 533 /* restore */ 534 COPY_CHAN4(ncv0->color, cSave); 535} 536 537 538/** 539 * Examine current state to determine which point drawing function to use. 540 */ 541void 542_swrast_choose_point(struct gl_context *ctx) 543{ 544 SWcontext *swrast = SWRAST_CONTEXT(ctx); 545 const GLfloat size = CLAMP(ctx->Point.Size, 546 ctx->Point.MinSize, 547 ctx->Point.MaxSize); 548 549 if (ctx->RenderMode == GL_RENDER) { 550 if (ctx->Point.PointSprite) { 551 swrast->Point = sprite_point; 552 } 553 else if (ctx->Point.SmoothFlag) { 554 swrast->Point = smooth_point; 555 } 556 else if (size > 1.0 || 557 ctx->Point._Attenuated || 558 ctx->VertexProgram.PointSizeEnabled) { 559 swrast->Point = large_point; 560 } 561 else { 562 swrast->Point = pixel_point; 563 } 564 } 565 else if (ctx->RenderMode == GL_FEEDBACK) { 566 swrast->Point = _swrast_feedback_point; 567 } 568 else { 569 /* GL_SELECT mode */ 570 swrast->Point = _swrast_select_point; 571 } 572} 573