diff options
Diffstat (limited to 'src/mesa/main/texutil.c')
-rw-r--r-- | src/mesa/main/texutil.c | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/src/mesa/main/texutil.c b/src/mesa/main/texutil.c new file mode 100644 index 0000000000..3023113c17 --- /dev/null +++ b/src/mesa/main/texutil.c @@ -0,0 +1,537 @@ +/* $Id: texutil.c,v 1.1 2000/03/24 20:54:21 brianp Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.3 + * + * Copyright (C) 1999-2000 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. + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include "glheader.h" +#include "image.h" +#include "mem.h" +#include "texutil.h" +#include "types.h" +#endif + + +/* + * Texture utilities which may be useful to device drivers. + */ + + + + +/* + * Convert texture image data into one a specific internal format. + * Input: + * dstFormat - the destination internal format + * dstWidth, dstHeight - the destination image size + * destImage - pointer to destination image buffer + * srcWidth, srcHeight - size of texture image + * srcFormat, srcType - format and datatype of source image + * srcImage - pointer to user's texture image + * packing - describes how user's texture image is packed. + * Return: pointer to resulting image data or NULL if error or out of memory + * or NULL if we can't process the given image format/type/internalFormat + * combination. + * + * Supported type conversions: + * srcFormat srcType dstFormat + * GL_INTENSITY GL_UNSIGNED_BYTE MESA_I8 + * GL_LUMINANCE GL_UNSIGNED_BYTE MESA_L8 + * GL_ALPHA GL_UNSIGNED_BYTE MESA_A8 + * GL_COLOR_INDEX GL_UNSIGNED_BYTE MESA_C8 + * GL_LUMINANCE_ALPHA GL_UNSIGNED_BYTE MESA_L8_A8 + * GL_RGB GL_UNSIGNED_BYTE MESA_R5_G6_B5 + * GL_RGB GL_UNSIGNED_SHORT_5_6_5 MESA_R5_G6_B5 + * GL_RGBA GL_UNSIGNED_BYTE MESA_A4_R4_G4_B4 + * GL_BGRA GL_UNSIGNED_SHORT_4_4_4_4_REV MESA_A4_R4_G4_B4 + * GL_BGRA GL_UNSIGHED_SHORT_1_5_5_5_REV MESA_A1_R5_G5_B5 + * GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV MESA_A8_R8_G8_B8 + * more to be added for new drivers... + * + * Notes: + * Some hardware only supports texture images of specific aspect ratios. + * This code will do power-of-two image up-scaling if that's needed. + * + * + */ +GLboolean +_mesa_convert_teximage(MesaIntTexFormat dstFormat, + GLint dstWidth, GLint dstHeight, GLvoid *dstImage, + GLsizei srcWidth, GLsizei srcHeight, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcImage, + const struct gl_pixelstore_attrib *packing) +{ + const GLint wScale = dstWidth / srcWidth; /* must be power of two */ + const GLint hScale = dstHeight / srcHeight; /* must be power of two */ + ASSERT(dstWidth >= srcWidth); + ASSERT(dstHeight >= srcHeight); + ASSERT(dstImage); + ASSERT(srcImage); + ASSERT(packing); + + switch (dstFormat) { + case MESA_I8: + case MESA_L8: + case MESA_A8: + case MESA_C8: + if (srcType != GL_UNSIGNED_BYTE || + ((srcFormat != GL_INTENSITY) && + (srcFormat != GL_LUMINANCE) && + (srcFormat != GL_ALPHA) && + (srcFormat != GL_COLOR_INDEX))) { + /* bad internal format / srcFormat combination */ + return GL_FALSE; + } + else { + /* store as 8-bit texels */ + if (wScale == 1 && hScale == 1) { + /* no scaling needed - fast case */ + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLubyte *dst = (GLubyte *) dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + MEMCPY(dst, src, dstWidth * sizeof(GLubyte)); + dst += dstWidth; + src += srcStride; + } + } + else { + /* must rescale image */ + GLubyte *dst = (GLubyte *) dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + dst[col] = src[col / wScale]; + } + dst += dstWidth; + } + } + } + break; + + case MESA_L8_A8: + if (srcType != GL_UNSIGNED_BYTE || srcFormat != GL_LUMINANCE_ALPHA) { + return GL_FALSE; + } + else { + /* store as 16-bit texels */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row, col; + for (row = 0; row < dstHeight; row++) { + for (col = 0; col < dstWidth; col++) { + GLubyte alpha = src[col * 2 + 0]; + GLubyte luminance = src[col * 2 + 1]; + dst[col] = ((GLushort) luminance << 8) | alpha; + } + dst += dstWidth; + src += srcStride; + } + } + else { + /* must rescale */ + GLushort *dst = dstImage; + GLint row, col; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + for (col = 0; col < dstWidth; col++) { + GLint srcCol = col / wScale; + GLubyte alpha = src[srcCol * 2 + 0]; + GLubyte luminance = src[srcCol * 2 + 1]; + dst[col] = ((GLushort) luminance << 8) | alpha; + } + dst += dstWidth; + src += srcStride; + } + } + } + break; + + case MESA_R5_G6_B5: + if (srcFormat == GL_RGB && srcType == GL_UNSIGNED_SHORT_5_6_5) { + /* special, optimized case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + MEMCPY(dst, src, dstWidth * sizeof(GLushort)); + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLushort *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + dst[col] = src[col / wScale]; + } + dst += dstWidth; + } + } + } + else if (srcFormat == GL_RGB && srcType == GL_UNSIGNED_BYTE) { + /* general case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint col, col3; + for (col = col3 = 0; col < dstWidth; col++, col3 += 3) { + GLubyte r = src[col3 + 0]; + GLubyte g = src[col3 + 1]; + GLubyte b = src[col3 + 2]; + dst[col] = ((r & 0xf8) << 8) + | ((g & 0xfc) << 3) + | ((b & 0xf8) >> 3); + } + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + GLint col3 = (col / wScale) * 3; + GLubyte r = src[col3 + 0]; + GLubyte g = src[col3 + 1]; + GLubyte b = src[col3 + 2]; + dst[col] = ((r & 0xf8) << 8) + | ((g & 0xfc) << 3) + | ((b & 0xf8) >> 3); + } + dst += dstWidth; + } + } + } + else { + /* can't handle this srcFormat/srcType combination */ + return GL_FALSE; + } + break; + + case MESA_A4_R4_G4_B4: + /* store as 16-bit texels (GR_TEXFMT_ARGB_4444) */ + if (srcFormat == GL_BGRA && srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV){ + /* special, optimized case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + MEMCPY(dst, src, dstWidth * sizeof(GLushort)); + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLushort *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + dst[col] = src[col / wScale]; + } + dst += dstWidth; + } + } + } + else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) { + /* general case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint col, col4; + for (col = col4 = 0; col < dstWidth; col++, col4 += 4) { + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = ((a & 0xf0) << 8) + | ((r & 0xf0) << 4) + | ((g & 0xf0) ) + | ((b & 0xf0) >> 4); + } + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + GLint col4 = (col / wScale) * 4; + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = ((a & 0xf0) << 8) + | ((r & 0xf0) << 4) + | ((g & 0xf0) ) + | ((b & 0xf0) >> 4); + } + dst += dstWidth; + } + } + } + else { + /* can't handle this format/srcType combination */ + return GL_FALSE; + } + break; + + case MESA_A1_R5_G5_B5: + /* store as 16-bit texels (GR_TEXFMT_ARGB_1555) */ + if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV){ + /* special, optimized case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + MEMCPY(dst, src, dstWidth * sizeof(GLushort)); + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLushort *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + dst[col] = src[col / wScale]; + } + dst += dstWidth; + } + } + } + else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) { + /* general case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint col, col4; + for (col = col4 = 0; col < dstWidth; col++, col4 += 4) { + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = ((a & 0x80) << 8) + | ((r & 0xf8) << 7) + | ((g & 0xf8) << 2) + | ((b & 0xf8) >> 3); + } + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + GLint col4 = (col / wScale) * 4; + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = ((a & 0x80) << 8) + | ((r & 0xf8) << 7) + | ((g & 0xf8) << 2) + | ((b & 0xf8) >> 3); + } + dst += dstWidth; + } + } + } + else { + /* can't handle this source format/type combination */ + return GL_FALSE; + } + break; + + case MESA_A8_R8_G8_B8: + /* 32-bit texels */ + if (srcFormat == GL_BGRA && srcType == GL_UNSIGNED_INT_8_8_8_8_REV){ + /* special, optimized case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLuint *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + MEMCPY(dst, src, dstWidth * sizeof(GLuint)); + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLuint *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLuint *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + dst[col] = src[col / wScale]; + } + dst += dstWidth; + } + } + } + else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) { + /* general case */ + if (wScale == 1 && hScale == 1) { + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint srcStride = _mesa_image_row_stride(packing, + srcWidth, srcFormat, srcType); + GLuint *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint col, col4; + for (col = col4 = 0; col < dstWidth; col++, col4 += 4) { + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = (a << 24) | (r << 16) | (g << 8) | b; + } + src += srcStride; + dst += dstWidth; + } + } + else { + /* must rescale image */ + GLushort *dst = dstImage; + GLint row; + for (row = 0; row < dstHeight; row++) { + GLint srcRow = row / hScale; + const GLubyte *src = _mesa_image_address(packing, srcImage, + srcWidth, srcHeight, srcFormat, srcType, 0, srcRow, 0); + GLint col; + for (col = 0; col < dstWidth; col++) { + GLint col4 = (col / wScale) * 4; + GLubyte r = src[col4 + 0]; + GLubyte g = src[col4 + 1]; + GLubyte b = src[col4 + 2]; + GLubyte a = src[col4 + 3]; + dst[col] = (a << 24) | (r << 16) | (g << 8) | b; + } + dst += dstWidth; + } + } + } + else { + /* can't handle this source format/type combination */ + return GL_FALSE; + } + break; + + + default: + /* unexpected internal format! */ + return GL_FALSE; + } + return GL_TRUE; +} |