OSDN Git Service

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