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 #include "c99_math.h"
     27 #include "main/glheader.h"
     28 #include "main/imports.h"
     29 #include "main/macros.h"
     30 #include "main/mtypes.h"
     31 #include "main/teximage.h"
     32 #include "swrast/s_aaline.h"
     33 #include "swrast/s_context.h"
     34 #include "swrast/s_span.h"
     35 #include "swrast/swrast.h"
     36 
     37 
     38 #define SUB_PIXEL 4
     39 
     40 
     41 /*
     42  * Info about the AA line we're rendering
     43  */
     44 struct LineInfo
     45 {
     46    GLfloat x0, y0;        /* start */
     47    GLfloat x1, y1;        /* end */
     48    GLfloat dx, dy;        /* direction vector */
     49    GLfloat len;           /* length */
     50    GLfloat halfWidth;     /* half of line width */
     51    GLfloat xAdj, yAdj;    /* X and Y adjustment for quad corners around line */
     52    /* for coverage computation */
     53    GLfloat qx0, qy0;      /* quad vertices */
     54    GLfloat qx1, qy1;
     55    GLfloat qx2, qy2;
     56    GLfloat qx3, qy3;
     57    GLfloat ex0, ey0;      /* quad edge vectors */
     58    GLfloat ex1, ey1;
     59    GLfloat ex2, ey2;
     60    GLfloat ex3, ey3;
     61 
     62    /* DO_Z */
     63    GLfloat zPlane[4];
     64    /* DO_RGBA - always enabled */
     65    GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
     66    /* DO_ATTRIBS */
     67    GLfloat wPlane[4];
     68    GLfloat attrPlane[VARYING_SLOT_MAX][4][4];
     69    GLfloat lambda[VARYING_SLOT_MAX];
     70    GLfloat texWidth[VARYING_SLOT_MAX];
     71    GLfloat texHeight[VARYING_SLOT_MAX];
     72 
     73    SWspan span;
     74 };
     75 
     76 
     77 
     78 /*
     79  * Compute the equation of a plane used to interpolate line fragment data
     80  * such as color, Z, texture coords, etc.
     81  * Input: (x0, y0) and (x1,y1) are the endpoints of the line.
     82  *        z0, and z1 are the end point values to interpolate.
     83  * Output:  plane - the plane equation.
     84  *
     85  * Note: we don't really have enough parameters to specify a plane.
     86  * We take the endpoints of the line and compute a plane such that
     87  * the cross product of the line vector and the plane normal is
     88  * parallel to the projection plane.
     89  */
     90 static void
     91 compute_plane(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
     92               GLfloat z0, GLfloat z1, GLfloat plane[4])
     93 {
     94 #if 0
     95    /* original */
     96    const GLfloat px = x1 - x0;
     97    const GLfloat py = y1 - y0;
     98    const GLfloat pz = z1 - z0;
     99    const GLfloat qx = -py;
    100    const GLfloat qy = px;
    101    const GLfloat qz = 0;
    102    const GLfloat a = py * qz - pz * qy;
    103    const GLfloat b = pz * qx - px * qz;
    104    const GLfloat c = px * qy - py * qx;
    105    const GLfloat d = -(a * x0 + b * y0 + c * z0);
    106    plane[0] = a;
    107    plane[1] = b;
    108    plane[2] = c;
    109    plane[3] = d;
    110 #else
    111    /* simplified */
    112    const GLfloat px = x1 - x0;
    113    const GLfloat py = y1 - y0;
    114    const GLfloat pz = z0 - z1;
    115    const GLfloat a = pz * px;
    116    const GLfloat b = pz * py;
    117    const GLfloat c = px * px + py * py;
    118    const GLfloat d = -(a * x0 + b * y0 + c * z0);
    119    if (a == 0.0F && b == 0.0F && c == 0.0F && d == 0.0F) {
    120       plane[0] = 0.0F;
    121       plane[1] = 0.0F;
    122       plane[2] = 1.0F;
    123       plane[3] = 0.0F;
    124    }
    125    else {
    126       plane[0] = a;
    127       plane[1] = b;
    128       plane[2] = c;
    129       plane[3] = d;
    130    }
    131 #endif
    132 }
    133 
    134 
    135 static inline void
    136 constant_plane(GLfloat value, GLfloat plane[4])
    137 {
    138    plane[0] = 0.0F;
    139    plane[1] = 0.0F;
    140    plane[2] = -1.0F;
    141    plane[3] = value;
    142 }
    143 
    144 
    145 static inline GLfloat
    146 solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
    147 {
    148    const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
    149    return z;
    150 }
    151 
    152 #define SOLVE_PLANE(X, Y, PLANE) \
    153    ((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
    154 
    155 
    156 /*
    157  * Return 1 / solve_plane().
    158  */
    159 static inline GLfloat
    160 solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4])
    161 {
    162    const GLfloat denom = plane[3] + plane[0] * x + plane[1] * y;
    163    if (denom == 0.0F)
    164       return 0.0F;
    165    else
    166       return -plane[2] / denom;
    167 }
    168 
    169 
    170 /*
    171  * Solve plane and return clamped GLchan value.
    172  */
    173 static inline GLchan
    174 solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
    175 {
    176    const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
    177 #if CHAN_TYPE == GL_FLOAT
    178    return CLAMP(z, 0.0F, CHAN_MAXF);
    179 #else
    180    if (z < 0)
    181       return 0;
    182    else if (z > CHAN_MAX)
    183       return CHAN_MAX;
    184    return (GLchan) IROUND_POS(z);
    185 #endif
    186 }
    187 
    188 
    189 /*
    190  * Compute mipmap level of detail.
    191  */
    192 static inline GLfloat
    193 compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4],
    194                GLfloat invQ, GLfloat width, GLfloat height)
    195 {
    196    GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width;
    197    GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width;
    198    GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height;
    199    GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height;
    200    GLfloat r1 = dudx * dudx + dudy * dudy;
    201    GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
    202    GLfloat rho2 = r1 + r2;
    203    /* return log base 2 of rho */
    204    if (rho2 == 0.0F)
    205       return 0.0;
    206    else
    207       return logf(rho2) * 1.442695f * 0.5f;/* 1.442695 = 1/log(2) */
    208 }
    209 
    210 
    211 
    212 
    213 /*
    214  * Fill in the samples[] array with the (x,y) subpixel positions of
    215  * xSamples * ySamples sample positions.
    216  * Note that the four corner samples are put into the first four
    217  * positions of the array.  This allows us to optimize for the common
    218  * case of all samples being inside the polygon.
    219  */
    220 static void
    221 make_sample_table(GLint xSamples, GLint ySamples, GLfloat samples[][2])
    222 {
    223    const GLfloat dx = 1.0F / (GLfloat) xSamples;
    224    const GLfloat dy = 1.0F / (GLfloat) ySamples;
    225    GLint x, y;
    226    GLint i;
    227 
    228    i = 4;
    229    for (x = 0; x < xSamples; x++) {
    230       for (y = 0; y < ySamples; y++) {
    231          GLint j;
    232          if (x == 0 && y == 0) {
    233             /* lower left */
    234             j = 0;
    235          }
    236          else if (x == xSamples - 1 && y == 0) {
    237             /* lower right */
    238             j = 1;
    239          }
    240          else if (x == 0 && y == ySamples - 1) {
    241             /* upper left */
    242             j = 2;
    243          }
    244          else if (x == xSamples - 1 && y == ySamples - 1) {
    245             /* upper right */
    246             j = 3;
    247          }
    248          else {
    249             j = i++;
    250          }
    251          samples[j][0] = x * dx + 0.5F * dx;
    252          samples[j][1] = y * dy + 0.5F * dy;
    253       }
    254    }
    255 }
    256 
    257 
    258 
    259 /*
    260  * Compute how much of the given pixel's area is inside the rectangle
    261  * defined by vertices v0, v1, v2, v3.
    262  * Vertices MUST be specified in counter-clockwise order.
    263  * Return:  coverage in [0, 1].
    264  */
    265 static GLfloat
    266 compute_coveragef(const struct LineInfo *info,
    267                   GLint winx, GLint winy)
    268 {
    269    static GLfloat samples[SUB_PIXEL * SUB_PIXEL][2];
    270    static GLboolean haveSamples = GL_FALSE;
    271    const GLfloat x = (GLfloat) winx;
    272    const GLfloat y = (GLfloat) winy;
    273    GLint stop = 4, i;
    274    GLfloat insideCount = SUB_PIXEL * SUB_PIXEL;
    275 
    276    if (!haveSamples) {
    277       make_sample_table(SUB_PIXEL, SUB_PIXEL, samples);
    278       haveSamples = GL_TRUE;
    279    }
    280 
    281 #if 0 /*DEBUG*/
    282    {
    283       const GLfloat area = dx0 * dy1 - dx1 * dy0;
    284       assert(area >= 0.0);
    285    }
    286 #endif
    287 
    288    for (i = 0; i < stop; i++) {
    289       const GLfloat sx = x + samples[i][0];
    290       const GLfloat sy = y + samples[i][1];
    291       const GLfloat fx0 = sx - info->qx0;
    292       const GLfloat fy0 = sy - info->qy0;
    293       const GLfloat fx1 = sx - info->qx1;
    294       const GLfloat fy1 = sy - info->qy1;
    295       const GLfloat fx2 = sx - info->qx2;
    296       const GLfloat fy2 = sy - info->qy2;
    297       const GLfloat fx3 = sx - info->qx3;
    298       const GLfloat fy3 = sy - info->qy3;
    299       /* cross product determines if sample is inside or outside each edge */
    300       GLfloat cross0 = (info->ex0 * fy0 - info->ey0 * fx0);
    301       GLfloat cross1 = (info->ex1 * fy1 - info->ey1 * fx1);
    302       GLfloat cross2 = (info->ex2 * fy2 - info->ey2 * fx2);
    303       GLfloat cross3 = (info->ex3 * fy3 - info->ey3 * fx3);
    304       /* Check if the sample is exactly on an edge.  If so, let cross be a
    305        * positive or negative value depending on the direction of the edge.
    306        */
    307       if (cross0 == 0.0F)
    308          cross0 = info->ex0 + info->ey0;
    309       if (cross1 == 0.0F)
    310          cross1 = info->ex1 + info->ey1;
    311       if (cross2 == 0.0F)
    312          cross2 = info->ex2 + info->ey2;
    313       if (cross3 == 0.0F)
    314          cross3 = info->ex3 + info->ey3;
    315       if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F || cross3 < 0.0F) {
    316          /* point is outside quadrilateral */
    317          insideCount -= 1.0F;
    318          stop = SUB_PIXEL * SUB_PIXEL;
    319       }
    320    }
    321    if (stop == 4)
    322       return 1.0F;
    323    else
    324       return insideCount * (1.0F / (SUB_PIXEL * SUB_PIXEL));
    325 }
    326 
    327 
    328 typedef void (*plot_func)(struct gl_context *ctx, struct LineInfo *line,
    329                           int ix, int iy);
    330 
    331 
    332 
    333 /*
    334  * Draw an AA line segment (called many times per line when stippling)
    335  */
    336 static void
    337 segment(struct gl_context *ctx,
    338         struct LineInfo *line,
    339         plot_func plot,
    340         GLfloat t0, GLfloat t1)
    341 {
    342    const GLfloat absDx = (line->dx < 0.0F) ? -line->dx : line->dx;
    343    const GLfloat absDy = (line->dy < 0.0F) ? -line->dy : line->dy;
    344    /* compute the actual segment's endpoints */
    345    const GLfloat x0 = line->x0 + t0 * line->dx;
    346    const GLfloat y0 = line->y0 + t0 * line->dy;
    347    const GLfloat x1 = line->x0 + t1 * line->dx;
    348    const GLfloat y1 = line->y0 + t1 * line->dy;
    349 
    350    /* compute vertices of the line-aligned quadrilateral */
    351    line->qx0 = x0 - line->yAdj;
    352    line->qy0 = y0 + line->xAdj;
    353    line->qx1 = x0 + line->yAdj;
    354    line->qy1 = y0 - line->xAdj;
    355    line->qx2 = x1 + line->yAdj;
    356    line->qy2 = y1 - line->xAdj;
    357    line->qx3 = x1 - line->yAdj;
    358    line->qy3 = y1 + line->xAdj;
    359    /* compute the quad's edge vectors (for coverage calc) */
    360    line->ex0 = line->qx1 - line->qx0;
    361    line->ey0 = line->qy1 - line->qy0;
    362    line->ex1 = line->qx2 - line->qx1;
    363    line->ey1 = line->qy2 - line->qy1;
    364    line->ex2 = line->qx3 - line->qx2;
    365    line->ey2 = line->qy3 - line->qy2;
    366    line->ex3 = line->qx0 - line->qx3;
    367    line->ey3 = line->qy0 - line->qy3;
    368 
    369    if (absDx > absDy) {
    370       /* X-major line */
    371       GLfloat dydx = line->dy / line->dx;
    372       GLfloat xLeft, xRight, yBot, yTop;
    373       GLint ix, ixRight;
    374       if (x0 < x1) {
    375          xLeft = x0 - line->halfWidth;
    376          xRight = x1 + line->halfWidth;
    377          if (line->dy >= 0.0F) {
    378             yBot = y0 - 3.0F * line->halfWidth;
    379             yTop = y0 + line->halfWidth;
    380          }
    381          else {
    382             yBot = y0 - line->halfWidth;
    383             yTop = y0 + 3.0F * line->halfWidth;
    384          }
    385       }
    386       else {
    387          xLeft = x1 - line->halfWidth;
    388          xRight = x0 + line->halfWidth;
    389          if (line->dy <= 0.0F) {
    390             yBot = y1 - 3.0F * line->halfWidth;
    391             yTop = y1 + line->halfWidth;
    392          }
    393          else {
    394             yBot = y1 - line->halfWidth;
    395             yTop = y1 + 3.0F * line->halfWidth;
    396          }
    397       }
    398 
    399       /* scan along the line, left-to-right */
    400       ixRight = (GLint) (xRight + 1.0F);
    401 
    402       /*printf("avg span height: %g\n", yTop - yBot);*/
    403       for (ix = (GLint) xLeft; ix < ixRight; ix++) {
    404          const GLint iyBot = (GLint) yBot;
    405          const GLint iyTop = (GLint) (yTop + 1.0F);
    406          GLint iy;
    407          /* scan across the line, bottom-to-top */
    408          for (iy = iyBot; iy < iyTop; iy++) {
    409             (*plot)(ctx, line, ix, iy);
    410          }
    411          yBot += dydx;
    412          yTop += dydx;
    413       }
    414    }
    415    else {
    416       /* Y-major line */
    417       GLfloat dxdy = line->dx / line->dy;
    418       GLfloat yBot, yTop, xLeft, xRight;
    419       GLint iy, iyTop;
    420       if (y0 < y1) {
    421          yBot = y0 - line->halfWidth;
    422          yTop = y1 + line->halfWidth;
    423          if (line->dx >= 0.0F) {
    424             xLeft = x0 - 3.0F * line->halfWidth;
    425             xRight = x0 + line->halfWidth;
    426          }
    427          else {
    428             xLeft = x0 - line->halfWidth;
    429             xRight = x0 + 3.0F * line->halfWidth;
    430          }
    431       }
    432       else {
    433          yBot = y1 - line->halfWidth;
    434          yTop = y0 + line->halfWidth;
    435          if (line->dx <= 0.0F) {
    436             xLeft = x1 - 3.0F * line->halfWidth;
    437             xRight = x1 + line->halfWidth;
    438          }
    439          else {
    440             xLeft = x1 - line->halfWidth;
    441             xRight = x1 + 3.0F * line->halfWidth;
    442          }
    443       }
    444 
    445       /* scan along the line, bottom-to-top */
    446       iyTop = (GLint) (yTop + 1.0F);
    447 
    448       /*printf("avg span width: %g\n", xRight - xLeft);*/
    449       for (iy = (GLint) yBot; iy < iyTop; iy++) {
    450          const GLint ixLeft = (GLint) xLeft;
    451          const GLint ixRight = (GLint) (xRight + 1.0F);
    452          GLint ix;
    453          /* scan across the line, left-to-right */
    454          for (ix = ixLeft; ix < ixRight; ix++) {
    455             (*plot)(ctx, line, ix, iy);
    456          }
    457          xLeft += dxdy;
    458          xRight += dxdy;
    459       }
    460    }
    461 }
    462 
    463 
    464 #define NAME(x) aa_rgba_##x
    465 #define DO_Z
    466 #include "s_aalinetemp.h"
    467 
    468 
    469 #define NAME(x)  aa_general_rgba_##x
    470 #define DO_Z
    471 #define DO_ATTRIBS
    472 #include "s_aalinetemp.h"
    473 
    474 
    475 
    476 void
    477 _swrast_choose_aa_line_function(struct gl_context *ctx)
    478 {
    479    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    480 
    481    assert(ctx->Line.SmoothFlag);
    482 
    483    if (ctx->Texture._EnabledCoordUnits != 0
    484        || _swrast_use_fragment_program(ctx)
    485        || (ctx->Light.Enabled &&
    486            ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
    487        || ctx->Fog.ColorSumEnabled
    488        || swrast->_FogEnabled) {
    489       swrast->Line = aa_general_rgba_line;
    490    }
    491    else {
    492       swrast->Line = aa_rgba_line;
    493    }
    494 }
    495