2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
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"
36 * Used to cull points with invalid coords
38 #define CULL_INVALID(V) \
40 float tmp = (V)->attrib[FRAG_ATTRIB_WPOS][0] \
41 + (V)->attrib[FRAG_ATTRIB_WPOS][1]; \
42 if (IS_INF_OR_NAN(tmp)) \
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.
55 get_size(const struct gl_context *ctx, const SWvertex *vert, GLboolean smoothed)
59 if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
60 /* use vertex's point size */
61 size = vert->pointSize;
64 /* use constant point size */
65 size = ctx->Point.Size;
67 /* always clamp to user-specified limits */
68 size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize);
69 /* clamp to implementation limits */
71 size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
73 size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
83 sprite_point(struct gl_context *ctx, const SWvertex *vert)
85 SWcontext *swrast = SWRAST_CONTEXT(ctx);
88 GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1];
89 GLuint numTcoords = 0;
95 if (ctx->DrawBuffer->Visual.depthBits <= 16)
96 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
98 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
101 size = get_size(ctx, vert, GL_FALSE);
104 INIT_SPAN(span, GL_POINT);
105 span.interpMask = SPAN_Z | SPAN_RGBA;
107 span.facing = swrast->PointLineFacing;
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]);
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;
126 /* texcoord / pointcoord interpolants */
129 if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
136 t0 = 1.0F + 0.5F * dtdy;
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;
147 if (ctx->Point.SpriteRMode == GL_ZERO)
149 else if (ctx->Point.SpriteRMode == GL_S)
150 r = vert->attrib[attr][0];
152 r = vert->attrib[attr][2];
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;
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;
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;
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;
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);
190 /* compute pos, bounds and render */
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;
199 iSize = MAX2(1, iSize);
204 xmin = (GLint) (x - iRadius);
205 xmax = (GLint) (x + iRadius);
206 ymin = (GLint) (y - iRadius);
207 ymax = (GLint) (y + iRadius);
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;
219 for (iy = ymin; iy <= ymax; iy++) {
221 /* setup texcoord T for this row */
222 for (i = 0; i < numTcoords; i++) {
223 span.attrStart[tCoords[i]][1] = tcoord;
226 /* these might get changed by span clipping */
229 span.end = xmax - xmin + 1;
231 _swrast_write_rgba_span(ctx, &span);
240 * Draw smooth/antialiased point. RGB or CI mode.
243 smooth_point(struct gl_context *ctx, const SWvertex *vert)
245 SWcontext *swrast = SWRAST_CONTEXT(ctx);
247 GLfloat size, alphaAtten;
252 if (ctx->DrawBuffer->Visual.depthBits <= 16)
253 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
255 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
258 size = get_size(ctx, vert, GL_TRUE);
260 /* alpha attenuation / fade factor */
261 if (ctx->Multisample._Enabled) {
262 if (vert->pointSize >= ctx->Point.Threshold) {
266 GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
267 alphaAtten = dsize * dsize;
273 (void) alphaAtten; /* not used */
276 INIT_SPAN(span, GL_POINT);
277 span.interpMask = SPAN_Z | SPAN_RGBA;
278 span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
280 span.facing = swrast->PointLineFacing;
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]);
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;
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);
302 /* compute pos, bounds and render */
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);
318 for (iy = ymin; iy <= ymax; iy++) {
320 /* these might get changed by span clipping */
323 span.end = xmax - xmin + 1;
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;
333 if (dist2 >= rmin2) {
334 /* compute partial coverage */
335 coverage = 1.0F - (dist2 - rmin2) * cscale;
341 span.array->mask[ix - xmin] = 1;
344 /* zero coverage - fragment outside the radius */
346 span.array->mask[ix - xmin] = 0;
348 span.array->coverage[ix - xmin] = coverage;
352 _swrast_write_rgba_span(ctx, &span);
360 * Draw large (size >= 1) non-AA point. RGB or CI mode.
363 large_point(struct gl_context *ctx, const SWvertex *vert)
365 SWcontext *swrast = SWRAST_CONTEXT(ctx);
372 if (ctx->DrawBuffer->Visual.depthBits <= 16)
373 span.z = FloatToFixed(vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
375 span.z = (GLuint) (vert->attrib[FRAG_ATTRIB_WPOS][2] + 0.5F);
378 size = get_size(ctx, vert, GL_FALSE);
381 INIT_SPAN(span, GL_POINT);
382 span.arrayMask = SPAN_XY;
383 span.facing = swrast->PointLineFacing;
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]);
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;
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);
406 /* compute pos, bounds and render */
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;
414 iSize = MAX2(1, iSize);
419 xmin = (GLint) (x - iRadius);
420 xmax = (GLint) (x + iRadius);
421 ymin = (GLint) (y - iRadius);
422 ymax = (GLint) (y + iRadius);
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;
433 /* generate fragments */
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;
442 assert(span.end <= MAX_WIDTH);
443 _swrast_write_rgba_span(ctx, &span);
449 * Draw size=1, single-pixel point
452 pixel_point(struct gl_context *ctx, const SWvertex *vert)
454 SWcontext *swrast = SWRAST_CONTEXT(ctx);
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.
460 SWspan *span = &(swrast->PointSpan);
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 */
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;
477 /* check if we need to flush */
478 if (span->end >= MAX_WIDTH ||
479 (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
480 span->facing != swrast->PointLineFacing) {
482 _swrast_write_rgba_span(ctx, span);
489 span->facing = swrast->PointLineFacing;
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];
498 COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
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);
506 span->end = count + 1;
507 ASSERT(span->end <= MAX_WIDTH);
512 * Add specular color to primary color, draw point, restore original
516 _swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0)
518 SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
519 GLfloat rSum, gSum, bSum;
523 COPY_CHAN4(cSave, ncv0->color);
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);
532 SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
534 COPY_CHAN4(ncv0->color, cSave);
539 * Examine current state to determine which point drawing function to use.
542 _swrast_choose_point(struct gl_context *ctx)
544 SWcontext *swrast = SWRAST_CONTEXT(ctx);
545 const GLfloat size = CLAMP(ctx->Point.Size,
549 if (ctx->RenderMode == GL_RENDER) {
550 if (ctx->Point.PointSprite) {
551 swrast->Point = sprite_point;
553 else if (ctx->Point.SmoothFlag) {
554 swrast->Point = smooth_point;
556 else if (size > 1.0 ||
557 ctx->Point._Attenuated ||
558 ctx->VertexProgram.PointSizeEnabled) {
559 swrast->Point = large_point;
562 swrast->Point = pixel_point;
565 else if (ctx->RenderMode == GL_FEEDBACK) {
566 swrast->Point = _swrast_feedback_point;
570 swrast->Point = _swrast_select_point;