X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fimage.c;h=cad9736b30b0a6df5fc70f4ec7730424ed960989;hb=ee5b7f0574c6c5bce9ab75a2825f1fe089a57fa5;hp=99cbcfa862543db5089b962358a3c8450772b7a0;hpb=b1394fa92aaaf859ce9efc8b5fc194397921320c;p=mesa.git diff --git a/src/mesa/main/image.c b/src/mesa/main/image.c index 99cbcfa8625..cad9736b30b 100644 --- a/src/mesa/main/image.c +++ b/src/mesa/main/image.c @@ -1,21 +1,19 @@ -/* $Id: image.c,v 1.42 2000/09/26 20:53:53 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.5 - * - * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. - * + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul 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 @@ -25,49 +23,82 @@ */ -#ifdef PC_HEADER -#include "all.h" -#else +/** + * \file image.c + * Image handling. + */ + + #include "glheader.h" +#include "colormac.h" #include "context.h" #include "image.h" -#include "imaging.h" +#include "imports.h" +#include "histogram.h" #include "macros.h" -#include "mem.h" -#include "mmath.h" #include "pixel.h" -#include "types.h" -#endif - -/* - * These are the image packing parameters for Mesa's internal images. - * That is, _mesa_unpack_image() returns image data in this format. - * When we execute image commands (glDrawPixels, glTexImage, etc) - * from within display lists we have to be sure to set the current - * unpacking params to these values! +/** + * NOTE: + * Normally, BYTE_TO_FLOAT(0) returns 0.00392 That causes problems when + * we later convert the float to a packed integer value (such as for + * GL_RGB5_A1) because we'll wind up with a non-zero value. + * + * We redefine the macros here so zero is handled correctly. */ -const struct gl_pixelstore_attrib _mesa_native_packing = { - 1, /* Alignment */ - 0, /* RowLength */ - 0, /* SkipPixels */ - 0, /* SkipRows */ - 0, /* ImageHeight */ - 0, /* SkipImages */ - GL_FALSE, /* SwapBytes */ - GL_FALSE /* LsbFirst */ -}; +#undef BYTE_TO_FLOAT +#define BYTE_TO_FLOAT(B) ((B) == 0 ? 0.0F : ((2.0F * (B) + 1.0F) * (1.0F/255.0F))) +#undef SHORT_TO_FLOAT +#define SHORT_TO_FLOAT(S) ((S) == 0 ? 0.0F : ((2.0F * (S) + 1.0F) * (1.0F/65535.0F))) -/* + +/** Compute ceiling of integer quotient of A divided by B. */ +#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + + +/** + * \return GL_TRUE if type is packed pixel type, GL_FALSE otherwise. + */ +static GLboolean +_mesa_type_is_packed(GLenum type) + { + switch (type) { + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + case GL_UNSIGNED_INT_24_8_EXT: + return GL_TRUE; + } + + return GL_FALSE; +} + +/** * Flip the 8 bits in each byte of the given array. * - * XXX try this trick to flip bytes someday: + * \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 ) @@ -89,8 +120,11 @@ flip_bytes( GLubyte *p, GLuint n ) } -/* +/** * Flip the order of the 2 bytes in each word in the given array. + * + * \param p array. + * \param n number of words. */ void _mesa_swap2( GLushort *p, GLuint n ) @@ -123,14 +157,16 @@ _mesa_swap4( GLuint *p, GLuint n ) } - - -/* - * Return the size, in bytes, of the given GL datatype. - * Return 0 if GL_BITMAP. - * Return -1 if invalid type enum. +/** + * Get the size of a GL data type. + * + * \param type GL data type. + * + * \return the size, in bytes, of the given data type, 0 if a GL_BITMAP, or -1 + * if an invalid type enum. */ -GLint _mesa_sizeof_type( GLenum type ) +GLint +_mesa_sizeof_type( GLenum type ) { switch (type) { case GL_BITMAP: @@ -149,17 +185,20 @@ GLint _mesa_sizeof_type( GLenum type ) return sizeof(GLint); case GL_FLOAT: return sizeof(GLfloat); + case GL_HALF_FLOAT_ARB: + return sizeof(GLhalfARB); default: return -1; } } -/* - * Same as _mesa_sizeof_packed_type() but we also accept the - * packed pixel format datatypes. +/** + * Same as _mesa_sizeof_type() but also accepting the packed pixel + * format data types. */ -GLint _mesa_sizeof_packed_type( GLenum type ) +GLint +_mesa_sizeof_packed_type( GLenum type ) { switch (type) { case GL_BITMAP: @@ -176,6 +215,8 @@ GLint _mesa_sizeof_packed_type( GLenum type ) return sizeof(GLuint); case GL_INT: return sizeof(GLint); + case GL_HALF_FLOAT_ARB: + return sizeof(GLhalfARB); case GL_FLOAT: return sizeof(GLfloat); case GL_UNSIGNED_BYTE_3_3_2: @@ -183,17 +224,17 @@ GLint _mesa_sizeof_packed_type( GLenum type ) case GL_UNSIGNED_BYTE_2_3_3_REV: return sizeof(GLubyte); case GL_UNSIGNED_SHORT_5_6_5: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_SHORT_5_6_5_REV: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_SHORT_4_4_4_4: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_SHORT_4_4_4_4_REV: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_SHORT_5_5_5_1: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_SHORT_1_5_5_5_REV: - return sizeof(GLshort); + return sizeof(GLushort); case GL_UNSIGNED_INT_8_8_8_8: return sizeof(GLuint); case GL_UNSIGNED_INT_8_8_8_8_REV: @@ -202,18 +243,26 @@ GLint _mesa_sizeof_packed_type( GLenum type ) return sizeof(GLuint); case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + return sizeof(GLushort); + case GL_UNSIGNED_INT_24_8_EXT: + return sizeof(GLuint); default: return -1; } } - -/* - * Return the number of components in a GL enum pixel type. - * Return -1 if bad format. +/** + * Get the number of components in a pixel format. + * + * \param format pixel format. + * + * \return the number of components in the given format, or -1 if a bad format. */ -GLint _mesa_components_in_format( GLenum format ) +GLint +_mesa_components_in_format( GLenum format ) { switch (format) { case GL_COLOR_INDEX: @@ -244,17 +293,26 @@ GLint _mesa_components_in_format( GLenum format ) return 4; case GL_ABGR_EXT: return 4; + case GL_YCBCR_MESA: + return 2; + case GL_DEPTH_STENCIL_EXT: + return 2; default: return -1; } } -/* - * Return bytes per pixel for given format and type - * Return -1 if bad format or type. +/** + * Get the bytes per pixel of pixel format type pair. + * + * \param format pixel format. + * \param type pixel type. + * + * \return bytes per pixel, or -1 if a bad format or type was given. */ -GLint _mesa_bytes_per_pixel( GLenum format, GLenum type ) +GLint +_mesa_bytes_per_pixel( GLenum format, GLenum type ) { GLint comps = _mesa_components_in_format( format ); if (comps < 0) @@ -274,6 +332,8 @@ GLint _mesa_bytes_per_pixel( GLenum format, GLenum type ) return comps * sizeof(GLint); case GL_FLOAT: return comps * sizeof(GLfloat); + case GL_HALF_FLOAT_ARB: + return comps * sizeof(GLhalfARB); case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: if (format == GL_RGB || format == GL_BGR) @@ -283,7 +343,7 @@ GLint _mesa_bytes_per_pixel( GLenum format, GLenum type ) case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: if (format == GL_RGB || format == GL_BGR) - return sizeof(GLshort); + return sizeof(GLushort); else return -1; /* error */ case GL_UNSIGNED_SHORT_4_4_4_4: @@ -302,18 +362,34 @@ GLint _mesa_bytes_per_pixel( GLenum format, GLenum type ) return sizeof(GLuint); else return -1; + case GL_UNSIGNED_SHORT_8_8_MESA: + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + if (format == GL_YCBCR_MESA) + return sizeof(GLushort); + else + return -1; + case GL_UNSIGNED_INT_24_8_EXT: + if (format == GL_DEPTH_STENCIL_EXT) + return sizeof(GLuint); + else + return -1; default: return -1; } } -/* - * Test if the given pixel format and type are legal. - * Return GL_TRUE for legal, GL_FALSE for illegal. +/** + * Test for a legal pixel format and type. + * + * \param format pixel format. + * \param type pixel type. + * + * \return GL_TRUE if the given pixel format and type are legal, or GL_FALSE + * otherwise. */ GLboolean -_mesa_is_legal_format_and_type( GLenum format, GLenum type ) +_mesa_is_legal_format_and_type( GLcontext *ctx, GLenum format, GLenum type ) { switch (format) { case GL_COLOR_INDEX: @@ -328,6 +404,8 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) case GL_UNSIGNED_INT: case GL_FLOAT: return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; default: return GL_FALSE; } @@ -335,11 +413,12 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) case GL_GREEN: case GL_BLUE: case GL_ALPHA: +#if 0 /* not legal! see table 3.6 of the 1.5 spec */ case GL_INTENSITY: +#endif case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: case GL_DEPTH_COMPONENT: - case GL_BGR: switch (type) { case GL_BYTE: case GL_UNSIGNED_BYTE: @@ -349,6 +428,8 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) case GL_UNSIGNED_INT: case GL_FLOAT: return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; default: return GL_FALSE; } @@ -366,6 +447,26 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; + default: + return GL_FALSE; + } + case GL_BGR: + switch (type) { + /* NOTE: no packed types are supported with BGR. That's + * intentional, according to the GL spec. + */ + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; default: return GL_FALSE; } @@ -389,9 +490,23 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_TRUE; + case GL_HALF_FLOAT_ARB: + return ctx->Extensions.ARB_half_float_pixel; default: return GL_FALSE; } + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_MESA || + type == GL_UNSIGNED_SHORT_8_8_REV_MESA) + return GL_TRUE; + else + return GL_FALSE; + case GL_DEPTH_STENCIL_EXT: + if (ctx->Extensions.EXT_packed_depth_stencil + && type == GL_UNSIGNED_INT_24_8_EXT) + return GL_TRUE; + else + return GL_FALSE; default: ; /* fall-through */ } @@ -399,23 +514,32 @@ _mesa_is_legal_format_and_type( GLenum format, GLenum type ) } - -/* - * Return the address of a pixel in an image (actually a volume). - * Pixel unpacking/packing parameters are observed according to 'packing'. - * Input: image - start of image data - * width, height - size of image - * format - image format - * type - pixel component type - * packing - the pixelstore attributes - * img - which image in the volume (0 for 1D or 2D images) - * row, column - location of pixel in the image - * Return: address of pixel at (image,row,column) in image or NULL if error. +/** + * Return the address of a specific pixel in an image (1D, 2D or 3D). + * + * Pixel unpacking/packing parameters are observed according to \p packing. + * + * \param dimensions either 1, 2 or 3 to indicate dimensionality of image + * \param image starting address of image data + * \param width the image width + * \param height theimage height + * \param format the pixel format + * \param type the pixel data type + * \param packing the pixelstore attributes + * \param img which image in the volume (0 for 1D or 2D images) + * \param row row of pixel in the image (0 for 1D images) + * \param column column of pixel in the image + * + * \return address of pixel on success, or NULL on error. + * + * \sa gl_pixelstore_attrib. */ GLvoid * -_mesa_image_address( const struct gl_pixelstore_attrib *packing, - const GLvoid *image, GLsizei width, - GLsizei height, GLenum format, GLenum type, +_mesa_image_address( GLuint dimensions, + const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, GLint img, GLint row, GLint column ) { GLint alignment; /* 1, 2 or 4 */ @@ -426,6 +550,8 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, GLint skipimages; /* for 3-D volume images */ GLubyte *pixel_addr; + ASSERT(dimensions >= 1 && dimensions <= 3); + alignment = packing->Alignment; if (packing->RowLength > 0) { pixels_per_row = packing->RowLength; @@ -439,11 +565,14 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, else { rows_per_image = height; } - skiprows = packing->SkipRows; + skippixels = packing->SkipPixels; - skipimages = packing->SkipImages; + /* Note: SKIP_ROWS _is_ used for 1D images */ + skiprows = packing->SkipRows; + /* Note: SKIP_IMAGES is only used for 3D images */ + skipimages = (dimensions == 3) ? packing->SkipImages : 0; - if (type==GL_BITMAP) { + if (type == GL_BITMAP) { /* BITMAP data */ GLint comp_per_pixel; /* components per pixel */ GLint bytes_per_comp; /* bytes per component */ @@ -452,13 +581,13 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, /* Compute bytes per component */ bytes_per_comp = _mesa_sizeof_packed_type( type ); - if (bytes_per_comp<0) { + if (bytes_per_comp < 0) { return NULL; } /* Compute number of components per pixel */ comp_per_pixel = _mesa_components_in_format( format ); - if (comp_per_pixel<0 && type != GL_BITMAP) { + if (comp_per_pixel < 0) { return NULL; } @@ -475,6 +604,7 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, else { /* Non-BITMAP data */ GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image; + GLint topOfImage; bytes_per_pixel = _mesa_bytes_per_pixel( format, type ); @@ -490,9 +620,19 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, bytes_per_image = bytes_per_row * rows_per_image; + if (packing->Invert) { + /* set pixel_addr to the last row */ + topOfImage = bytes_per_row * (height - 1); + bytes_per_row = -bytes_per_row; + } + else { + topOfImage = 0; + } + /* compute final pixel address */ pixel_addr = (GLubyte *) image + (skipimages + img) * bytes_per_image + + topOfImage + (skiprows + row) * bytes_per_row + (skippixels + column) * bytes_per_pixel; } @@ -501,31 +641,114 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing, } +GLvoid * +_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, + GLenum format, GLenum type, + GLint column ) +{ + return _mesa_image_address(1, packing, image, width, 1, + format, type, 0, 0, column); +} -/* - * Compute the stride between image rows (in bytes) for the given - * pixel packing parameters and image width, format and type. + +GLvoid * +_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint row, GLint column ) +{ + return _mesa_image_address(2, packing, image, width, height, + format, type, 0, row, column); +} + + +GLvoid * +_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, + const GLvoid *image, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLint img, GLint row, GLint column ) +{ + return _mesa_image_address(3, packing, image, width, height, + format, type, img, row, column); +} + + + +/** + * Compute the stride (in bytes) between image rows. + * + * \param packing the pixelstore attributes + * \param width image width. + * \param format pixel format. + * \param type pixel data type. + * + * \return the stride in bytes for the given parameters, or -1 if error */ GLint _mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, GLint width, GLenum format, GLenum type ) { + GLint bytesPerRow, remainder; + ASSERT(packing); + if (type == GL_BITMAP) { - /* BITMAP data */ if (packing->RowLength == 0) { - GLint bytes = (width + 7) / 8; - return bytes; + bytesPerRow = (width + 7) / 8; } else { - GLint bytes = (packing->RowLength + 7) / 8; - return bytes; + bytesPerRow = (packing->RowLength + 7) / 8; } } else { /* Non-BITMAP data */ const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); - GLint bytesPerRow, remainder; + if (bytesPerPixel <= 0) + return -1; /* error */ + if (packing->RowLength == 0) { + bytesPerRow = bytesPerPixel * width; + } + else { + bytesPerRow = bytesPerPixel * packing->RowLength; + } + } + + remainder = bytesPerRow % packing->Alignment; + if (remainder > 0) { + bytesPerRow += (packing->Alignment - remainder); + } + + if (packing->Invert) { + /* negate the bytes per row (negative row stride) */ + bytesPerRow = -bytesPerRow; + } + + return bytesPerRow; +} + + +#if _HAVE_FULL_GL + +/* + * Compute the stride between images in a 3D texture (in bytes) for the given + * pixel packing parameters and image width, format and type. + */ +GLint +_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, + GLint width, GLint height, + GLenum format, GLenum type ) +{ + ASSERT(packing); + ASSERT(type != GL_BITMAP); + + { + const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); + GLint bytesPerRow, bytesPerImage, remainder; + if (bytesPerPixel <= 0) return -1; /* error */ if (packing->RowLength == 0) { @@ -537,12 +760,17 @@ _mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, remainder = bytesPerRow % packing->Alignment; if (remainder > 0) bytesPerRow += (packing->Alignment - remainder); - return bytesPerRow; + + if (packing->ImageHeight == 0) + bytesPerImage = bytesPerRow * height; + else + bytesPerImage = bytesPerRow * packing->ImageHeight; + + return bytesPerImage; } } - /* * Unpack a 32x32 pixel polygon stipple from user memory using the * current pixel unpack settings. @@ -551,7 +779,7 @@ 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 ); + GLubyte *ptrn = (GLubyte *) _mesa_unpack_bitmap(32, 32, pattern, unpacking); if (ptrn) { /* Convert pattern from GLubytes to GLuints and handle big/little * endian differences @@ -565,12 +793,11 @@ _mesa_unpack_polygon_stipple( const GLubyte *pattern, GLuint dest[32], | (p[3] ); p += 4; } - FREE(ptrn); + _mesa_free(ptrn); } } - /* * Pack polygon stipple into user memory given current pixel packing * settings. @@ -595,149 +822,414 @@ _mesa_pack_polygon_stipple( const GLuint pattern[32], GLubyte *dest, } - /* - * Pack the given RGBA span into client memory at 'dest' address - * in the given pixel format and type. - * Optionally apply the enabled pixel transfer ops. - * Pack into memory using the given packing params struct. - * This is used by glReadPixels and glGetTexImage?D() - * Input: ctx - the context - * n - number of pixels in the span - * rgba - the pixels - * format - dest packing format - * type - dest packing datatype - * destination - destination packing address - * packing - pixel packing parameters - * transferOps - bitmask of IMAGE_*_BIT operations to apply + * Unpack bitmap data. Resulting data will be in most-significant-bit-first + * order with row alignment = 1 byte. */ -void -_mesa_pack_rgba_span( GLcontext *ctx, - GLuint n, CONST GLubyte srcRgba[][4], - GLenum dstFormat, GLenum dstType, - GLvoid *dstAddr, - const struct gl_pixelstore_attrib *dstPacking, - GLuint transferOps) +GLvoid * +_mesa_unpack_bitmap( GLint width, GLint height, const GLubyte *pixels, + const struct gl_pixelstore_attrib *packing ) { - ASSERT(ctx->ImageTransferState != UPDATE_IMAGE_TRANSFER_STATE); + GLint bytes, row, width_in_bytes; + GLubyte *buffer, *dst; - /* Test for optimized case first */ - if (transferOps == 0 && dstFormat == GL_RGBA - && dstType == GL_UNSIGNED_BYTE) { - /* common simple case */ - MEMCPY(dstAddr, srcRgba, n * 4 * sizeof(GLubyte)); - } - else if (transferOps == 0 && dstFormat == GL_RGB - && dstType == GL_UNSIGNED_BYTE) { - /* common simple case */ - GLint i; - GLubyte *dest = (GLubyte *) dstAddr; - for (i = 0; i < n; i++) { - dest[0] = srcRgba[i][RCOMP]; - dest[1] = srcRgba[i][GCOMP]; - dest[2] = srcRgba[i][BCOMP]; - dest += 3; + if (!pixels) + return NULL; + + /* Alloc dest storage */ + bytes = ((width + 7) / 8 * height); + buffer = (GLubyte *) _mesa_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) { + _mesa_free(buffer); + return NULL; } - } - else { - /* general solution */ - GLfloat rgba[MAX_WIDTH][4]; - const GLfloat rscale = 1.0F / 255.0F; - const GLfloat gscale = 1.0F / 255.0F; - const GLfloat bscale = 1.0F / 255.0F; - const GLfloat ascale = 1.0F / 255.0F; - GLuint i; - assert(n <= MAX_WIDTH); - /* convert color components to floating point */ - for (i=0;iSkipPixels == 0) { + _mesa_memcpy( dst, src, width_in_bytes ); + if (packing->LsbFirst) { + flip_bytes( dst, width_in_bytes ); + } } - _mesa_pack_float_rgba_span(ctx, n, (const GLfloat (*)[4]) rgba, - dstFormat, dstType, dstAddr, - dstPacking, transferOps); + 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_float_rgba_span( GLcontext *ctx, - GLuint n, CONST GLfloat rgbaIn[][4], - GLenum dstFormat, GLenum dstType, - GLvoid *dstAddr, - const struct gl_pixelstore_attrib *dstPacking, - GLuint transferOps ) +_mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source, + GLubyte *dest, const struct gl_pixelstore_attrib *packing ) { - const GLint comps = _mesa_components_in_format(dstFormat); - GLfloat luminance[MAX_WIDTH]; - GLfloat (*rgba)[4]; - GLuint i; + GLint row, width_in_bytes; + const GLubyte *src; - if (transferOps) { - /* make copy of incoming data */ - GLfloat rgbaCopy[MAX_WIDTH][4]; - for (i = 0; i < n; i++) { - rgbaCopy[i][0] = rgbaIn[i][0]; - rgbaCopy[i][1] = rgbaIn[i][1]; - rgbaCopy[i][2] = rgbaIn[i][2]; - rgbaCopy[i][3] = rgbaIn[i][3]; - } + if (!source) + return; - rgba = (GLfloat (*)[4]) rgbaCopy; + 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; - /* scale & bias */ - if (transferOps & IMAGE_SCALE_BIAS_BIT) { - _mesa_scale_and_bias_rgba( ctx, n, rgba ); + if (packing->SkipPixels == 0) { + _mesa_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; + } + } + } } - /* color map lookup */ - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_rgba( ctx, n, rgba ); + src += width_in_bytes; + } +} + + +/** + * Apply various pixel transfer operations to an array of RGBA pixels + * as indicated by the transferOps bitmask + */ +void +_mesa_apply_rgba_transfer_ops(GLcontext *ctx, GLbitfield transferOps, + GLuint n, GLfloat rgba[][4]) +{ + /* scale & bias */ + if (transferOps & IMAGE_SCALE_BIAS_BIT) { + _mesa_scale_and_bias_rgba(n, rgba, + ctx->Pixel.RedScale, ctx->Pixel.GreenScale, + ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, + ctx->Pixel.RedBias, ctx->Pixel.GreenBias, + ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); + } + /* color map lookup */ + if (transferOps & IMAGE_MAP_COLOR_BIT) { + _mesa_map_rgba( ctx, n, rgba ); + } + /* GL_COLOR_TABLE lookup */ + if (transferOps & IMAGE_COLOR_TABLE_BIT) { + _mesa_lookup_rgba_float(&ctx->ColorTable[COLORTABLE_PRECONVOLUTION], n, rgba); + } + /* convolution */ + if (transferOps & IMAGE_CONVOLUTION_BIT) { + /* this has to be done in the calling code */ + _mesa_problem(ctx, "IMAGE_CONVOLUTION_BIT set in _mesa_apply_transfer_ops"); + } + /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */ + if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) { + _mesa_scale_and_bias_rgba(n, rgba, + ctx->Pixel.PostConvolutionScale[RCOMP], + ctx->Pixel.PostConvolutionScale[GCOMP], + ctx->Pixel.PostConvolutionScale[BCOMP], + ctx->Pixel.PostConvolutionScale[ACOMP], + ctx->Pixel.PostConvolutionBias[RCOMP], + ctx->Pixel.PostConvolutionBias[GCOMP], + ctx->Pixel.PostConvolutionBias[BCOMP], + ctx->Pixel.PostConvolutionBias[ACOMP]); + } + /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ + if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { + _mesa_lookup_rgba_float(&ctx->ColorTable[COLORTABLE_POSTCONVOLUTION], n, rgba); + } + /* color matrix transform */ + if (transferOps & IMAGE_COLOR_MATRIX_BIT) { + _mesa_transform_rgba(ctx, n, rgba); + } + /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ + if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { + _mesa_lookup_rgba_float(&ctx->ColorTable[COLORTABLE_POSTCOLORMATRIX], n, rgba); + } + /* update histogram count */ + if (transferOps & IMAGE_HISTOGRAM_BIT) { + _mesa_update_histogram(ctx, n, (CONST GLfloat (*)[4]) rgba); + } + /* update min/max values */ + if (transferOps & IMAGE_MIN_MAX_BIT) { + _mesa_update_minmax(ctx, n, (CONST GLfloat (*)[4]) rgba); + } + /* clamping to [0,1] */ + if (transferOps & IMAGE_CLAMP_BIT) { + GLuint i; + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); + rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); + rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); + rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); } - /* GL_COLOR_TABLE lookup */ - if (transferOps & IMAGE_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->ColorTable, n, rgba); + } +} + + +/* + * Apply color index shift and offset to an array of pixels. + */ +static void +shift_and_offset_ci( const GLcontext *ctx, GLuint n, GLuint indexes[] ) +{ + GLint shift = ctx->Pixel.IndexShift; + GLint offset = ctx->Pixel.IndexOffset; + GLuint i; + if (shift > 0) { + for (i=0;i> shift) + offset; } - /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, n, rgba); + } + else { + for (i=0;iPixelMaps.ItoI.Size - 1; + GLuint i; + for (i = 0; i < n; i++) { + const GLuint j = indexes[i] & mask; + indexes[i] = IROUND(ctx->PixelMaps.ItoI.Map[j]); } - /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, n, rgba); + } +} + + +/** + * Apply stencil index shift, offset and table lookup to an array + * of stencil values. + */ +void +_mesa_apply_stencil_transfer_ops(const GLcontext *ctx, GLuint n, + GLstencil stencil[]) +{ + if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) { + const GLint offset = ctx->Pixel.IndexOffset; + GLint shift = ctx->Pixel.IndexShift; + GLuint i; + if (shift > 0) { + for (i = 0; i < n; i++) { + stencil[i] = (stencil[i] << shift) + offset; + } } - /* update histogram count */ - if (transferOps & IMAGE_HISTOGRAM_BIT) { - _mesa_update_histogram(ctx, n, (CONST GLfloat (*)[4]) rgba); + else if (shift < 0) { + shift = -shift; + for (i = 0; i < n; i++) { + stencil[i] = (stencil[i] >> shift) + offset; + } } - /* min/max here */ - if (transferOps & IMAGE_MIN_MAX_BIT) { - _mesa_update_minmax(ctx, n, (CONST GLfloat (*)[4]) rgba); - if (ctx->MinMax.Sink) - return; + else { + for (i = 0; i < n; i++) { + stencil[i] = stencil[i] + offset; + } } } - else { - /* use incoming data, not a copy */ - rgba = (GLfloat (*)[4]) rgbaIn; + if (ctx->Pixel.MapStencilFlag) { + GLuint mask = ctx->PixelMaps.StoS.Size - 1; + GLuint i; + for (i = 0; i < n; i++) { + stencil[i] = ctx->PixelMaps.StoS.Map[ stencil[i] & mask ]; + } } +} + + +/** + * Used to pack an array [][4] of RGBA float colors as specified + * by the dstFormat, dstType and dstPacking. Used by glReadPixels, + * glGetConvolutionFilter(), etc. + * Incoming colors will be clamped to [0,1] if needed. + * Note: the rgba values will be modified by this function when any pixel + * transfer ops are enabled. + */ +void +_mesa_pack_rgba_span_float(GLcontext *ctx, GLuint n, GLfloat rgba[][4], + GLenum dstFormat, GLenum dstType, + GLvoid *dstAddr, + const struct gl_pixelstore_attrib *dstPacking, + GLbitfield transferOps) +{ + GLfloat luminance[MAX_WIDTH]; + const GLint comps = _mesa_components_in_format(dstFormat); + GLuint i; - /* XXX clamp rgba to [0,1]? */ + if (dstType != GL_FLOAT || ctx->Color.ClampReadColor == GL_TRUE) { + /* need to clamp to [0, 1] */ + transferOps |= IMAGE_CLAMP_BIT; + } + if (transferOps) { + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); + if ((transferOps & IMAGE_MIN_MAX_BIT) && ctx->MinMax.Sink) { + return; + } + } if (dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA) { - 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); + /* compute luminance values */ + if (transferOps & IMAGE_RED_TO_LUMINANCE) { + /* Luminance = Red (glGetTexImage) */ + for (i = 0; i < n; i++) { + luminance[i] = rgba[i][RCOMP]; + } + } + else { + /* Luminance = Red + Green + Blue (glReadPixels) */ + if (dstType != GL_FLOAT || ctx->Color.ClampReadColor == GL_TRUE) { + 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]; + } + } } } @@ -814,7 +1306,7 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, } break; default: - gl_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } } break; @@ -877,6 +1369,7 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, dst[i*4+2] = FLOAT_TO_BYTE(rgba[i][RCOMP]); dst[i*4+3] = FLOAT_TO_BYTE(rgba[i][ACOMP]); } + break; case GL_ABGR_EXT: for (i=0;iSwapBytes) { - _mesa_swap2( (GLushort *) dst, n * comps); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } } break; @@ -1025,6 +1515,7 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, dst[i*4+2] = FLOAT_TO_SHORT(rgba[i][RCOMP]); dst[i*4+3] = FLOAT_TO_SHORT(rgba[i][ACOMP]); } + break; case GL_ABGR_EXT: for (i=0;iSwapBytes) { - _mesa_swap2( (GLushort *) dst, n * comps ); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } } break; @@ -1110,10 +1598,7 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, } break; default: - gl_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n * comps ); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } } break; @@ -1186,10 +1671,7 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, } break; default: - gl_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); - } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n * comps ); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } } break; @@ -1262,10 +1744,80 @@ _mesa_pack_float_rgba_span( GLcontext *ctx, } break; default: - gl_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); + _mesa_problem(ctx, "bad format in _mesa_pack_rgba_span\n"); } - if (dstPacking->SwapBytes) { - _mesa_swap4( (GLuint *) dst, n * comps ); + } + break; + case GL_HALF_FLOAT_ARB: + { + GLhalfARB *dst = (GLhalfARB *) 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); + } + } + } +} #define SWAP2BYTE(VALUE) \ @@ -1573,7 +2139,7 @@ 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); + ASSERT(srcFormat == GL_COLOR_INDEX || srcFormat == GL_STENCIL_INDEX); ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || @@ -1582,6 +2148,8 @@ extract_uint_indexes(GLuint n, GLuint indexes[], 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); switch (srcType) { @@ -1719,14 +2287,48 @@ extract_uint_indexes(GLuint n, GLuint indexes[], } } 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] & 0xfff; /* lower 8 bits */ + } + } + break; + default: - gl_problem(NULL, "bad srcType in extract_uint_indexes"); + _mesa_problem(NULL, "bad srcType in extract_uint_indexes"); return; } } - /* * This function extracts floating point RGBA values from arbitrary * image data. srcFormat and srcType are the format and type parameters @@ -1739,7 +2341,7 @@ extract_uint_indexes(GLuint n, GLuint indexes[], * Args: n - number of pixels * rgba - output colors * srcFormat - format of incoming data - * srcType - datatype of incoming data + * srcType - data type of incoming data * src - source data pointer * swapBytes - perform byteswapping of incoming data? */ @@ -1771,6 +2373,7 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], 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 || @@ -1808,7 +2411,7 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], alphaIndex = 0; stride = 1; break; - case GL_LUMINANCE: + case GL_LUMINANCE: redIndex = greenIndex = blueIndex = 0; alphaIndex = -1; stride = 1; @@ -1819,8 +2422,7 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], stride = 2; break; case GL_INTENSITY: - redIndex = 0; - greenIndex = blueIndex = alphaIndex = -1; + redIndex = greenIndex = blueIndex = alphaIndex = 0; stride = 1; break; case GL_RGB: @@ -1828,6 +2430,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], greenIndex = 1; blueIndex = 2; alphaIndex = -1; + rComp = 0; + gComp = 1; + bComp = 2; + aComp = 3; stride = 3; break; case GL_BGR: @@ -1835,6 +2441,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], greenIndex = 1; blueIndex = 0; alphaIndex = -1; + rComp = 2; + gComp = 1; + bComp = 0; + aComp = 3; stride = 3; break; case GL_RGBA: @@ -1871,7 +2481,7 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], stride = 4; break; default: - gl_problem(NULL, "bad srcFormat in extract float data"); + _mesa_problem(NULL, "bad srcFormat in extract float data"); return; } @@ -1950,16 +2560,22 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], PROCESS(blueIndex, BCOMP, 0.0F, GLfloat, (GLfloat)); PROCESS(alphaIndex, ACOMP, 1.0F, GLfloat, (GLfloat)); break; + case GL_HALF_FLOAT_ARB: + PROCESS(redIndex, RCOMP, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(greenIndex, GCOMP, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(blueIndex, BCOMP, 0.0F, GLhalfARB, _mesa_half_to_float); + PROCESS(alphaIndex, ACOMP, 1.0F, GLhalfARB, _mesa_half_to_float); + 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][RCOMP] = ((p >> 5) ) * (1.0F / 7.0F); - rgba[i][GCOMP] = ((p >> 2) & 0x7) * (1.0F / 7.0F); - rgba[i][BCOMP] = ((p ) & 0x3) * (1.0F / 3.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p >> 5) ) * (1.0F / 7.0F); + rgba[i][gComp] = ((p >> 2) & 0x7) * (1.0F / 7.0F); + rgba[i][bComp] = ((p ) & 0x3) * (1.0F / 3.0F); + rgba[i][aComp] = 1.0F; } } break; @@ -1969,10 +2585,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLubyte p = ubsrc[i]; - rgba[i][RCOMP] = ((p ) & 0x7) * (1.0F / 7.0F); - rgba[i][GCOMP] = ((p >> 3) & 0x7) * (1.0F / 7.0F); - rgba[i][BCOMP] = ((p >> 6) ) * (1.0F / 3.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p ) & 0x7) * (1.0F / 7.0F); + rgba[i][gComp] = ((p >> 3) & 0x7) * (1.0F / 7.0F); + rgba[i][bComp] = ((p >> 6) ) * (1.0F / 3.0F); + rgba[i][aComp] = 1.0F; } } break; @@ -1983,10 +2599,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); - rgba[i][RCOMP] = ((p >> 11) ) * (1.0F / 31.0F); - rgba[i][GCOMP] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); - rgba[i][BCOMP] = ((p ) & 0x1f) * (1.0F / 31.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p >> 11) ) * (1.0F / 31.0F); + rgba[i][gComp] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); + rgba[i][bComp] = ((p ) & 0x1f) * (1.0F / 31.0F); + rgba[i][aComp] = 1.0F; } } else { @@ -1994,10 +2610,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; - rgba[i][RCOMP] = ((p >> 11) ) * (1.0F / 31.0F); - rgba[i][GCOMP] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); - rgba[i][BCOMP] = ((p ) & 0x1f) * (1.0F / 31.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p >> 11) ) * (1.0F / 31.0F); + rgba[i][gComp] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); + rgba[i][bComp] = ((p ) & 0x1f) * (1.0F / 31.0F); + rgba[i][aComp] = 1.0F; } } break; @@ -2008,10 +2624,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; SWAP2BYTE(p); - rgba[i][RCOMP] = ((p ) & 0x1f) * (1.0F / 31.0F); - rgba[i][GCOMP] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); - rgba[i][BCOMP] = ((p >> 11) ) * (1.0F / 31.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p ) & 0x1f) * (1.0F / 31.0F); + rgba[i][gComp] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); + rgba[i][bComp] = ((p >> 11) ) * (1.0F / 31.0F); + rgba[i][aComp] = 1.0F; } } else { @@ -2019,10 +2635,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLushort p = ussrc[i]; - rgba[i][RCOMP] = ((p ) & 0x1f) * (1.0F / 31.0F); - rgba[i][GCOMP] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); - rgba[i][BCOMP] = ((p >> 11) ) * (1.0F / 31.0F); - rgba[i][ACOMP] = 1.0F; + rgba[i][rComp] = ((p ) & 0x1f) * (1.0F / 31.0F); + rgba[i][gComp] = ((p >> 5) & 0x3f) * (1.0F / 63.0F); + rgba[i][bComp] = ((p >> 11) ) * (1.0F / 31.0F); + rgba[i][aComp] = 1.0F; } } break; @@ -2132,10 +2748,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; - rgba[i][rComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p ) & 0xff); - rgba[i][gComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 8) & 0xff); - rgba[i][bComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 16) & 0xff); - rgba[i][aComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 24) ); + rgba[i][rComp] = UBYTE_TO_FLOAT((p ) & 0xff); + rgba[i][gComp] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][bComp] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][aComp] = UBYTE_TO_FLOAT((p >> 24) ); } } else { @@ -2143,10 +2759,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; - rgba[i][rComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 24) ); - rgba[i][gComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 16) & 0xff); - rgba[i][bComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 8) & 0xff); - rgba[i][aComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p ) & 0xff); + rgba[i][rComp] = UBYTE_TO_FLOAT((p >> 24) ); + rgba[i][gComp] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][bComp] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][aComp] = UBYTE_TO_FLOAT((p ) & 0xff); } } break; @@ -2156,10 +2772,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; - rgba[i][rComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 24) ); - rgba[i][gComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 16) & 0xff); - rgba[i][bComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 8) & 0xff); - rgba[i][aComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p ) & 0xff); + rgba[i][rComp] = UBYTE_TO_FLOAT((p >> 24) ); + rgba[i][gComp] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][bComp] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][aComp] = UBYTE_TO_FLOAT((p ) & 0xff); } } else { @@ -2167,10 +2783,10 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], GLuint i; for (i = 0; i < n; i ++) { GLuint p = uisrc[i]; - rgba[i][rComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p ) & 0xff); - rgba[i][gComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 8) & 0xff); - rgba[i][bComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 16) & 0xff); - rgba[i][aComp] = UBYTE_COLOR_TO_FLOAT_COLOR((p >> 24) ); + rgba[i][rComp] = UBYTE_TO_FLOAT((p ) & 0xff); + rgba[i][gComp] = UBYTE_TO_FLOAT((p >> 8) & 0xff); + rgba[i][bComp] = UBYTE_TO_FLOAT((p >> 16) & 0xff); + rgba[i][aComp] = UBYTE_TO_FLOAT((p >> 24) ); } } break; @@ -2225,24 +2841,23 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], } break; default: - gl_problem(NULL, "bad srcType in extract float data"); + _mesa_problem(NULL, "bad srcType in extract float data"); break; } } - /* * 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 (or will be) used by glDrawPixels and glTexImage?D(). - * Input: ctx - the context + * Return GLchan 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 datatype + * srcType - source image data type * source - source image pointer * srcPacking - pixel unpacking parameters * transferOps - bitmask of IMAGE_*_BIT values of operations to apply @@ -2250,15 +2865,15 @@ extract_float_rgba(GLuint n, GLfloat rgba[][4], * XXX perhaps expand this to process whole images someday. */ void -_mesa_unpack_ubyte_color_span( GLcontext *ctx, - GLuint n, GLenum dstFormat, GLubyte dest[], - GLenum srcFormat, GLenum srcType, - const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLuint transferOps ) +_mesa_unpack_color_span_chan( GLcontext *ctx, + GLuint n, GLenum dstFormat, GLchan 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 || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_INTENSITY || dstFormat == GL_RGB || @@ -2286,6 +2901,7 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, 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 || @@ -2300,65 +2916,128 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV); - /* this is intended for RGBA mode only */ - assert(ctx->Visual.RGBAflag); - /* Try simple cases first */ - if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE) { - if (dstFormat == GL_RGBA) { - if (srcFormat == GL_RGBA) { - MEMCPY( dest, source, n * 4 * sizeof(GLubyte) ); - return; + if (transferOps == 0) { + if (srcType == CHAN_TYPE) { + if (dstFormat == GL_RGBA) { + if (srcFormat == GL_RGBA) { + _mesa_memcpy( dest, source, n * 4 * sizeof(GLchan) ); + return; + } + else if (srcFormat == GL_RGB) { + GLuint i; + const GLchan *src = (const GLchan *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = CHAN_MAX; + src += 3; + dst += 4; + } + 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; + else if (dstFormat == GL_RGB) { + if (srcFormat == GL_RGB) { + _mesa_memcpy( dest, source, n * 3 * sizeof(GLchan) ); + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLchan *src = (const GLchan *) source; + GLchan *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); + _mesa_memcpy( dest, source, n * comps * sizeof(GLchan) ); return; } } - else if (dstFormat == GL_RGB) { - if (srcFormat == GL_RGB) { - MEMCPY( dest, source, n * 3 * sizeof(GLubyte) ); - return; + /* + * Common situation, loading 8bit RGBA/RGB source images + * into 16/32 bit destination. (OSMesa16/32) + */ + else if (srcType == GL_UNSIGNED_BYTE) { + if (dstFormat == GL_RGBA) { + if (srcFormat == GL_RGB) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + dst[3] = CHAN_MAX; + src += 3; + dst += 4; + } + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + dst[3] = UBYTE_TO_CHAN(src[3]); + src += 4; + dst += 4; + } + 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; + else if (dstFormat == GL_RGB) { + if (srcFormat == GL_RGB) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + src += 3; + dst += 3; + } + return; + } + else if (srcFormat == GL_RGBA) { + GLuint i; + const GLubyte *src = (const GLubyte *) source; + GLchan *dst = dest; + for (i = 0; i < n; i++) { + dst[0] = UBYTE_TO_CHAN(src[0]); + dst[1] = UBYTE_TO_CHAN(src[1]); + dst[2] = UBYTE_TO_CHAN(src[2]); + src += 4; + dst += 3; + } + return; } - 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 */ { - GLfloat rgba[MAX_WIDTH][4]; GLint dstComponents; GLint dstRedIndex, dstGreenIndex, dstBlueIndex, dstAlphaIndex; GLint dstLuminanceIndex, dstIntensityIndex; + GLfloat rgba[MAX_WIDTH][4]; dstComponents = _mesa_components_in_format( dstFormat ); /* source & dest image formats should have been error checked by now */ @@ -2373,80 +3052,41 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_ci(ctx, n, indexes); - } - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - if (dstFormat == GL_COLOR_INDEX) { - /* convert to GLubyte and return */ GLuint i; + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + /* convert to GLchan and return */ for (i = 0; i < n; i++) { - dest[i] = (GLubyte) (indexes[i] & 0xff); + dest[i] = (GLchan) (indexes[i] & 0xff); } return; } else { /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + 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); } else { + /* non-color index data */ extract_float_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); - - /* scale and bias colors */ - if (transferOps & IMAGE_SCALE_BIAS_BIT) { - _mesa_scale_and_bias_rgba(ctx, n, rgba); - } - /* color map lookup */ - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_rgba(ctx, n, rgba); - } } - if (transferOps) { - /* GL_COLOR_TABLE lookup */ - if (transferOps & IMAGE_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->ColorTable, n, rgba); - } - /* convolution */ - if (transferOps & IMAGE_CONVOLUTION_BIT) { - /* this has to be done in the calling code */ - } - /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, n, rgba); - } - /* color matrix transform */ - if (transferOps & IMAGE_COLOR_MATRIX_BIT) { - _mesa_transform_rgba(ctx, n, rgba); - } - /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, n, rgba); - } - /* update histogram count */ - if (transferOps & IMAGE_HISTOGRAM_BIT) { - _mesa_update_histogram(ctx, n, (CONST GLfloat (*)[4]) rgba); - } - /* min/max here */ - if (transferOps & IMAGE_MIN_MAX_BIT) { - _mesa_update_minmax(ctx, n, (CONST GLfloat (*)[4]) rgba); - } - } + /* Need to clamp if returning GLubytes or GLushorts */ +#if CHAN_TYPE != GL_FLOAT + transferOps |= IMAGE_CLAMP_BIT; +#endif - /* clamp to [0,1] */ - { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); - rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); - rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); - rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); - } + if (transferOps) { + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); } /* Now determine which color channels we need to produce. @@ -2458,7 +3098,7 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, dstRedIndex = dstGreenIndex = dstBlueIndex = -1; dstLuminanceIndex = dstIntensityIndex = -1; break; - case GL_LUMINANCE: + case GL_LUMINANCE: dstLuminanceIndex = 0; dstRedIndex = dstGreenIndex = dstBlueIndex = dstAlphaIndex = -1; dstIntensityIndex = -1; @@ -2488,67 +3128,67 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, dstLuminanceIndex = dstIntensityIndex = -1; break; default: - gl_problem(ctx, "bad dstFormat in _mesa_unpack_ubyte_span()"); + _mesa_problem(ctx, "bad dstFormat in _mesa_unpack_chan_span()"); return; } - /* Now return the GLubyte data in the requested dstFormat */ + /* Now return the GLchan data in the requested dstFormat */ if (dstRedIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; for (i = 0; i < n; i++) { - dst[dstRedIndex] = FLOAT_TO_UBYTE(rgba[i][RCOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[dstRedIndex], rgba[i][RCOMP]); dst += dstComponents; } } if (dstGreenIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; for (i = 0; i < n; i++) { - dst[dstGreenIndex] = FLOAT_TO_UBYTE(rgba[i][GCOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[dstGreenIndex], rgba[i][GCOMP]); dst += dstComponents; } } if (dstBlueIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; for (i = 0; i < n; i++) { - dst[dstBlueIndex] = FLOAT_TO_UBYTE(rgba[i][BCOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[dstBlueIndex], rgba[i][BCOMP]); dst += dstComponents; } } if (dstAlphaIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; for (i = 0; i < n; i++) { - dst[dstAlphaIndex] = FLOAT_TO_UBYTE(rgba[i][ACOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[dstAlphaIndex], rgba[i][ACOMP]); dst += dstComponents; } } if (dstIntensityIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; assert(dstIntensityIndex == 0); assert(dstComponents == 1); for (i = 0; i < n; i++) { /* Intensity comes from red channel */ - dst[i] = FLOAT_TO_UBYTE(rgba[i][RCOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[i], rgba[i][RCOMP]); } } if (dstLuminanceIndex >= 0) { - GLubyte *dst = dest; + GLchan *dst = dest; GLuint i; assert(dstLuminanceIndex == 0); for (i = 0; i < n; i++) { /* Luminance comes from red channel */ - dst[0] = FLOAT_TO_UBYTE(rgba[i][RCOMP]); + CLAMPED_FLOAT_TO_CHAN(dst[0], rgba[i][RCOMP]); dst += dstComponents; } } @@ -2556,16 +3196,20 @@ _mesa_unpack_ubyte_color_span( GLcontext *ctx, } +/** + * Same as _mesa_unpack_color_span_chan(), but return GLfloat data + * instead of GLchan. + */ void -_mesa_unpack_float_color_span( GLcontext *ctx, +_mesa_unpack_color_span_float( GLcontext *ctx, GLuint n, GLenum dstFormat, GLfloat dest[], GLenum srcFormat, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, - GLuint transferOps, GLboolean clamp ) + GLbitfield transferOps ) { ASSERT(dstFormat == GL_ALPHA || - dstFormat == GL_LUMINANCE || + dstFormat == GL_LUMINANCE || dstFormat == GL_LUMINANCE_ALPHA || dstFormat == GL_INTENSITY || dstFormat == GL_RGB || @@ -2593,6 +3237,7 @@ _mesa_unpack_float_color_span( GLcontext *ctx, 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 || @@ -2607,15 +3252,12 @@ _mesa_unpack_float_color_span( GLcontext *ctx, srcType == GL_UNSIGNED_INT_10_10_10_2 || srcType == GL_UNSIGNED_INT_2_10_10_10_REV); - /* this is intended for RGBA mode only */ - assert(ctx->Visual.RGBAflag); - /* general solution, no special cases, yet */ { - GLfloat rgba[MAX_WIDTH][4]; GLint dstComponents; GLint dstRedIndex, dstGreenIndex, dstBlueIndex, dstAlphaIndex; GLint dstLuminanceIndex, dstIntensityIndex; + GLfloat rgba[MAX_WIDTH][4]; dstComponents = _mesa_components_in_format( dstFormat ); /* source & dest image formats should have been error checked by now */ @@ -2630,80 +3272,36 @@ _mesa_unpack_float_color_span( GLcontext *ctx, extract_uint_indexes(n, indexes, srcFormat, srcType, source, srcPacking); - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_ci(ctx, n, indexes); - } - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - if (dstFormat == GL_COLOR_INDEX) { - /* convert to GLubyte and return */ GLuint i; + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); + /* convert to GLchan and return */ for (i = 0; i < n; i++) { - dest[i] = (GLubyte) (indexes[i] & 0xff); + dest[i] = (GLchan) (indexes[i] & 0xff); } return; } else { /* Convert indexes to RGBA */ + if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { + 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); } else { + /* non-color index data */ extract_float_rgba(n, rgba, srcFormat, srcType, source, srcPacking->SwapBytes); - - /* scale and bias colors */ - if (transferOps & IMAGE_SCALE_BIAS_BIT) { - _mesa_scale_and_bias_rgba(ctx, n, rgba); - } - /* color map lookup */ - if (transferOps & IMAGE_MAP_COLOR_BIT) { - _mesa_map_rgba(ctx, n, rgba); - } } if (transferOps) { - /* GL_COLOR_TABLE lookup */ - if (transferOps & IMAGE_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->ColorTable, n, rgba); - } - /* convolution */ - if (transferOps & IMAGE_CONVOLUTION_BIT) { - /* XXX to do */ - } - /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, n, rgba); - } - /* color matrix transform */ - if (transferOps & IMAGE_COLOR_MATRIX_BIT) { - _mesa_transform_rgba(ctx, n, rgba); - } - /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ - if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { - _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, n, rgba); - } - /* update histogram count */ - if (transferOps & IMAGE_HISTOGRAM_BIT) { - _mesa_update_histogram(ctx, n, (CONST GLfloat (*)[4]) rgba); - } - /* min/max here */ - if (transferOps & IMAGE_MIN_MAX_BIT) { - _mesa_update_minmax(ctx, n, (CONST GLfloat (*)[4]) rgba); - } - } - - /* clamp to [0,1] */ - if (clamp) { - GLuint i; - for (i = 0; i < n; i++) { - rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F); - rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F); - rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F); - rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F); - } + _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgba); } /* Now determine which color channels we need to produce. @@ -2715,7 +3313,7 @@ _mesa_unpack_float_color_span( GLcontext *ctx, dstRedIndex = dstGreenIndex = dstBlueIndex = -1; dstLuminanceIndex = dstIntensityIndex = -1; break; - case GL_LUMINANCE: + case GL_LUMINANCE: dstLuminanceIndex = 0; dstRedIndex = dstGreenIndex = dstBlueIndex = dstAlphaIndex = -1; dstIntensityIndex = -1; @@ -2745,7 +3343,7 @@ _mesa_unpack_float_color_span( GLcontext *ctx, dstLuminanceIndex = dstIntensityIndex = -1; break; default: - gl_problem(ctx, "bad dstFormat in _mesa_unpack_float_color_span()"); + _mesa_problem(ctx, "bad dstFormat in _mesa_unpack_color_span_float()"); return; } @@ -2811,8 +3409,6 @@ _mesa_unpack_float_color_span( GLcontext *ctx, } - - /* * Unpack a row of color index data from a client buffer according to * the pixel unpacking parameters. @@ -2820,7 +3416,7 @@ _mesa_unpack_float_color_span( GLcontext *ctx, * * Args: ctx - the context * n - number of pixels - * dstType - destination datatype + * dstType - destination data type * dest - destination array * srcType - source pixel type * source - source data pointer @@ -2832,7 +3428,7 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, GLenum dstType, GLvoid *dest, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, - GLuint transferOps ) + GLbitfield transferOps ) { ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || @@ -2841,6 +3437,7 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, srcType == GL_SHORT || srcType == GL_UNSIGNED_INT || srcType == GL_INT || + srcType == GL_HALF_FLOAT_ARB || srcType == GL_FLOAT); ASSERT(dstType == GL_UNSIGNED_BYTE || @@ -2855,11 +3452,11 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, */ if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE) { - MEMCPY(dest, source, n * sizeof(GLubyte)); + _mesa_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)); + _mesa_memcpy(dest, source, n * sizeof(GLuint)); } else { /* @@ -2871,14 +3468,8 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, extract_uint_indexes(n, indexes, GL_COLOR_INDEX, srcType, source, srcPacking); - if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { - /* shift and offset indexes */ - _mesa_shift_and_offset_ci(ctx, n, indexes); - } - if (transferOps & IMAGE_MAP_COLOR_BIT) { - /* Apply lookup table */ - _mesa_map_ci(ctx, n, indexes); - } + if (transferOps) + _mesa_apply_ci_transfer_ops(ctx, transferOps, n, indexes); /* convert to dest type */ switch (dstType) { @@ -2901,11 +3492,127 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, } break; case GL_UNSIGNED_INT: - MEMCPY(dest, indexes, n * sizeof(GLuint)); + _mesa_memcpy(dest, indexes, n * sizeof(GLuint)); break; default: - gl_problem(ctx, "bad dstType in _mesa_unpack_index_span"); + _mesa_problem(ctx, "bad dstType in _mesa_unpack_index_span"); + } + } +} + + +void +_mesa_pack_index_span( const GLcontext *ctx, GLuint n, + GLenum dstType, GLvoid *dest, const GLuint *source, + const struct gl_pixelstore_attrib *dstPacking, + GLbitfield transferOps ) +{ + GLuint indexes[MAX_WIDTH]; + + ASSERT(n <= MAX_WIDTH); + + transferOps &= (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT); + + if (transferOps & (IMAGE_MAP_COLOR_BIT | IMAGE_SHIFT_OFFSET_BIT)) { + /* make a copy of input */ + _mesa_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"); } } @@ -2917,7 +3624,7 @@ _mesa_unpack_index_span( const GLcontext *ctx, GLuint n, * * Args: ctx - the context * n - number of pixels - * dstType - destination datatype + * dstType - destination data type * dest - destination array * srcType - source pixel type * source - source data pointer @@ -2929,7 +3636,7 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n, GLenum dstType, GLvoid *dest, GLenum srcType, const GLvoid *source, const struct gl_pixelstore_attrib *srcPacking, - GLuint transferOps ) + GLbitfield transferOps ) { ASSERT(srcType == GL_BITMAP || srcType == GL_UNSIGNED_BYTE || @@ -2938,6 +3645,8 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n, 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); ASSERT(dstType == GL_UNSIGNED_BYTE || @@ -2953,13 +3662,13 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n, if (transferOps == 0 && srcType == GL_UNSIGNED_BYTE && dstType == GL_UNSIGNED_BYTE) { - MEMCPY(dest, source, n * sizeof(GLubyte)); + _mesa_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)); + _mesa_memcpy(dest, source, n * sizeof(GLuint)); } else { /* @@ -2968,21 +3677,21 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n, GLuint indexes[MAX_WIDTH]; assert(n <= MAX_WIDTH); - extract_uint_indexes(n, indexes, GL_COLOR_INDEX, srcType, source, + extract_uint_indexes(n, indexes, GL_STENCIL_INDEX, srcType, source, srcPacking); if (transferOps) { if (transferOps & IMAGE_SHIFT_OFFSET_BIT) { /* shift and offset indexes */ - _mesa_shift_and_offset_ci(ctx, n, indexes); + shift_and_offset_ci(ctx, n, indexes); } if (ctx->Pixel.MapStencilFlag) { /* Apply stencil lookup table */ - GLuint mask = ctx->Pixel.MapStoSsize - 1; + GLuint mask = ctx->PixelMaps.StoS.Size - 1; GLuint i; for (i=0;iPixel.MapStoS[ indexes[i] & mask ]; + indexes[i] = ctx->PixelMaps.StoS.Map[ indexes[i] & mask ]; } } } @@ -3008,25 +3717,184 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n, } break; case GL_UNSIGNED_INT: - MEMCPY(dest, indexes, n * sizeof(GLuint)); + _mesa_memcpy(dest, indexes, n * sizeof(GLuint)); break; default: - gl_problem(ctx, "bad dstType in _mesa_unpack_stencil_span"); + _mesa_problem(ctx, "bad dstType in _mesa_unpack_stencil_span"); } } } +void +_mesa_pack_stencil_span( const GLcontext *ctx, GLuint n, + GLenum dstType, GLvoid *dest, const GLstencil *source, + const struct gl_pixelstore_attrib *dstPacking ) +{ + GLstencil stencil[MAX_WIDTH]; + + ASSERT(n <= MAX_WIDTH); + + if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || + ctx->Pixel.MapStencilFlag) { + /* make a copy of input */ + _mesa_memcpy(stencil, source, n * sizeof(GLstencil)); + _mesa_apply_stencil_transfer_ops(ctx, n, stencil); + source = stencil; + } + + switch (dstType) { + case GL_UNSIGNED_BYTE: + if (sizeof(GLstencil) == 8) { + _mesa_memcpy( dest, source, n ); + } + else { + GLubyte *dst = (GLubyte *) 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"); + } +} + void -_mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, +_mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, + GLenum dstType, GLvoid *dest, GLfloat depthScale, GLenum srcType, const GLvoid *source, - const struct gl_pixelstore_attrib *srcPacking, - GLuint transferOps ) + const struct gl_pixelstore_attrib *srcPacking ) { - GLfloat *depth = MALLOC(n * sizeof(GLfloat)); - if (!depth) - return; + GLfloat depthTemp[MAX_WIDTH], *depthValues; + + if (dstType == GL_FLOAT) { + depthValues = (GLfloat *) dest; + } + else { + depthValues = depthTemp; + } + + /* XXX we need to obey srcPacking->SwapBytes here!!! */ + (void) srcPacking; switch (srcType) { case GL_BYTE: @@ -3034,7 +3902,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLubyte *src = (const GLubyte *) source; for (i = 0; i < n; i++) { - depth[i] = BYTE_TO_FLOAT(src[i]); + depthValues[i] = BYTE_TO_FLOAT(src[i]); } } break; @@ -3043,7 +3911,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLubyte *src = (const GLubyte *) source; for (i = 0; i < n; i++) { - depth[i] = UBYTE_TO_FLOAT(src[i]); + depthValues[i] = UBYTE_TO_FLOAT(src[i]); } } break; @@ -3052,7 +3920,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLshort *src = (const GLshort *) source; for (i = 0; i < n; i++) { - depth[i] = SHORT_TO_FLOAT(src[i]); + depthValues[i] = SHORT_TO_FLOAT(src[i]); } } break; @@ -3061,7 +3929,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLushort *src = (const GLushort *) source; for (i = 0; i < n; i++) { - depth[i] = USHORT_TO_FLOAT(src[i]); + depthValues[i] = USHORT_TO_FLOAT(src[i]); } } break; @@ -3070,7 +3938,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLint *src = (const GLint *) source; for (i = 0; i < n; i++) { - depth[i] = INT_TO_FLOAT(src[i]); + depthValues[i] = INT_TO_FLOAT(src[i]); } } break; @@ -3079,48 +3947,257 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLdepth *dest, GLuint i; const GLuint *src = (const GLuint *) source; for (i = 0; i < n; i++) { - depth[i] = UINT_TO_FLOAT(src[i]); + depthValues[i] = UINT_TO_FLOAT(src[i]); + } + } + break; + case GL_UNSIGNED_INT_24_8_EXT: /* GL_EXT_packed_depth_stencil */ + if (dstType == GL_UNSIGNED_INT && + depthScale == (GLfloat) 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++) { + zValues[i] = src[i] & 0xffffff00; + } + return; + } + else { + const GLuint *src = (const GLuint *) source; + const GLfloat scale = 1.0f / 0xffffff; + GLuint i; + for (i = 0; i < n; i++) { + depthValues[i] = (src[i] >> 8) * scale; } } break; case GL_FLOAT: - MEMCPY(depth, source, n * sizeof(GLfloat)); + _mesa_memcpy(depthValues, source, n * sizeof(GLfloat)); + break; + case GL_HALF_FLOAT_ARB: + { + GLuint i; + const GLhalfARB *src = (const GLhalfARB *) source; + for (i = 0; i < n; i++) { + depthValues[i] = _mesa_half_to_float(src[i]); + } + } break; default: - gl_problem(NULL, "bad type in _mesa_unpack_depth_span()"); - FREE(depth); + _mesa_problem(NULL, "bad type in _mesa_unpack_depth_span()"); return; } - /* apply depth scale and bias */ + /* apply depth scale and bias and clamp to [0,1] */ if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { + _mesa_scale_and_bias_depth(ctx, n, depthValues); + } + + if (dstType == GL_UNSIGNED_INT) { + GLuint *zValues = (GLuint *) dest; GLuint i; - for (i = 0; i < n; i++) { - depth[i] = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; + if (depthScale <= (GLfloat) 0xffffff) { + /* no overflow worries */ + for (i = 0; i < n; i++) { + zValues[i] = (GLuint) (depthValues[i] * depthScale); + } + } + else { + /* need to use double precision to prevent overflow problems */ + for (i = 0; i < n; i++) { + GLdouble z = depthValues[i] * depthScale; + if (z >= (GLdouble) 0xffffffff) + zValues[i] = 0xffffffff; + else + zValues[i] = (GLuint) z; + } } } - - /* clamp depth values to [0,1] and convert from floats to integers */ - { - const GLfloat zs = ctx->Visual.DepthMaxF; + else if (dstType == GL_UNSIGNED_SHORT) { + GLushort *zValues = (GLushort *) dest; GLuint i; + ASSERT(depthScale <= 65535.0); for (i = 0; i < n; i++) { - dest[i] = (GLdepth) (CLAMP(depth[i], 0.0F, 1.0F) * zs); + zValues[i] = (GLushort) (depthValues[i] * depthScale); } } + else { + ASSERT(dstType == GL_FLOAT); + ASSERT(depthScale == 1.0F); + } +} + + +/* + * Pack an array of depth values. The values are floats in [0,1]. + */ +void +_mesa_pack_depth_span( const GLcontext *ctx, GLuint n, GLvoid *dest, + GLenum dstType, const GLfloat *depthSpan, + const struct gl_pixelstore_attrib *dstPacking ) +{ + GLfloat depthCopy[MAX_WIDTH]; + + ASSERT(n <= MAX_WIDTH); + + if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { + _mesa_memcpy(depthCopy, depthSpan, n * sizeof(GLfloat)); + _mesa_scale_and_bias_depth(ctx, n, depthCopy); + depthSpan = depthCopy; + } - FREE(depth); + 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"); + } } -/* - * Unpack image data. Apply byteswapping, byte flipping (bitmap). - * Return all image data in a contiguous block. +/** + * Pack depth and stencil values as GL_DEPTH_STENCIL/GL_UNSIGNED_INT_24_8. + */ +void +_mesa_pack_depth_stencil_span(const GLcontext *ctx, GLuint n, GLuint *dest, + const GLfloat *depthVals, + const GLstencil *stencilVals, + const struct gl_pixelstore_attrib *dstPacking) +{ + GLfloat depthCopy[MAX_WIDTH]; + GLstencil stencilCopy[MAX_WIDTH]; + GLuint i; + + ASSERT(n <= MAX_WIDTH); + + if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) { + _mesa_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) { + _mesa_memcpy(stencilCopy, stencilVals, n * sizeof(GLstencil)); + _mesa_apply_stencil_transfer_ops(ctx, n, stencilCopy); + stencilVals = stencilCopy; + } + + for (i = 0; i < n; i++) { + GLuint z = (GLuint) (depthVals[i] * 0xffffff); + dest[i] = (z << 8) | (stencilVals[i] & 0xff); + } + + if (dstPacking->SwapBytes) { + _mesa_swap4(dest, n); + } +} + + + + +/** + * 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( GLsizei width, GLsizei height, GLsizei depth, +_mesa_unpack_image( GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *unpack ) { @@ -3133,16 +4210,20 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth, if (width <= 0 || height <= 0 || depth <= 0) return NULL; /* generate error later */ - if (format == GL_BITMAP) { + if (type == GL_BITMAP) { bytesPerRow = (width + 7) >> 3; - flipBytes = !unpack->LsbFirst; + flipBytes = unpack->LsbFirst; swap2 = swap4 = GL_FALSE; compsPerRow = 0; } else { const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); - const GLint components = _mesa_components_in_format(format); + 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; @@ -3155,7 +4236,8 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth, } { - GLubyte *destBuffer = MALLOC(bytesPerRow * height * depth); + GLubyte *destBuffer + = (GLubyte *) _mesa_malloc(bytesPerRow * height * depth); GLubyte *dst; GLint img, row; if (!destBuffer) @@ -3164,9 +4246,63 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth, dst = destBuffer; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { - const GLvoid *src = _mesa_image_address(unpack, pixels, + const GLvoid *src = _mesa_image_address(dimensions, unpack, pixels, width, height, format, type, img, row, 0); - MEMCPY(dst, src, bytesPerRow); + + 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 + _mesa_memcpy(dst, src, bytesPerRow); /* byte flipping/swapping */ if (flipBytes) { flip_bytes((GLubyte *) dst, bytesPerRow); @@ -3184,196 +4320,292 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth, } } +#endif /* _HAVE_FULL_GL */ -/* - * 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; +/** + * Convert an array of RGBA colors from one datatype to another. + * NOTE: src may equal dst. In that case, we use a temporary buffer. + */ +void +_mesa_convert_colors(GLenum srcType, const GLvoid *src, + GLenum dstType, GLvoid *dst, + GLuint count, const GLubyte mask[]) +{ + GLuint tempBuffer[MAX_WIDTH][4]; + const GLboolean useTemp = (src == dst); + ASSERT(srcType != dstType); - width_in_bytes = CEILING( width, 8 ); - dst = buffer; - for (row = 0; row < height; row++) { - GLubyte *src = _mesa_image_address( packing, pixels, width, height, - GL_COLOR_INDEX, GL_BITMAP, - 0, row, 0 ); - if (!src) { - FREE(buffer); - return NULL; + switch (srcType) { + case GL_UNSIGNED_BYTE: + if (dstType == GL_UNSIGNED_SHORT) { + const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; + GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]); + dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]); + dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]); + dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]); + } + } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); } - - if (packing->SkipPixels == 0) { - MEMCPY( dst, src, width_in_bytes ); - if (packing->LsbFirst) { - flip_bytes( dst, width_in_bytes ); + else { + const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; + GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_FLOAT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]); + dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]); + dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]); + dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]); + } } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); + } + break; + case GL_UNSIGNED_SHORT: + if (dstType == GL_UNSIGNED_BYTE) { + const GLushort (*src2)[4] = (const GLushort (*)[4]) src; + GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]); + dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]); + dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]); + dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]); + } + } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); } else { - /* handling SkipPixels is a bit tricky (no pun intended!) */ - GLint i; - if (packing->LsbFirst) { - GLubyte srcMask = 1 << (packing->SkipPixels & 0x7); - GLubyte dstMask = 128; - 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; - } + const GLushort (*src2)[4] = (const GLushort (*)[4]) src; + GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_FLOAT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]); + dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]); + dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]); + dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]); } } - else { - GLubyte srcMask = 128 >> (packing->SkipPixels & 0x7); - GLubyte dstMask = 128; - 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; - } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); + } + break; + case GL_FLOAT: + if (dstType == GL_UNSIGNED_BYTE) { + const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; + GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][RCOMP], src4[i][RCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][GCOMP], src4[i][GCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][BCOMP], src4[i][BCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][ACOMP], src4[i][ACOMP]); } } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); } - dst += width_in_bytes; + else { + const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; + GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); + GLuint i; + ASSERT(dstType == GL_UNSIGNED_SHORT); + for (i = 0; i < count; i++) { + if (!mask || mask[i]) { + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]); + } + } + if (useTemp) + _mesa_memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); + } + break; + default: + _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors"); } - - return buffer; } -/* - * Pack bitmap data. + + +/** + * Perform basic clipping for glDrawPixels. The image's position and size + * and the unpack SkipPixels and SkipRows are adjusted so that the image + * region is entirely within the window and scissor bounds. + * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1). + * If Pixel.ZoomY is -1, *destY will be changed to be the first row which + * we'll actually write. Beforehand, *destY-1 is the first drawing row. + * + * \return GL_TRUE if image is ready for drawing or + * GL_FALSE if image was completely clipped away (draw nothing) */ -void -_mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source, - GLubyte *dest, const struct gl_pixelstore_attrib *packing ) +GLboolean +_mesa_clip_drawpixels(const GLcontext *ctx, + GLint *destX, GLint *destY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *unpack) { - GLint row, width_in_bytes; - const GLubyte *src; + const GLframebuffer *buffer = ctx->DrawBuffer; - if (!source) - return; + if (unpack->RowLength == 0) { + unpack->RowLength = *width; + } - width_in_bytes = CEILING( width, 8 ); - src = source; - for (row = 0; row < height; row++) { - GLubyte *dst = _mesa_image_address( packing, dest, width, height, - GL_COLOR_INDEX, GL_BITMAP, - 0, row, 0 ); - if (!dst) - return; + ASSERT(ctx->Pixel.ZoomX == 1.0F); + ASSERT(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F); - if (packing->SkipPixels == 0) { - MEMCPY( dst, src, width_in_bytes ); - if (packing->LsbFirst) { - flip_bytes( dst, width_in_bytes ); - } + /* left clipping */ + if (*destX < buffer->_Xmin) { + unpack->SkipPixels += (buffer->_Xmin - *destX); + *width -= (buffer->_Xmin - *destX); + *destX = buffer->_Xmin; + } + /* right clipping */ + if (*destX + *width > buffer->_Xmax) + *width -= (*destX + *width - buffer->_Xmax); + + if (*width <= 0) + return GL_FALSE; + + if (ctx->Pixel.ZoomY == 1.0F) { + /* bottom clipping */ + if (*destY < buffer->_Ymin) { + unpack->SkipRows += (buffer->_Ymin - *destY); + *height -= (buffer->_Ymin - *destY); + *destY = buffer->_Ymin; } - 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; - } - } - } + /* top clipping */ + if (*destY + *height > buffer->_Ymax) + *height -= (*destY + *height - buffer->_Ymax); + } + else { /* upside down */ + /* top clipping */ + if (*destY > buffer->_Ymax) { + unpack->SkipRows += (*destY - buffer->_Ymax); + *height -= (*destY - buffer->_Ymax); + *destY = buffer->_Ymax; } - src += width_in_bytes; + /* bottom clipping */ + if (*destY - *height < buffer->_Ymin) + *height -= (buffer->_Ymin - (*destY - *height)); + /* adjust destY so it's the first row to write to */ + (*destY)--; + } + + if (*height <= 0) + return GL_TRUE; + + return GL_TRUE; +} + + +/** + * Perform clipping for glReadPixels. The image's window position + * and size, and the pack skipPixels, skipRows and rowLength are adjusted + * so that the image region is entirely within the window bounds. + * Note: this is different from _mesa_clip_drawpixels() in that the + * scissor box is ignored, and we use the bounds of the current readbuffer + * surface. + * + * \return GL_TRUE if image is ready for drawing or + * GL_FALSE if image was completely clipped away (draw nothing) + */ +GLboolean +_mesa_clip_readpixels(const GLcontext *ctx, + GLint *srcX, GLint *srcY, + GLsizei *width, GLsizei *height, + struct gl_pixelstore_attrib *pack) +{ + const GLframebuffer *buffer = ctx->ReadBuffer; + + if (pack->RowLength == 0) { + pack->RowLength = *width; } + + /* left clipping */ + if (*srcX < 0) { + pack->SkipPixels += (0 - *srcX); + *width -= (0 - *srcX); + *srcX = 0; + } + /* right clipping */ + if (*srcX + *width > (GLsizei) buffer->Width) + *width -= (*srcX + *width - buffer->Width); + + if (*width <= 0) + return GL_FALSE; + + /* bottom clipping */ + if (*srcY < 0) { + pack->SkipRows += (0 - *srcY); + *height -= (0 - *srcY); + *srcY = 0; + } + /* top clipping */ + if (*srcY + *height > (GLsizei) buffer->Height) + *height -= (*srcY + *height - buffer->Height); + + if (*height <= 0) + return GL_TRUE; + + return GL_TRUE; +} + + +/** + * Clip the rectangle defined by (x, y, width, height) against the bounds + * specified by [xmin, xmax) and [ymin, ymax). + * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise. + */ +GLboolean +_mesa_clip_to_region(GLint xmin, GLint ymin, + GLint xmax, GLint ymax, + GLint *x, GLint *y, + GLsizei *width, GLsizei *height ) +{ + /* left clipping */ + if (*x < xmin) { + *width -= (xmin - *x); + *x = xmin; + } + + /* right clipping */ + if (*x + *width > xmax) + *width -= (*x + *width - xmax - 1); + + if (*width <= 0) + return GL_FALSE; + + /* bottom (or top) clipping */ + if (*y < ymin) { + *height -= (ymin - *y); + *y = ymin; + } + + /* top (or bottom) clipping */ + if (*y + *height > ymax) + *height -= (*y + *height - ymax - 1); + + if (*height <= 0) + return GL_FALSE; + + return GL_TRUE; }