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