Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  * Copyright (C) 2009  VMware, Inc.  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.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26.  
  27. /**
  28.  * \file image.c
  29.  * Image handling.
  30.  */
  31.  
  32.  
  33. #include "glheader.h"
  34. #include "colormac.h"
  35. #include "glformats.h"
  36. #include "image.h"
  37. #include "imports.h"
  38. #include "macros.h"
  39. #include "mtypes.h"
  40.  
  41.  
  42.  
  43. /**
  44.  * Flip the order of the 2 bytes in each word in the given array.
  45.  *
  46.  * \param p array.
  47.  * \param n number of words.
  48.  */
  49. void
  50. _mesa_swap2( GLushort *p, GLuint n )
  51. {
  52.    GLuint i;
  53.    for (i = 0; i < n; i++) {
  54.       p[i] = (p[i] >> 8) | ((p[i] << 8) & 0xff00);
  55.    }
  56. }
  57.  
  58.  
  59.  
  60. /*
  61.  * Flip the order of the 4 bytes in each word in the given array.
  62.  */
  63. void
  64. _mesa_swap4( GLuint *p, GLuint n )
  65. {
  66.    GLuint i, a, b;
  67.    for (i = 0; i < n; i++) {
  68.       b = p[i];
  69.       a =  (b >> 24)
  70.         | ((b >> 8) & 0xff00)
  71.         | ((b << 8) & 0xff0000)
  72.         | ((b << 24) & 0xff000000);
  73.       p[i] = a;
  74.    }
  75. }
  76.  
  77.  
  78. /**
  79.  * Return the byte offset of a specific pixel in an image (1D, 2D or 3D).
  80.  *
  81.  * Pixel unpacking/packing parameters are observed according to \p packing.
  82.  *
  83.  * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
  84.  * \param packing  the pixelstore attributes
  85.  * \param width  the image width
  86.  * \param height  the image height
  87.  * \param format  the pixel format (must be validated beforehand)
  88.  * \param type  the pixel data type (must be validated beforehand)
  89.  * \param img  which image in the volume (0 for 1D or 2D images)
  90.  * \param row  row of pixel in the image (0 for 1D images)
  91.  * \param column column of pixel in the image
  92.  *
  93.  * \return offset of pixel.
  94.  *
  95.  * \sa gl_pixelstore_attrib.
  96.  */
  97. GLintptr
  98. _mesa_image_offset( GLuint dimensions,
  99.                     const struct gl_pixelstore_attrib *packing,
  100.                     GLsizei width, GLsizei height,
  101.                     GLenum format, GLenum type,
  102.                     GLint img, GLint row, GLint column )
  103. {
  104.    GLint alignment;        /* 1, 2 or 4 */
  105.    GLint pixels_per_row;
  106.    GLint rows_per_image;
  107.    GLint skiprows;
  108.    GLint skippixels;
  109.    GLint skipimages;       /* for 3-D volume images */
  110.    GLintptr offset;
  111.  
  112.    ASSERT(dimensions >= 1 && dimensions <= 3);
  113.  
  114.    alignment = packing->Alignment;
  115.    if (packing->RowLength > 0) {
  116.       pixels_per_row = packing->RowLength;
  117.    }
  118.    else {
  119.       pixels_per_row = width;
  120.    }
  121.    if (packing->ImageHeight > 0) {
  122.       rows_per_image = packing->ImageHeight;
  123.    }
  124.    else {
  125.       rows_per_image = height;
  126.    }
  127.  
  128.    skippixels = packing->SkipPixels;
  129.    /* Note: SKIP_ROWS _is_ used for 1D images */
  130.    skiprows = packing->SkipRows;
  131.    /* Note: SKIP_IMAGES is only used for 3D images */
  132.    skipimages = (dimensions == 3) ? packing->SkipImages : 0;
  133.  
  134.    if (type == GL_BITMAP) {
  135.       /* BITMAP data */
  136.       GLint bytes_per_row;
  137.       GLint bytes_per_image;
  138.       /* components per pixel for color or stencil index: */
  139.       const GLint comp_per_pixel = 1;
  140.  
  141.       /* The pixel type and format should have been error checked earlier */
  142.       assert(format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX);
  143.  
  144.       bytes_per_row = alignment
  145.                     * CEILING( comp_per_pixel*pixels_per_row, 8*alignment );
  146.  
  147.       bytes_per_image = bytes_per_row * rows_per_image;
  148.  
  149.       offset = (skipimages + img) * bytes_per_image
  150.                  + (skiprows + row) * bytes_per_row
  151.                  + (skippixels + column) / 8;
  152.    }
  153.    else {
  154.       /* Non-BITMAP data */
  155.       GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image;
  156.       GLint topOfImage;
  157.  
  158.       bytes_per_pixel = _mesa_bytes_per_pixel( format, type );
  159.  
  160.       /* The pixel type and format should have been error checked earlier */
  161.       assert(bytes_per_pixel > 0);
  162.  
  163.       bytes_per_row = pixels_per_row * bytes_per_pixel;
  164.       remainder = bytes_per_row % alignment;
  165.       if (remainder > 0)
  166.          bytes_per_row += (alignment - remainder);
  167.  
  168.       ASSERT(bytes_per_row % alignment == 0);
  169.  
  170.       bytes_per_image = bytes_per_row * rows_per_image;
  171.  
  172.       if (packing->Invert) {
  173.          /* set pixel_addr to the last row */
  174.          topOfImage = bytes_per_row * (height - 1);
  175.          bytes_per_row = -bytes_per_row;
  176.       }
  177.       else {
  178.          topOfImage = 0;
  179.       }
  180.  
  181.       /* compute final pixel address */
  182.       offset = (skipimages + img) * bytes_per_image
  183.                  + topOfImage
  184.                  + (skiprows + row) * bytes_per_row
  185.                  + (skippixels + column) * bytes_per_pixel;
  186.    }
  187.  
  188.    return offset;
  189. }
  190.  
  191.  
  192. /**
  193.  * Return the address of a specific pixel in an image (1D, 2D or 3D).
  194.  *
  195.  * Pixel unpacking/packing parameters are observed according to \p packing.
  196.  *
  197.  * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
  198.  * \param packing  the pixelstore attributes
  199.  * \param image  starting address of image data
  200.  * \param width  the image width
  201.  * \param height  the image height
  202.  * \param format  the pixel format (must be validated beforehand)
  203.  * \param type  the pixel data type (must be validated beforehand)
  204.  * \param img  which image in the volume (0 for 1D or 2D images)
  205.  * \param row  row of pixel in the image (0 for 1D images)
  206.  * \param column column of pixel in the image
  207.  *
  208.  * \return address of pixel.
  209.  *
  210.  * \sa gl_pixelstore_attrib.
  211.  */
  212. GLvoid *
  213. _mesa_image_address( GLuint dimensions,
  214.                      const struct gl_pixelstore_attrib *packing,
  215.                      const GLvoid *image,
  216.                      GLsizei width, GLsizei height,
  217.                      GLenum format, GLenum type,
  218.                      GLint img, GLint row, GLint column )
  219. {
  220.    const GLubyte *addr = (const GLubyte *) image;
  221.  
  222.    addr += _mesa_image_offset(dimensions, packing, width, height,
  223.                               format, type, img, row, column);
  224.  
  225.    return (GLvoid *) addr;
  226. }
  227.  
  228.  
  229. GLvoid *
  230. _mesa_image_address1d( const struct gl_pixelstore_attrib *packing,
  231.                        const GLvoid *image,
  232.                        GLsizei width,
  233.                        GLenum format, GLenum type,
  234.                        GLint column )
  235. {
  236.    return _mesa_image_address(1, packing, image, width, 1,
  237.                               format, type, 0, 0, column);
  238. }
  239.  
  240.  
  241. GLvoid *
  242. _mesa_image_address2d( const struct gl_pixelstore_attrib *packing,
  243.                        const GLvoid *image,
  244.                        GLsizei width, GLsizei height,
  245.                        GLenum format, GLenum type,
  246.                        GLint row, GLint column )
  247. {
  248.    return _mesa_image_address(2, packing, image, width, height,
  249.                               format, type, 0, row, column);
  250. }
  251.  
  252.  
  253. GLvoid *
  254. _mesa_image_address3d( const struct gl_pixelstore_attrib *packing,
  255.                        const GLvoid *image,
  256.                        GLsizei width, GLsizei height,
  257.                        GLenum format, GLenum type,
  258.                        GLint img, GLint row, GLint column )
  259. {
  260.    return _mesa_image_address(3, packing, image, width, height,
  261.                               format, type, img, row, column);
  262. }
  263.  
  264.  
  265.  
  266. /**
  267.  * Compute the stride (in bytes) between image rows.
  268.  *
  269.  * \param packing the pixelstore attributes
  270.  * \param width image width.
  271.  * \param format pixel format.
  272.  * \param type pixel data type.
  273.  *
  274.  * \return the stride in bytes for the given parameters, or -1 if error
  275.  */
  276. GLint
  277. _mesa_image_row_stride( const struct gl_pixelstore_attrib *packing,
  278.                         GLint width, GLenum format, GLenum type )
  279. {
  280.    GLint bytesPerRow, remainder;
  281.  
  282.    ASSERT(packing);
  283.  
  284.    if (type == GL_BITMAP) {
  285.       if (packing->RowLength == 0) {
  286.          bytesPerRow = (width + 7) / 8;
  287.       }
  288.       else {
  289.          bytesPerRow = (packing->RowLength + 7) / 8;
  290.       }
  291.    }
  292.    else {
  293.       /* Non-BITMAP data */
  294.       const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
  295.       if (bytesPerPixel <= 0)
  296.          return -1;  /* error */
  297.       if (packing->RowLength == 0) {
  298.          bytesPerRow = bytesPerPixel * width;
  299.       }
  300.       else {
  301.          bytesPerRow = bytesPerPixel * packing->RowLength;
  302.       }
  303.    }
  304.  
  305.    remainder = bytesPerRow % packing->Alignment;
  306.    if (remainder > 0) {
  307.       bytesPerRow += (packing->Alignment - remainder);
  308.    }
  309.  
  310.    if (packing->Invert) {
  311.       /* negate the bytes per row (negative row stride) */
  312.       bytesPerRow = -bytesPerRow;
  313.    }
  314.  
  315.    return bytesPerRow;
  316. }
  317.  
  318.  
  319. /*
  320.  * Compute the stride between images in a 3D texture (in bytes) for the given
  321.  * pixel packing parameters and image width, format and type.
  322.  */
  323. GLint
  324. _mesa_image_image_stride( const struct gl_pixelstore_attrib *packing,
  325.                           GLint width, GLint height,
  326.                           GLenum format, GLenum type )
  327. {
  328.    GLint bytesPerRow, bytesPerImage, remainder;
  329.  
  330.    ASSERT(packing);
  331.  
  332.    if (type == GL_BITMAP) {
  333.       if (packing->RowLength == 0) {
  334.          bytesPerRow = (width + 7) / 8;
  335.       }
  336.       else {
  337.          bytesPerRow = (packing->RowLength + 7) / 8;
  338.       }
  339.    }
  340.    else {
  341.       const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
  342.  
  343.       if (bytesPerPixel <= 0)
  344.          return -1;  /* error */
  345.       if (packing->RowLength == 0) {
  346.          bytesPerRow = bytesPerPixel * width;
  347.       }
  348.       else {
  349.          bytesPerRow = bytesPerPixel * packing->RowLength;
  350.       }
  351.    }
  352.  
  353.    remainder = bytesPerRow % packing->Alignment;
  354.    if (remainder > 0)
  355.       bytesPerRow += (packing->Alignment - remainder);
  356.  
  357.    if (packing->ImageHeight == 0)
  358.       bytesPerImage = bytesPerRow * height;
  359.    else
  360.       bytesPerImage = bytesPerRow * packing->ImageHeight;
  361.  
  362.    return bytesPerImage;
  363. }
  364.  
  365.  
  366.  
  367. /**
  368.  * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel.
  369.  * This is typically used to convert a bitmap into a GLubyte/pixel texture.
  370.  * "On" bits will set texels to \p onValue.
  371.  * "Off" bits will not modify texels.
  372.  * \param width  src bitmap width in pixels
  373.  * \param height  src bitmap height in pixels
  374.  * \param unpack  bitmap unpacking state
  375.  * \param bitmap  the src bitmap data
  376.  * \param destBuffer  start of dest buffer
  377.  * \param destStride  row stride in dest buffer
  378.  * \param onValue  if bit is 1, set destBuffer pixel to this value
  379.  */
  380. void
  381. _mesa_expand_bitmap(GLsizei width, GLsizei height,
  382.                     const struct gl_pixelstore_attrib *unpack,
  383.                     const GLubyte *bitmap,
  384.                     GLubyte *destBuffer, GLint destStride,
  385.                     GLubyte onValue)
  386. {
  387.    const GLubyte *srcRow = (const GLubyte *)
  388.       _mesa_image_address2d(unpack, bitmap, width, height,
  389.                             GL_COLOR_INDEX, GL_BITMAP, 0, 0);
  390.    const GLint srcStride = _mesa_image_row_stride(unpack, width,
  391.                                                   GL_COLOR_INDEX, GL_BITMAP);
  392.    GLint row, col;
  393.  
  394. #define SET_PIXEL(COL, ROW) \
  395.    destBuffer[(ROW) * destStride + (COL)] = onValue;
  396.  
  397.    for (row = 0; row < height; row++) {
  398.       const GLubyte *src = srcRow;
  399.  
  400.       if (unpack->LsbFirst) {
  401.          /* Lsb first */
  402.          GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
  403.          for (col = 0; col < width; col++) {
  404.  
  405.             if (*src & mask) {
  406.                SET_PIXEL(col, row);
  407.             }
  408.  
  409.             if (mask == 128U) {
  410.                src++;
  411.                mask = 1U;
  412.             }
  413.             else {
  414.                mask = mask << 1;
  415.             }
  416.          }
  417.  
  418.          /* get ready for next row */
  419.          if (mask != 1)
  420.             src++;
  421.       }
  422.       else {
  423.          /* Msb first */
  424.          GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
  425.          for (col = 0; col < width; col++) {
  426.  
  427.             if (*src & mask) {
  428.                SET_PIXEL(col, row);
  429.             }
  430.  
  431.             if (mask == 1U) {
  432.                src++;
  433.                mask = 128U;
  434.             }
  435.             else {
  436.                mask = mask >> 1;
  437.             }
  438.          }
  439.  
  440.          /* get ready for next row */
  441.          if (mask != 128)
  442.             src++;
  443.       }
  444.  
  445.       srcRow += srcStride;
  446.    } /* row */
  447.  
  448. #undef SET_PIXEL
  449. }
  450.  
  451.  
  452.  
  453.  
  454. /**
  455.  * Convert an array of RGBA colors from one datatype to another.
  456.  * NOTE: src may equal dst.  In that case, we use a temporary buffer.
  457.  */
  458. void
  459. _mesa_convert_colors(GLenum srcType, const GLvoid *src,
  460.                      GLenum dstType, GLvoid *dst,
  461.                      GLuint count, const GLubyte mask[])
  462. {
  463.    GLuint *tempBuffer;
  464.    const GLboolean useTemp = (src == dst);
  465.  
  466.    tempBuffer = malloc(count * MAX_PIXEL_BYTES);
  467.    if (!tempBuffer)
  468.       return;
  469.  
  470.    ASSERT(srcType != dstType);
  471.  
  472.    switch (srcType) {
  473.    case GL_UNSIGNED_BYTE:
  474.       if (dstType == GL_UNSIGNED_SHORT) {
  475.          const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
  476.          GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
  477.          GLuint i;
  478.          for (i = 0; i < count; i++) {
  479.             if (!mask || mask[i]) {
  480.                dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]);
  481.                dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]);
  482.                dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]);
  483.                dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]);
  484.             }
  485.          }
  486.          if (useTemp)
  487.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
  488.       }
  489.       else {
  490.          const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
  491.          GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
  492.          GLuint i;
  493.          ASSERT(dstType == GL_FLOAT);
  494.          for (i = 0; i < count; i++) {
  495.             if (!mask || mask[i]) {
  496.                dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]);
  497.                dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]);
  498.                dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]);
  499.                dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]);
  500.             }
  501.          }
  502.          if (useTemp)
  503.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
  504.       }
  505.       break;
  506.    case GL_UNSIGNED_SHORT:
  507.       if (dstType == GL_UNSIGNED_BYTE) {
  508.          const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
  509.          GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
  510.          GLuint i;
  511.          for (i = 0; i < count; i++) {
  512.             if (!mask || mask[i]) {
  513.                dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]);
  514.                dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]);
  515.                dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]);
  516.                dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]);
  517.             }
  518.          }
  519.          if (useTemp)
  520.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
  521.       }
  522.       else {
  523.          const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
  524.          GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
  525.          GLuint i;
  526.          ASSERT(dstType == GL_FLOAT);
  527.          for (i = 0; i < count; i++) {
  528.             if (!mask || mask[i]) {
  529.                dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]);
  530.                dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]);
  531.                dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]);
  532.                dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]);
  533.             }
  534.          }
  535.          if (useTemp)
  536.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
  537.       }
  538.       break;
  539.    case GL_FLOAT:
  540.       if (dstType == GL_UNSIGNED_BYTE) {
  541.          const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
  542.          GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
  543.          GLuint i;
  544.          for (i = 0; i < count; i++) {
  545.             if (!mask || mask[i])
  546.                _mesa_unclamped_float_rgba_to_ubyte(dst1[i], src4[i]);
  547.          }
  548.          if (useTemp)
  549.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
  550.       }
  551.       else {
  552.          const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
  553.          GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
  554.          GLuint i;
  555.          ASSERT(dstType == GL_UNSIGNED_SHORT);
  556.          for (i = 0; i < count; i++) {
  557.             if (!mask || mask[i]) {
  558.                UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]);
  559.                UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]);
  560.                UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]);
  561.                UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]);
  562.             }
  563.          }
  564.          if (useTemp)
  565.             memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
  566.       }
  567.       break;
  568.    default:
  569.       _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors");
  570.    }
  571.  
  572.    free(tempBuffer);
  573. }
  574.  
  575.  
  576.  
  577.  
  578. /**
  579.  * Perform basic clipping for glDrawPixels.  The image's position and size
  580.  * and the unpack SkipPixels and SkipRows are adjusted so that the image
  581.  * region is entirely within the window and scissor bounds.
  582.  * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1).
  583.  * If Pixel.ZoomY is -1, *destY will be changed to be the first row which
  584.  * we'll actually write.  Beforehand, *destY-1 is the first drawing row.
  585.  *
  586.  * \return  GL_TRUE if image is ready for drawing or
  587.  *          GL_FALSE if image was completely clipped away (draw nothing)
  588.  */
  589. GLboolean
  590. _mesa_clip_drawpixels(const struct gl_context *ctx,
  591.                       GLint *destX, GLint *destY,
  592.                       GLsizei *width, GLsizei *height,
  593.                       struct gl_pixelstore_attrib *unpack)
  594. {
  595.    const struct gl_framebuffer *buffer = ctx->DrawBuffer;
  596.  
  597.    if (unpack->RowLength == 0) {
  598.       unpack->RowLength = *width;
  599.    }
  600.  
  601.    ASSERT(ctx->Pixel.ZoomX == 1.0F);
  602.    ASSERT(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F);
  603.  
  604.    /* left clipping */
  605.    if (*destX < buffer->_Xmin) {
  606.       unpack->SkipPixels += (buffer->_Xmin - *destX);
  607.       *width -= (buffer->_Xmin - *destX);
  608.       *destX = buffer->_Xmin;
  609.    }
  610.    /* right clipping */
  611.    if (*destX + *width > buffer->_Xmax)
  612.       *width -= (*destX + *width - buffer->_Xmax);
  613.  
  614.    if (*width <= 0)
  615.       return GL_FALSE;
  616.  
  617.    if (ctx->Pixel.ZoomY == 1.0F) {
  618.       /* bottom clipping */
  619.       if (*destY < buffer->_Ymin) {
  620.          unpack->SkipRows += (buffer->_Ymin - *destY);
  621.          *height -= (buffer->_Ymin - *destY);
  622.          *destY = buffer->_Ymin;
  623.       }
  624.       /* top clipping */
  625.       if (*destY + *height > buffer->_Ymax)
  626.          *height -= (*destY + *height - buffer->_Ymax);
  627.    }
  628.    else { /* upside down */
  629.       /* top clipping */
  630.       if (*destY > buffer->_Ymax) {
  631.          unpack->SkipRows += (*destY - buffer->_Ymax);
  632.          *height -= (*destY - buffer->_Ymax);
  633.          *destY = buffer->_Ymax;
  634.       }
  635.       /* bottom clipping */
  636.       if (*destY - *height < buffer->_Ymin)
  637.          *height -= (buffer->_Ymin - (*destY - *height));
  638.       /* adjust destY so it's the first row to write to */
  639.       (*destY)--;
  640.    }
  641.  
  642.    if (*height <= 0)
  643.       return GL_FALSE;
  644.  
  645.    return GL_TRUE;
  646. }
  647.  
  648.  
  649. /**
  650.  * Perform clipping for glReadPixels.  The image's window position
  651.  * and size, and the pack skipPixels, skipRows and rowLength are adjusted
  652.  * so that the image region is entirely within the window bounds.
  653.  * Note: this is different from _mesa_clip_drawpixels() in that the
  654.  * scissor box is ignored, and we use the bounds of the current readbuffer
  655.  * surface.
  656.  *
  657.  * \return  GL_TRUE if region to read is in bounds
  658.  *          GL_FALSE if region is completely out of bounds (nothing to read)
  659.  */
  660. GLboolean
  661. _mesa_clip_readpixels(const struct gl_context *ctx,
  662.                       GLint *srcX, GLint *srcY,
  663.                       GLsizei *width, GLsizei *height,
  664.                       struct gl_pixelstore_attrib *pack)
  665. {
  666.    const struct gl_framebuffer *buffer = ctx->ReadBuffer;
  667.  
  668.    if (pack->RowLength == 0) {
  669.       pack->RowLength = *width;
  670.    }
  671.  
  672.    /* left clipping */
  673.    if (*srcX < 0) {
  674.       pack->SkipPixels += (0 - *srcX);
  675.       *width -= (0 - *srcX);
  676.       *srcX = 0;
  677.    }
  678.    /* right clipping */
  679.    if (*srcX + *width > (GLsizei) buffer->Width)
  680.       *width -= (*srcX + *width - buffer->Width);
  681.  
  682.    if (*width <= 0)
  683.       return GL_FALSE;
  684.  
  685.    /* bottom clipping */
  686.    if (*srcY < 0) {
  687.       pack->SkipRows += (0 - *srcY);
  688.       *height -= (0 - *srcY);
  689.       *srcY = 0;
  690.    }
  691.    /* top clipping */
  692.    if (*srcY + *height > (GLsizei) buffer->Height)
  693.       *height -= (*srcY + *height - buffer->Height);
  694.  
  695.    if (*height <= 0)
  696.       return GL_FALSE;
  697.  
  698.    return GL_TRUE;
  699. }
  700.  
  701.  
  702. /**
  703.  * Do clipping for a glCopyTexSubImage call.
  704.  * The framebuffer source region might extend outside the framebuffer
  705.  * bounds.  Clip the source region against the framebuffer bounds and
  706.  * adjust the texture/dest position and size accordingly.
  707.  *
  708.  * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise.
  709.  */
  710. GLboolean
  711. _mesa_clip_copytexsubimage(const struct gl_context *ctx,
  712.                            GLint *destX, GLint *destY,
  713.                            GLint *srcX, GLint *srcY,
  714.                            GLsizei *width, GLsizei *height)
  715. {
  716.    const struct gl_framebuffer *fb = ctx->ReadBuffer;
  717.    const GLint srcX0 = *srcX, srcY0 = *srcY;
  718.  
  719.    if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height,
  720.                             srcX, srcY, width, height)) {
  721.       *destX = *destX + *srcX - srcX0;
  722.       *destY = *destY + *srcY - srcY0;
  723.  
  724.       return GL_TRUE;
  725.    }
  726.    else {
  727.       return GL_FALSE;
  728.    }
  729. }
  730.  
  731.  
  732.  
  733. /**
  734.  * Clip the rectangle defined by (x, y, width, height) against the bounds
  735.  * specified by [xmin, xmax) and [ymin, ymax).
  736.  * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise.
  737.  */
  738. GLboolean
  739. _mesa_clip_to_region(GLint xmin, GLint ymin,
  740.                      GLint xmax, GLint ymax,
  741.                      GLint *x, GLint *y,
  742.                      GLsizei *width, GLsizei *height )
  743. {
  744.    /* left clipping */
  745.    if (*x < xmin) {
  746.       *width -= (xmin - *x);
  747.       *x = xmin;
  748.    }
  749.  
  750.    /* right clipping */
  751.    if (*x + *width > xmax)
  752.       *width -= (*x + *width - xmax);
  753.  
  754.    if (*width <= 0)
  755.       return GL_FALSE;
  756.  
  757.    /* bottom (or top) clipping */
  758.    if (*y < ymin) {
  759.       *height -= (ymin - *y);
  760.       *y = ymin;
  761.    }
  762.  
  763.    /* top (or bottom) clipping */
  764.    if (*y + *height > ymax)
  765.       *height -= (*y + *height - ymax);
  766.  
  767.    if (*height <= 0)
  768.       return GL_FALSE;
  769.  
  770.    return GL_TRUE;
  771. }
  772.  
  773.  
  774. /**
  775.  * Clip dst coords against Xmax (or Ymax).
  776.  */
  777. static inline void
  778. clip_right_or_top(GLint *srcX0, GLint *srcX1,
  779.                   GLint *dstX0, GLint *dstX1,
  780.                   GLint maxValue)
  781. {
  782.    GLfloat t, bias;
  783.  
  784.    if (*dstX1 > maxValue) {
  785.       /* X1 outside right edge */
  786.       ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */
  787.       t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
  788.       /* chop off [t, 1] part */
  789.       ASSERT(t >= 0.0 && t <= 1.0);
  790.       *dstX1 = maxValue;
  791.       bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
  792.       *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
  793.    }
  794.    else if (*dstX0 > maxValue) {
  795.       /* X0 outside right edge */
  796.       ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */
  797.       t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
  798.       /* chop off [t, 1] part */
  799.       ASSERT(t >= 0.0 && t <= 1.0);
  800.       *dstX0 = maxValue;
  801.       bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
  802.       *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
  803.    }
  804. }
  805.  
  806.  
  807. /**
  808.  * Clip dst coords against Xmin (or Ymin).
  809.  */
  810. static inline void
  811. clip_left_or_bottom(GLint *srcX0, GLint *srcX1,
  812.                     GLint *dstX0, GLint *dstX1,
  813.                     GLint minValue)
  814. {
  815.    GLfloat t, bias;
  816.  
  817.    if (*dstX0 < minValue) {
  818.       /* X0 outside left edge */
  819.       ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */
  820.       t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
  821.       /* chop off [0, t] part */
  822.       ASSERT(t >= 0.0 && t <= 1.0);
  823.       *dstX0 = minValue;
  824.       bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
  825.       *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
  826.    }
  827.    else if (*dstX1 < minValue) {
  828.       /* X1 outside left edge */
  829.       ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */
  830.       t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
  831.       /* chop off [0, t] part */
  832.       ASSERT(t >= 0.0 && t <= 1.0);
  833.       *dstX1 = minValue;
  834.       bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
  835.       *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
  836.    }
  837. }
  838.  
  839.  
  840. /**
  841.  * Do clipping of blit src/dest rectangles.
  842.  * The dest rect is clipped against both the buffer bounds and scissor bounds.
  843.  * The src rect is just clipped against the buffer bounds.
  844.  *
  845.  * When either the src or dest rect is clipped, the other is also clipped
  846.  * proportionately!
  847.  *
  848.  * Note that X0 need not be less than X1 (same for Y) for either the source
  849.  * and dest rects.  That makes the clipping a little trickier.
  850.  *
  851.  * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
  852.  */
  853. GLboolean
  854. _mesa_clip_blit(struct gl_context *ctx,
  855.                 GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
  856.                 GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
  857. {
  858.    const GLint srcXmin = 0;
  859.    const GLint srcXmax = ctx->ReadBuffer->Width;
  860.    const GLint srcYmin = 0;
  861.    const GLint srcYmax = ctx->ReadBuffer->Height;
  862.  
  863.    /* these include scissor bounds */
  864.    const GLint dstXmin = ctx->DrawBuffer->_Xmin;
  865.    const GLint dstXmax = ctx->DrawBuffer->_Xmax;
  866.    const GLint dstYmin = ctx->DrawBuffer->_Ymin;
  867.    const GLint dstYmax = ctx->DrawBuffer->_Ymax;
  868.  
  869.    /*
  870.    printf("PreClipX:  src: %d .. %d  dst: %d .. %d\n",
  871.           *srcX0, *srcX1, *dstX0, *dstX1);
  872.    printf("PreClipY:  src: %d .. %d  dst: %d .. %d\n",
  873.           *srcY0, *srcY1, *dstY0, *dstY1);
  874.    */
  875.  
  876.    /* trivial rejection tests */
  877.    if (*dstX0 == *dstX1)
  878.       return GL_FALSE; /* no width */
  879.    if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
  880.       return GL_FALSE; /* totally out (left) of bounds */
  881.    if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
  882.       return GL_FALSE; /* totally out (right) of bounds */
  883.  
  884.    if (*dstY0 == *dstY1)
  885.       return GL_FALSE;
  886.    if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
  887.       return GL_FALSE;
  888.    if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
  889.       return GL_FALSE;
  890.  
  891.    if (*srcX0 == *srcX1)
  892.       return GL_FALSE;
  893.    if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
  894.       return GL_FALSE;
  895.    if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
  896.       return GL_FALSE;
  897.  
  898.    if (*srcY0 == *srcY1)
  899.       return GL_FALSE;
  900.    if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
  901.       return GL_FALSE;
  902.    if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
  903.       return GL_FALSE;
  904.  
  905.    /*
  906.     * dest clip
  907.     */
  908.    clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
  909.    clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
  910.    clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
  911.    clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
  912.  
  913.    /*
  914.     * src clip (just swap src/dst values from above)
  915.     */
  916.    clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
  917.    clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
  918.    clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
  919.    clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
  920.  
  921.    /*
  922.    printf("PostClipX: src: %d .. %d  dst: %d .. %d\n",
  923.           *srcX0, *srcX1, *dstX0, *dstX1);
  924.    printf("PostClipY: src: %d .. %d  dst: %d .. %d\n",
  925.           *srcY0, *srcY1, *dstY0, *dstY1);
  926.    */
  927.  
  928.    ASSERT(*dstX0 >= dstXmin);
  929.    ASSERT(*dstX0 <= dstXmax);
  930.    ASSERT(*dstX1 >= dstXmin);
  931.    ASSERT(*dstX1 <= dstXmax);
  932.  
  933.    ASSERT(*dstY0 >= dstYmin);
  934.    ASSERT(*dstY0 <= dstYmax);
  935.    ASSERT(*dstY1 >= dstYmin);
  936.    ASSERT(*dstY1 <= dstYmax);
  937.  
  938.    ASSERT(*srcX0 >= srcXmin);
  939.    ASSERT(*srcX0 <= srcXmax);
  940.    ASSERT(*srcX1 >= srcXmin);
  941.    ASSERT(*srcX1 <= srcXmax);
  942.  
  943.    ASSERT(*srcY0 >= srcYmin);
  944.    ASSERT(*srcY0 <= srcYmax);
  945.    ASSERT(*srcY1 >= srcYmin);
  946.    ASSERT(*srcY1 <= srcYmax);
  947.  
  948.    return GL_TRUE;
  949. }
  950.