--- /dev/null
+/* $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;
+}