/* * Mesa 3-D graphics library * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THEA AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * \file pack.c * Image and pixel span packing and unpacking. */ #include "glheader.h" #include "colormac.h" #include "enums.h" #include "image.h" #include "imports.h" #include "macros.h" #include "mtypes.h" #include "pack.h" #include "pixeltransfer.h" #include "imports.h" #include "../../gallium/auxiliary/util/u_format_rgb9e5.h" #include "../../gallium/auxiliary/util/u_format_r11g11b10f.h" /** * Flip the 8 bits in each byte of the given array. * * \param p array. * \param n number of bytes. * * \todo try this trick to flip bytes someday: * \code * v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); * v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); * v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); * \endcode */ static void flip_bytes( GLubyte *p, GLuint n ) { GLuint i, a, b; for (i = 0; i < n; i++) { b = (GLuint) p[i]; /* words are often faster than bytes */ a = ((b & 0x01) << 7) | ((b & 0x02) << 5) | ((b & 0x04) << 3) | ((b & 0x08) << 1) | ((b & 0x10) >> 1) | ((b & 0x20) >> 3) | ((b & 0x40) >> 5) | ((b & 0x80) >> 7); p[i] = (GLubyte) a; } } /* * Unpack a 32x32 pixel polygon stipple from user memory using the * current pixel unpack settings. */ void _mesa_unpack_polygon_stipple( const GLubyte *pattern, GLuint dest[32], const struct gl_pixelstore_attrib *unpacking ) { GLubyte *ptrn = (GLubyte *) _mesa_unpack_bitmap(32, 32, pattern, unpacking); if (ptrn) { /* Convert pattern from GLubytes to GLuints and handle big/little * endian differences */ GLubyte *p = ptrn; GLint i; for (i = 0; i < 32; i++) { dest[i] = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] ); p += 4; } free(ptrn); } } /* * Pack polygon stipple into user memory given current pixel packing * settings. */ void _mesa_pack_polygon_stipple( const GLuint pattern[32], GLubyte *dest, const struct gl_pixelstore_attrib *packing ) { /* Convert pattern from GLuints to GLubytes to handle big/little * endian differences. */ GLubyte ptrn[32*4]; GLint i; for (i = 0; i < 32; i++) { ptrn[i * 4 + 0] = (GLubyte) ((pattern[i] >> 24) & 0xff); ptrn[i * 4 + 1] = (GLubyte) ((pattern[i] >> 16) & 0xff); ptrn[i * 4 + 2] = (GLubyte) ((pattern[i] >> 8 ) & 0xff); ptrn[i * 4 + 3] = (GLubyte) ((pattern[i] ) & 0xff); } _mesa_pack_bitmap(32, 32, ptrn, dest, packing); } /* * Unpack bitmap data. Resulting data will be in most-significant-bit-first * order with row alignment = 1 byte. */ GLvoid * _mesa_unpack_bitmap( GLint width, GLint height, const GLubyte *pixels, const struct gl_pixelstore_attrib *packing ) { GLint bytes, row, width_in_bytes; GLubyte *buffer, *dst; if (!pixels) return NULL; /* Alloc dest storage */ bytes = ((width + 7) / 8 * height); buffer = (GLubyte *) malloc( bytes ); if (!buffer) return NULL; width_in_bytes = CEILING( width, 8 ); dst = buffer; for (row = 0; row < height; row++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (!src) { free(buffer); return NULL; } if ((packing->SkipPixels & 7) == 0) { memcpy( dst, src, width_in_bytes ); if (packing->LsbFirst) { flip_bytes( dst, width_in_bytes ); } } else { /* handling SkipPixels is a bit tricky (no pun intended!) */ GLint i; if (packing->LsbFirst) { GLubyte srcMask = 1 << (packing->SkipPixels & 0x7); GLubyte dstMask = 128; const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 128) { srcMask = 1; s++; } else { srcMask = srcMask << 1; } if (dstMask == 1) { dstMask = 128; d++; *d = 0; } else { dstMask = dstMask >> 1; } } } else { GLubyte srcMask = 128 >> (packing->SkipPixels & 0x7); GLubyte dstMask = 128; const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 1) { srcMask = 128; s++; } else { srcMask = srcMask >> 1; } if (dstMask == 1) { dstMask = 128; d++; *d = 0; } else { dstMask = dstMask >> 1; } } } } dst += width_in_bytes; } return buffer; } /* * Pack bitmap data. */ void _mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source, GLubyte *dest, const struct gl_pixelstore_attrib *packing ) { GLint row, width_in_bytes; const GLubyte *src; if (!source) return; width_in_bytes = CEILING( width, 8 ); src = source; for (row = 0; row < height; row++) { GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, dest, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (!dst) return; if ((packing->SkipPixels & 7) == 0) { memcpy( dst, src, width_in_bytes ); if (packing->LsbFirst) { flip_bytes( dst, width_in_bytes ); } } else { /* handling SkipPixels is a bit tricky (no pun intended!) */ GLint i; if (packing->LsbFirst) { GLubyte srcMask = 128; GLubyte dstMask = 1 << (packing->SkipPixels & 0x7); const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 1) { srcMask = 128; s++; } else { srcMask = srcMask >> 1; } if (dstMask == 128) { dstMask = 1; d++; *d = 0; } else { dstMask = dstMask << 1; } } } else { GLubyte srcMask = 128; GLubyte dstMask = 128 >> (packing->SkipPixels & 0x7); const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 1) { srcMask = 128; s++; } else { srcMask = srcMask >> 1; } if (dstMask == 1) { dstMask = 128; d++; *d = 0; } else { dstMask = dstMask >> 1; } } } } src += width_in_bytes; } } /** * Get indexes of color components for a basic color format, such as * GL_RGBA, GL_RED, GL_LUMINANCE_ALPHA, etc. Return -1 for indexes * that do not apply. */ static void get_component_indexes(GLenum format, GLint *redIndex, GLint *greenIndex, GLint *blueIndex, GLint *alphaIndex, GLint *luminanceIndex, GLint *intensityIndex) { *redIndex = -1; *greenIndex = -1; *blueIndex = -1; *alphaIndex = -1; *luminanceIndex = -1; *intensityIndex = -1; switch (format) { case GL_LUMINANCE: case GL_LUMINANCE_INTEGER_EXT: *luminanceIndex = 0; break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA_INTEGER_EXT: *luminanceIndex = 0; *alphaIndex = 1; break; case GL_INTENSITY: *intensityIndex = 0; break; case GL_RED: case GL_RED_INTEGER_EXT: *redIndex = 0; break; case GL_GREEN: case GL_GREEN_INTEGER_EXT: *greenIndex = 0; break; case GL_BLUE: case GL_BLUE_INTEGER_EXT: *blueIndex = 0; break; case GL_ALPHA: case GL_ALPHA_INTEGER_EXT: *alphaIndex = 0; break; case GL_RG: case GL_RG_INTEGER: *redIndex = 0; *greenIndex = 1; break; case GL_RGB: case GL_RGB_INTEGER_EXT: *redIndex = 0; *greenIndex = 1; *blueIndex = 2; break; case GL_BGR: case GL_BGR_INTEGER_EXT: *blueIndex = 0; *greenIndex = 1; *redIndex = 2; break; case GL_RGBA: case GL_RGBA_INTEGER_EXT: *redIndex = 0; *greenIndex = 1; *blueIndex = 2; *alphaIndex = 3; break; case GL_BGRA: case GL_BGRA_INTEGER: *redIndex = 2; *greenIndex = 1; *blueIndex = 0; *alphaIndex = 3; break; case GL_ABGR_EXT: *redIndex = 3; *greenIndex = 2; *blueIndex = 1; *alphaIndex = 0; break; case GL_DU8DV8_ATI: case GL_DUDV_ATI: *redIndex = 0; *greenIndex = 1; break; default: assert(0 && "bad format in get_component_indexes()"); } } /** * For small integer types, return the min and max possible values. * Used for clamping floats to unscaled integer types. * \return GL_TRUE if type is handled, GL_FALSE otherwise. */ static GLboolean get_type_min_max(GLenum type, GLfloat *min, GLfloat *max) { switch (type) { case GL_BYTE: *min = -128.0; *max = 127.0; return GL_TRUE; case GL_UNSIGNED_BYTE: *min = 0.0; *max = 255.0; return GL_TRUE; case GL_SHORT: *min = -32768.0; *max = 32767.0; return GL_TRUE; case GL_UNSIGNED_SHORT: *min = 0.0; *max = 65535.0; return GL_TRUE; default: return GL_FALSE; } } /* Customization of integer packing. We always treat src as uint, and can pack dst * as any integer type/format combo. */ #define SRC_TYPE GLuint #define DST_TYPE GLuint #define SRC_CONVERT(x) (x) #define FN_NAME pack_uint_from_uint_rgba #include "pack_tmp.h" #undef DST_TYPE #undef SRC_CONVERT #undef FN_NAME #define DST_TYPE GLushort #define SRC_CONVERT(x) MIN2(x, 0xffff) #define FN_NAME pack_ushort_from_uint_rgba #include "pack_tmp.h" #undef DST_TYPE #undef SRC_CONVERT #undef FN_NAME #define DST_TYPE GLshort #define SRC_CONVERT(x) CLAMP((int)x, -32768, 32767) #define FN_NAME pack_short_from_uint_rgba #include "pack_tmp.h" #undef DST_TYPE #undef SRC_CONVERT #undef FN_NAME #define DST_TYPE GLubyte #define SRC_CONVERT(x) MIN2(x, 0xff) #define FN_NAME pack_ubyte_from_uint_rgba #include "pack_tmp.h" #undef DST_TYPE #undef SRC_CONVERT #undef FN_NAME #define DST_TYPE GLbyte #define SRC_CONVERT(x) CLAMP((int)x, -128, 127) #define FN_NAME pack_byte_from_uint_rgba #include "pack_tmp.h" #undef DST_TYPE #undef SRC_CONVERT #undef FN_NAME void _mesa_pack_rgba_span_int(struct gl_context *ctx, GLuint n, GLuint rgba[][4], GLenum dstFormat, GLenum dstType, GLvoid *dstAddr) { switch(dstType) { case GL_UNSIGNED_INT: pack_uint_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; case GL_INT: /* No conversion necessary. */ pack_uint_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; case GL_UNSIGNED_SHORT: pack_ushort_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; case GL_SHORT: pack_short_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; case GL_UNSIGNED_BYTE: pack_ubyte_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; case GL_BYTE: pack_byte_from_uint_rgba(dstAddr, dstFormat, rgba, n); break; default: assert(0); return; } } /** * Used to pack an array [][4] of RGBA float colors as specified * by the dstFormat, dstType and dstPacking. Used by glReadPixels. * Historically, the RGBA values were in [0,1] and rescaled to fit * into GLubytes, etc. But with new integer formats, the RGBA values * may have any value and we don't always rescale when converting to * integers. * * Note: the rgba values will be modified by this function when any pixel * transfer ops are enabled. */ void _mesa_pack_rgba_span_float(struct gl_context *ctx, GLuint n, GLfloat rgba[][4], GLenum dstFormat, GLenum dstType, GLvoid *dstAddr, const struct gl_pixelstore_attrib *dstPacking, GLbitfield transferOps) { GLfloat *luminance; const GLint comps = _mesa_components_in_format(dstFormat); const GLboolean intDstFormat = _mesa_is_integer_format(dstFormat); GLuint i; if (dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_LUMINANCE_INTEGER_EXT || dstFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT) { luminance = (GLfloat *) malloc(n * sizeof(GLfloat)); if (!luminance) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); return; } } else { luminance = NULL; } /* EXT_texture_integer specifies no transfer ops on integer * types in the resolved issues section. Just set them to 0 * for integer surfaces. */ if (intDstFormat) transferOps = 0; if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); } /* * Component clamping (besides clamping to [0,1] in * _mesa_apply_rgba_transfer_ops()). */ if (intDstFormat) { /* clamping to dest type's min/max values */ GLfloat min, max; if (get_type_min_max(dstType, &min, &max)) { for (i = 0; i < n; i++) { rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], min, max); rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], min, max); rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], min, max); rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], min, max); } } } else if (dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA) { /* compute luminance values */ if (transferOps & IMAGE_CLAMP_BIT) { for (i = 0; i < n; i++) { GLfloat sum = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; luminance[i] = CLAMP(sum, 0.0F, 1.0F); } } else { for (i = 0; i < n; i++) { luminance[i] = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; } } } /* * Pack/store the pixels. Ugh! Lots of cases!!! */ switch (dstType) { case GL_UNSIGNED_BYTE: { GLubyte *dst = (GLubyte *) dstAddr; switch (dstFormat) { case GL_RED: for (i=0;iSwapBytes) { GLint swapSize = _mesa_sizeof_packed_type(dstType); if (swapSize == 2) { if (dstPacking->SwapBytes) { _mesa_swap2((GLushort *) dstAddr, n * comps); } } else if (swapSize == 4) { if (dstPacking->SwapBytes) { _mesa_swap4((GLuint *) dstAddr, n * comps); } } } free(luminance); } #define SWAP2BYTE(VALUE) \ { \ GLubyte *bytes = (GLubyte *) &(VALUE); \ GLubyte tmp = bytes[0]; \ bytes[0] = bytes[1]; \ bytes[1] = tmp; \ } #define SWAP4BYTE(VALUE) \ { \ GLubyte *bytes = (GLubyte *) &(VALUE); \ GLubyte tmp = bytes[0]; \ bytes[0] = bytes[3]; \ bytes[3] = tmp; \ tmp = bytes[1]; \ bytes[1] = bytes[2]; \ bytes[2] = tmp; \ } static void extract_uint_indexes(GLuint n, GLuint indexes[], GLenum srcFormat, GLenum srcType, const GLvoid *src, const struct gl_pixelstore_attrib *unpack ) { ASSERT(srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX); ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_UNSIGNED_INT_24_8_EXT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); switch (srcType) { case GL_BITMAP: { GLubyte *ubsrc = (GLubyte *) src; if (unpack->LsbFirst) { GLubyte mask = 1 << (unpack->SkipPixels & 0x7); GLuint i; for (i = 0; i < n; i++) { indexes[i] = (*ubsrc & mask) ? 1 : 0; if (mask == 128) { mask = 1; ubsrc++; } else { mask = mask << 1; } } } else { GLubyte mask = 128 >> (unpack->SkipPixels & 0x7); GLuint i; for (i = 0; i < n; i++) { indexes[i] = (*ubsrc & mask) ? 1 : 0; if (mask == 1) { mask = 128; ubsrc++; } else { mask = mask >> 1; } } } } break; case GL_UNSIGNED_BYTE: { GLuint i; const GLubyte *s = (const GLubyte *) src; for (i = 0; i < n; i++) indexes[i] = s[i]; } break; case GL_BYTE: { GLuint i; const GLbyte *s = (const GLbyte *) src; for (i = 0; i < n; i++) indexes[i] = s[i]; } break; case GL_UNSIGNED_SHORT: { GLuint i; const GLushort *s = (const GLushort *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLushort value = s[i]; SWAP2BYTE(value); indexes[i] = value; } } else { for (i = 0; i < n; i++) indexes[i] = s[i]; } } break; case GL_SHORT: { GLuint i; const GLshort *s = (const GLshort *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLshort value = s[i]; SWAP2BYTE(value); indexes[i] = value; } } else { for (i = 0; i < n; i++) indexes[i] = s[i]; } } break; case GL_UNSIGNED_INT: { GLuint i; const GLuint *s = (const GLuint *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLuint value = s[i]; SWAP4BYTE(value); indexes[i] = value; } } else { for (i = 0; i < n; i++) indexes[i] = s[i]; } } break; case GL_INT: { GLuint i; const GLint *s = (const GLint *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLint value = s[i]; SWAP4BYTE(value); indexes[i] = value; } } else { for (i = 0; i < n; i++) indexes[i] = s[i]; } } break; case GL_FLOAT: { GLuint i; const GLfloat *s = (const GLfloat *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLfloat value = s[i]; SWAP4BYTE(value); indexes[i] = (GLuint) value; } } else { for (i = 0; i < n; i++) indexes[i] = (GLuint) s[i]; } } break; case GL_HALF_FLOAT_ARB: { GLuint i; const GLhalfARB *s = (const GLhalfARB *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLhalfARB value = s[i]; SWAP2BYTE(value); indexes[i] = (GLuint) _mesa_half_to_float(value); } } else { for (i = 0; i < n; i++) indexes[i] = (GLuint) _mesa_half_to_float(s[i]); } } break; case GL_UNSIGNED_INT_24_8_EXT: { GLuint i; const GLuint *s = (const GLuint *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLuint value = s[i]; SWAP4BYTE(value); indexes[i] = value & 0xff; /* lower 8 bits */ } } else { for (i = 0; i < n; i++) indexes[i] = s[i] & 0xff; /* lower 8 bits */ } } break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: { GLuint i; const GLuint *s = (const GLuint *) src; if (unpack->SwapBytes) { for (i = 0; i < n; i++) { GLuint value = s[i*2+1]; SWAP4BYTE(value); indexes[i] = value & 0xff; /* lower 8 bits */ } } else { for (i = 0; i < n; i++) indexes[i] = s[i*2+1] & 0xff; /* lower 8 bits */ } } break; default: _mesa_problem(NULL, "bad srcType in extract_uint_indexes"); return; } } /** * Return source/dest RGBA indexes for unpacking pixels. */ static void get_component_mapping(GLenum format, GLint *rSrc, GLint *gSrc, GLint *bSrc, GLint *aSrc, GLint *rDst, GLint *gDst, GLint *bDst, GLint *aDst) { switch (format) { case GL_RED: case GL_RED_INTEGER_EXT: *rSrc = 0; *gSrc = *bSrc = *aSrc = -1; break; case GL_GREEN: case GL_GREEN_INTEGER_EXT: *gSrc = 0; *rSrc = *bSrc = *aSrc = -1; break; case GL_BLUE: case GL_BLUE_INTEGER_EXT: *bSrc = 0; *rSrc = *gSrc = *aSrc = -1; break; case GL_ALPHA: case GL_ALPHA_INTEGER_EXT: *rSrc = *gSrc = *bSrc = -1; *aSrc = 0; break; case GL_LUMINANCE: case GL_LUMINANCE_INTEGER_EXT: *rSrc = *gSrc = *bSrc = 0; *aSrc = -1; break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA_INTEGER_EXT: *rSrc = *gSrc = *bSrc = 0; *aSrc = 1; break; case GL_INTENSITY: *rSrc = *gSrc = *bSrc = *aSrc = 0; break; case GL_RG: case GL_RG_INTEGER: *rSrc = 0; *gSrc = 1; *bSrc = -1; *aSrc = -1; *rDst = 0; *gDst = 1; *bDst = 2; *aDst = 3; break; case GL_RGB: case GL_RGB_INTEGER: *rSrc = 0; *gSrc = 1; *bSrc = 2; *aSrc = -1; *rDst = 0; *gDst = 1; *bDst = 2; *aDst = 3; break; case GL_BGR: case GL_BGR_INTEGER: *rSrc = 2; *gSrc = 1; *bSrc = 0; *aSrc = -1; *rDst = 2; *gDst = 1; *bDst = 0; *aDst = 3; break; case GL_RGBA: case GL_RGBA_INTEGER: *rSrc = 0; *gSrc = 1; *bSrc = 2; *aSrc = 3; *rDst = 0; *gDst = 1; *bDst = 2; *aDst = 3; break; case GL_BGRA: case GL_BGRA_INTEGER: *rSrc = 2; *gSrc = 1; *bSrc = 0; *aSrc = 3; *rDst = 2; *gDst = 1; *bDst = 0; *aDst = 3; break; case GL_ABGR_EXT: *rSrc = 3; *gSrc = 2; *bSrc = 1; *aSrc = 0; *rDst = 3; *gDst = 2; *bDst = 1; *aDst = 0; break; case GL_DU8DV8_ATI: case GL_DUDV_ATI: *rSrc = 0; *gSrc = 1; *bSrc = -1; *aSrc = -1; break; default: _mesa_problem(NULL, "bad srcFormat %s in get_component_mapping", _mesa_lookup_enum_by_nr(format)); return; } } /* * This function extracts floating point RGBA values from arbitrary * image data. srcFormat and srcType are the format and type parameters * passed to glDrawPixels, glTexImage[123]D, glTexSubImage[123]D, etc. * * Refering to section 3.6.4 of the OpenGL 1.2 spec, this function * implements the "Conversion to floating point", "Conversion to RGB", * and "Final Expansion to RGBA" operations. * * Args: n - number of pixels * rgba - output colors * srcFormat - format of incoming data * srcType - data type of incoming data * src - source data pointer * swapBytes - perform byteswapping of incoming data? */ static void extract_float_rgba(GLuint n, GLfloat rgba[][4], GLenum srcFormat, GLenum srcType, const GLvoid *src, GLboolean swapBytes) { GLint rSrc, gSrc, bSrc, aSrc; GLint stride; GLint rDst, bDst, gDst, aDst; GLboolean intFormat; GLfloat rs = 1.0f, gs = 1.0f, bs = 1.0f, as = 1.0f; /* scale factors */ ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA || srcFormat == GL_LUMINANCE || srcFormat == GL_LUMINANCE_ALPHA || srcFormat == GL_INTENSITY || srcFormat == GL_RG || srcFormat == GL_RGB || srcFormat == GL_BGR || srcFormat == GL_RGBA || srcFormat == GL_BGRA || srcFormat == GL_ABGR_EXT || srcFormat == GL_DU8DV8_ATI || srcFormat == GL_DUDV_ATI || srcFormat == GL_RED_INTEGER_EXT || srcFormat == GL_GREEN_INTEGER_EXT || srcFormat == GL_BLUE_INTEGER_EXT || srcFormat == GL_ALPHA_INTEGER_EXT || srcFormat == GL_RG_INTEGER || srcFormat == GL_RGB_INTEGER_EXT || srcFormat == GL_RGBA_INTEGER_EXT || srcFormat == GL_BGR_INTEGER_EXT || srcFormat == GL_BGRA_INTEGER_EXT || srcFormat == GL_LUMINANCE_INTEGER_EXT || srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); ASSERT(srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_UNSIGNED_BYTE_3_3_2 || srcType == GL_UNSIGNED_BYTE_2_3_3_REV || srcType == GL_UNSIGNED_SHORT_5_6_5 || srcType == GL_UNSIGNED_SHORT_5_6_5_REV || srcType == GL_UNSIGNED_SHORT_4_4_4_4 || srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || srcType == GL_UNSIGNED_SHORT_5_5_5_1 || srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || srcType == GL_UNSIGNED_INT_8_8_8_8 || srcType == GL_UNSIGNED_INT_8_8_8_8_REV || srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV || srcType == GL_UNSIGNED_INT_5_9_9_9_REV || srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); get_component_mapping(srcFormat, &rSrc, &gSrc, &bSrc, &aSrc, &rDst, &gDst, &bDst, &aDst); stride = _mesa_components_in_format(srcFormat); intFormat = _mesa_is_integer_format(srcFormat); #define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT_FLT, DEFAULT_INT, TYPE, CONVERSION) \ if ((SRC_INDEX) < 0) { \ GLuint i; \ if (intFormat) { \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = DEFAULT_INT; \ } \ } \ else { \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = DEFAULT_FLT; \ } \ } \ } \ else if (swapBytes) { \ const TYPE *s = (const TYPE *) src; \ GLuint i; \ for (i = 0; i < n; i++) { \ TYPE value = s[SRC_INDEX]; \ if (sizeof(TYPE) == 2) { \ SWAP2BYTE(value); \ } \ else if (sizeof(TYPE) == 4) { \ SWAP4BYTE(value); \ } \ if (intFormat) \ rgba[i][DST_INDEX] = (GLfloat) value; \ else \ rgba[i][DST_INDEX] = (GLfloat) CONVERSION(value); \ s += stride; \ } \ } \ else { \ const TYPE *s = (const TYPE *) src; \ GLuint i; \ if (intFormat) { \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = (GLfloat) s[SRC_INDEX]; \ s += stride; \ } \ } \ else { \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = (GLfloat) CONVERSION(s[SRC_INDEX]); \ s += stride; \ } \ } \ } switch (srcType) { case GL_UNSIGNED_BYTE: PROCESS(rSrc, RCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); PROCESS(gSrc, GCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); PROCESS(bSrc, BCOMP, 0.0F, 0, GLubyte, UBYTE_TO_FLOAT); PROCESS(aSrc, ACOMP, 1.0F, 255, GLubyte, UBYTE_TO_FLOAT); break; case GL_BYTE: PROCESS(rSrc, RCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOATZ); PROCESS(gSrc, GCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOATZ); PROCESS(bSrc, BCOMP, 0.0F, 0, GLbyte, BYTE_TO_FLOATZ); PROCESS(aSrc, ACOMP, 1.0F, 127, GLbyte, BYTE_TO_FLOATZ); break; case GL_UNSIGNED_SHORT: PROCESS(rSrc, RCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); PROCESS(gSrc, GCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); PROCESS(bSrc, BCOMP, 0.0F, 0, GLushort, USHORT_TO_FLOAT); PROCESS(aSrc, ACOMP, 1.0F, 0xffff, GLushort, USHORT_TO_FLOAT); break; case GL_SHORT: PROCESS(rSrc, RCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOATZ); PROCESS(gSrc, GCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOATZ); PROCESS(bSrc, BCOMP, 0.0F, 0, GLshort, SHORT_TO_FLOATZ); PROCESS(aSrc, ACOMP, 1.0F, 32767, GLshort, SHORT_TO_FLOATZ); break; case GL_UNSIGNED_INT: PROCESS(rSrc, RCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); PROCESS(gSrc, GCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); PROCESS(bSrc, BCOMP, 0.0F, 0, GLuint, UINT_TO_FLOAT); PROCESS(aSrc, ACOMP, 1.0F, 0xffffffff, GLuint, UINT_TO_FLOAT); break; case GL_INT: PROCESS(rSrc, RCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); PROCESS(gSrc, GCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); PROCESS(bSrc, BCOMP, 0.0F, 0, GLint, INT_TO_FLOAT); PROCESS(aSrc, ACOMP, 1.0F, 2147483647, GLint, INT_TO_FLOAT); break; case GL_FLOAT: PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLfloat, (GLfloat)); PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLfloat, (GLfloat)); break; case GL_HALF_FLOAT_ARB: PROCESS(rSrc, RCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); PROCESS(gSrc, GCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); PROCESS(bSrc, BCOMP, 0.0F, 0.0F, GLhalfARB, _mesa_half_to_float); PROCESS(aSrc, ACOMP, 1.0F, 1.0F, GLhalfARB, _mesa_half_to_float); break; case GL_UNSIGNED_BYTE_3_3_2: { const GLubyte *ubsrc = (const GLubyte *) src; GLuint i; if (!intFormat) { rs = 1.0F / 7.0F; gs = 1.0F / 7.0F; bs = 1.0F / 3.0F; } for (i = 0; i < n; i ++) { GLubyte p = ubsrc[i]; rgba[i][rDst] = ((p >> 5) ) * rs; rgba[i][gDst] = ((p >> 2) & 0x7) * gs; rgba[i][bDst] = ((p ) & 0x3) * bs; rgba[i][aDst] = 1.0F; } } break; case GL_UNSIGNED_BYTE_2_3_3_REV: { const GLubyte *ubsrc = (const GLubyte *) src; GLuint i; if (!intFormat) { rs = 1.0F / 7.0F; gs = 1.0F / 7.0F; bs = 1.0F / 3.0F; } for (i = 0; i < n; i ++) { GLubyte p = ubsrc[i]; rgba[i][rDst] = ((p ) & 0x7) * rs; rgba[i][gDst] = ((p >> 3) & 0x7) * gs; rgba[i][bDst] = ((p >> 6) ) * bs; rgba[i][aDst] = 1.0F; } } break; case GL_UNSIGNED_SHORT_5_6_5: if (!intFormat) { rs = 1.0F / 31.0F; gs = 1.0F / 63.0F; bs = 1.0F / 31.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 11) ) * rs; rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; rgba[i][bDst] = ((p ) & 0x1f) * bs; rgba[i][aDst] = 1.0F; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 11) ) * rs; rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; rgba[i][bDst] = ((p ) & 0x1f) * bs; rgba[i][aDst] = 1.0F; } } break; case GL_UNSIGNED_SHORT_5_6_5_REV: if (!intFormat) { rs = 1.0F / 31.0F; gs = 1.0F / 63.0F; bs = 1.0F / 31.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0x1f) * rs; rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; rgba[i][bDst] = ((p >> 11) ) * bs; rgba[i][aDst] = 1.0F; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0x1f) * rs; rgba[i][gDst] = ((p >> 5) & 0x3f) * gs; rgba[i][bDst] = ((p >> 11) ) * bs; rgba[i][aDst] = 1.0F; } } break; case GL_UNSIGNED_SHORT_4_4_4_4: if (!intFormat) { rs = gs = bs = as = 1.0F / 15.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 12) ) * rs; rgba[i][gDst] = ((p >> 8) & 0xf) * gs; rgba[i][bDst] = ((p >> 4) & 0xf) * bs; rgba[i][aDst] = ((p ) & 0xf) * as; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 12) ) * rs; rgba[i][gDst] = ((p >> 8) & 0xf) * gs; rgba[i][bDst] = ((p >> 4) & 0xf) * bs; rgba[i][aDst] = ((p ) & 0xf) * as; } } break; case GL_UNSIGNED_SHORT_4_4_4_4_REV: if (!intFormat) { rs = gs = bs = as = 1.0F / 15.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0xf) * rs; rgba[i][gDst] = ((p >> 4) & 0xf) * gs; rgba[i][bDst] = ((p >> 8) & 0xf) * bs; rgba[i][aDst] = ((p >> 12) ) * as; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0xf) * rs; rgba[i][gDst] = ((p >> 4) & 0xf) * gs; rgba[i][bDst] = ((p >> 8) & 0xf) * bs; rgba[i][aDst] = ((p >> 12) ) * as; } } break; case GL_UNSIGNED_SHORT_5_5_5_1: if (!intFormat) { rs = gs = bs = 1.0F / 31.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 11) ) * rs; rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; rgba[i][aDst] = ((p ) & 0x1) * as; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 11) ) * rs; rgba[i][gDst] = ((p >> 6) & 0x1f) * gs; rgba[i][bDst] = ((p >> 1) & 0x1f) * bs; rgba[i][aDst] = ((p ) & 0x1) * as; } } break; case GL_UNSIGNED_SHORT_1_5_5_5_REV: if (!intFormat) { rs = gs = bs = 1.0F / 31.0F; } if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0x1f) * rs; rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; rgba[i][aDst] = ((p >> 15) ) * as; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0x1f) * rs; rgba[i][gDst] = ((p >> 5) & 0x1f) * gs; rgba[i][bDst] = ((p >> 10) & 0x1f) * bs; rgba[i][aDst] = ((p >> 15) ) * as; } } break; case GL_UNSIGNED_INT_8_8_8_8: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; if (intFormat) { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = (GLfloat) ((p ) & 0xff); rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); rgba[i][aDst] = (GLfloat) ((p >> 24) ); } } else { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); } } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; if (intFormat) { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = (GLfloat) ((p >> 24) ); rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); rgba[i][aDst] = (GLfloat) ((p ) & 0xff); } } else { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); } } } break; case GL_UNSIGNED_INT_8_8_8_8_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; if (intFormat) { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = (GLfloat) ((p >> 24) ); rgba[i][gDst] = (GLfloat) ((p >> 16) & 0xff); rgba[i][bDst] = (GLfloat) ((p >> 8) & 0xff); rgba[i][aDst] = (GLfloat) ((p ) & 0xff); } } else { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = UBYTE_TO_FLOAT((p >> 24) ); rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); rgba[i][aDst] = UBYTE_TO_FLOAT((p ) & 0xff); } } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; if (intFormat) { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = (GLfloat) ((p ) & 0xff); rgba[i][gDst] = (GLfloat) ((p >> 8) & 0xff); rgba[i][bDst] = (GLfloat) ((p >> 16) & 0xff); rgba[i][aDst] = (GLfloat) ((p >> 24) ); } } else { for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = UBYTE_TO_FLOAT((p ) & 0xff); rgba[i][gDst] = UBYTE_TO_FLOAT((p >> 8) & 0xff); rgba[i][bDst] = UBYTE_TO_FLOAT((p >> 16) & 0xff); rgba[i][aDst] = UBYTE_TO_FLOAT((p >> 24) ); } } } break; case GL_UNSIGNED_INT_10_10_10_2: if (!intFormat) { rs = 1.0F / 1023.0F; gs = 1.0F / 1023.0F; bs = 1.0F / 1023.0F; as = 1.0F / 3.0F; } if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgba[i][rDst] = ((p >> 22) ) * rs; rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; rgba[i][aDst] = ((p ) & 0x3 ) * as; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p >> 22) ) * rs; rgba[i][gDst] = ((p >> 12) & 0x3ff) * gs; rgba[i][bDst] = ((p >> 2) & 0x3ff) * bs; rgba[i][aDst] = ((p ) & 0x3 ) * as; } } break; case GL_UNSIGNED_INT_2_10_10_10_REV: if (!intFormat) { rs = 1.0F / 1023.0F; gs = 1.0F / 1023.0F; bs = 1.0F / 1023.0F; as = 1.0F / 3.0F; } if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgba[i][rDst] = ((p ) & 0x3ff) * rs; rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; rgba[i][aDst] = ((p >> 30) ) * as; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p ) & 0x3ff) * rs; rgba[i][gDst] = ((p >> 10) & 0x3ff) * gs; rgba[i][bDst] = ((p >> 20) & 0x3ff) * bs; rgba[i][aDst] = ((p >> 30) ) * as; } } break; case GL_UNSIGNED_INT_5_9_9_9_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; GLfloat f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgb9e5_to_float3(p, f); rgba[i][rDst] = f[0]; rgba[i][gDst] = f[1]; rgba[i][bDst] = f[2]; rgba[i][aDst] = 1.0F; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; GLfloat f[3]; for (i = 0; i < n; i ++) { rgb9e5_to_float3(uisrc[i], f); rgba[i][rDst] = f[0]; rgba[i][gDst] = f[1]; rgba[i][bDst] = f[2]; rgba[i][aDst] = 1.0F; } } break; case GL_UNSIGNED_INT_10F_11F_11F_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; GLfloat f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); r11g11b10f_to_float3(p, f); rgba[i][rDst] = f[0]; rgba[i][gDst] = f[1]; rgba[i][bDst] = f[2]; rgba[i][aDst] = 1.0F; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; GLfloat f[3]; for (i = 0; i < n; i ++) { r11g11b10f_to_float3(uisrc[i], f); rgba[i][rDst] = f[0]; rgba[i][gDst] = f[1]; rgba[i][bDst] = f[2]; rgba[i][aDst] = 1.0F; } } break; default: _mesa_problem(NULL, "bad srcType in extract float data"); break; } #undef PROCESS } static inline GLuint clamp_byte_to_uint(GLbyte b) { return b < 0 ? 0 : b; } static inline GLuint clamp_short_to_uint(GLshort s) { return s < 0 ? 0 : s; } static inline GLuint clamp_int_to_uint(GLint i) { return i < 0 ? 0 : i; } static inline GLuint clamp_float_to_uint(GLfloat f) { return f < 0.0F ? 0 : IROUND(f); } static inline GLuint clamp_half_to_uint(GLhalfARB h) { GLfloat f = _mesa_half_to_float(h); return f < 0.0F ? 0 : IROUND(f); } /** * \sa extract_float_rgba() */ static void extract_uint_rgba(GLuint n, GLuint rgba[][4], GLenum srcFormat, GLenum srcType, const GLvoid *src, GLboolean swapBytes) { GLint rSrc, gSrc, bSrc, aSrc; GLint stride; GLint rDst, bDst, gDst, aDst; ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA || srcFormat == GL_LUMINANCE || srcFormat == GL_LUMINANCE_ALPHA || srcFormat == GL_INTENSITY || srcFormat == GL_RG || srcFormat == GL_RGB || srcFormat == GL_BGR || srcFormat == GL_RGBA || srcFormat == GL_BGRA || srcFormat == GL_ABGR_EXT || srcFormat == GL_DU8DV8_ATI || srcFormat == GL_DUDV_ATI || srcFormat == GL_RED_INTEGER_EXT || srcFormat == GL_RG_INTEGER || srcFormat == GL_GREEN_INTEGER_EXT || srcFormat == GL_BLUE_INTEGER_EXT || srcFormat == GL_ALPHA_INTEGER_EXT || srcFormat == GL_RGB_INTEGER_EXT || srcFormat == GL_RGBA_INTEGER_EXT || srcFormat == GL_BGR_INTEGER_EXT || srcFormat == GL_BGRA_INTEGER_EXT || srcFormat == GL_LUMINANCE_INTEGER_EXT || srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); ASSERT(srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_UNSIGNED_BYTE_3_3_2 || srcType == GL_UNSIGNED_BYTE_2_3_3_REV || srcType == GL_UNSIGNED_SHORT_5_6_5 || srcType == GL_UNSIGNED_SHORT_5_6_5_REV || srcType == GL_UNSIGNED_SHORT_4_4_4_4 || srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || srcType == GL_UNSIGNED_SHORT_5_5_5_1 || srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || srcType == GL_UNSIGNED_INT_8_8_8_8 || srcType == GL_UNSIGNED_INT_8_8_8_8_REV || srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV || srcType == GL_UNSIGNED_INT_5_9_9_9_REV || srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); get_component_mapping(srcFormat, &rSrc, &gSrc, &bSrc, &aSrc, &rDst, &gDst, &bDst, &aDst); stride = _mesa_components_in_format(srcFormat); #define PROCESS(SRC_INDEX, DST_INDEX, DEFAULT, TYPE, CONVERSION) \ if ((SRC_INDEX) < 0) { \ GLuint i; \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = DEFAULT; \ } \ } \ else if (swapBytes) { \ const TYPE *s = (const TYPE *) src; \ GLuint i; \ for (i = 0; i < n; i++) { \ TYPE value = s[SRC_INDEX]; \ if (sizeof(TYPE) == 2) { \ SWAP2BYTE(value); \ } \ else if (sizeof(TYPE) == 4) { \ SWAP4BYTE(value); \ } \ rgba[i][DST_INDEX] = CONVERSION(value); \ s += stride; \ } \ } \ else { \ const TYPE *s = (const TYPE *) src; \ GLuint i; \ for (i = 0; i < n; i++) { \ rgba[i][DST_INDEX] = CONVERSION(s[SRC_INDEX]); \ s += stride; \ } \ } switch (srcType) { case GL_UNSIGNED_BYTE: PROCESS(rSrc, RCOMP, 0, GLubyte, (GLuint)); PROCESS(gSrc, GCOMP, 0, GLubyte, (GLuint)); PROCESS(bSrc, BCOMP, 0, GLubyte, (GLuint)); PROCESS(aSrc, ACOMP, 1, GLubyte, (GLuint)); break; case GL_BYTE: PROCESS(rSrc, RCOMP, 0, GLbyte, clamp_byte_to_uint); PROCESS(gSrc, GCOMP, 0, GLbyte, clamp_byte_to_uint); PROCESS(bSrc, BCOMP, 0, GLbyte, clamp_byte_to_uint); PROCESS(aSrc, ACOMP, 1, GLbyte, clamp_byte_to_uint); break; case GL_UNSIGNED_SHORT: PROCESS(rSrc, RCOMP, 0, GLushort, (GLuint)); PROCESS(gSrc, GCOMP, 0, GLushort, (GLuint)); PROCESS(bSrc, BCOMP, 0, GLushort, (GLuint)); PROCESS(aSrc, ACOMP, 1, GLushort, (GLuint)); break; case GL_SHORT: PROCESS(rSrc, RCOMP, 0, GLshort, clamp_short_to_uint); PROCESS(gSrc, GCOMP, 0, GLshort, clamp_short_to_uint); PROCESS(bSrc, BCOMP, 0, GLshort, clamp_short_to_uint); PROCESS(aSrc, ACOMP, 1, GLshort, clamp_short_to_uint); break; case GL_UNSIGNED_INT: PROCESS(rSrc, RCOMP, 0, GLuint, (GLuint)); PROCESS(gSrc, GCOMP, 0, GLuint, (GLuint)); PROCESS(bSrc, BCOMP, 0, GLuint, (GLuint)); PROCESS(aSrc, ACOMP, 1, GLuint, (GLuint)); break; case GL_INT: PROCESS(rSrc, RCOMP, 0, GLint, clamp_int_to_uint); PROCESS(gSrc, GCOMP, 0, GLint, clamp_int_to_uint); PROCESS(bSrc, BCOMP, 0, GLint, clamp_int_to_uint); PROCESS(aSrc, ACOMP, 1, GLint, clamp_int_to_uint); break; case GL_FLOAT: PROCESS(rSrc, RCOMP, 0, GLfloat, clamp_float_to_uint); PROCESS(gSrc, GCOMP, 0, GLfloat, clamp_float_to_uint); PROCESS(bSrc, BCOMP, 0, GLfloat, clamp_float_to_uint); PROCESS(aSrc, ACOMP, 1, GLfloat, clamp_float_to_uint); break; case GL_HALF_FLOAT_ARB: PROCESS(rSrc, RCOMP, 0, GLhalfARB, clamp_half_to_uint); PROCESS(gSrc, GCOMP, 0, GLhalfARB, clamp_half_to_uint); PROCESS(bSrc, BCOMP, 0, GLhalfARB, clamp_half_to_uint); PROCESS(aSrc, ACOMP, 1, GLhalfARB, clamp_half_to_uint); break; case GL_UNSIGNED_BYTE_3_3_2: { const GLubyte *ubsrc = (const GLubyte *) src; GLuint i; for (i = 0; i < n; i ++) { GLubyte p = ubsrc[i]; rgba[i][rDst] = ((p >> 5) ); rgba[i][gDst] = ((p >> 2) & 0x7); rgba[i][bDst] = ((p ) & 0x3); rgba[i][aDst] = 1; } } break; case GL_UNSIGNED_BYTE_2_3_3_REV: { const GLubyte *ubsrc = (const GLubyte *) src; GLuint i; for (i = 0; i < n; i ++) { GLubyte p = ubsrc[i]; rgba[i][rDst] = ((p ) & 0x7); rgba[i][gDst] = ((p >> 3) & 0x7); rgba[i][bDst] = ((p >> 6) ); rgba[i][aDst] = 1; } } break; case GL_UNSIGNED_SHORT_5_6_5: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 11) ); rgba[i][gDst] = ((p >> 5) & 0x3f); rgba[i][bDst] = ((p ) & 0x1f); rgba[i][aDst] = 1; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 11) ); rgba[i][gDst] = ((p >> 5) & 0x3f); rgba[i][bDst] = ((p ) & 0x1f); rgba[i][aDst] = 1; } } break; case GL_UNSIGNED_SHORT_5_6_5_REV: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0x1f); rgba[i][gDst] = ((p >> 5) & 0x3f); rgba[i][bDst] = ((p >> 11) ); rgba[i][aDst] = 1; } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0x1f); rgba[i][gDst] = ((p >> 5) & 0x3f); rgba[i][bDst] = ((p >> 11) ); rgba[i][aDst] = 1; } } break; case GL_UNSIGNED_SHORT_4_4_4_4: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 12) ); rgba[i][gDst] = ((p >> 8) & 0xf); rgba[i][bDst] = ((p >> 4) & 0xf); rgba[i][aDst] = ((p ) & 0xf); } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 12) ); rgba[i][gDst] = ((p >> 8) & 0xf); rgba[i][bDst] = ((p >> 4) & 0xf); rgba[i][aDst] = ((p ) & 0xf); } } break; case GL_UNSIGNED_SHORT_4_4_4_4_REV: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0xf); rgba[i][gDst] = ((p >> 4) & 0xf); rgba[i][bDst] = ((p >> 8) & 0xf); rgba[i][aDst] = ((p >> 12) ); } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0xf); rgba[i][gDst] = ((p >> 4) & 0xf); rgba[i][bDst] = ((p >> 8) & 0xf); rgba[i][aDst] = ((p >> 12) ); } } break; case GL_UNSIGNED_SHORT_5_5_5_1: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p >> 11) ); rgba[i][gDst] = ((p >> 6) & 0x1f); rgba[i][bDst] = ((p >> 1) & 0x1f); rgba[i][aDst] = ((p ) & 0x1 ); } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p >> 11) ); rgba[i][gDst] = ((p >> 6) & 0x1f); rgba[i][bDst] = ((p >> 1) & 0x1f); rgba[i][aDst] = ((p ) & 0x1 ); } } break; case GL_UNSIGNED_SHORT_1_5_5_5_REV: if (swapBytes) { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); rgba[i][rDst] = ((p ) & 0x1f); rgba[i][gDst] = ((p >> 5) & 0x1f); rgba[i][bDst] = ((p >> 10) & 0x1f); rgba[i][aDst] = ((p >> 15) ); } } else { const GLushort *ussrc = (const GLushort *) src; GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; rgba[i][rDst] = ((p ) & 0x1f); rgba[i][gDst] = ((p >> 5) & 0x1f); rgba[i][bDst] = ((p >> 10) & 0x1f); rgba[i][aDst] = ((p >> 15) ); } } break; case GL_UNSIGNED_INT_8_8_8_8: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p ) & 0xff); rgba[i][gDst] = ((p >> 8) & 0xff); rgba[i][bDst] = ((p >> 16) & 0xff); rgba[i][aDst] = ((p >> 24) ); } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p >> 24) ); rgba[i][gDst] = ((p >> 16) & 0xff); rgba[i][bDst] = ((p >> 8) & 0xff); rgba[i][aDst] = ((p ) & 0xff); } } break; case GL_UNSIGNED_INT_8_8_8_8_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p >> 24) ); rgba[i][gDst] = ((p >> 16) & 0xff); rgba[i][bDst] = ((p >> 8) & 0xff); rgba[i][aDst] = ((p ) & 0xff); } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p ) & 0xff); rgba[i][gDst] = ((p >> 8) & 0xff); rgba[i][bDst] = ((p >> 16) & 0xff); rgba[i][aDst] = ((p >> 24) ); } } break; case GL_UNSIGNED_INT_10_10_10_2: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgba[i][rDst] = ((p >> 22) ); rgba[i][gDst] = ((p >> 12) & 0x3ff); rgba[i][bDst] = ((p >> 2) & 0x3ff); rgba[i][aDst] = ((p ) & 0x3 ); } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p >> 22) ); rgba[i][gDst] = ((p >> 12) & 0x3ff); rgba[i][bDst] = ((p >> 2) & 0x3ff); rgba[i][aDst] = ((p ) & 0x3 ); } } break; case GL_UNSIGNED_INT_2_10_10_10_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgba[i][rDst] = ((p ) & 0x3ff); rgba[i][gDst] = ((p >> 10) & 0x3ff); rgba[i][bDst] = ((p >> 20) & 0x3ff); rgba[i][aDst] = ((p >> 30) ); } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgba[i][rDst] = ((p ) & 0x3ff); rgba[i][gDst] = ((p >> 10) & 0x3ff); rgba[i][bDst] = ((p >> 20) & 0x3ff); rgba[i][aDst] = ((p >> 30) ); } } break; case GL_UNSIGNED_INT_5_9_9_9_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; float f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); rgb9e5_to_float3(p, f); rgba[i][rDst] = clamp_float_to_uint(f[0]); rgba[i][gDst] = clamp_float_to_uint(f[1]); rgba[i][bDst] = clamp_float_to_uint(f[2]); rgba[i][aDst] = 1; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; float f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; rgb9e5_to_float3(p, f); rgba[i][rDst] = clamp_float_to_uint(f[0]); rgba[i][gDst] = clamp_float_to_uint(f[1]); rgba[i][bDst] = clamp_float_to_uint(f[2]); rgba[i][aDst] = 1; } } break; case GL_UNSIGNED_INT_10F_11F_11F_REV: if (swapBytes) { const GLuint *uisrc = (const GLuint *) src; GLuint i; float f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; SWAP4BYTE(p); r11g11b10f_to_float3(p, f); rgba[i][rDst] = clamp_float_to_uint(f[0]); rgba[i][gDst] = clamp_float_to_uint(f[1]); rgba[i][bDst] = clamp_float_to_uint(f[2]); rgba[i][aDst] = 1; } } else { const GLuint *uisrc = (const GLuint *) src; GLuint i; float f[3]; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; r11g11b10f_to_float3(p, f); rgba[i][rDst] = clamp_float_to_uint(f[0]); rgba[i][gDst] = clamp_float_to_uint(f[1]); rgba[i][bDst] = clamp_float_to_uint(f[2]); rgba[i][aDst] = 1; } } break; default: _mesa_problem(NULL, "bad srcType in extract uint data"); break; } #undef PROCESS } /* * Unpack a row of color image data from a client buffer according to * the pixel unpacking parameters. * Return GLubyte values in the specified dest image format. * This is used by glDrawPixels and glTexImage?D(). * \param ctx - the context * n - number of pixels in the span * dstFormat - format of destination color array * dest - the destination color array * srcFormat - source image format * srcType - source image data type * source - source image pointer * srcPacking - pixel unpacking parameters * transferOps - bitmask of IMAGE_*_BIT values of operations to apply * * XXX perhaps expand this to process whole images someday. */ void _mesa_unpack_color_span_ubyte(struct gl_context *ctx, GLuint n, GLenum dstFormat, GLubyte dest[], GLenum srcFormat, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, GLbitfield transferOps ) { GLboolean intFormat = _mesa_is_integer_format(srcFormat); ASSERT(dstFormat == GL_ALPHA || dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_INTENSITY || dstFormat == GL_RED || dstFormat == GL_RG || dstFormat == GL_RGB || dstFormat == GL_RGBA); ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA || srcFormat == GL_LUMINANCE || srcFormat == GL_LUMINANCE_ALPHA || srcFormat == GL_INTENSITY || srcFormat == GL_RG || srcFormat == GL_RGB || srcFormat == GL_BGR || srcFormat == GL_RGBA || srcFormat == GL_BGRA || srcFormat == GL_ABGR_EXT || srcFormat == GL_COLOR_INDEX); ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_UNSIGNED_BYTE_3_3_2 || srcType == GL_UNSIGNED_BYTE_2_3_3_REV || srcType == GL_UNSIGNED_SHORT_5_6_5 || srcType == GL_UNSIGNED_SHORT_5_6_5_REV || srcType == GL_UNSIGNED_SHORT_4_4_4_4 || srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || srcType == GL_UNSIGNED_SHORT_5_5_5_1 || srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || srcType == GL_UNSIGNED_INT_8_8_8_8 || srcType == GL_UNSIGNED_INT_8_8_8_8_REV || srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV || srcType == GL_UNSIGNED_INT_5_9_9_9_REV || srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); /* EXT_texture_integer specifies no transfer ops on integer * types in the resolved issues section. Just set them to 0 * for integer surfaces. */ if (intFormat) transferOps = 0; /* Try simple cases first */ if (transferOps == 0) { if (srcType == GL_UNSIGNED_BYTE) { if (dstFormat == GL_RGBA) { if (srcFormat == GL_RGBA) { memcpy( dest, source, n * 4 * sizeof(GLubyte) ); return; } else if (srcFormat == GL_RGB) { GLuint i; const GLubyte *src = (const GLubyte *) source; GLubyte *dst = dest; for (i = 0; i < n; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = 255; src += 3; dst += 4; } return; } } else if (dstFormat == GL_RGB) { if (srcFormat == GL_RGB) { memcpy( dest, source, n * 3 * sizeof(GLubyte) ); return; } else if (srcFormat == GL_RGBA) { GLuint i; const GLubyte *src = (const GLubyte *) source; GLubyte *dst = dest; for (i = 0; i < n; i++) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; src += 4; dst += 3; } return; } } else if (dstFormat == srcFormat) { GLint comps = _mesa_components_in_format(srcFormat); assert(comps > 0); memcpy( dest, source, n * comps * sizeof(GLubyte) ); return; } } } /* general solution begins here */ { GLint dstComponents; GLint rDst, gDst, bDst, aDst, lDst, iDst; GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } dstComponents = _mesa_components_in_format( dstFormat ); /* source & dest image formats should have been error checked by now */ assert(dstComponents > 0); /* * Extract image data and convert to RGBA floats */ if (srcFormat == GL_COLOR_INDEX) { GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); if (!indexes) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); free(rgba); return; } extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); /* Convert indexes to RGBA */ if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { _mesa_shift_and_offset_ci(ctx, n, indexes); } _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting * with color indexes. */ transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); free(indexes); } else { /* non-color index data */ extract_float_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); } /* Need to clamp if returning GLubytes */ transferOps |= IMAGE_CLAMP_BIT; if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); } get_component_indexes(dstFormat, &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); /* Now return the GLubyte data in the requested dstFormat */ if (rDst >= 0) { GLubyte *dst = dest; GLuint i; for (i = 0; i < n; i++) { CLAMPED_FLOAT_TO_UBYTE(dst[rDst], rgba[i][RCOMP]); dst += dstComponents; } } if (gDst >= 0) { GLubyte *dst = dest; GLuint i; for (i = 0; i < n; i++) { CLAMPED_FLOAT_TO_UBYTE(dst[gDst], rgba[i][GCOMP]); dst += dstComponents; } } if (bDst >= 0) { GLubyte *dst = dest; GLuint i; for (i = 0; i < n; i++) { CLAMPED_FLOAT_TO_UBYTE(dst[bDst], rgba[i][BCOMP]); dst += dstComponents; } } if (aDst >= 0) { GLubyte *dst = dest; GLuint i; for (i = 0; i < n; i++) { CLAMPED_FLOAT_TO_UBYTE(dst[aDst], rgba[i][ACOMP]); dst += dstComponents; } } if (iDst >= 0) { GLubyte *dst = dest; GLuint i; assert(iDst == 0); assert(dstComponents == 1); for (i = 0; i < n; i++) { /* Intensity comes from red channel */ CLAMPED_FLOAT_TO_UBYTE(dst[i], rgba[i][RCOMP]); } } if (lDst >= 0) { GLubyte *dst = dest; GLuint i; assert(lDst == 0); for (i = 0; i < n; i++) { /* Luminance comes from red channel */ CLAMPED_FLOAT_TO_UBYTE(dst[0], rgba[i][RCOMP]); dst += dstComponents; } } free(rgba); } } /** * Same as _mesa_unpack_color_span_ubyte(), but return GLfloat data * instead of GLubyte. */ void _mesa_unpack_color_span_float( struct gl_context *ctx, GLuint n, GLenum dstFormat, GLfloat dest[], GLenum srcFormat, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, GLbitfield transferOps ) { ASSERT(dstFormat == GL_ALPHA || dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_INTENSITY || dstFormat == GL_RED || dstFormat == GL_RG || dstFormat == GL_RGB || dstFormat == GL_RGBA); ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA || srcFormat == GL_LUMINANCE || srcFormat == GL_LUMINANCE_ALPHA || srcFormat == GL_INTENSITY || srcFormat == GL_RG || srcFormat == GL_RGB || srcFormat == GL_BGR || srcFormat == GL_RGBA || srcFormat == GL_BGRA || srcFormat == GL_ABGR_EXT || srcFormat == GL_RED_INTEGER_EXT || srcFormat == GL_GREEN_INTEGER_EXT || srcFormat == GL_BLUE_INTEGER_EXT || srcFormat == GL_ALPHA_INTEGER_EXT || srcFormat == GL_RG_INTEGER || srcFormat == GL_RGB_INTEGER_EXT || srcFormat == GL_RGBA_INTEGER_EXT || srcFormat == GL_BGR_INTEGER_EXT || srcFormat == GL_BGRA_INTEGER_EXT || srcFormat == GL_LUMINANCE_INTEGER_EXT || srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT || srcFormat == GL_COLOR_INDEX); ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_UNSIGNED_BYTE_3_3_2 || srcType == GL_UNSIGNED_BYTE_2_3_3_REV || srcType == GL_UNSIGNED_SHORT_5_6_5 || srcType == GL_UNSIGNED_SHORT_5_6_5_REV || srcType == GL_UNSIGNED_SHORT_4_4_4_4 || srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || srcType == GL_UNSIGNED_SHORT_5_5_5_1 || srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || srcType == GL_UNSIGNED_INT_8_8_8_8 || srcType == GL_UNSIGNED_INT_8_8_8_8_REV || srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV || srcType == GL_UNSIGNED_INT_5_9_9_9_REV || srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); /* general solution, no special cases, yet */ { GLint dstComponents; GLint rDst, gDst, bDst, aDst, lDst, iDst; GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); GLboolean intFormat = _mesa_is_integer_format(srcFormat); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } dstComponents = _mesa_components_in_format( dstFormat ); /* source & dest image formats should have been error checked by now */ assert(dstComponents > 0); /* EXT_texture_integer specifies no transfer ops on integer * types in the resolved issues section. Just set them to 0 * for integer surfaces. */ if (intFormat) transferOps = 0; /* * Extract image data and convert to RGBA floats */ if (srcFormat == GL_COLOR_INDEX) { GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); if (!indexes) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); free(rgba); return; } extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); /* Convert indexes to RGBA */ if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { _mesa_shift_and_offset_ci(ctx, n, indexes); } _mesa_map_ci_to_rgba(ctx, n, indexes, rgba); /* Don't do RGBA scale/bias or RGBA->RGBA mapping if starting * with color indexes. */ transferOps &= ~(IMAGE_SCALE_BIAS_BIT | IMAGE_MAP_COLOR_BIT); free(indexes); } else { /* non-color index data */ extract_float_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); } if (transferOps) { _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); } get_component_indexes(dstFormat, &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); /* Now pack results in the requested dstFormat */ if (rDst >= 0) { GLfloat *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[rDst] = rgba[i][RCOMP]; dst += dstComponents; } } if (gDst >= 0) { GLfloat *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[gDst] = rgba[i][GCOMP]; dst += dstComponents; } } if (bDst >= 0) { GLfloat *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[bDst] = rgba[i][BCOMP]; dst += dstComponents; } } if (aDst >= 0) { GLfloat *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[aDst] = rgba[i][ACOMP]; dst += dstComponents; } } if (iDst >= 0) { GLfloat *dst = dest; GLuint i; assert(iDst == 0); assert(dstComponents == 1); for (i = 0; i < n; i++) { /* Intensity comes from red channel */ dst[i] = rgba[i][RCOMP]; } } if (lDst >= 0) { GLfloat *dst = dest; GLuint i; assert(lDst == 0); for (i = 0; i < n; i++) { /* Luminance comes from red channel */ dst[0] = rgba[i][RCOMP]; dst += dstComponents; } } free(rgba); } } /** * Same as _mesa_unpack_color_span_ubyte(), but return GLuint data * instead of GLubyte. * No pixel transfer ops are applied. */ void _mesa_unpack_color_span_uint(struct gl_context *ctx, GLuint n, GLenum dstFormat, GLuint *dest, GLenum srcFormat, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking) { GLuint (*rgba)[4] = (GLuint (*)[4]) malloc(n * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } ASSERT(dstFormat == GL_ALPHA || dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_INTENSITY || dstFormat == GL_RED || dstFormat == GL_RG || dstFormat == GL_RGB || dstFormat == GL_RGBA); ASSERT(srcFormat == GL_RED || srcFormat == GL_GREEN || srcFormat == GL_BLUE || srcFormat == GL_ALPHA || srcFormat == GL_LUMINANCE || srcFormat == GL_LUMINANCE_ALPHA || srcFormat == GL_INTENSITY || srcFormat == GL_RG || srcFormat == GL_RGB || srcFormat == GL_BGR || srcFormat == GL_RGBA || srcFormat == GL_BGRA || srcFormat == GL_ABGR_EXT || srcFormat == GL_RED_INTEGER_EXT || srcFormat == GL_GREEN_INTEGER_EXT || srcFormat == GL_BLUE_INTEGER_EXT || srcFormat == GL_ALPHA_INTEGER_EXT || srcFormat == GL_RG_INTEGER || srcFormat == GL_RGB_INTEGER_EXT || srcFormat == GL_RGBA_INTEGER_EXT || srcFormat == GL_BGR_INTEGER_EXT || srcFormat == GL_BGRA_INTEGER_EXT || srcFormat == GL_LUMINANCE_INTEGER_EXT || srcFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT); ASSERT(srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_UNSIGNED_BYTE_3_3_2 || srcType == GL_UNSIGNED_BYTE_2_3_3_REV || srcType == GL_UNSIGNED_SHORT_5_6_5 || srcType == GL_UNSIGNED_SHORT_5_6_5_REV || srcType == GL_UNSIGNED_SHORT_4_4_4_4 || srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV || srcType == GL_UNSIGNED_SHORT_5_5_5_1 || srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV || srcType == GL_UNSIGNED_INT_8_8_8_8 || srcType == GL_UNSIGNED_INT_8_8_8_8_REV || srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV || srcType == GL_UNSIGNED_INT_5_9_9_9_REV || srcType == GL_UNSIGNED_INT_10F_11F_11F_REV); /* Extract image data as uint[4] pixels */ extract_uint_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); if (dstFormat == GL_RGBA) { /* simple case */ memcpy(dest, rgba, 4 * sizeof(GLuint) * n); } else { /* general case */ GLint rDst, gDst, bDst, aDst, lDst, iDst; GLint dstComponents = _mesa_components_in_format( dstFormat ); assert(dstComponents > 0); get_component_indexes(dstFormat, &rDst, &gDst, &bDst, &aDst, &lDst, &iDst); /* Now pack values in the requested dest format */ if (rDst >= 0) { GLuint *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[rDst] = rgba[i][RCOMP]; dst += dstComponents; } } if (gDst >= 0) { GLuint *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[gDst] = rgba[i][GCOMP]; dst += dstComponents; } } if (bDst >= 0) { GLuint *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[bDst] = rgba[i][BCOMP]; dst += dstComponents; } } if (aDst >= 0) { GLuint *dst = dest; GLuint i; for (i = 0; i < n; i++) { dst[aDst] = rgba[i][ACOMP]; dst += dstComponents; } } if (iDst >= 0) { GLuint *dst = dest; GLuint i; assert(iDst == 0); assert(dstComponents == 1); for (i = 0; i < n; i++) { /* Intensity comes from red channel */ dst[i] = rgba[i][RCOMP]; } } if (lDst >= 0) { GLuint *dst = dest; GLuint i; assert(lDst == 0); for (i = 0; i < n; i++) { /* Luminance comes from red channel */ dst[0] = rgba[i][RCOMP]; dst += dstComponents; } } } free(rgba); } /** * Similar to _mesa_unpack_color_span_float(), but for dudv data instead of rgba, * directly return GLbyte data, no transfer ops apply. */ void _mesa_unpack_dudv_span_byte( struct gl_context *ctx, GLuint n, GLenum dstFormat, GLbyte dest[], GLenum srcFormat, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, GLbitfield transferOps ) { ASSERT(dstFormat == GL_DUDV_ATI); ASSERT(srcFormat == GL_DUDV_ATI || srcFormat == GL_DU8DV8_ATI); ASSERT(srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT); /* general solution */ { GLint dstComponents; GLbyte *dst = dest; GLuint i; GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } dstComponents = _mesa_components_in_format( dstFormat ); /* source & dest image formats should have been error checked by now */ assert(dstComponents > 0); /* * Extract image data and convert to RGBA floats */ extract_float_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); /* Now determine which color channels we need to produce. * And determine the dest index (offset) within each color tuple. */ /* Now pack results in the requested dstFormat */ for (i = 0; i < n; i++) { /* not sure - need clamp[-1,1] here? */ dst[0] = FLOAT_TO_BYTE(rgba[i][RCOMP]); dst[1] = FLOAT_TO_BYTE(rgba[i][GCOMP]); dst += dstComponents; } free(rgba); } } /* * Unpack a row of color index data from a client buffer according to * the pixel unpacking parameters. * This is (or will be) used by glDrawPixels, glTexImage[123]D, etc. * * Args: ctx - the context * n - number of pixels * dstType - destination data type * dest - destination array * srcType - source pixel type * source - source data pointer * srcPacking - pixel unpacking parameters * transferOps - the pixel transfer operations to apply */ void _mesa_unpack_index_span( struct gl_context *ctx, GLuint n, GLenum dstType, GLvoid *dest, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, GLbitfield transferOps ) { ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT); ASSERT(dstType == GL_UNSIGNED_BYTE || dstType == GL_UNSIGNED_SHORT || dstType == GL_UNSIGNED_INT); transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); /* * Try simple cases first */ if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE) { memcpy(dest, source, n * sizeof(GLubyte)); } else if (transferOps == 0 && srcType == GL_UNSIGNED_INT && dstType == GL_UNSIGNED_INT && !srcPacking->SwapBytes) { memcpy(dest, source, n * sizeof(GLuint)); } else { /* * general solution */ GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); if (!indexes) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } extract_uint_indexes(n, indexes, GL_COLOR_INDEX, srcType, source, srcPacking); if (transferOps) _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); /* convert to dest type */ switch (dstType) { case GL_UNSIGNED_BYTE: { GLubyte *dst = (GLubyte *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLubyte) (indexes[i] & 0xff); } } break; case GL_UNSIGNED_SHORT: { GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLushort) (indexes[i] & 0xffff); } } break; case GL_UNSIGNED_INT: memcpy(dest, indexes, n * sizeof(GLuint)); break; default: _mesa_problem(ctx, "bad dstType in _mesa_unpack_index_span"); } free(indexes); } } void _mesa_pack_index_span( struct gl_context *ctx, GLuint n, GLenum dstType, GLvoid *dest, const GLuint *source, const struct gl_pixelstore_attrib *dstPacking, GLbitfield transferOps ) { GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); if (!indexes) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); return; } transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); if (transferOps & (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT)) { /* make a copy of input */ memcpy(indexes, source, n * sizeof(GLuint)); _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); source = indexes; } switch (dstType) { case GL_UNSIGNED_BYTE: { GLubyte *dst = (GLubyte *) dest; GLuint i; for (i = 0; i < n; i++) { *dst++ = (GLubyte) source[i]; } } break; case GL_BYTE: { GLbyte *dst = (GLbyte *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLbyte) source[i]; } } break; case GL_UNSIGNED_SHORT: { GLushort *dst = (GLushort *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLushort) source[i]; } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_SHORT: { GLshort *dst = (GLshort *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLshort) source[i]; } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_UNSIGNED_INT: { GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLuint) source[i]; } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_INT: { GLint *dst = (GLint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLint) source[i]; } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_FLOAT: { GLfloat *dst = (GLfloat *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLfloat) source[i]; } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_HALF_FLOAT_ARB: { GLhalfARB *dst = (GLhalfARB *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = _mesa_float_to_half((GLfloat) source[i]); } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; default: _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); } free(indexes); } /* * Unpack a row of stencil data from a client buffer according to * the pixel unpacking parameters. * This is (or will be) used by glDrawPixels * * Args: ctx - the context * n - number of pixels * dstType - destination data type * dest - destination array * srcType - source pixel type * source - source data pointer * srcPacking - pixel unpacking parameters * transferOps - apply offset/bias/lookup ops? */ void _mesa_unpack_stencil_span( struct gl_context *ctx, GLuint n, GLenum dstType, GLvoid *dest, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, GLbitfield transferOps ) { ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || srcType == GL_BYTE || srcType == GL_UNSIGNED_SHORT || srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || srcType == GL_UNSIGNED_INT_24_8_EXT || srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT || srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); ASSERT(dstType == GL_UNSIGNED_BYTE || dstType == GL_UNSIGNED_SHORT || dstType == GL_UNSIGNED_INT || dstType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); /* only shift and offset apply to stencil */ transferOps &= IMAGE_SHIFT_OFFSET_BIT; /* * Try simple cases first */ if (transferOps == 0 && !ctx->Pixel.MapStencilFlag && srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE) { memcpy(dest, source, n * sizeof(GLubyte)); } else if (transferOps == 0 && !ctx->Pixel.MapStencilFlag && srcType == GL_UNSIGNED_INT && dstType == GL_UNSIGNED_INT && !srcPacking->SwapBytes) { memcpy(dest, source, n * sizeof(GLuint)); } else { /* * general solution */ GLuint *indexes = (GLuint *) malloc(n * sizeof(GLuint)); if (!indexes) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil unpacking"); return; } extract_uint_indexes(n, indexes, GL_STENCIL_INDEX, srcType, source, srcPacking); if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { /* shift and offset indexes */ _mesa_shift_and_offset_ci(ctx, n, indexes); } if (ctx->Pixel.MapStencilFlag) { /* Apply stencil lookup table */ const GLuint mask = ctx->PixelMaps.StoS.Size - 1; GLuint i; for (i = 0; i < n; i++) { indexes[i] = (GLuint)ctx->PixelMaps.StoS.Map[ indexes[i] & mask ]; } } /* convert to dest type */ switch (dstType) { case GL_UNSIGNED_BYTE: { GLubyte *dst = (GLubyte *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLubyte) (indexes[i] & 0xff); } } break; case GL_UNSIGNED_SHORT: { GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = (GLushort) (indexes[i] & 0xffff); } } break; case GL_UNSIGNED_INT: memcpy(dest, indexes, n * sizeof(GLuint)); break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: { GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i*2+1] = indexes[i] & 0xff; /* lower 8 bits */ } } break; default: _mesa_problem(ctx, "bad dstType in _mesa_unpack_stencil_span"); } free(indexes); } } void _mesa_pack_stencil_span( struct gl_context *ctx, GLuint n, GLenum dstType, GLvoid *dest, const GLubyte *source, const struct gl_pixelstore_attrib *dstPacking ) { GLubyte *stencil = (GLubyte *) malloc(n * sizeof(GLubyte)); if (!stencil) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "stencil packing"); return; } if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag) { /* make a copy of input */ memcpy(stencil, source, n * sizeof(GLubyte)); _mesa_apply_stencil_transfer_ops(ctx, n, stencil); source = stencil; } switch (dstType) { case GL_UNSIGNED_BYTE: memcpy(dest, source, n); break; case GL_BYTE: { GLbyte *dst = (GLbyte *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_SHORT: { GLshort *dst = (GLshort *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_UNSIGNED_INT: { GLuint *dst = (GLuint *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_INT: { GLint *dst = (GLint *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_FLOAT: { GLfloat *dst = (GLfloat *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_HALF_FLOAT_ARB: { GLhalfARB *dst = (GLhalfARB *) dest; GLuint i; for (i=0;iSwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_BITMAP: if (dstPacking->LsbFirst) { GLubyte *dst = (GLubyte *) dest; GLint shift = 0; GLuint i; for (i = 0; i < n; i++) { if (shift == 0) *dst = 0; *dst |= ((source[i] != 0) << shift); shift++; if (shift == 8) { shift = 0; dst++; } } } else { GLubyte *dst = (GLubyte *) dest; GLint shift = 7; GLuint i; for (i = 0; i < n; i++) { if (shift == 7) *dst = 0; *dst |= ((source[i] != 0) << shift); shift--; if (shift < 0) { shift = 7; dst++; } } } break; default: _mesa_problem(ctx, "bad type in _mesa_pack_index_span"); } free(stencil); } #define DEPTH_VALUES(GLTYPE, GLTYPE2FLOAT) \ do { \ GLuint i; \ const GLTYPE *src = (const GLTYPE *)source; \ for (i = 0; i < n; i++) { \ GLTYPE value = src[i]; \ if (srcPacking->SwapBytes) { \ if (sizeof(GLTYPE) == 2) { \ SWAP2BYTE(value); \ } else if (sizeof(GLTYPE) == 4) { \ SWAP4BYTE(value); \ } \ } \ depthValues[i] = GLTYPE2FLOAT(value); \ } \ } while (0) /** * Unpack a row of depth/z values from memory, returning GLushort, GLuint * or GLfloat values. * The glPixelTransfer (scale/bias) params will be applied. * * \param dstType one of GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_FLOAT * \param depthMax max value for returned GLushort or GLuint values * (ignored for GLfloat). */ void _mesa_unpack_depth_span( struct gl_context *ctx, GLuint n, GLenum dstType, GLvoid *dest, GLuint depthMax, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking ) { GLfloat *depthTemp = NULL, *depthValues; GLboolean needClamp = GL_FALSE; /* Look for special cases first. * Not only are these faster, they're less prone to numeric conversion * problems. Otherwise, converting from an int type to a float then * back to an int type can introduce errors that will show up as * artifacts in things like depth peeling which uses glCopyTexImage. */ if (ctx->Pixel.DepthScale == 1.0 && ctx->Pixel.DepthBias == 0.0) { if (srcType == GL_UNSIGNED_INT && dstType == GL_UNSIGNED_SHORT) { const GLuint *src = (const GLuint *) source; GLushort *dst = (GLushort *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = src[i] >> 16; } return; } if (srcType == GL_UNSIGNED_SHORT && dstType == GL_UNSIGNED_INT && depthMax == 0xffffffff) { const GLushort *src = (const GLushort *) source; GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = src[i] | (src[i] << 16); } return; } if (srcType == GL_UNSIGNED_INT_24_8 && dstType == GL_UNSIGNED_INT && depthMax == 0xffffff) { const GLuint *src = (const GLuint *) source; GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = src[i] >> 8; } return; } /* XXX may want to add additional cases here someday */ } /* general case path follows */ if (dstType == GL_FLOAT) { depthValues = (GLfloat *) dest; } else { depthTemp = (GLfloat *) malloc(n * sizeof(GLfloat)); if (!depthTemp) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel unpacking"); return; } depthValues = depthTemp; } /* Convert incoming values to GLfloat. Some conversions will require * clamping, below. */ switch (srcType) { case GL_BYTE: DEPTH_VALUES(GLbyte, BYTE_TO_FLOATZ); needClamp = GL_TRUE; break; case GL_UNSIGNED_BYTE: DEPTH_VALUES(GLubyte, UBYTE_TO_FLOAT); break; case GL_SHORT: DEPTH_VALUES(GLshort, SHORT_TO_FLOATZ); needClamp = GL_TRUE; break; case GL_UNSIGNED_SHORT: DEPTH_VALUES(GLushort, USHORT_TO_FLOAT); break; case GL_INT: DEPTH_VALUES(GLint, INT_TO_FLOAT); needClamp = GL_TRUE; break; case GL_UNSIGNED_INT: DEPTH_VALUES(GLuint, UINT_TO_FLOAT); break; case GL_UNSIGNED_INT_24_8_EXT: /* GL_EXT_packed_depth_stencil */ if (dstType == GL_UNSIGNED_INT_24_8_EXT && depthMax == 0xffffff && ctx->Pixel.DepthScale == 1.0 && ctx->Pixel.DepthBias == 0.0) { const GLuint *src = (const GLuint *) source; GLuint *zValues = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { GLuint value = src[i]; if (srcPacking->SwapBytes) { SWAP4BYTE(value); } zValues[i] = value & 0xffffff00; } free(depthTemp); return; } else { const GLuint *src = (const GLuint *) source; const GLfloat scale = 1.0f / 0xffffff; GLuint i; for (i = 0; i < n; i++) { GLuint value = src[i]; if (srcPacking->SwapBytes) { SWAP4BYTE(value); } depthValues[i] = (value >> 8) * scale; } } break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: { GLuint i; const GLfloat *src = (const GLfloat *)source; for (i = 0; i < n; i++) { GLfloat value = src[i * 2]; if (srcPacking->SwapBytes) { SWAP4BYTE(value); } depthValues[i] = value; } needClamp = GL_TRUE; } break; case GL_FLOAT: DEPTH_VALUES(GLfloat, 1*); needClamp = GL_TRUE; break; case GL_HALF_FLOAT_ARB: { GLuint i; const GLhalfARB *src = (const GLhalfARB *) source; for (i = 0; i < n; i++) { GLhalfARB value = src[i]; if (srcPacking->SwapBytes) { SWAP2BYTE(value); } depthValues[i] = _mesa_half_to_float(value); } needClamp = GL_TRUE; } break; default: _mesa_problem(NULL, "bad type in _mesa_unpack_depth_span()"); free(depthTemp); return; } /* apply depth scale and bias */ { const GLfloat scale = ctx->Pixel.DepthScale; const GLfloat bias = ctx->Pixel.DepthBias; if (scale != 1.0 || bias != 0.0) { GLuint i; for (i = 0; i < n; i++) { depthValues[i] = depthValues[i] * scale + bias; } needClamp = GL_TRUE; } } /* clamp to [0, 1] */ if (needClamp) { GLuint i; for (i = 0; i < n; i++) { depthValues[i] = (GLfloat)CLAMP(depthValues[i], 0.0, 1.0); } } /* * Convert values to dstType */ if (dstType == GL_UNSIGNED_INT) { GLuint *zValues = (GLuint *) dest; GLuint i; if (depthMax <= 0xffffff) { /* no overflow worries */ for (i = 0; i < n; i++) { zValues[i] = (GLuint) (depthValues[i] * (GLfloat) depthMax); } } else { /* need to use double precision to prevent overflow problems */ for (i = 0; i < n; i++) { GLdouble z = depthValues[i] * (GLfloat) depthMax; if (z >= (GLdouble) 0xffffffff) zValues[i] = 0xffffffff; else zValues[i] = (GLuint) z; } } } else if (dstType == GL_UNSIGNED_SHORT) { GLushort *zValues = (GLushort *) dest; GLuint i; ASSERT(depthMax <= 0xffff); for (i = 0; i < n; i++) { zValues[i] = (GLushort) (depthValues[i] * (GLfloat) depthMax); } } else if (dstType == GL_FLOAT) { /* Nothing to do. depthValues is pointing to dest. */ } else if (dstType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV) { GLfloat *zValues = (GLfloat*) dest; GLuint i; for (i = 0; i < n; i++) { zValues[i*2] = depthValues[i]; } } else { ASSERT(0); } free(depthTemp); } /* * Pack an array of depth values. The values are floats in [0,1]. */ void _mesa_pack_depth_span( struct gl_context *ctx, GLuint n, GLvoid *dest, GLenum dstType, const GLfloat *depthSpan, const struct gl_pixelstore_attrib *dstPacking ) { GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); if (!depthCopy) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); return; } if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { memcpy(depthCopy, depthSpan, n * sizeof(GLfloat)); _mesa_scale_and_bias_depth(ctx, n, depthCopy); depthSpan = depthCopy; } switch (dstType) { case GL_UNSIGNED_BYTE: { GLubyte *dst = (GLubyte *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = FLOAT_TO_UBYTE( depthSpan[i] ); } } break; case GL_BYTE: { GLbyte *dst = (GLbyte *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = FLOAT_TO_BYTE( depthSpan[i] ); } } break; case GL_UNSIGNED_SHORT: { GLushort *dst = (GLushort *) dest; GLuint i; for (i = 0; i < n; i++) { CLAMPED_FLOAT_TO_USHORT(dst[i], depthSpan[i]); } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_SHORT: { GLshort *dst = (GLshort *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = FLOAT_TO_SHORT( depthSpan[i] ); } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; case GL_UNSIGNED_INT: { GLuint *dst = (GLuint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = FLOAT_TO_UINT( depthSpan[i] ); } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_INT: { GLint *dst = (GLint *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = FLOAT_TO_INT( depthSpan[i] ); } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_FLOAT: { GLfloat *dst = (GLfloat *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = depthSpan[i]; } if (dstPacking->SwapBytes) { _mesa_swap4( (GLuint *) dst, n ); } } break; case GL_HALF_FLOAT_ARB: { GLhalfARB *dst = (GLhalfARB *) dest; GLuint i; for (i = 0; i < n; i++) { dst[i] = _mesa_float_to_half(depthSpan[i]); } if (dstPacking->SwapBytes) { _mesa_swap2( (GLushort *) dst, n ); } } break; default: _mesa_problem(ctx, "bad type in _mesa_pack_depth_span"); } free(depthCopy); } /** * Pack depth and stencil values as GL_DEPTH_STENCIL (GL_UNSIGNED_INT_24_8 etc) */ void _mesa_pack_depth_stencil_span(struct gl_context *ctx,GLuint n, GLenum dstType, GLuint *dest, const GLfloat *depthVals, const GLubyte *stencilVals, const struct gl_pixelstore_attrib *dstPacking) { GLfloat *depthCopy = (GLfloat *) malloc(n * sizeof(GLfloat)); GLubyte *stencilCopy = (GLubyte *) malloc(n * sizeof(GLubyte)); GLuint i; if (!depthCopy || !stencilCopy) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "pixel packing"); free(depthCopy); free(stencilCopy); return; } if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { memcpy(depthCopy, depthVals, n * sizeof(GLfloat)); _mesa_scale_and_bias_depth(ctx, n, depthCopy); depthVals = depthCopy; } if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag) { memcpy(stencilCopy, stencilVals, n * sizeof(GLubyte)); _mesa_apply_stencil_transfer_ops(ctx, n, stencilCopy); stencilVals = stencilCopy; } switch (dstType) { case GL_UNSIGNED_INT_24_8: for (i = 0; i < n; i++) { GLuint z = (GLuint) (depthVals[i] * 0xffffff); dest[i] = (z << 8) | (stencilVals[i] & 0xff); } break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: for (i = 0; i < n; i++) { ((GLfloat*)dest)[i*2] = depthVals[i]; dest[i*2+1] = stencilVals[i] & 0xff; } break; } if (dstPacking->SwapBytes) { _mesa_swap4(dest, n); } free(depthCopy); free(stencilCopy); } /** * Unpack image data. Apply byte swapping, byte flipping (bitmap). * Return all image data in a contiguous block. This is used when we * compile glDrawPixels, glTexImage, etc into a display list. We * need a copy of the data in a standard format. */ void * _mesa_unpack_image( GLuint dimensions, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *unpack ) { GLint bytesPerRow, compsPerRow; GLboolean flipBytes, swap2, swap4; if (!pixels) return NULL; /* not necessarily an error */ if (width <= 0 || height <= 0 || depth <= 0) return NULL; /* generate error later */ if (type == GL_BITMAP) { bytesPerRow = (width + 7) >> 3; flipBytes = unpack->LsbFirst; swap2 = swap4 = GL_FALSE; compsPerRow = 0; } else { const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); GLint components = _mesa_components_in_format(format); GLint bytesPerComp; if (_mesa_type_is_packed(type)) components = 1; if (bytesPerPixel <= 0 || components <= 0) return NULL; /* bad format or type. generate error later */ bytesPerRow = bytesPerPixel * width; bytesPerComp = bytesPerPixel / components; flipBytes = GL_FALSE; swap2 = (bytesPerComp == 2) && unpack->SwapBytes; swap4 = (bytesPerComp == 4) && unpack->SwapBytes; compsPerRow = components * width; assert(compsPerRow >= width); } { GLubyte *destBuffer = (GLubyte *) malloc(bytesPerRow * height * depth); GLubyte *dst; GLint img, row; if (!destBuffer) return NULL; /* generate GL_OUT_OF_MEMORY later */ dst = destBuffer; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { const GLvoid *src = _mesa_image_address(dimensions, unpack, pixels, width, height, format, type, img, row, 0); if ((type == GL_BITMAP) && (unpack->SkipPixels & 0x7)) { GLint i; flipBytes = GL_FALSE; if (unpack->LsbFirst) { GLubyte srcMask = 1 << (unpack->SkipPixels & 0x7); GLubyte dstMask = 128; const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 128) { srcMask = 1; s++; } else { srcMask = srcMask << 1; } if (dstMask == 1) { dstMask = 128; d++; *d = 0; } else { dstMask = dstMask >> 1; } } } else { GLubyte srcMask = 128 >> (unpack->SkipPixels & 0x7); GLubyte dstMask = 128; const GLubyte *s = src; GLubyte *d = dst; *d = 0; for (i = 0; i < width; i++) { if (*s & srcMask) { *d |= dstMask; } if (srcMask == 1) { srcMask = 128; s++; } else { srcMask = srcMask >> 1; } if (dstMask == 1) { dstMask = 128; d++; *d = 0; } else { dstMask = dstMask >> 1; } } } } else { memcpy(dst, src, bytesPerRow); } /* byte flipping/swapping */ if (flipBytes) { flip_bytes((GLubyte *) dst, bytesPerRow); } else if (swap2) { _mesa_swap2((GLushort*) dst, compsPerRow); } else if (swap4) { _mesa_swap4((GLuint*) dst, compsPerRow); } dst += bytesPerRow; } } return destBuffer; } }