/* $Id: texutil.c,v 1.25 2001/06/15 15:22:08 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 3.5 * * Copyright (C) 1999-2001 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 * BRIAN PAUL 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. * * Authors: * Gareth Hughes */ #ifdef PC_HEADER #include "all.h" #else #include "glheader.h" #include "context.h" #include "enums.h" #include "image.h" #include "macros.h" #include "mem.h" #include "mtypes.h" #include "texformat.h" #include "texutil.h" #endif #define DEBUG_TEXUTIL 0 struct gl_texture_convert { GLint xoffset, yoffset, zoffset; /* Subimage offset */ GLint width, height, depth; /* Subimage region */ GLint dstImageWidth, dstImageHeight; /* Dest image size */ /* Needed for subimage replacement */ GLenum format, type; /* Source (user) format and type */ const struct gl_pixelstore_attrib *packing; const GLvoid *srcImage; GLvoid *dstImage; GLint index; }; typedef GLboolean (*convert_func)( struct gl_texture_convert *convert ); #define CONVERT_STRIDE_BIT 0x1 #define CONVERT_PACKING_BIT 0x2 /* ============================================================= * RGBA8888 textures: */ #define DST_TYPE GLuint #define DST_TEXELS_PER_DWORD 1 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( src[3], src[2], src[1], src[0] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_rgba8888_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( src[0], src[1], src[2], src[3] ) #define CONVERT_TEXEL_DWORD( dst, src ) CONVERT_TEXEL( dst, src ) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_rgba8888 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( src[0], src[1], src[2], 0xff ) #define CONVERT_TEXEL_DWORD( dst, src ) CONVERT_TEXEL( dst, src ) #define SRC_TEXEL_BYTES 3 #define TAG(x) x##_bgr888_to_rgba8888 #include "texutil_tmp.h" #define CONVERT_RGBA8888( name ) \ static GLboolean \ convert_##name##_rgba8888( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_ABGR_EXT && \ convert->type == GL_UNSIGNED_INT_8_8_8_8_REV ) \ { \ tab = name##_tab_rgba8888_direct; \ } \ else if ( convert->format == GL_RGBA && \ ( convert->type == GL_UNSIGNED_BYTE || \ convert->type == GL_UNSIGNED_INT_8_8_8_8 ) ) \ { \ tab = name##_tab_abgr8888_to_rgba8888; \ } \ else if ( convert->format == GL_RGB && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_bgr888_to_rgba8888; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_RGBA8888( texsubimage2d ) CONVERT_RGBA8888( texsubimage3d ) /* ============================================================= * ARGB8888 textures: */ #define DST_TYPE GLuint #define DST_TEXELS_PER_DWORD 1 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( src[3], src[2], src[1], src[0] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_argb8888_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( src[3], src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) CONVERT_TEXEL( dst, src ) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_argb8888 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_8888( 0xff, src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) CONVERT_TEXEL( dst, src ) #define SRC_TEXEL_BYTES 3 #define TAG(x) x##_bgr888_to_argb8888 #include "texutil_tmp.h" #define CONVERT_ARGB8888( name ) \ static GLboolean \ convert_##name##_argb8888( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_BGRA && \ convert->type == GL_UNSIGNED_INT_8_8_8_8_REV ) \ { \ tab = name##_tab_argb8888_direct; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_abgr8888_to_argb8888; \ } \ else if ( convert->format == GL_RGB && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_bgr888_to_argb8888; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_ARGB8888( texsubimage2d ) CONVERT_ARGB8888( texsubimage3d ) /* ============================================================= * RGB888 textures: */ static GLboolean convert_texsubimage2d_rgb888( struct gl_texture_convert *convert ) { /* This is a placeholder for now... */ return GL_FALSE; } static GLboolean convert_texsubimage3d_rgb888( struct gl_texture_convert *convert ) { /* This is a placeholder for now... */ return GL_FALSE; } /* ============================================================= * RGB565 textures: */ #define DST_TYPE GLushort #define DST_TEXELS_PER_DWORD 2 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_565( src[0], src[1], src[2] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 2 #define TAG(x) x##_rgb565_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_565( src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_565( src[0], src[1], src[2] )) | \ (PACK_COLOR_565( src[3], src[4], src[5] ) << 16)) #define SRC_TEXEL_BYTES 3 #define TAG(x) x##_bgr888_to_rgb565 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_565( src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_565( src[0], src[1], src[2] )) | \ (PACK_COLOR_565( src[4], src[5], src[6] ) << 16)) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_rgb565 #include "texutil_tmp.h" #define CONVERT_RGB565( name ) \ static GLboolean \ convert_##name##_rgb565( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_RGB && \ convert->type == GL_UNSIGNED_SHORT_5_6_5 ) \ { \ tab = name##_tab_rgb565_direct; \ } \ else if ( convert->format == GL_RGB && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_bgr888_to_rgb565; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_abgr8888_to_rgb565; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_RGB565( texsubimage2d ) CONVERT_RGB565( texsubimage3d ) /* ============================================================= * ARGB4444 textures: */ #define DST_TYPE GLushort #define DST_TEXELS_PER_DWORD 2 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_4444( src[3], src[0], src[1], src[2] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 2 #define TAG(x) x##_argb4444_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_4444( src[3], src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_4444( src[3], src[0], src[1], src[2] )) | \ (PACK_COLOR_4444( src[7], src[4], src[5], src[6] ) << 16)) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_argb4444 #include "texutil_tmp.h" #define CONVERT_ARGB4444( name ) \ static GLboolean \ convert_##name##_argb4444( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_BGRA && \ convert->type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) \ { \ tab = name##_tab_argb4444_direct; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_abgr8888_to_argb4444; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_ARGB4444( texsubimage2d ) CONVERT_ARGB4444( texsubimage3d ) /* ============================================================= * ARGB1555 textures: */ #define DST_TYPE GLushort #define DST_TEXELS_PER_DWORD 2 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_1555( src[3], src[0], src[1], src[2] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 2 #define TAG(x) x##_argb1555_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ { const GLushort s = *(GLushort *)src; \ dst = (s >> 1) | ((s & 1) << 15); } #define CONVERT_TEXEL_DWORD( dst, src ) \ { const GLuint s = ((fi_type *)src)->i; \ dst = (((s & 0xfffefffe) >> 1) | \ ((s & 0x00010001) << 15)); } #define SRC_TEXEL_BYTES 2 #define TAG(x) x##_rgba5551_to_argb1555 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_1555( src[3], src[0], src[1], src[2] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_1555( src[3], src[0], src[1], src[2] )) | \ (PACK_COLOR_1555( src[7], src[4], src[5], src[6] ) << 16)) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_argb1555 #include "texutil_tmp.h" #define CONVERT_ARGB1555( name ) \ static GLboolean \ convert_##name##_argb1555( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_BGRA && \ convert->type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) \ { \ tab = name##_tab_argb1555_direct; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_SHORT_5_5_5_1 ) \ { \ tab = name##_tab_rgba5551_to_argb1555; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_abgr8888_to_argb1555; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_ARGB1555( texsubimage2d ) CONVERT_ARGB1555( texsubimage3d ) /* ============================================================= * AL88 textures: */ #define DST_TYPE GLushort #define DST_TEXELS_PER_DWORD 2 #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_88( src[0], src[1] ) #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 2 #define TAG(x) x##_al88_direct #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_88( src[0], 0x00 ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_88( src[0], 0x00 )) | \ (PACK_COLOR_88( src[1], 0x00 ) << 16)) #define SRC_TEXEL_BYTES 1 #define TAG(x) x##_a8_to_al88 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_88( 0xff, src[0] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_88( 0xff, src[0] )) | \ (PACK_COLOR_88( 0xff, src[1] ) << 16)) #define SRC_TEXEL_BYTES 1 #define TAG(x) x##_l8_to_al88 #define PRESERVE_DST_TYPE #include "texutil_tmp.h" #define CONVERT_TEXEL( dst, src ) \ dst = PACK_COLOR_88( src[3], src[0] ) #define CONVERT_TEXEL_DWORD( dst, src ) \ dst = ((PACK_COLOR_88( src[3], src[0] )) | \ (PACK_COLOR_88( src[7], src[1] ) << 16)) #define SRC_TEXEL_BYTES 4 #define TAG(x) x##_abgr8888_to_al88 #include "texutil_tmp.h" #define CONVERT_AL88( name ) \ static GLboolean \ convert_##name##_al88( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( convert->format == GL_LUMINANCE_ALPHA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_al88_direct; \ } \ else if ( convert->format == GL_ALPHA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_a8_to_al88; \ } \ else if ( convert->format == GL_LUMINANCE && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_l8_to_al88; \ } \ else if ( convert->format == GL_RGBA && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_abgr8888_to_al88; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_AL88( texsubimage2d ) CONVERT_AL88( texsubimage3d ) /* ============================================================= * RGB332 textures: */ static GLboolean convert_texsubimage2d_rgb332( struct gl_texture_convert *convert ) { /* This is a placeholder for now... */ return GL_FALSE; } static GLboolean convert_texsubimage3d_rgb332( struct gl_texture_convert *convert ) { /* This is a placeholder for now... */ return GL_FALSE; } /* ============================================================= * CI8 (and all other single-byte texel) textures: */ #define DST_TYPE GLubyte #define DST_TEXELS_PER_DWORD 4 #define CONVERT_TEXEL( dst, src ) dst = src[0] #define CONVERT_DIRECT #define SRC_TEXEL_BYTES 1 #define TAG(x) x##_ci8_direct #include "texutil_tmp.h" #define CONVERT_CI8( name ) \ static GLboolean \ convert_##name##_ci8( struct gl_texture_convert *convert ) \ { \ convert_func *tab; \ GLint index = convert->index; \ \ if ( ( convert->format == GL_ALPHA || \ convert->format == GL_LUMINANCE || \ convert->format == GL_INTENSITY || \ convert->format == GL_COLOR_INDEX ) && \ convert->type == GL_UNSIGNED_BYTE ) \ { \ tab = name##_tab_ci8_direct; \ } \ else \ { \ /* Can't handle this source format/type combination */ \ return GL_FALSE; \ } \ \ return tab[index]( convert ); \ } CONVERT_CI8( texsubimage2d ) CONVERT_CI8( texsubimage3d ) /* ============================================================= * Global entry points */ static convert_func gl_convert_texsubimage2d_tab[] = { convert_texsubimage2d_rgba8888, convert_texsubimage2d_argb8888, convert_texsubimage2d_rgb888, convert_texsubimage2d_rgb565, convert_texsubimage2d_argb4444, convert_texsubimage2d_argb1555, convert_texsubimage2d_al88, convert_texsubimage2d_rgb332, convert_texsubimage2d_ci8, /* These are all the same... */ convert_texsubimage2d_ci8, convert_texsubimage2d_ci8, convert_texsubimage2d_ci8, }; static convert_func gl_convert_texsubimage3d_tab[] = { convert_texsubimage3d_rgba8888, convert_texsubimage3d_argb8888, convert_texsubimage3d_rgb888, convert_texsubimage3d_rgb565, convert_texsubimage3d_argb4444, convert_texsubimage3d_argb1555, convert_texsubimage3d_al88, convert_texsubimage3d_rgb332, convert_texsubimage3d_ci8, /* These are all the same... */ convert_texsubimage3d_ci8, convert_texsubimage3d_ci8, convert_texsubimage3d_ci8, }; /* See if we need to care about the pixel store attributes when we're * converting the texture image. This should be stored as * packing->_SomeBoolean and updated when the values change, to avoid * testing every time... */ static INLINE GLboolean convert_needs_packing( const struct gl_pixelstore_attrib *packing, GLenum format, GLenum type ) { if ( ( packing->Alignment == 1 || ( packing->Alignment == 4 && /* Pick up the common Q3A case... */ format == GL_RGBA && type == GL_UNSIGNED_BYTE ) ) && packing->RowLength == 0 && packing->SkipPixels == 0 && packing->SkipRows == 0 && packing->ImageHeight == 0 && packing->SkipImages == 0 && packing->SwapBytes == GL_FALSE && packing->LsbFirst == GL_FALSE ) { return GL_FALSE; } else { return GL_TRUE; } } GLboolean _mesa_convert_texsubimage1d( GLint mesaFormat, GLint xoffset, GLint width, GLenum format, GLenum type, const struct gl_pixelstore_attrib *packing, const GLvoid *srcImage, GLvoid *dstImage ) { struct gl_texture_convert convert; ASSERT( packing ); ASSERT( srcImage ); ASSERT( dstImage ); ASSERT( mesaFormat >= MESA_FORMAT_RGBA8888 ); ASSERT( mesaFormat <= MESA_FORMAT_CI8 ); /* Make it easier to pass all the parameters around. */ convert.xoffset = xoffset; convert.yoffset = 0; convert.width = width; convert.height = 1; convert.format = format; convert.type = type; convert.packing = packing; convert.srcImage = srcImage; convert.dstImage = dstImage; convert.index = 0; if ( convert_needs_packing( packing, format, type ) ) convert.index |= CONVERT_PACKING_BIT; return gl_convert_texsubimage2d_tab[mesaFormat]( &convert ); } /* Convert a user's 2D image into a texture image. This basically * repacks pixel data into the special texture formats used by core Mesa * and the DRI drivers. This function can do full images or subimages. * * We return a boolean because this function may not accept some kinds * of source image formats and/or types. For example, if the incoming * format/type = GL_BGR, GL_UNSIGNED_INT this function probably won't * be able to do the conversion. * * In that case, the incoming image should first be simplified to one of * the "canonical" formats (GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, * GL_INTENSITY, GL_RGB, GL_RGBA) and types (GL_CHAN). We can do that * with the _mesa_transfer_teximage() function. That function will also * do image transfer operations such as scale/bias and convolution. * * Input: * mesaFormat - one of the MESA_FORMAT_* values from texformat.h * xoffset, yoffset - position in dest image to put data * width, height - incoming image size, also size of dest region. * dstImageWidth - width (row stride) of dest image in pixels * format, type - incoming image format and type * packing - describes incoming image packing * srcImage - pointer to source image * destImage - pointer to dest image */ GLboolean _mesa_convert_texsubimage2d( GLint mesaFormat, GLint xoffset, GLint yoffset, GLint width, GLint height, GLint destImageWidth, GLenum format, GLenum type, const struct gl_pixelstore_attrib *packing, const GLvoid *srcImage, GLvoid *dstImage ) { struct gl_texture_convert convert; ASSERT( packing ); ASSERT( srcImage ); ASSERT( dstImage ); ASSERT( mesaFormat >= MESA_FORMAT_RGBA8888 ); ASSERT( mesaFormat <= MESA_FORMAT_CI8 ); /* Make it easier to pass all the parameters around. */ convert.xoffset = xoffset; convert.yoffset = yoffset; convert.width = width; convert.height = height; convert.dstImageWidth = destImageWidth; convert.format = format; convert.type = type; convert.packing = packing; convert.srcImage = srcImage; convert.dstImage = dstImage; convert.index = 0; if ( convert_needs_packing( packing, format, type ) ) convert.index |= CONVERT_PACKING_BIT; if ( width != destImageWidth ) convert.index |= CONVERT_STRIDE_BIT; return gl_convert_texsubimage2d_tab[mesaFormat]( &convert ); } GLboolean _mesa_convert_texsubimage3d( GLint mesaFormat, GLint xoffset, GLint yoffset, GLint zoffset, GLint width, GLint height, GLint depth, GLint dstImageWidth, GLint dstImageHeight, GLenum format, GLenum type, const struct gl_pixelstore_attrib *packing, const GLvoid *srcImage, GLvoid *dstImage ) { struct gl_texture_convert convert; ASSERT( packing ); ASSERT( srcImage ); ASSERT( dstImage ); ASSERT( mesaFormat >= MESA_FORMAT_RGBA8888 ); ASSERT( mesaFormat <= MESA_FORMAT_CI8 ); /* Make it easier to pass all the parameters around. */ convert.xoffset = xoffset; convert.yoffset = yoffset; convert.zoffset = zoffset; convert.width = width; convert.height = height; convert.depth = depth; convert.dstImageWidth = dstImageWidth; convert.dstImageHeight = dstImageHeight; convert.format = format; convert.type = type; convert.packing = packing; convert.srcImage = srcImage; convert.dstImage = dstImage; convert.index = 0; if ( convert_needs_packing( packing, format, type ) ) convert.index |= CONVERT_PACKING_BIT; if ( width != dstImageWidth || height != dstImageHeight ) convert.index |= CONVERT_STRIDE_BIT; return gl_convert_texsubimage3d_tab[mesaFormat]( &convert ); } /* Nearest filtering only (for broken hardware that can't support * all aspect ratios). This can be made a lot faster, but I don't * really care enough... */ void _mesa_rescale_teximage2d( GLuint bytesPerPixel, GLuint dstRowStride, GLint srcWidth, GLint srcHeight, GLint dstWidth, GLint dstHeight, const GLvoid *srcImage, GLvoid *dstImage ) { GLint row, col; #define INNER_LOOP( TYPE, HOP, WOP ) \ for ( row = 0 ; row < dstHeight ; row++ ) { \ GLint srcRow = row HOP hScale; \ for ( col = 0 ; col < dstWidth ; col++ ) { \ GLint srcCol = col WOP wScale; \ dst[col] = src[srcRow * srcWidth + srcCol]; \ } \ dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \ } \ #define RESCALE_IMAGE( TYPE ) \ do { \ const TYPE *src = (const TYPE *)srcImage; \ TYPE *dst = (TYPE *)dstImage; \ \ if ( srcHeight <= dstHeight ) { \ const GLint hScale = dstHeight / srcHeight; \ if ( srcWidth <= dstWidth ) { \ const GLint wScale = dstWidth / srcWidth; \ INNER_LOOP( TYPE, /, / ); \ } \ else { \ const GLint wScale = srcWidth / dstWidth; \ INNER_LOOP( TYPE, /, * ); \ } \ } \ else { \ const GLint hScale = srcHeight / dstHeight; \ if ( srcWidth <= dstWidth ) { \ const GLint wScale = dstWidth / srcWidth; \ INNER_LOOP( TYPE, *, / ); \ } \ else { \ const GLint wScale = srcWidth / dstWidth; \ INNER_LOOP( TYPE, *, * ); \ } \ } \ } while (0) switch ( bytesPerPixel ) { case 4: RESCALE_IMAGE( GLuint ); break; case 2: RESCALE_IMAGE( GLushort ); break; case 1: RESCALE_IMAGE( GLubyte ); break; default: _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d"); } }