Tizen 2.0 Release
[profile/ivi/osmesa.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  * 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  */
54 static INLINE GLfloat
55 get_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  */
82 static void
83 sprite_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  */
242 static void
243 smooth_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  */
362 static void
363 large_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 <= MAX_WIDTH);
443       _swrast_write_rgba_span(ctx, &span);
444    }
445 }
446
447
448 /**
449  * Draw size=1, single-pixel point
450  */
451 static void
452 pixel_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 >= 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 <= MAX_WIDTH);
508 }
509
510
511 /**
512  * Add specular color to primary color, draw point, restore original
513  * primary color.
514  */
515 void
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  */
541 void
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 }