Home | History | Annotate | Download | only in swrast
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 1999-2008  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 #include "main/glheader.h"
     26 #include "main/macros.h"
     27 #include "main/imports.h"
     28 #include "main/format_pack.h"
     29 
     30 #include "s_context.h"
     31 #include "s_span.h"
     32 #include "s_stencil.h"
     33 #include "s_zoom.h"
     34 
     35 
     36 /**
     37  * Compute the bounds of the region resulting from zooming a pixel span.
     38  * The resulting region will be entirely inside the window/scissor bounds
     39  * so no additional clipping is needed.
     40  * \param imageX, imageY  position of the mage being drawn (gl WindowPos)
     41  * \param spanX, spanY  position of span being drawing
     42  * \param width  number of pixels in span
     43  * \param x0, x1  returned X bounds of zoomed region [x0, x1)
     44  * \param y0, y1  returned Y bounds of zoomed region [y0, y1)
     45  * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
     46  */
     47 static GLboolean
     48 compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
     49                       GLint spanX, GLint spanY, GLint width,
     50                       GLint *x0, GLint *x1, GLint *y0, GLint *y1)
     51 {
     52    const struct gl_framebuffer *fb = ctx->DrawBuffer;
     53    GLint c0, c1, r0, r1;
     54 
     55    assert(spanX >= imageX);
     56    assert(spanY >= imageY);
     57 
     58    /*
     59     * Compute destination columns: [c0, c1)
     60     */
     61    c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
     62    c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
     63    if (c1 < c0) {
     64       /* swap */
     65       GLint tmp = c1;
     66       c1 = c0;
     67       c0 = tmp;
     68    }
     69    c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
     70    c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
     71    if (c0 == c1) {
     72       return GL_FALSE; /* no width */
     73    }
     74 
     75    /*
     76     * Compute destination rows: [r0, r1)
     77     */
     78    r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
     79    r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
     80    if (r1 < r0) {
     81       /* swap */
     82       GLint tmp = r1;
     83       r1 = r0;
     84       r0 = tmp;
     85    }
     86    r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
     87    r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
     88    if (r0 == r1) {
     89       return GL_FALSE; /* no height */
     90    }
     91 
     92    *x0 = c0;
     93    *x1 = c1;
     94    *y0 = r0;
     95    *y1 = r1;
     96 
     97    return GL_TRUE;
     98 }
     99 
    100 
    101 /**
    102  * Convert a zoomed x image coordinate back to an unzoomed x coord.
    103  * 'zx' is screen position of a pixel in the zoomed image, who's left edge
    104  * is at 'imageX'.
    105  * return corresponding x coord in the original, unzoomed image.
    106  * This can use this for unzooming X or Y values.
    107  */
    108 static inline GLint
    109 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
    110 {
    111    /*
    112    zx = imageX + (x - imageX) * zoomX;
    113    zx - imageX = (x - imageX) * zoomX;
    114    (zx - imageX) / zoomX = x - imageX;
    115    */
    116    GLint x;
    117    if (zoomX < 0.0F)
    118       zx++;
    119    x = imageX + (GLint) ((zx - imageX) / zoomX);
    120    return x;
    121 }
    122 
    123 
    124 
    125 /**
    126  * Helper function called from _swrast_write_zoomed_rgba/rgb/
    127  * index/depth_span().
    128  */
    129 static void
    130 zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
    131            const GLvoid *src, GLenum format )
    132 {
    133    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    134    SWspan zoomed;
    135    GLint x0, x1, y0, y1;
    136    GLint zoomedWidth;
    137 
    138    if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
    139                               &x0, &x1, &y0, &y1)) {
    140       return;  /* totally clipped */
    141    }
    142 
    143    if (!swrast->ZoomedArrays) {
    144       /* allocate on demand */
    145       swrast->ZoomedArrays = (SWspanarrays *) calloc(1, sizeof(SWspanarrays));
    146       if (!swrast->ZoomedArrays)
    147          return;
    148    }
    149 
    150    zoomedWidth = x1 - x0;
    151    assert(zoomedWidth > 0);
    152    assert(zoomedWidth <= SWRAST_MAX_WIDTH);
    153 
    154    /* no pixel arrays! must be horizontal spans. */
    155    assert((span->arrayMask & SPAN_XY) == 0);
    156    assert(span->primitive == GL_BITMAP);
    157 
    158    INIT_SPAN(zoomed, GL_BITMAP);
    159    zoomed.x = x0;
    160    zoomed.end = zoomedWidth;
    161    zoomed.array = swrast->ZoomedArrays;
    162    zoomed.array->ChanType = span->array->ChanType;
    163    if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
    164       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
    165    else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
    166       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
    167    else
    168       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[VARYING_SLOT_COL0];
    169 
    170    COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
    171    COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
    172    COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
    173 
    174    zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
    175    zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
    176    zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_FOGC][0];
    177 
    178    if (format == GL_RGBA || format == GL_RGB) {
    179       /* copy Z info */
    180       zoomed.z = span->z;
    181       zoomed.zStep = span->zStep;
    182       /* we'll generate an array of colorss */
    183       zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
    184       zoomed.arrayMask |= SPAN_RGBA;
    185       zoomed.arrayAttribs |= VARYING_BIT_COL0;  /* we'll produce these values */
    186       assert(span->arrayMask & SPAN_RGBA);
    187    }
    188    else if (format == GL_DEPTH_COMPONENT) {
    189       /* Copy color info */
    190       zoomed.red = span->red;
    191       zoomed.green = span->green;
    192       zoomed.blue = span->blue;
    193       zoomed.alpha = span->alpha;
    194       zoomed.redStep = span->redStep;
    195       zoomed.greenStep = span->greenStep;
    196       zoomed.blueStep = span->blueStep;
    197       zoomed.alphaStep = span->alphaStep;
    198       /* we'll generate an array of depth values */
    199       zoomed.interpMask = span->interpMask & ~SPAN_Z;
    200       zoomed.arrayMask |= SPAN_Z;
    201       assert(span->arrayMask & SPAN_Z);
    202    }
    203    else {
    204       _mesa_problem(ctx, "Bad format in zoom_span");
    205       return;
    206    }
    207 
    208    /* zoom the span horizontally */
    209    if (format == GL_RGBA) {
    210       if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
    211          const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
    212          GLint i;
    213          for (i = 0; i < zoomedWidth; i++) {
    214             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    215             assert(j >= 0);
    216             assert(j < (GLint) span->end);
    217             COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
    218          }
    219       }
    220       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
    221          const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
    222          GLint i;
    223          for (i = 0; i < zoomedWidth; i++) {
    224             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    225             assert(j >= 0);
    226             assert(j < (GLint) span->end);
    227             COPY_4V(zoomed.array->rgba16[i], rgba[j]);
    228          }
    229       }
    230       else {
    231          const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
    232          GLint i;
    233          for (i = 0; i < zoomedWidth; i++) {
    234             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    235             assert(j >= 0);
    236             assert(j < (GLint) span->end);
    237             COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]);
    238          }
    239       }
    240    }
    241    else if (format == GL_RGB) {
    242       if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
    243          const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
    244          GLint i;
    245          for (i = 0; i < zoomedWidth; i++) {
    246             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    247             assert(j >= 0);
    248             assert(j < (GLint) span->end);
    249             zoomed.array->rgba8[i][0] = rgb[j][0];
    250             zoomed.array->rgba8[i][1] = rgb[j][1];
    251             zoomed.array->rgba8[i][2] = rgb[j][2];
    252             zoomed.array->rgba8[i][3] = 0xff;
    253          }
    254       }
    255       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
    256          const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
    257          GLint i;
    258          for (i = 0; i < zoomedWidth; i++) {
    259             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    260             assert(j >= 0);
    261             assert(j < (GLint) span->end);
    262             zoomed.array->rgba16[i][0] = rgb[j][0];
    263             zoomed.array->rgba16[i][1] = rgb[j][1];
    264             zoomed.array->rgba16[i][2] = rgb[j][2];
    265             zoomed.array->rgba16[i][3] = 0xffff;
    266          }
    267       }
    268       else {
    269          const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
    270          GLint i;
    271          for (i = 0; i < zoomedWidth; i++) {
    272             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    273             assert(j >= 0);
    274             assert(j < (GLint) span->end);
    275             zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
    276             zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
    277             zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
    278             zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F;
    279          }
    280       }
    281    }
    282    else if (format == GL_DEPTH_COMPONENT) {
    283       const GLuint *zValues = (const GLuint *) src;
    284       GLint i;
    285       for (i = 0; i < zoomedWidth; i++) {
    286          GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
    287          assert(j >= 0);
    288          assert(j < (GLint) span->end);
    289          zoomed.array->z[i] = zValues[j];
    290       }
    291       /* Now, fall into the RGB path below */
    292       format = GL_RGBA;
    293    }
    294 
    295    /* write the span in rows [r0, r1) */
    296    if (format == GL_RGBA || format == GL_RGB) {
    297       /* Writing the span may modify the colors, so make a backup now if we're
    298        * going to call _swrast_write_zoomed_span() more than once.
    299        * Also, clipping may change the span end value, so store it as well.
    300        */
    301       const GLint end = zoomed.end; /* save */
    302       void *rgbaSave;
    303       const GLint pixelSize =
    304          (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
    305          ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
    306           : 4 * sizeof(GLfloat));
    307 
    308       rgbaSave = malloc(zoomed.end * pixelSize);
    309       if (!rgbaSave) {
    310          return;
    311       }
    312 
    313       if (y1 - y0 > 1) {
    314          memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
    315       }
    316       for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
    317          _swrast_write_rgba_span(ctx, &zoomed);
    318          zoomed.end = end;  /* restore */
    319          if (y1 - y0 > 1) {
    320             /* restore the colors */
    321             memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
    322          }
    323       }
    324 
    325       free(rgbaSave);
    326    }
    327 }
    328 
    329 
    330 void
    331 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
    332                                const SWspan *span, const GLvoid *rgba)
    333 {
    334    zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
    335 }
    336 
    337 
    338 void
    339 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
    340                               const SWspan *span, const GLvoid *rgb)
    341 {
    342    zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
    343 }
    344 
    345 
    346 void
    347 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
    348                                 const SWspan *span)
    349 {
    350    zoom_span(ctx, imgX, imgY, span,
    351              (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
    352 }
    353 
    354 
    355 /**
    356  * Zoom/write stencil values.
    357  * No per-fragment operations are applied.
    358  */
    359 void
    360 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
    361                                   GLint width, GLint spanX, GLint spanY,
    362                                   const GLubyte stencil[])
    363 {
    364    GLubyte *zoomedVals;
    365    GLint x0, x1, y0, y1, y;
    366    GLint i, zoomedWidth;
    367 
    368    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
    369                               &x0, &x1, &y0, &y1)) {
    370       return;  /* totally clipped */
    371    }
    372 
    373    zoomedWidth = x1 - x0;
    374    assert(zoomedWidth > 0);
    375    assert(zoomedWidth <= SWRAST_MAX_WIDTH);
    376 
    377    zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
    378    if (!zoomedVals)
    379       return;
    380 
    381    /* zoom the span horizontally */
    382    for (i = 0; i < zoomedWidth; i++) {
    383       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
    384       assert(j >= 0);
    385       assert(j < width);
    386       zoomedVals[i] = stencil[j];
    387    }
    388 
    389    /* write the zoomed spans */
    390    for (y = y0; y < y1; y++) {
    391       _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
    392    }
    393 
    394    free(zoomedVals);
    395 }
    396 
    397 
    398 /**
    399  * Zoom/write 32-bit Z values.
    400  * No per-fragment operations are applied.
    401  */
    402 void
    403 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
    404                             GLint width, GLint spanX, GLint spanY,
    405                             const GLuint *zVals)
    406 {
    407    struct gl_renderbuffer *rb =
    408       ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
    409    GLuint *zoomedVals;
    410    GLint x0, x1, y0, y1, y;
    411    GLint i, zoomedWidth;
    412 
    413    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
    414                               &x0, &x1, &y0, &y1)) {
    415       return;  /* totally clipped */
    416    }
    417 
    418    zoomedWidth = x1 - x0;
    419    assert(zoomedWidth > 0);
    420    assert(zoomedWidth <= SWRAST_MAX_WIDTH);
    421 
    422    zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
    423    if (!zoomedVals)
    424       return;
    425 
    426    /* zoom the span horizontally */
    427    for (i = 0; i < zoomedWidth; i++) {
    428       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
    429       assert(j >= 0);
    430       assert(j < width);
    431       zoomedVals[i] = zVals[j];
    432    }
    433 
    434    /* write the zoomed spans */
    435    for (y = y0; y < y1; y++) {
    436       GLubyte *dst = _swrast_pixel_address(rb, x0, y);
    437       _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
    438    }
    439 
    440    free(zoomedVals);
    441 }
    442