• 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, r, 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                if (ctx->Point.SpriteRMode == GL_ZERO)
147                   r = 0.0F;
148                else if (ctx->Point.SpriteRMode == GL_S)
149                   r = vert->attrib[attr][0];
150                else /* GL_R */
151                   r = vert->attrib[attr][2];
152 
153                span.attrStart[attr][0] = s;
154                span.attrStart[attr][1] = 0.0; /* overwritten below */
155                span.attrStart[attr][2] = r;
156                span.attrStart[attr][3] = 1.0;
157 
158                span.attrStepX[attr][0] = dsdx;
159                span.attrStepX[attr][1] = 0.0;
160                span.attrStepX[attr][2] = 0.0;
161                span.attrStepX[attr][3] = 0.0;
162 
163                span.attrStepY[attr][0] = 0.0;
164                span.attrStepY[attr][1] = dtdy;
165                span.attrStepY[attr][2] = 0.0;
166                span.attrStepY[attr][3] = 0.0;
167 
168                continue;
169             }
170          }
171          else if (attr == VARYING_SLOT_PNTC) {
172             /* GLSL gl_PointCoord.xy (.zw undefined) */
173             span.attrStart[VARYING_SLOT_PNTC][0] = 0.0;
174             span.attrStart[VARYING_SLOT_PNTC][1] = 0.0; /* t0 set below */
175             span.attrStepX[VARYING_SLOT_PNTC][0] = dsdx;
176             span.attrStepX[VARYING_SLOT_PNTC][1] = 0.0;
177             span.attrStepY[VARYING_SLOT_PNTC][0] = 0.0;
178             span.attrStepY[VARYING_SLOT_PNTC][1] = dtdy;
179             tCoords[numTcoords++] = VARYING_SLOT_PNTC;
180             continue;
181          }
182          /* use vertex's texcoord/attrib */
183          COPY_4V(span.attrStart[attr], vert->attrib[attr]);
184          ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
185          ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
186       ATTRIB_LOOP_END;
187    }
188 
189    /* compute pos, bounds and render */
190    {
191       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
192       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
193       GLint iSize = (GLint) (size + 0.5F);
194       GLint xmin, xmax, ymin, ymax, iy;
195       GLint iRadius;
196       GLfloat tcoord = t0;
197 
198       iSize = MAX2(1, iSize);
199       iRadius = iSize / 2;
200 
201       if (iSize & 1) {
202          /* odd size */
203          xmin = (GLint) (x - iRadius);
204          xmax = (GLint) (x + iRadius);
205          ymin = (GLint) (y - iRadius);
206          ymax = (GLint) (y + iRadius);
207       }
208       else {
209          /* even size */
210          /* 0.501 factor allows conformance to pass */
211          xmin = (GLint) (x + 0.501F) - iRadius;
212          xmax = xmin + iSize - 1;
213          ymin = (GLint) (y + 0.501F) - iRadius;
214          ymax = ymin + iSize - 1;
215       }
216 
217       /* render spans */
218       for (iy = ymin; iy <= ymax; iy++) {
219          GLuint i;
220          /* setup texcoord T for this row */
221          for (i = 0; i < numTcoords; i++) {
222             span.attrStart[tCoords[i]][1] = tcoord;
223          }
224 
225          /* these might get changed by span clipping */
226          span.x = xmin;
227          span.y = iy;
228          span.end = xmax - xmin + 1;
229 
230          _swrast_write_rgba_span(ctx, &span);
231 
232          tcoord += dtdy;
233       }
234    }
235 }
236 
237 
238 /**
239  * Draw smooth/antialiased point.  RGB or CI mode.
240  */
241 static void
smooth_point(struct gl_context * ctx,const SWvertex * vert)242 smooth_point(struct gl_context *ctx, const SWvertex *vert)
243 {
244    SWcontext *swrast = SWRAST_CONTEXT(ctx);
245    SWspan span;
246    GLfloat size, alphaAtten;
247 
248    CULL_INVALID(vert);
249 
250    /* z coord */
251    if (ctx->DrawBuffer->Visual.depthBits <= 16)
252       span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
253    else
254       span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
255    span.zStep = 0;
256 
257    size = get_size(ctx, vert, GL_TRUE);
258 
259    /* alpha attenuation / fade factor */
260    if (_mesa_is_multisample_enabled(ctx)) {
261       if (vert->pointSize >= ctx->Point.Threshold) {
262          alphaAtten = 1.0F;
263       }
264       else {
265          GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
266          alphaAtten = dsize * dsize;
267       }
268    }
269    else {
270       alphaAtten = 1.0;
271    }
272    (void) alphaAtten; /* not used */
273 
274    /* span init */
275    INIT_SPAN(span, GL_POINT);
276    span.interpMask = SPAN_Z | SPAN_RGBA;
277    span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
278 
279    span.facing = swrast->PointLineFacing;
280 
281    span.red   = ChanToFixed(vert->color[0]);
282    span.green = ChanToFixed(vert->color[1]);
283    span.blue  = ChanToFixed(vert->color[2]);
284    span.alpha = ChanToFixed(vert->color[3]);
285    span.redStep = 0;
286    span.greenStep = 0;
287    span.blueStep = 0;
288    span.alphaStep = 0;
289 
290    /* need these for fragment programs */
291    span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
292    span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
293    span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
294 
295    ATTRIB_LOOP_BEGIN
296       COPY_4V(span.attrStart[attr], vert->attrib[attr]);
297       ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
298       ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
299    ATTRIB_LOOP_END
300 
301    /* compute pos, bounds and render */
302    {
303       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
304       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
305       const GLfloat radius = 0.5F * size;
306       const GLfloat rmin = radius - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
307       const GLfloat rmax = radius + 0.7071F;
308       const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
309       const GLfloat rmax2 = rmax * rmax;
310       const GLfloat cscale = 1.0F / (rmax2 - rmin2);
311       const GLint xmin = (GLint) (x - radius);
312       const GLint xmax = (GLint) (x + radius);
313       const GLint ymin = (GLint) (y - radius);
314       const GLint ymax = (GLint) (y + radius);
315       GLint ix, iy;
316 
317       for (iy = ymin; iy <= ymax; iy++) {
318 
319          /* these might get changed by span clipping */
320          span.x = xmin;
321          span.y = iy;
322          span.end = xmax - xmin + 1;
323 
324          /* compute coverage for each pixel in span */
325          for (ix = xmin; ix <= xmax; ix++) {
326             const GLfloat dx = ix - x + 0.5F;
327             const GLfloat dy = iy - y + 0.5F;
328             const GLfloat dist2 = dx * dx + dy * dy;
329             GLfloat coverage;
330 
331             if (dist2 < rmax2) {
332                if (dist2 >= rmin2) {
333                   /* compute partial coverage */
334                   coverage = 1.0F - (dist2 - rmin2) * cscale;
335                }
336                else {
337                   /* full coverage */
338                   coverage = 1.0F;
339                }
340                span.array->mask[ix - xmin] = 1;
341             }
342             else {
343                /* zero coverage - fragment outside the radius */
344                coverage = 0.0;
345                span.array->mask[ix - xmin] = 0;
346             }
347             span.array->coverage[ix - xmin] = coverage;
348          }
349 
350          /* render span */
351          _swrast_write_rgba_span(ctx, &span);
352 
353       }
354    }
355 }
356 
357 
358 /**
359  * Draw large (size >= 1) non-AA point.  RGB or CI mode.
360  */
361 static void
large_point(struct gl_context * ctx,const SWvertex * vert)362 large_point(struct gl_context *ctx, const SWvertex *vert)
363 {
364    SWcontext *swrast = SWRAST_CONTEXT(ctx);
365    SWspan span;
366    GLfloat size;
367 
368    CULL_INVALID(vert);
369 
370    /* z coord */
371    if (ctx->DrawBuffer->Visual.depthBits <= 16)
372       span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
373    else
374       span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
375    span.zStep = 0;
376 
377    size = get_size(ctx, vert, GL_FALSE);
378 
379    /* span init */
380    INIT_SPAN(span, GL_POINT);
381    span.arrayMask = SPAN_XY;
382    span.facing = swrast->PointLineFacing;
383 
384    span.interpMask = SPAN_Z | SPAN_RGBA;
385    span.red   = ChanToFixed(vert->color[0]);
386    span.green = ChanToFixed(vert->color[1]);
387    span.blue  = ChanToFixed(vert->color[2]);
388    span.alpha = ChanToFixed(vert->color[3]);
389    span.redStep = 0;
390    span.greenStep = 0;
391    span.blueStep = 0;
392    span.alphaStep = 0;
393 
394    /* need these for fragment programs */
395    span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
396    span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
397    span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
398 
399    ATTRIB_LOOP_BEGIN
400       COPY_4V(span.attrStart[attr], vert->attrib[attr]);
401       ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
402       ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
403    ATTRIB_LOOP_END
404 
405    /* compute pos, bounds and render */
406    {
407       const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
408       const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
409       GLint iSize = (GLint) (size + 0.5F);
410       GLint xmin, xmax, ymin, ymax, ix, iy;
411       GLint iRadius;
412 
413       iSize = MAX2(1, iSize);
414       iRadius = iSize / 2;
415 
416       if (iSize & 1) {
417          /* odd size */
418          xmin = (GLint) (x - iRadius);
419          xmax = (GLint) (x + iRadius);
420          ymin = (GLint) (y - iRadius);
421          ymax = (GLint) (y + iRadius);
422       }
423       else {
424          /* even size */
425          /* 0.501 factor allows conformance to pass */
426          xmin = (GLint) (x + 0.501F) - iRadius;
427          xmax = xmin + iSize - 1;
428          ymin = (GLint) (y + 0.501F) - iRadius;
429          ymax = ymin + iSize - 1;
430       }
431 
432       /* generate fragments */
433       span.end = 0;
434       for (iy = ymin; iy <= ymax; iy++) {
435          for (ix = xmin; ix <= xmax; ix++) {
436             span.array->x[span.end] = ix;
437             span.array->y[span.end] = iy;
438             span.end++;
439          }
440       }
441       assert(span.end <= SWRAST_MAX_WIDTH);
442       _swrast_write_rgba_span(ctx, &span);
443    }
444 }
445 
446 
447 /**
448  * Draw size=1, single-pixel point
449  */
450 static void
pixel_point(struct gl_context * ctx,const SWvertex * vert)451 pixel_point(struct gl_context *ctx, const SWvertex *vert)
452 {
453    SWcontext *swrast = SWRAST_CONTEXT(ctx);
454    /*
455     * Note that unlike the other functions, we put single-pixel points
456     * into a special span array in order to render as many points as
457     * possible with a single _swrast_write_rgba_span() call.
458     */
459    SWspan *span = &(swrast->PointSpan);
460    GLuint count;
461 
462    CULL_INVALID(vert);
463 
464    /* Span init */
465    span->interpMask = 0;
466    span->arrayMask = SPAN_XY | SPAN_Z;
467    span->arrayMask |= SPAN_RGBA;
468    /*span->arrayMask |= SPAN_LAMBDA;*/
469    span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
470 
471    /* need these for fragment programs */
472    span->attrStart[VARYING_SLOT_POS][3] = 1.0F;
473    span->attrStepX[VARYING_SLOT_POS][3] = 0.0F;
474    span->attrStepY[VARYING_SLOT_POS][3] = 0.0F;
475 
476    /* check if we need to flush */
477    if (span->end >= SWRAST_MAX_WIDTH ||
478        (swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
479        span->facing != swrast->PointLineFacing) {
480       if (span->end > 0) {
481 	 _swrast_write_rgba_span(ctx, span);
482          span->end = 0;
483       }
484    }
485 
486    count = span->end;
487 
488    span->facing = swrast->PointLineFacing;
489 
490    /* fragment attributes */
491    span->array->rgba[count][RCOMP] = vert->color[0];
492    span->array->rgba[count][GCOMP] = vert->color[1];
493    span->array->rgba[count][BCOMP] = vert->color[2];
494    span->array->rgba[count][ACOMP] = vert->color[3];
495 
496    ATTRIB_LOOP_BEGIN
497       COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
498    ATTRIB_LOOP_END
499 
500    /* fragment position */
501    span->array->x[count] = (GLint) vert->attrib[VARYING_SLOT_POS][0];
502    span->array->y[count] = (GLint) vert->attrib[VARYING_SLOT_POS][1];
503    span->array->z[count] = (GLint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
504 
505    span->end = count + 1;
506    assert(span->end <= SWRAST_MAX_WIDTH);
507 }
508 
509 
510 /**
511  * Add specular color to primary color, draw point, restore original
512  * primary color.
513  */
514 void
_swrast_add_spec_terms_point(struct gl_context * ctx,const SWvertex * v0)515 _swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0)
516 {
517    SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
518    GLfloat rSum, gSum, bSum;
519    GLchan cSave[4];
520 
521    /* save */
522    COPY_CHAN4(cSave, ncv0->color);
523    /* sum */
524    rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
525    gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
526    bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
527    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
528    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
529    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
530    /* draw */
531    SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
532    /* restore */
533    COPY_CHAN4(ncv0->color, cSave);
534 }
535 
536 
537 /**
538  * Examine current state to determine which point drawing function to use.
539  */
540 void
_swrast_choose_point(struct gl_context * ctx)541 _swrast_choose_point(struct gl_context *ctx)
542 {
543    SWcontext *swrast = SWRAST_CONTEXT(ctx);
544    const GLfloat size = CLAMP(ctx->Point.Size,
545                               ctx->Point.MinSize,
546                               ctx->Point.MaxSize);
547 
548    if (ctx->RenderMode == GL_RENDER) {
549       if (ctx->Point.PointSprite) {
550          swrast->Point = sprite_point;
551       }
552       else if (ctx->Point.SmoothFlag) {
553          swrast->Point = smooth_point;
554       }
555       else if (size > 1.0F ||
556                ctx->Point._Attenuated ||
557                ctx->VertexProgram.PointSizeEnabled) {
558          swrast->Point = large_point;
559       }
560       else {
561          swrast->Point = pixel_point;
562       }
563    }
564    else if (ctx->RenderMode == GL_FEEDBACK) {
565       swrast->Point = _swrast_feedback_point;
566    }
567    else {
568       /* GL_SELECT mode */
569       swrast->Point = _swrast_select_point;
570    }
571 }
572