17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5c7037ccdSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/**
287117f1b4Smrg * \file image.c
297117f1b4Smrg * Image handling.
307117f1b4Smrg */
317117f1b4Smrg
327117f1b4Smrg
337117f1b4Smrg#include "glheader.h"
347117f1b4Smrg#include "colormac.h"
35af69d88dSmrg#include "glformats.h"
367117f1b4Smrg#include "image.h"
377ec681f3Smrg
387117f1b4Smrg#include "macros.h"
393464ebd5Sriastradh#include "mtypes.h"
407117f1b4Smrg
417117f1b4Smrg
427117f1b4Smrg
437117f1b4Smrg/**
4401e04c3fSmrg * Flip the order of the 2 bytes in each word in the given array (src) and
4501e04c3fSmrg * store the result in another array (dst). For in-place byte-swapping this
4601e04c3fSmrg * function can be called with the same array for src and dst.
477117f1b4Smrg *
4801e04c3fSmrg * \param dst the array where byte-swapped data will be stored.
4901e04c3fSmrg * \param src the array with the source data we want to byte-swap.
507117f1b4Smrg * \param n number of words.
517117f1b4Smrg */
5201e04c3fSmrgstatic void
5301e04c3fSmrgswap2_copy( GLushort *dst, GLushort *src, GLuint n )
547117f1b4Smrg{
557117f1b4Smrg   GLuint i;
567117f1b4Smrg   for (i = 0; i < n; i++) {
5701e04c3fSmrg      dst[i] = (src[i] >> 8) | ((src[i] << 8) & 0xff00);
587117f1b4Smrg   }
597117f1b4Smrg}
607117f1b4Smrg
6101e04c3fSmrgvoid
6201e04c3fSmrg_mesa_swap2(GLushort *p, GLuint n)
6301e04c3fSmrg{
6401e04c3fSmrg   swap2_copy(p, p, n);
6501e04c3fSmrg}
667117f1b4Smrg
677117f1b4Smrg/*
6801e04c3fSmrg * Flip the order of the 4 bytes in each word in the given array (src) and
6901e04c3fSmrg * store the result in another array (dst). For in-place byte-swapping this
7001e04c3fSmrg * function can be called with the same array for src and dst.
7101e04c3fSmrg *
7201e04c3fSmrg * \param dst the array where byte-swapped data will be stored.
7301e04c3fSmrg * \param src the array with the source data we want to byte-swap.
7401e04c3fSmrg * \param n number of words.
757117f1b4Smrg */
7601e04c3fSmrgstatic void
7701e04c3fSmrgswap4_copy( GLuint *dst, GLuint *src, GLuint n )
787117f1b4Smrg{
797117f1b4Smrg   GLuint i, a, b;
807117f1b4Smrg   for (i = 0; i < n; i++) {
8101e04c3fSmrg      b = src[i];
827117f1b4Smrg      a =  (b >> 24)
837117f1b4Smrg	| ((b >> 8) & 0xff00)
847117f1b4Smrg	| ((b << 8) & 0xff0000)
857117f1b4Smrg	| ((b << 24) & 0xff000000);
8601e04c3fSmrg      dst[i] = a;
877117f1b4Smrg   }
887117f1b4Smrg}
897117f1b4Smrg
9001e04c3fSmrgvoid
9101e04c3fSmrg_mesa_swap4(GLuint *p, GLuint n)
9201e04c3fSmrg{
9301e04c3fSmrg   swap4_copy(p, p, n);
9401e04c3fSmrg}
957117f1b4Smrg
967117f1b4Smrg/**
97af69d88dSmrg * Return the byte offset of a specific pixel in an image (1D, 2D or 3D).
987117f1b4Smrg *
997117f1b4Smrg * Pixel unpacking/packing parameters are observed according to \p packing.
1007117f1b4Smrg *
1017117f1b4Smrg * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
1027117f1b4Smrg * \param packing  the pixelstore attributes
103af69d88dSmrg * \param width  the image width
104af69d88dSmrg * \param height  the image height
105af69d88dSmrg * \param format  the pixel format (must be validated beforehand)
106af69d88dSmrg * \param type  the pixel data type (must be validated beforehand)
1077117f1b4Smrg * \param img  which image in the volume (0 for 1D or 2D images)
1087117f1b4Smrg * \param row  row of pixel in the image (0 for 1D images)
1097117f1b4Smrg * \param column column of pixel in the image
110af69d88dSmrg *
111af69d88dSmrg * \return offset of pixel.
1127117f1b4Smrg *
1137117f1b4Smrg * \sa gl_pixelstore_attrib.
1147117f1b4Smrg */
115af69d88dSmrgGLintptr
116af69d88dSmrg_mesa_image_offset( GLuint dimensions,
117af69d88dSmrg                    const struct gl_pixelstore_attrib *packing,
118af69d88dSmrg                    GLsizei width, GLsizei height,
119af69d88dSmrg                    GLenum format, GLenum type,
120af69d88dSmrg                    GLint img, GLint row, GLint column )
1217117f1b4Smrg{
1227117f1b4Smrg   GLint alignment;        /* 1, 2 or 4 */
1237117f1b4Smrg   GLint pixels_per_row;
1247117f1b4Smrg   GLint rows_per_image;
1257117f1b4Smrg   GLint skiprows;
1267117f1b4Smrg   GLint skippixels;
1277117f1b4Smrg   GLint skipimages;       /* for 3-D volume images */
128af69d88dSmrg   GLintptr offset;
1297117f1b4Smrg
13001e04c3fSmrg   assert(dimensions >= 1 && dimensions <= 3);
1317117f1b4Smrg
1327117f1b4Smrg   alignment = packing->Alignment;
1337117f1b4Smrg   if (packing->RowLength > 0) {
1347117f1b4Smrg      pixels_per_row = packing->RowLength;
1357117f1b4Smrg   }
1367117f1b4Smrg   else {
1377117f1b4Smrg      pixels_per_row = width;
1387117f1b4Smrg   }
1397117f1b4Smrg   if (packing->ImageHeight > 0) {
1407117f1b4Smrg      rows_per_image = packing->ImageHeight;
1417117f1b4Smrg   }
1427117f1b4Smrg   else {
1437117f1b4Smrg      rows_per_image = height;
1447117f1b4Smrg   }
1457117f1b4Smrg
1467117f1b4Smrg   skippixels = packing->SkipPixels;
1477117f1b4Smrg   /* Note: SKIP_ROWS _is_ used for 1D images */
1487117f1b4Smrg   skiprows = packing->SkipRows;
1497117f1b4Smrg   /* Note: SKIP_IMAGES is only used for 3D images */
1507117f1b4Smrg   skipimages = (dimensions == 3) ? packing->SkipImages : 0;
1517117f1b4Smrg
1527117f1b4Smrg   if (type == GL_BITMAP) {
1537117f1b4Smrg      /* BITMAP data */
15401e04c3fSmrg      GLintptr bytes_per_row;
15501e04c3fSmrg      GLintptr bytes_per_image;
156af69d88dSmrg      /* components per pixel for color or stencil index: */
157af69d88dSmrg      const GLint comp_per_pixel = 1;
1587117f1b4Smrg
159af69d88dSmrg      /* The pixel type and format should have been error checked earlier */
160af69d88dSmrg      assert(format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX);
1617117f1b4Smrg
1627117f1b4Smrg      bytes_per_row = alignment
16301e04c3fSmrg                    * DIV_ROUND_UP( comp_per_pixel*pixels_per_row, 8*alignment );
1647117f1b4Smrg
1657117f1b4Smrg      bytes_per_image = bytes_per_row * rows_per_image;
1667117f1b4Smrg
167af69d88dSmrg      offset = (skipimages + img) * bytes_per_image
1687117f1b4Smrg                 + (skiprows + row) * bytes_per_row
1697117f1b4Smrg                 + (skippixels + column) / 8;
1707117f1b4Smrg   }
1717117f1b4Smrg   else {
1727117f1b4Smrg      /* Non-BITMAP data */
17301e04c3fSmrg      GLintptr bytes_per_pixel, bytes_per_row, remainder, bytes_per_image;
17401e04c3fSmrg      GLintptr topOfImage;
1757117f1b4Smrg
1767117f1b4Smrg      bytes_per_pixel = _mesa_bytes_per_pixel( format, type );
1777117f1b4Smrg
1787117f1b4Smrg      /* The pixel type and format should have been error checked earlier */
1797117f1b4Smrg      assert(bytes_per_pixel > 0);
1807117f1b4Smrg
1817117f1b4Smrg      bytes_per_row = pixels_per_row * bytes_per_pixel;
1827117f1b4Smrg      remainder = bytes_per_row % alignment;
1837117f1b4Smrg      if (remainder > 0)
1847117f1b4Smrg         bytes_per_row += (alignment - remainder);
1857117f1b4Smrg
18601e04c3fSmrg      assert(bytes_per_row % alignment == 0);
1877117f1b4Smrg
1887117f1b4Smrg      bytes_per_image = bytes_per_row * rows_per_image;
1897117f1b4Smrg
1907117f1b4Smrg      if (packing->Invert) {
1917117f1b4Smrg         /* set pixel_addr to the last row */
1927117f1b4Smrg         topOfImage = bytes_per_row * (height - 1);
1937117f1b4Smrg         bytes_per_row = -bytes_per_row;
1947117f1b4Smrg      }
1957117f1b4Smrg      else {
1967117f1b4Smrg         topOfImage = 0;
1977117f1b4Smrg      }
1987117f1b4Smrg
1997117f1b4Smrg      /* compute final pixel address */
200af69d88dSmrg      offset = (skipimages + img) * bytes_per_image
2017117f1b4Smrg                 + topOfImage
2027117f1b4Smrg                 + (skiprows + row) * bytes_per_row
2037117f1b4Smrg                 + (skippixels + column) * bytes_per_pixel;
2047117f1b4Smrg   }
2057117f1b4Smrg
206af69d88dSmrg   return offset;
207af69d88dSmrg}
208af69d88dSmrg
209af69d88dSmrg
210af69d88dSmrg/**
211af69d88dSmrg * Return the address of a specific pixel in an image (1D, 2D or 3D).
212af69d88dSmrg *
213af69d88dSmrg * Pixel unpacking/packing parameters are observed according to \p packing.
214af69d88dSmrg *
215af69d88dSmrg * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
216af69d88dSmrg * \param packing  the pixelstore attributes
217af69d88dSmrg * \param image  starting address of image data
218af69d88dSmrg * \param width  the image width
219af69d88dSmrg * \param height  the image height
220af69d88dSmrg * \param format  the pixel format (must be validated beforehand)
221af69d88dSmrg * \param type  the pixel data type (must be validated beforehand)
222af69d88dSmrg * \param img  which image in the volume (0 for 1D or 2D images)
223af69d88dSmrg * \param row  row of pixel in the image (0 for 1D images)
224af69d88dSmrg * \param column column of pixel in the image
225af69d88dSmrg *
226af69d88dSmrg * \return address of pixel.
227af69d88dSmrg *
228af69d88dSmrg * \sa gl_pixelstore_attrib.
229af69d88dSmrg */
230af69d88dSmrgGLvoid *
231af69d88dSmrg_mesa_image_address( GLuint dimensions,
232af69d88dSmrg                     const struct gl_pixelstore_attrib *packing,
233af69d88dSmrg                     const GLvoid *image,
234af69d88dSmrg                     GLsizei width, GLsizei height,
235af69d88dSmrg                     GLenum format, GLenum type,
236af69d88dSmrg                     GLint img, GLint row, GLint column )
237af69d88dSmrg{
238af69d88dSmrg   const GLubyte *addr = (const GLubyte *) image;
239af69d88dSmrg
240af69d88dSmrg   addr += _mesa_image_offset(dimensions, packing, width, height,
241af69d88dSmrg                              format, type, img, row, column);
242af69d88dSmrg
243af69d88dSmrg   return (GLvoid *) addr;
2447117f1b4Smrg}
2457117f1b4Smrg
2467117f1b4Smrg
2477117f1b4SmrgGLvoid *
2487117f1b4Smrg_mesa_image_address1d( const struct gl_pixelstore_attrib *packing,
2497117f1b4Smrg                       const GLvoid *image,
2507117f1b4Smrg                       GLsizei width,
2517117f1b4Smrg                       GLenum format, GLenum type,
2527117f1b4Smrg                       GLint column )
2537117f1b4Smrg{
2547117f1b4Smrg   return _mesa_image_address(1, packing, image, width, 1,
2557117f1b4Smrg                              format, type, 0, 0, column);
2567117f1b4Smrg}
2577117f1b4Smrg
2587117f1b4Smrg
2597117f1b4SmrgGLvoid *
2607117f1b4Smrg_mesa_image_address2d( const struct gl_pixelstore_attrib *packing,
2617117f1b4Smrg                       const GLvoid *image,
2627117f1b4Smrg                       GLsizei width, GLsizei height,
2637117f1b4Smrg                       GLenum format, GLenum type,
2647117f1b4Smrg                       GLint row, GLint column )
2657117f1b4Smrg{
2667117f1b4Smrg   return _mesa_image_address(2, packing, image, width, height,
2677117f1b4Smrg                              format, type, 0, row, column);
2687117f1b4Smrg}
2697117f1b4Smrg
2707117f1b4Smrg
2717117f1b4SmrgGLvoid *
2727117f1b4Smrg_mesa_image_address3d( const struct gl_pixelstore_attrib *packing,
2737117f1b4Smrg                       const GLvoid *image,
2747117f1b4Smrg                       GLsizei width, GLsizei height,
2757117f1b4Smrg                       GLenum format, GLenum type,
2767117f1b4Smrg                       GLint img, GLint row, GLint column )
2777117f1b4Smrg{
2787117f1b4Smrg   return _mesa_image_address(3, packing, image, width, height,
2797117f1b4Smrg                              format, type, img, row, column);
2807117f1b4Smrg}
2817117f1b4Smrg
2827117f1b4Smrg
2837117f1b4Smrg
2847117f1b4Smrg/**
2857117f1b4Smrg * Compute the stride (in bytes) between image rows.
2867117f1b4Smrg *
2877117f1b4Smrg * \param packing the pixelstore attributes
2887117f1b4Smrg * \param width image width.
2897117f1b4Smrg * \param format pixel format.
2907117f1b4Smrg * \param type pixel data type.
2917ec681f3Smrg *
2927117f1b4Smrg * \return the stride in bytes for the given parameters, or -1 if error
2937117f1b4Smrg */
2947117f1b4SmrgGLint
2957117f1b4Smrg_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing,
2967117f1b4Smrg                        GLint width, GLenum format, GLenum type )
2977117f1b4Smrg{
2987117f1b4Smrg   GLint bytesPerRow, remainder;
2997117f1b4Smrg
30001e04c3fSmrg   assert(packing);
3017117f1b4Smrg
3027117f1b4Smrg   if (type == GL_BITMAP) {
3037117f1b4Smrg      if (packing->RowLength == 0) {
3047117f1b4Smrg         bytesPerRow = (width + 7) / 8;
3057117f1b4Smrg      }
3067117f1b4Smrg      else {
3077117f1b4Smrg         bytesPerRow = (packing->RowLength + 7) / 8;
3087117f1b4Smrg      }
3097117f1b4Smrg   }
3107117f1b4Smrg   else {
3117117f1b4Smrg      /* Non-BITMAP data */
3127117f1b4Smrg      const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
3137117f1b4Smrg      if (bytesPerPixel <= 0)
3147117f1b4Smrg         return -1;  /* error */
3157117f1b4Smrg      if (packing->RowLength == 0) {
3167117f1b4Smrg         bytesPerRow = bytesPerPixel * width;
3177117f1b4Smrg      }
3187117f1b4Smrg      else {
3197117f1b4Smrg         bytesPerRow = bytesPerPixel * packing->RowLength;
3207117f1b4Smrg      }
3217117f1b4Smrg   }
3227117f1b4Smrg
3237117f1b4Smrg   remainder = bytesPerRow % packing->Alignment;
3247117f1b4Smrg   if (remainder > 0) {
3257117f1b4Smrg      bytesPerRow += (packing->Alignment - remainder);
3267117f1b4Smrg   }
3277117f1b4Smrg
3287117f1b4Smrg   if (packing->Invert) {
3297117f1b4Smrg      /* negate the bytes per row (negative row stride) */
3307117f1b4Smrg      bytesPerRow = -bytesPerRow;
3317117f1b4Smrg   }
3327117f1b4Smrg
3337117f1b4Smrg   return bytesPerRow;
3347117f1b4Smrg}
3357117f1b4Smrg
3367117f1b4Smrg
3377117f1b4Smrg/*
3387117f1b4Smrg * Compute the stride between images in a 3D texture (in bytes) for the given
3397117f1b4Smrg * pixel packing parameters and image width, format and type.
3407117f1b4Smrg */
3417117f1b4SmrgGLint
3427117f1b4Smrg_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing,
3437117f1b4Smrg                          GLint width, GLint height,
3447117f1b4Smrg                          GLenum format, GLenum type )
3457117f1b4Smrg{
346c7037ccdSmrg   GLint bytesPerRow, bytesPerImage, remainder;
347c7037ccdSmrg
34801e04c3fSmrg   assert(packing);
3497117f1b4Smrg
350c7037ccdSmrg   if (type == GL_BITMAP) {
351c7037ccdSmrg      if (packing->RowLength == 0) {
352c7037ccdSmrg         bytesPerRow = (width + 7) / 8;
353c7037ccdSmrg      }
354c7037ccdSmrg      else {
355c7037ccdSmrg         bytesPerRow = (packing->RowLength + 7) / 8;
356c7037ccdSmrg      }
357c7037ccdSmrg   }
358c7037ccdSmrg   else {
3597117f1b4Smrg      const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
3607117f1b4Smrg
3617117f1b4Smrg      if (bytesPerPixel <= 0)
3627117f1b4Smrg         return -1;  /* error */
3637117f1b4Smrg      if (packing->RowLength == 0) {
3647117f1b4Smrg         bytesPerRow = bytesPerPixel * width;
3657117f1b4Smrg      }
3667117f1b4Smrg      else {
3677117f1b4Smrg         bytesPerRow = bytesPerPixel * packing->RowLength;
3687117f1b4Smrg      }
369c7037ccdSmrg   }
3707117f1b4Smrg
371c7037ccdSmrg   remainder = bytesPerRow % packing->Alignment;
372c7037ccdSmrg   if (remainder > 0)
373c7037ccdSmrg      bytesPerRow += (packing->Alignment - remainder);
3747117f1b4Smrg
375c7037ccdSmrg   if (packing->ImageHeight == 0)
376c7037ccdSmrg      bytesPerImage = bytesPerRow * height;
377c7037ccdSmrg   else
378c7037ccdSmrg      bytesPerImage = bytesPerRow * packing->ImageHeight;
379c7037ccdSmrg
380c7037ccdSmrg   return bytesPerImage;
3817117f1b4Smrg}
3827117f1b4Smrg
3837117f1b4Smrg
3847117f1b4Smrg
3854a49301eSmrg/**
3864a49301eSmrg * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel.
3874a49301eSmrg * This is typically used to convert a bitmap into a GLubyte/pixel texture.
3884a49301eSmrg * "On" bits will set texels to \p onValue.
3894a49301eSmrg * "Off" bits will not modify texels.
3904a49301eSmrg * \param width  src bitmap width in pixels
3914a49301eSmrg * \param height  src bitmap height in pixels
3924a49301eSmrg * \param unpack  bitmap unpacking state
3934a49301eSmrg * \param bitmap  the src bitmap data
3944a49301eSmrg * \param destBuffer  start of dest buffer
3954a49301eSmrg * \param destStride  row stride in dest buffer
3964a49301eSmrg * \param onValue  if bit is 1, set destBuffer pixel to this value
3974a49301eSmrg */
3984a49301eSmrgvoid
3994a49301eSmrg_mesa_expand_bitmap(GLsizei width, GLsizei height,
4004a49301eSmrg                    const struct gl_pixelstore_attrib *unpack,
4014a49301eSmrg                    const GLubyte *bitmap,
4024a49301eSmrg                    GLubyte *destBuffer, GLint destStride,
4034a49301eSmrg                    GLubyte onValue)
4044a49301eSmrg{
4054a49301eSmrg   const GLubyte *srcRow = (const GLubyte *)
4064a49301eSmrg      _mesa_image_address2d(unpack, bitmap, width, height,
4074a49301eSmrg                            GL_COLOR_INDEX, GL_BITMAP, 0, 0);
4084a49301eSmrg   const GLint srcStride = _mesa_image_row_stride(unpack, width,
4094a49301eSmrg                                                  GL_COLOR_INDEX, GL_BITMAP);
4104a49301eSmrg   GLint row, col;
41101e04c3fSmrg   GLubyte *dstRow = destBuffer;
4124a49301eSmrg
4134a49301eSmrg   for (row = 0; row < height; row++) {
4144a49301eSmrg      const GLubyte *src = srcRow;
4154a49301eSmrg
4164a49301eSmrg      if (unpack->LsbFirst) {
4174a49301eSmrg         /* Lsb first */
4184a49301eSmrg         GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
4194a49301eSmrg         for (col = 0; col < width; col++) {
4204a49301eSmrg
4214a49301eSmrg            if (*src & mask) {
42201e04c3fSmrg               dstRow[col] = onValue;
4234a49301eSmrg            }
4244a49301eSmrg
4254a49301eSmrg            if (mask == 128U) {
4264a49301eSmrg               src++;
4274a49301eSmrg               mask = 1U;
4284a49301eSmrg            }
4294a49301eSmrg            else {
4304a49301eSmrg               mask = mask << 1;
4314a49301eSmrg            }
4324a49301eSmrg         }
4334a49301eSmrg
4344a49301eSmrg         /* get ready for next row */
4354a49301eSmrg         if (mask != 1)
4364a49301eSmrg            src++;
4374a49301eSmrg      }
4384a49301eSmrg      else {
4394a49301eSmrg         /* Msb first */
4404a49301eSmrg         GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
4414a49301eSmrg         for (col = 0; col < width; col++) {
4424a49301eSmrg
4434a49301eSmrg            if (*src & mask) {
44401e04c3fSmrg               dstRow[col] = onValue;
4454a49301eSmrg            }
4464a49301eSmrg
4474a49301eSmrg            if (mask == 1U) {
4484a49301eSmrg               src++;
4494a49301eSmrg               mask = 128U;
4504a49301eSmrg            }
4514a49301eSmrg            else {
4524a49301eSmrg               mask = mask >> 1;
4534a49301eSmrg            }
4544a49301eSmrg         }
4554a49301eSmrg
4564a49301eSmrg         /* get ready for next row */
4574a49301eSmrg         if (mask != 128)
4584a49301eSmrg            src++;
4594a49301eSmrg      }
4604a49301eSmrg
4614a49301eSmrg      srcRow += srcStride;
46201e04c3fSmrg      dstRow += destStride;
4634a49301eSmrg   } /* row */
4644a49301eSmrg}
4654a49301eSmrg
4664a49301eSmrg
467c1f859d4Smrg
468c1f859d4Smrg
469c1f859d4Smrg/**
4703464ebd5Sriastradh * Convert an array of RGBA colors from one datatype to another.
4713464ebd5Sriastradh * NOTE: src may equal dst.  In that case, we use a temporary buffer.
472c1f859d4Smrg */
473c1f859d4Smrgvoid
4743464ebd5Sriastradh_mesa_convert_colors(GLenum srcType, const GLvoid *src,
4753464ebd5Sriastradh                     GLenum dstType, GLvoid *dst,
4763464ebd5Sriastradh                     GLuint count, const GLubyte mask[])
477c1f859d4Smrg{
478af69d88dSmrg   GLuint *tempBuffer;
4793464ebd5Sriastradh   const GLboolean useTemp = (src == dst);
480c1f859d4Smrg
481af69d88dSmrg   tempBuffer = malloc(count * MAX_PIXEL_BYTES);
482af69d88dSmrg   if (!tempBuffer)
483af69d88dSmrg      return;
484af69d88dSmrg
48501e04c3fSmrg   assert(srcType != dstType);
4867117f1b4Smrg
4877117f1b4Smrg   switch (srcType) {
4887117f1b4Smrg   case GL_UNSIGNED_BYTE:
4897117f1b4Smrg      if (dstType == GL_UNSIGNED_SHORT) {
4907117f1b4Smrg         const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
4917117f1b4Smrg         GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
4927117f1b4Smrg         GLuint i;
4937117f1b4Smrg         for (i = 0; i < count; i++) {
4947117f1b4Smrg            if (!mask || mask[i]) {
4957117f1b4Smrg               dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]);
4967117f1b4Smrg               dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]);
4977117f1b4Smrg               dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]);
4987117f1b4Smrg               dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]);
4997117f1b4Smrg            }
5007117f1b4Smrg         }
5017117f1b4Smrg         if (useTemp)
502cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
5037117f1b4Smrg      }
5047117f1b4Smrg      else {
5057117f1b4Smrg         const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
5067117f1b4Smrg         GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
5077117f1b4Smrg         GLuint i;
50801e04c3fSmrg         assert(dstType == GL_FLOAT);
5097117f1b4Smrg         for (i = 0; i < count; i++) {
5107117f1b4Smrg            if (!mask || mask[i]) {
5117117f1b4Smrg               dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]);
5127117f1b4Smrg               dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]);
5137117f1b4Smrg               dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]);
5147117f1b4Smrg               dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]);
5157117f1b4Smrg            }
5167117f1b4Smrg         }
5177117f1b4Smrg         if (useTemp)
518cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
5197117f1b4Smrg      }
5207117f1b4Smrg      break;
5217117f1b4Smrg   case GL_UNSIGNED_SHORT:
5227117f1b4Smrg      if (dstType == GL_UNSIGNED_BYTE) {
5237117f1b4Smrg         const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
5247117f1b4Smrg         GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
5257117f1b4Smrg         GLuint i;
5267117f1b4Smrg         for (i = 0; i < count; i++) {
5277117f1b4Smrg            if (!mask || mask[i]) {
5287117f1b4Smrg               dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]);
5297117f1b4Smrg               dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]);
5307117f1b4Smrg               dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]);
5317117f1b4Smrg               dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]);
5327117f1b4Smrg            }
5337117f1b4Smrg         }
5347117f1b4Smrg         if (useTemp)
535cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
5367117f1b4Smrg      }
5377117f1b4Smrg      else {
5387117f1b4Smrg         const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
5397117f1b4Smrg         GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
5407117f1b4Smrg         GLuint i;
54101e04c3fSmrg         assert(dstType == GL_FLOAT);
5427117f1b4Smrg         for (i = 0; i < count; i++) {
5437117f1b4Smrg            if (!mask || mask[i]) {
5447117f1b4Smrg               dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]);
5457117f1b4Smrg               dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]);
5467117f1b4Smrg               dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]);
5477117f1b4Smrg               dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]);
5487117f1b4Smrg            }
5497117f1b4Smrg         }
5507117f1b4Smrg         if (useTemp)
551cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
5527117f1b4Smrg      }
5537117f1b4Smrg      break;
5547117f1b4Smrg   case GL_FLOAT:
5557117f1b4Smrg      if (dstType == GL_UNSIGNED_BYTE) {
5567117f1b4Smrg         const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
5577117f1b4Smrg         GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
5587117f1b4Smrg         GLuint i;
5597117f1b4Smrg         for (i = 0; i < count; i++) {
560af69d88dSmrg            if (!mask || mask[i])
561af69d88dSmrg               _mesa_unclamped_float_rgba_to_ubyte(dst1[i], src4[i]);
5627117f1b4Smrg         }
5637117f1b4Smrg         if (useTemp)
564cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
5657117f1b4Smrg      }
5667117f1b4Smrg      else {
5677117f1b4Smrg         const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
5687117f1b4Smrg         GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
5697117f1b4Smrg         GLuint i;
57001e04c3fSmrg         assert(dstType == GL_UNSIGNED_SHORT);
5717117f1b4Smrg         for (i = 0; i < count; i++) {
5727117f1b4Smrg            if (!mask || mask[i]) {
5737117f1b4Smrg               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]);
5747117f1b4Smrg               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]);
5757117f1b4Smrg               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]);
5767117f1b4Smrg               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]);
5777117f1b4Smrg            }
5787117f1b4Smrg         }
5797117f1b4Smrg         if (useTemp)
580cdc920a0Smrg            memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
5817117f1b4Smrg      }
5827117f1b4Smrg      break;
5837117f1b4Smrg   default:
58401e04c3fSmrg      unreachable("Invalid datatype in _mesa_convert_colors");
5857117f1b4Smrg   }
586af69d88dSmrg
587af69d88dSmrg   free(tempBuffer);
5887117f1b4Smrg}
5897117f1b4Smrg
5907117f1b4Smrg
5917117f1b4Smrg
5927117f1b4Smrg
5937117f1b4Smrg/**
5947117f1b4Smrg * Perform basic clipping for glDrawPixels.  The image's position and size
5957117f1b4Smrg * and the unpack SkipPixels and SkipRows are adjusted so that the image
5967117f1b4Smrg * region is entirely within the window and scissor bounds.
5977117f1b4Smrg * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1).
5987117f1b4Smrg * If Pixel.ZoomY is -1, *destY will be changed to be the first row which
5997117f1b4Smrg * we'll actually write.  Beforehand, *destY-1 is the first drawing row.
6007117f1b4Smrg *
6017117f1b4Smrg * \return  GL_TRUE if image is ready for drawing or
6027117f1b4Smrg *          GL_FALSE if image was completely clipped away (draw nothing)
6037117f1b4Smrg */
6047117f1b4SmrgGLboolean
6053464ebd5Sriastradh_mesa_clip_drawpixels(const struct gl_context *ctx,
6067117f1b4Smrg                      GLint *destX, GLint *destY,
6077117f1b4Smrg                      GLsizei *width, GLsizei *height,
6087117f1b4Smrg                      struct gl_pixelstore_attrib *unpack)
6097117f1b4Smrg{
6103464ebd5Sriastradh   const struct gl_framebuffer *buffer = ctx->DrawBuffer;
6117117f1b4Smrg
6127117f1b4Smrg   if (unpack->RowLength == 0) {
6137117f1b4Smrg      unpack->RowLength = *width;
6147117f1b4Smrg   }
6157117f1b4Smrg
61601e04c3fSmrg   assert(ctx->Pixel.ZoomX == 1.0F);
61701e04c3fSmrg   assert(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F);
6187117f1b4Smrg
6197117f1b4Smrg   /* left clipping */
6207117f1b4Smrg   if (*destX < buffer->_Xmin) {
6217117f1b4Smrg      unpack->SkipPixels += (buffer->_Xmin - *destX);
6227117f1b4Smrg      *width -= (buffer->_Xmin - *destX);
6237117f1b4Smrg      *destX = buffer->_Xmin;
6247117f1b4Smrg   }
6257117f1b4Smrg   /* right clipping */
6267117f1b4Smrg   if (*destX + *width > buffer->_Xmax)
6277117f1b4Smrg      *width -= (*destX + *width - buffer->_Xmax);
6287117f1b4Smrg
6297117f1b4Smrg   if (*width <= 0)
6307117f1b4Smrg      return GL_FALSE;
6317117f1b4Smrg
6327117f1b4Smrg   if (ctx->Pixel.ZoomY == 1.0F) {
6337117f1b4Smrg      /* bottom clipping */
6347117f1b4Smrg      if (*destY < buffer->_Ymin) {
6357117f1b4Smrg         unpack->SkipRows += (buffer->_Ymin - *destY);
6367117f1b4Smrg         *height -= (buffer->_Ymin - *destY);
6377117f1b4Smrg         *destY = buffer->_Ymin;
6387117f1b4Smrg      }
6397117f1b4Smrg      /* top clipping */
6407117f1b4Smrg      if (*destY + *height > buffer->_Ymax)
6417117f1b4Smrg         *height -= (*destY + *height - buffer->_Ymax);
6427117f1b4Smrg   }
6437117f1b4Smrg   else { /* upside down */
6447117f1b4Smrg      /* top clipping */
6457117f1b4Smrg      if (*destY > buffer->_Ymax) {
6467117f1b4Smrg         unpack->SkipRows += (*destY - buffer->_Ymax);
6477117f1b4Smrg         *height -= (*destY - buffer->_Ymax);
6487117f1b4Smrg         *destY = buffer->_Ymax;
6497117f1b4Smrg      }
6507117f1b4Smrg      /* bottom clipping */
6517117f1b4Smrg      if (*destY - *height < buffer->_Ymin)
6527117f1b4Smrg         *height -= (buffer->_Ymin - (*destY - *height));
6537117f1b4Smrg      /* adjust destY so it's the first row to write to */
6547117f1b4Smrg      (*destY)--;
6557117f1b4Smrg   }
6567117f1b4Smrg
6577117f1b4Smrg   if (*height <= 0)
6584a49301eSmrg      return GL_FALSE;
6597117f1b4Smrg
6607117f1b4Smrg   return GL_TRUE;
6617117f1b4Smrg}
6627117f1b4Smrg
6637117f1b4Smrg
6647117f1b4Smrg/**
6657117f1b4Smrg * Perform clipping for glReadPixels.  The image's window position
6667117f1b4Smrg * and size, and the pack skipPixels, skipRows and rowLength are adjusted
6677117f1b4Smrg * so that the image region is entirely within the window bounds.
6687117f1b4Smrg * Note: this is different from _mesa_clip_drawpixels() in that the
6697117f1b4Smrg * scissor box is ignored, and we use the bounds of the current readbuffer
67001e04c3fSmrg * surface or the attached image.
6717117f1b4Smrg *
6723464ebd5Sriastradh * \return  GL_TRUE if region to read is in bounds
6733464ebd5Sriastradh *          GL_FALSE if region is completely out of bounds (nothing to read)
6747117f1b4Smrg */
6757117f1b4SmrgGLboolean
6763464ebd5Sriastradh_mesa_clip_readpixels(const struct gl_context *ctx,
6777117f1b4Smrg                      GLint *srcX, GLint *srcY,
6787117f1b4Smrg                      GLsizei *width, GLsizei *height,
6797117f1b4Smrg                      struct gl_pixelstore_attrib *pack)
6807117f1b4Smrg{
6813464ebd5Sriastradh   const struct gl_framebuffer *buffer = ctx->ReadBuffer;
68201e04c3fSmrg   struct gl_renderbuffer *rb = buffer->_ColorReadBuffer;
68301e04c3fSmrg   GLsizei clip_width;
68401e04c3fSmrg   GLsizei clip_height;
68501e04c3fSmrg
68601e04c3fSmrg   if (rb) {
68701e04c3fSmrg      clip_width = rb->Width;
68801e04c3fSmrg      clip_height = rb->Height;
68901e04c3fSmrg   } else {
69001e04c3fSmrg      clip_width = buffer->Width;
69101e04c3fSmrg      clip_height = buffer->Height;
69201e04c3fSmrg   }
69301e04c3fSmrg
6947117f1b4Smrg
6957117f1b4Smrg   if (pack->RowLength == 0) {
6967117f1b4Smrg      pack->RowLength = *width;
6977117f1b4Smrg   }
6987117f1b4Smrg
6997117f1b4Smrg   /* left clipping */
7007117f1b4Smrg   if (*srcX < 0) {
7017117f1b4Smrg      pack->SkipPixels += (0 - *srcX);
7027117f1b4Smrg      *width -= (0 - *srcX);
7037117f1b4Smrg      *srcX = 0;
7047117f1b4Smrg   }
7057117f1b4Smrg   /* right clipping */
70601e04c3fSmrg   if (*srcX + *width > clip_width)
70701e04c3fSmrg      *width -= (*srcX + *width - clip_width);
7087117f1b4Smrg
7097117f1b4Smrg   if (*width <= 0)
7107117f1b4Smrg      return GL_FALSE;
7117117f1b4Smrg
7127117f1b4Smrg   /* bottom clipping */
7137117f1b4Smrg   if (*srcY < 0) {
7147117f1b4Smrg      pack->SkipRows += (0 - *srcY);
7157117f1b4Smrg      *height -= (0 - *srcY);
7167117f1b4Smrg      *srcY = 0;
7177117f1b4Smrg   }
7187117f1b4Smrg   /* top clipping */
71901e04c3fSmrg   if (*srcY + *height > clip_height)
72001e04c3fSmrg      *height -= (*srcY + *height - clip_height);
7217117f1b4Smrg
7227117f1b4Smrg   if (*height <= 0)
7234a49301eSmrg      return GL_FALSE;
7247117f1b4Smrg
7257117f1b4Smrg   return GL_TRUE;
7267117f1b4Smrg}
7277117f1b4Smrg
7287117f1b4Smrg
729c1f859d4Smrg/**
730c1f859d4Smrg * Do clipping for a glCopyTexSubImage call.
731c1f859d4Smrg * The framebuffer source region might extend outside the framebuffer
732c1f859d4Smrg * bounds.  Clip the source region against the framebuffer bounds and
733c1f859d4Smrg * adjust the texture/dest position and size accordingly.
734c1f859d4Smrg *
735c1f859d4Smrg * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise.
736c1f859d4Smrg */
737c1f859d4SmrgGLboolean
7383464ebd5Sriastradh_mesa_clip_copytexsubimage(const struct gl_context *ctx,
739c1f859d4Smrg                           GLint *destX, GLint *destY,
740c1f859d4Smrg                           GLint *srcX, GLint *srcY,
741c1f859d4Smrg                           GLsizei *width, GLsizei *height)
742c1f859d4Smrg{
743c1f859d4Smrg   const struct gl_framebuffer *fb = ctx->ReadBuffer;
744c1f859d4Smrg   const GLint srcX0 = *srcX, srcY0 = *srcY;
745c1f859d4Smrg
746c1f859d4Smrg   if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height,
747c1f859d4Smrg                            srcX, srcY, width, height)) {
748c1f859d4Smrg      *destX = *destX + *srcX - srcX0;
749c1f859d4Smrg      *destY = *destY + *srcY - srcY0;
750c1f859d4Smrg
751c1f859d4Smrg      return GL_TRUE;
752c1f859d4Smrg   }
753c1f859d4Smrg   else {
754c1f859d4Smrg      return GL_FALSE;
755c1f859d4Smrg   }
756c1f859d4Smrg}
757c1f859d4Smrg
758c1f859d4Smrg
759c1f859d4Smrg
7607117f1b4Smrg/**
7617117f1b4Smrg * Clip the rectangle defined by (x, y, width, height) against the bounds
7627117f1b4Smrg * specified by [xmin, xmax) and [ymin, ymax).
7637117f1b4Smrg * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise.
7647117f1b4Smrg */
7657117f1b4SmrgGLboolean
7667117f1b4Smrg_mesa_clip_to_region(GLint xmin, GLint ymin,
7677117f1b4Smrg                     GLint xmax, GLint ymax,
7687117f1b4Smrg                     GLint *x, GLint *y,
7697117f1b4Smrg                     GLsizei *width, GLsizei *height )
7707117f1b4Smrg{
7717117f1b4Smrg   /* left clipping */
7727117f1b4Smrg   if (*x < xmin) {
7737117f1b4Smrg      *width -= (xmin - *x);
7747117f1b4Smrg      *x = xmin;
7757117f1b4Smrg   }
7767117f1b4Smrg
7777117f1b4Smrg   /* right clipping */
7787117f1b4Smrg   if (*x + *width > xmax)
779c1f859d4Smrg      *width -= (*x + *width - xmax);
7807117f1b4Smrg
7817117f1b4Smrg   if (*width <= 0)
7827117f1b4Smrg      return GL_FALSE;
7837117f1b4Smrg
7847117f1b4Smrg   /* bottom (or top) clipping */
7857117f1b4Smrg   if (*y < ymin) {
7867117f1b4Smrg      *height -= (ymin - *y);
7877117f1b4Smrg      *y = ymin;
7887117f1b4Smrg   }
7897117f1b4Smrg
7907117f1b4Smrg   /* top (or bottom) clipping */
7917117f1b4Smrg   if (*y + *height > ymax)
792c1f859d4Smrg      *height -= (*y + *height - ymax);
7937117f1b4Smrg
7947117f1b4Smrg   if (*height <= 0)
7957117f1b4Smrg      return GL_FALSE;
7967117f1b4Smrg
7977117f1b4Smrg   return GL_TRUE;
7987117f1b4Smrg}
7994a49301eSmrg
8004a49301eSmrg
8014a49301eSmrg/**
8024a49301eSmrg * Clip dst coords against Xmax (or Ymax).
8034a49301eSmrg */
804af69d88dSmrgstatic inline void
8054a49301eSmrgclip_right_or_top(GLint *srcX0, GLint *srcX1,
8064a49301eSmrg                  GLint *dstX0, GLint *dstX1,
8074a49301eSmrg                  GLint maxValue)
8084a49301eSmrg{
8094a49301eSmrg   GLfloat t, bias;
8104a49301eSmrg
8114a49301eSmrg   if (*dstX1 > maxValue) {
8124a49301eSmrg      /* X1 outside right edge */
81301e04c3fSmrg      assert(*dstX0 < maxValue); /* X0 should be inside right edge */
8144a49301eSmrg      t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
8154a49301eSmrg      /* chop off [t, 1] part */
81601e04c3fSmrg      assert(t >= 0.0 && t <= 1.0);
8174a49301eSmrg      *dstX1 = maxValue;
818cdc920a0Smrg      bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
8194a49301eSmrg      *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
8204a49301eSmrg   }
8214a49301eSmrg   else if (*dstX0 > maxValue) {
8224a49301eSmrg      /* X0 outside right edge */
82301e04c3fSmrg      assert(*dstX1 < maxValue); /* X1 should be inside right edge */
8244a49301eSmrg      t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
8254a49301eSmrg      /* chop off [t, 1] part */
82601e04c3fSmrg      assert(t >= 0.0 && t <= 1.0);
8274a49301eSmrg      *dstX0 = maxValue;
828cdc920a0Smrg      bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
8294a49301eSmrg      *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
8304a49301eSmrg   }
8314a49301eSmrg}
8324a49301eSmrg
8334a49301eSmrg
8344a49301eSmrg/**
8354a49301eSmrg * Clip dst coords against Xmin (or Ymin).
8364a49301eSmrg */
837af69d88dSmrgstatic inline void
8384a49301eSmrgclip_left_or_bottom(GLint *srcX0, GLint *srcX1,
8394a49301eSmrg                    GLint *dstX0, GLint *dstX1,
8404a49301eSmrg                    GLint minValue)
8414a49301eSmrg{
8424a49301eSmrg   GLfloat t, bias;
8434a49301eSmrg
8444a49301eSmrg   if (*dstX0 < minValue) {
8454a49301eSmrg      /* X0 outside left edge */
84601e04c3fSmrg      assert(*dstX1 > minValue); /* X1 should be inside left edge */
8474a49301eSmrg      t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
8484a49301eSmrg      /* chop off [0, t] part */
84901e04c3fSmrg      assert(t >= 0.0 && t <= 1.0);
8504a49301eSmrg      *dstX0 = minValue;
851af69d88dSmrg      bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
8524a49301eSmrg      *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
8534a49301eSmrg   }
8544a49301eSmrg   else if (*dstX1 < minValue) {
8554a49301eSmrg      /* X1 outside left edge */
85601e04c3fSmrg      assert(*dstX0 > minValue); /* X0 should be inside left edge */
8574a49301eSmrg      t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
8584a49301eSmrg      /* chop off [0, t] part */
85901e04c3fSmrg      assert(t >= 0.0 && t <= 1.0);
8604a49301eSmrg      *dstX1 = minValue;
861af69d88dSmrg      bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
8624a49301eSmrg      *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
8634a49301eSmrg   }
8644a49301eSmrg}
8654a49301eSmrg
8664a49301eSmrg
8674a49301eSmrg/**
8684a49301eSmrg * Do clipping of blit src/dest rectangles.
8694a49301eSmrg * The dest rect is clipped against both the buffer bounds and scissor bounds.
8704a49301eSmrg * The src rect is just clipped against the buffer bounds.
8714a49301eSmrg *
8724a49301eSmrg * When either the src or dest rect is clipped, the other is also clipped
8734a49301eSmrg * proportionately!
8744a49301eSmrg *
8754a49301eSmrg * Note that X0 need not be less than X1 (same for Y) for either the source
8764a49301eSmrg * and dest rects.  That makes the clipping a little trickier.
8774a49301eSmrg *
8784a49301eSmrg * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
8794a49301eSmrg */
8804a49301eSmrgGLboolean
8813464ebd5Sriastradh_mesa_clip_blit(struct gl_context *ctx,
88201e04c3fSmrg                const struct gl_framebuffer *readFb,
88301e04c3fSmrg                const struct gl_framebuffer *drawFb,
8844a49301eSmrg                GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
8854a49301eSmrg                GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
8864a49301eSmrg{
8874a49301eSmrg   const GLint srcXmin = 0;
88801e04c3fSmrg   const GLint srcXmax = readFb->Width;
8894a49301eSmrg   const GLint srcYmin = 0;
89001e04c3fSmrg   const GLint srcYmax = readFb->Height;
8914a49301eSmrg
8924a49301eSmrg   /* these include scissor bounds */
89301e04c3fSmrg   const GLint dstXmin = drawFb->_Xmin;
89401e04c3fSmrg   const GLint dstXmax = drawFb->_Xmax;
89501e04c3fSmrg   const GLint dstYmin = drawFb->_Ymin;
89601e04c3fSmrg   const GLint dstYmax = drawFb->_Ymax;
8974a49301eSmrg
8984a49301eSmrg   /*
8994a49301eSmrg   printf("PreClipX:  src: %d .. %d  dst: %d .. %d\n",
9004a49301eSmrg          *srcX0, *srcX1, *dstX0, *dstX1);
9014a49301eSmrg   printf("PreClipY:  src: %d .. %d  dst: %d .. %d\n",
9024a49301eSmrg          *srcY0, *srcY1, *dstY0, *dstY1);
9034a49301eSmrg   */
9044a49301eSmrg
9054a49301eSmrg   /* trivial rejection tests */
9064a49301eSmrg   if (*dstX0 == *dstX1)
9074a49301eSmrg      return GL_FALSE; /* no width */
9084a49301eSmrg   if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
9094a49301eSmrg      return GL_FALSE; /* totally out (left) of bounds */
9104a49301eSmrg   if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
9114a49301eSmrg      return GL_FALSE; /* totally out (right) of bounds */
9124a49301eSmrg
9134a49301eSmrg   if (*dstY0 == *dstY1)
9144a49301eSmrg      return GL_FALSE;
9154a49301eSmrg   if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
9164a49301eSmrg      return GL_FALSE;
9174a49301eSmrg   if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
9184a49301eSmrg      return GL_FALSE;
9194a49301eSmrg
9204a49301eSmrg   if (*srcX0 == *srcX1)
9214a49301eSmrg      return GL_FALSE;
9224a49301eSmrg   if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
9234a49301eSmrg      return GL_FALSE;
9244a49301eSmrg   if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
9254a49301eSmrg      return GL_FALSE;
9264a49301eSmrg
9274a49301eSmrg   if (*srcY0 == *srcY1)
9284a49301eSmrg      return GL_FALSE;
9294a49301eSmrg   if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
9304a49301eSmrg      return GL_FALSE;
9314a49301eSmrg   if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
9324a49301eSmrg      return GL_FALSE;
9334a49301eSmrg
9344a49301eSmrg   /*
9354a49301eSmrg    * dest clip
9364a49301eSmrg    */
9374a49301eSmrg   clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
9384a49301eSmrg   clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
9394a49301eSmrg   clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
9404a49301eSmrg   clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
9414a49301eSmrg
9424a49301eSmrg   /*
9434a49301eSmrg    * src clip (just swap src/dst values from above)
9444a49301eSmrg    */
9454a49301eSmrg   clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
9464a49301eSmrg   clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
9474a49301eSmrg   clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
9484a49301eSmrg   clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
9494a49301eSmrg
9504a49301eSmrg   /*
9514a49301eSmrg   printf("PostClipX: src: %d .. %d  dst: %d .. %d\n",
9524a49301eSmrg          *srcX0, *srcX1, *dstX0, *dstX1);
9534a49301eSmrg   printf("PostClipY: src: %d .. %d  dst: %d .. %d\n",
9544a49301eSmrg          *srcY0, *srcY1, *dstY0, *dstY1);
9554a49301eSmrg   */
9564a49301eSmrg
95701e04c3fSmrg   assert(*dstX0 >= dstXmin);
95801e04c3fSmrg   assert(*dstX0 <= dstXmax);
95901e04c3fSmrg   assert(*dstX1 >= dstXmin);
96001e04c3fSmrg   assert(*dstX1 <= dstXmax);
9614a49301eSmrg
96201e04c3fSmrg   assert(*dstY0 >= dstYmin);
96301e04c3fSmrg   assert(*dstY0 <= dstYmax);
96401e04c3fSmrg   assert(*dstY1 >= dstYmin);
96501e04c3fSmrg   assert(*dstY1 <= dstYmax);
9664a49301eSmrg
96701e04c3fSmrg   assert(*srcX0 >= srcXmin);
96801e04c3fSmrg   assert(*srcX0 <= srcXmax);
96901e04c3fSmrg   assert(*srcX1 >= srcXmin);
97001e04c3fSmrg   assert(*srcX1 <= srcXmax);
9714a49301eSmrg
97201e04c3fSmrg   assert(*srcY0 >= srcYmin);
97301e04c3fSmrg   assert(*srcY0 <= srcYmax);
97401e04c3fSmrg   assert(*srcY1 >= srcYmin);
97501e04c3fSmrg   assert(*srcY1 <= srcYmax);
9764a49301eSmrg
9774a49301eSmrg   return GL_TRUE;
9784a49301eSmrg}
97901e04c3fSmrg
98001e04c3fSmrg/**
98101e04c3fSmrg * Swap the bytes in a 2D image.
98201e04c3fSmrg *
98301e04c3fSmrg * using the packing information this swaps the bytes
98401e04c3fSmrg * according to the format and type of data being input.
98501e04c3fSmrg * It takes into a/c various packing parameters like
98601e04c3fSmrg * Alignment and RowLength.
98701e04c3fSmrg */
98801e04c3fSmrgvoid
98901e04c3fSmrg_mesa_swap_bytes_2d_image(GLenum format, GLenum type,
99001e04c3fSmrg                          const struct gl_pixelstore_attrib *packing,
99101e04c3fSmrg                          GLsizei width, GLsizei height,
99201e04c3fSmrg                          GLvoid *dst, const GLvoid *src)
99301e04c3fSmrg{
99401e04c3fSmrg   GLint swapSize = _mesa_sizeof_packed_type(type);
99501e04c3fSmrg
99601e04c3fSmrg   assert(packing->SwapBytes);
99701e04c3fSmrg
99801e04c3fSmrg   if (swapSize == 2 || swapSize == 4) {
99901e04c3fSmrg      int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize;
100001e04c3fSmrg      int stride = _mesa_image_row_stride(packing, width, format, type);
100101e04c3fSmrg      int row;
100201e04c3fSmrg      uint8_t *dstrow;
100301e04c3fSmrg      const uint8_t *srcrow;
100401e04c3fSmrg      assert(swapsPerPixel > 0);
100501e04c3fSmrg      assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0);
100601e04c3fSmrg      dstrow = dst;
100701e04c3fSmrg      srcrow = src;
100801e04c3fSmrg      for (row = 0; row < height; row++) {
100901e04c3fSmrg         if (swapSize == 2)
101001e04c3fSmrg            swap2_copy((GLushort *)dstrow, (GLushort *)srcrow, width * swapsPerPixel);
101101e04c3fSmrg         else if (swapSize == 4)
101201e04c3fSmrg            swap4_copy((GLuint *)dstrow, (GLuint *)srcrow, width * swapsPerPixel);
101301e04c3fSmrg         dstrow += stride;
101401e04c3fSmrg         srcrow += stride;
101501e04c3fSmrg      }
101601e04c3fSmrg   }
101701e04c3fSmrg}
1018