Home | History | Annotate | Download | only in swrast
      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 <= SWRAST_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 >= SWRAST_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 <= SWRAST_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 }
    573