Home | History | Annotate | Download | only in swrast
      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 
     26 /*
     27  * Antialiased Triangle Rasterizer Template
     28  *
     29  * This file is #include'd to generate custom AA triangle rasterizers.
     30  * NOTE: this code hasn't been optimized yet.  That'll come after it
     31  * works correctly.
     32  *
     33  * The following macros may be defined to indicate what auxillary information
     34  * must be copmuted across the triangle:
     35  *    DO_Z         - if defined, compute Z values
     36  *    DO_ATTRIBS   - if defined, compute texcoords, varying, etc.
     37  */
     38 
     39 /*void triangle( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
     40 {
     41    const SWcontext *swrast = SWRAST_CONTEXT(ctx);
     42    const GLfloat *p0 = v0->attrib[VARYING_SLOT_POS];
     43    const GLfloat *p1 = v1->attrib[VARYING_SLOT_POS];
     44    const GLfloat *p2 = v2->attrib[VARYING_SLOT_POS];
     45    const SWvertex *vMin, *vMid, *vMax;
     46    GLint iyMin, iyMax;
     47    GLfloat yMin, yMax;
     48    GLboolean ltor;
     49    GLfloat majDx, majDy;  /* major (i.e. long) edge dx and dy */
     50 
     51    SWspan span;
     52 
     53 #ifdef DO_Z
     54    GLfloat zPlane[4];
     55 #endif
     56    GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
     57 #if defined(DO_ATTRIBS)
     58    GLfloat attrPlane[VARYING_SLOT_MAX][4][4];
     59    GLfloat wPlane[4];  /* win[3] */
     60 #endif
     61    GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceCullSign;
     62 
     63    (void) swrast;
     64 
     65    INIT_SPAN(span, GL_POLYGON);
     66    span.arrayMask = SPAN_COVERAGE;
     67 
     68    /* determine bottom to top order of vertices */
     69    {
     70       GLfloat y0 = v0->attrib[VARYING_SLOT_POS][1];
     71       GLfloat y1 = v1->attrib[VARYING_SLOT_POS][1];
     72       GLfloat y2 = v2->attrib[VARYING_SLOT_POS][1];
     73       if (y0 <= y1) {
     74 	 if (y1 <= y2) {
     75 	    vMin = v0;   vMid = v1;   vMax = v2;   /* y0<=y1<=y2 */
     76 	 }
     77 	 else if (y2 <= y0) {
     78 	    vMin = v2;   vMid = v0;   vMax = v1;   /* y2<=y0<=y1 */
     79 	 }
     80 	 else {
     81 	    vMin = v0;   vMid = v2;   vMax = v1;  bf = -bf; /* y0<=y2<=y1 */
     82 	 }
     83       }
     84       else {
     85 	 if (y0 <= y2) {
     86 	    vMin = v1;   vMid = v0;   vMax = v2;  bf = -bf; /* y1<=y0<=y2 */
     87 	 }
     88 	 else if (y2 <= y1) {
     89 	    vMin = v2;   vMid = v1;   vMax = v0;  bf = -bf; /* y2<=y1<=y0 */
     90 	 }
     91 	 else {
     92 	    vMin = v1;   vMid = v2;   vMax = v0;   /* y1<=y2<=y0 */
     93 	 }
     94       }
     95    }
     96 
     97    majDx = vMax->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
     98    majDy = vMax->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
     99 
    100    /* front/back-face determination and cullling */
    101    {
    102       const GLfloat botDx = vMid->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
    103       const GLfloat botDy = vMid->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
    104       const GLfloat area = majDx * botDy - botDx * majDy;
    105       /* Do backface culling */
    106       if (area * bf < 0 || area == 0 || IS_INF_OR_NAN(area))
    107 	 return;
    108       ltor = (GLboolean) (area < 0.0F);
    109 
    110       span.facing = area * swrast->_BackfaceSign > 0.0F;
    111    }
    112 
    113    /* Plane equation setup:
    114     * We evaluate plane equations at window (x,y) coordinates in order
    115     * to compute color, Z, fog, texcoords, etc.  This isn't terribly
    116     * efficient but it's easy and reliable.
    117     */
    118 #ifdef DO_Z
    119    compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
    120    span.arrayMask |= SPAN_Z;
    121 #endif
    122    if (ctx->Light.ShadeModel == GL_SMOOTH) {
    123       compute_plane(p0, p1, p2, v0->color[RCOMP], v1->color[RCOMP], v2->color[RCOMP], rPlane);
    124       compute_plane(p0, p1, p2, v0->color[GCOMP], v1->color[GCOMP], v2->color[GCOMP], gPlane);
    125       compute_plane(p0, p1, p2, v0->color[BCOMP], v1->color[BCOMP], v2->color[BCOMP], bPlane);
    126       compute_plane(p0, p1, p2, v0->color[ACOMP], v1->color[ACOMP], v2->color[ACOMP], aPlane);
    127    }
    128    else {
    129       constant_plane(v2->color[RCOMP], rPlane);
    130       constant_plane(v2->color[GCOMP], gPlane);
    131       constant_plane(v2->color[BCOMP], bPlane);
    132       constant_plane(v2->color[ACOMP], aPlane);
    133    }
    134    span.arrayMask |= SPAN_RGBA;
    135 #if defined(DO_ATTRIBS)
    136    {
    137       const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3];
    138       const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3];
    139       const GLfloat invW2 = v2->attrib[VARYING_SLOT_POS][3];
    140       compute_plane(p0, p1, p2, invW0, invW1, invW2, wPlane);
    141       span.attrStepX[VARYING_SLOT_POS][3] = plane_dx(wPlane);
    142       span.attrStepY[VARYING_SLOT_POS][3] = plane_dy(wPlane);
    143       ATTRIB_LOOP_BEGIN
    144          GLuint c;
    145          if (swrast->_InterpMode[attr] == GL_FLAT) {
    146             for (c = 0; c < 4; c++) {
    147                constant_plane(v2->attrib[attr][c] * invW2, attrPlane[attr][c]);
    148             }
    149          }
    150          else {
    151             for (c = 0; c < 4; c++) {
    152                const GLfloat a0 = v0->attrib[attr][c] * invW0;
    153                const GLfloat a1 = v1->attrib[attr][c] * invW1;
    154                const GLfloat a2 = v2->attrib[attr][c] * invW2;
    155                compute_plane(p0, p1, p2, a0, a1, a2, attrPlane[attr][c]);
    156             }
    157          }
    158          for (c = 0; c < 4; c++) {
    159             span.attrStepX[attr][c] = plane_dx(attrPlane[attr][c]);
    160             span.attrStepY[attr][c] = plane_dy(attrPlane[attr][c]);
    161          }
    162       ATTRIB_LOOP_END
    163    }
    164 #endif
    165 
    166    /* Begin bottom-to-top scan over the triangle.
    167     * The long edge will either be on the left or right side of the
    168     * triangle.  We always scan from the long edge toward the shorter
    169     * edges, stopping when we find that coverage = 0.  If the long edge
    170     * is on the left we scan left-to-right.  Else, we scan right-to-left.
    171     */
    172    yMin = vMin->attrib[VARYING_SLOT_POS][1];
    173    yMax = vMax->attrib[VARYING_SLOT_POS][1];
    174    iyMin = (GLint) yMin;
    175    iyMax = (GLint) yMax + 1;
    176 
    177    if (ltor) {
    178       /* scan left to right */
    179       const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
    180       const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
    181       const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
    182       const GLfloat dxdy = majDx / majDy;
    183       const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
    184       GLint iy;
    185 #ifdef _OPENMP
    186 #pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
    187 #endif
    188       for (iy = iyMin; iy < iyMax; iy++) {
    189          GLfloat x = pMin[0] - (yMin - iy) * dxdy;
    190          GLint ix, startX = (GLint) (x - xAdj);
    191          GLuint count;
    192          GLfloat coverage = 0.0F;
    193 
    194 #ifdef _OPENMP
    195          /* each thread needs to use a different (global) SpanArrays variable */
    196          span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
    197 #endif
    198          /* skip over fragments with zero coverage */
    199          while (startX < SWRAST_MAX_WIDTH) {
    200             coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
    201             if (coverage > 0.0F)
    202                break;
    203             startX++;
    204          }
    205 
    206          /* enter interior of triangle */
    207          ix = startX;
    208 
    209 #if defined(DO_ATTRIBS)
    210          /* compute attributes at left-most fragment */
    211          span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 0.5F, iy + 0.5F, wPlane);
    212          ATTRIB_LOOP_BEGIN
    213             GLuint c;
    214             for (c = 0; c < 4; c++) {
    215                span.attrStart[attr][c] = solve_plane(ix + 0.5F, iy + 0.5F, attrPlane[attr][c]);
    216             }
    217          ATTRIB_LOOP_END
    218 #endif
    219 
    220          count = 0;
    221          while (coverage > 0.0F) {
    222             /* (cx,cy) = center of fragment */
    223             const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
    224             SWspanarrays *array = span.array;
    225             array->coverage[count] = coverage;
    226 #ifdef DO_Z
    227             array->z[count] = (GLuint) solve_plane(cx, cy, zPlane);
    228 #endif
    229             array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane);
    230             array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane);
    231             array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane);
    232             array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane);
    233             ix++;
    234             count++;
    235             coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
    236          }
    237 
    238          if (ix > startX) {
    239             span.x = startX;
    240             span.y = iy;
    241             span.end = (GLuint) ix - (GLuint) startX;
    242             _swrast_write_rgba_span(ctx, &span);
    243          }
    244       }
    245    }
    246    else {
    247       /* scan right to left */
    248       const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
    249       const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
    250       const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
    251       const GLfloat dxdy = majDx / majDy;
    252       const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
    253       GLint iy;
    254 #ifdef _OPENMP
    255 #pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
    256 #endif
    257       for (iy = iyMin; iy < iyMax; iy++) {
    258          GLfloat x = pMin[0] - (yMin - iy) * dxdy;
    259          GLint ix, left, startX = (GLint) (x + xAdj);
    260          GLuint count, n;
    261          GLfloat coverage = 0.0F;
    262 
    263 #ifdef _OPENMP
    264          /* each thread needs to use a different (global) SpanArrays variable */
    265          span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
    266 #endif
    267          /* make sure we're not past the window edge */
    268          if (startX >= ctx->DrawBuffer->_Xmax) {
    269             startX = ctx->DrawBuffer->_Xmax - 1;
    270          }
    271 
    272          /* skip fragments with zero coverage */
    273          while (startX > 0) {
    274             coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
    275             if (coverage > 0.0F)
    276                break;
    277             startX--;
    278          }
    279 
    280          /* enter interior of triangle */
    281          ix = startX;
    282          count = 0;
    283          while (coverage > 0.0F) {
    284             /* (cx,cy) = center of fragment */
    285             const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
    286             SWspanarrays *array = span.array;
    287             assert(ix >= 0);
    288             array->coverage[ix] = coverage;
    289 #ifdef DO_Z
    290             array->z[ix] = (GLuint) solve_plane(cx, cy, zPlane);
    291 #endif
    292             array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane);
    293             array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane);
    294             array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane);
    295             array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane);
    296             ix--;
    297             count++;
    298             coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
    299          }
    300 
    301 #if defined(DO_ATTRIBS)
    302          /* compute attributes at left-most fragment */
    303          span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 1.5F, iy + 0.5F, wPlane);
    304          ATTRIB_LOOP_BEGIN
    305             GLuint c;
    306             for (c = 0; c < 4; c++) {
    307                span.attrStart[attr][c] = solve_plane(ix + 1.5F, iy + 0.5F, attrPlane[attr][c]);
    308             }
    309          ATTRIB_LOOP_END
    310 #endif
    311 
    312          if (startX > ix) {
    313             n = (GLuint) startX - (GLuint) ix;
    314 
    315             left = ix + 1;
    316 
    317             /* shift all values to the left */
    318             /* XXX this is temporary */
    319             {
    320                SWspanarrays *array = span.array;
    321                GLint j;
    322                for (j = 0; j < (GLint) n; j++) {
    323                   array->coverage[j] = array->coverage[j + left];
    324                   COPY_CHAN4(array->rgba[j], array->rgba[j + left]);
    325 #ifdef DO_Z
    326                   array->z[j] = array->z[j + left];
    327 #endif
    328                }
    329             }
    330 
    331             span.x = left;
    332             span.y = iy;
    333             span.end = n;
    334             _swrast_write_rgba_span(ctx, &span);
    335          }
    336       }
    337    }
    338 }
    339 
    340 
    341 #undef DO_Z
    342 #undef DO_ATTRIBS
    343 #undef DO_OCCLUSION_TEST
    344