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