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