texcompress_fxt1.c revision fab1f07d6ad01463897ae792f4b33738afb07369
18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Mesa 3-D graphics library
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Version:  7.1
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com *
7fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * Permission is hereby granted, free of charge, to any person obtaining a
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * copy of this software and associated documentation files (the "Software"),
9fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * to deal in the Software without restriction, including without limitation
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * and/or sell copies of the Software, and to permit persons to whom the
12fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * Software is furnished to do so, subject to the following conditions:
13fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com *
14fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * The above copyright notice and this permission notice shall be included
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * in all copies or substantial portions of the Software.
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com */
24fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
25fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
26fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com/**
27fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com * \file texcompress_fxt1.c
2847e0a09052eb4c93a4506ebf3c64070fafc3d4b3tomhudson@google.com * GL_EXT_texture_compression_fxt1 support.
2947e0a09052eb4c93a4506ebf3c64070fafc3d4b3tomhudson@google.com */
30fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
31fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
32fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "glheader.h"
33fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "imports.h"
34fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "colormac.h"
35fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "context.h"
36fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "convolve.h"
37fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "image.h"
38fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "mipmap.h"
39fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "texcompress.h"
40fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "texcompress_fxt1.h"
41fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#include "texstore.h"
42fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
43fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
44fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com#if FEATURE_texture_fxt1
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
464e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_encode (GLuint width, GLuint height, GLint comps,
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             const void *source, GLint srcRowStride,
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             void *dest, GLint destRowStride);
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
524e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.orgvoid
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_decode_1 (const void *texture, GLint stride,
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               GLint i, GLint j, GLchan *rgba);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/**
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Store user's image in rgb_fxt1 format.
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comGLboolean
614e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org_mesa_texstore_rgb_fxt1(TEXSTORE_PARAMS)
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   const GLchan *pixels;
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLint srcRowStride;
654e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLubyte *dst;
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   const GLint texWidth = dstRowStride * 8 / 16; /* a bit of a hack */
674e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   const GLchan *tempImage = NULL;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   ASSERT(dstFormat == MESA_FORMAT_RGB_FXT1);
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   ASSERT(dstXoffset % 8 == 0);
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   ASSERT(dstYoffset % 4 == 0);
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   ASSERT(dstZoffset     == 0);
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   (void) dstZoffset;
744e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   (void) dstImageOffsets;
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   if (srcFormat != GL_RGB ||
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       srcType != CHAN_TYPE ||
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       ctx->_ImageTransferState ||
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       srcPacking->SwapBytes) {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      /* convert image to RGB/GLchan */
814e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      tempImage = _mesa_make_temp_chan_image(ctx, dims,
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                             baseInternalFormat,
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                             _mesa_get_format_base_format(dstFormat),
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                             srcWidth, srcHeight, srcDepth,
854e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org                                             srcFormat, srcType, srcAddr,
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                             srcPacking);
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (!tempImage)
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         return GL_FALSE; /* out of memory */
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
904e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      pixels = tempImage;
914e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      srcRowStride = 3 * srcWidth;
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      srcFormat = GL_RGB;
934e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   }
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   else {
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      pixels = (const GLchan *) srcAddr;
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
974e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org                                            srcType) / sizeof(GLchan);
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
994e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        dstFormat,
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        texWidth, (GLubyte *) dstAddr);
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1044e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   fxt1_encode(srcWidth, srcHeight, 3, pixels, srcRowStride,
105d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org               dst, dstRowStride);
106d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
107d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   if (tempImage)
108d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org      free((void*) tempImage);
109d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
110d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   return GL_TRUE;
111d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org}
112d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
113d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
114d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org/**
1154e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org * Store user's image in rgba_fxt1 format.
116d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org */
117d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgGLboolean
118d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org_mesa_texstore_rgba_fxt1(TEXSTORE_PARAMS)
119d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org{
120d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   const GLchan *pixels;
1214e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint srcRowStride;
122d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   GLubyte *dst;
123d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   GLint texWidth = dstRowStride * 8 / 16; /* a bit of a hack */
124d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   const GLchan *tempImage = NULL;
125d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
126d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   ASSERT(dstFormat == MESA_FORMAT_RGBA_FXT1);
1274e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   ASSERT(dstXoffset % 8 == 0);
1284e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   ASSERT(dstYoffset % 4 == 0);
1294e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   ASSERT(dstZoffset     == 0);
130d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   (void) dstZoffset;
131d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   (void) dstImageOffsets;
132d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
133d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   if (srcFormat != GL_RGBA ||
134d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org       srcType != CHAN_TYPE ||
135d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org       ctx->_ImageTransferState ||
136d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org       srcPacking->SwapBytes) {
137d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org      /* convert image to RGBA/GLchan */
138d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org      tempImage = _mesa_make_temp_chan_image(ctx, dims,
139677cbedda7dc43844cbc58dbebbe52e37381be8evandebo@chromium.org                                             baseInternalFormat,
1404e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org                                             _mesa_get_format_base_format(dstFormat),
1418072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com                                             srcWidth, srcHeight, srcDepth,
1428072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com                                             srcFormat, srcType, srcAddr,
1438072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com                                             srcPacking);
1448072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com      if (!tempImage)
1458072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com         return GL_FALSE; /* out of memory */
1468072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
147677cbedda7dc43844cbc58dbebbe52e37381be8evandebo@chromium.org      pixels = tempImage;
1488072e4fdc8261b1ca8937aa5c31db967280eae2areed@google.com      srcRowStride = 4 * srcWidth;
149677cbedda7dc43844cbc58dbebbe52e37381be8evandebo@chromium.org      srcFormat = GL_RGBA;
150677cbedda7dc43844cbc58dbebbe52e37381be8evandebo@chromium.org   }
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   else {
1524e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      pixels = (const GLchan *) srcAddr;
153677cbedda7dc43844cbc58dbebbe52e37381be8evandebo@chromium.org      srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
1544e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org                                            srcType) / sizeof(GLchan);
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   dst = _mesa_compressed_image_address(dstXoffset, dstYoffset, 0,
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        dstFormat,
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        texWidth, (GLubyte *) dstAddr);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1614e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   fxt1_encode(srcWidth, srcHeight, 4, pixels, srcRowStride,
1624e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org               dst, dstRowStride);
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   if (tempImage)
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      free((void*) tempImage);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return GL_TRUE;
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1694e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com_mesa_fetch_texel_2d_f_rgba_fxt1( const struct gl_texture_image *texImage,
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  GLint i, GLint j, GLint k, GLfloat *texel )
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   /* just sample as GLchan and convert to float here */
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLchan rgba[4];
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   (void) k;
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   fxt1_decode_1(texImage->Data, texImage->RowStride, i, j, rgba);
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]);
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]);
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]);
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[ACOMP] = CHAN_TO_FLOAT(rgba[ACOMP]);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
185fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com_mesa_fetch_texel_2d_f_rgb_fxt1( const struct gl_texture_image *texImage,
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                 GLint i, GLint j, GLint k, GLfloat *texel )
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1904e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   /* just sample as GLchan and convert to float here */
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLchan rgba[4];
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   (void) k;
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   fxt1_decode_1(texImage->Data, texImage->RowStride, i, j, rgba);
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[RCOMP] = CHAN_TO_FLOAT(rgba[RCOMP]);
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[GCOMP] = CHAN_TO_FLOAT(rgba[GCOMP]);
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[BCOMP] = CHAN_TO_FLOAT(rgba[BCOMP]);
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   texel[ACOMP] = 1.0F;
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1994e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2024e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org/***************************************************************************\
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FXT1 encoder
2044e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org *
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * The encoder was built by reversing the decoder,
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * and is vaguely based on Texus2 by 3dfx. Note that this code
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * is merely a proof of concept, since it is highly UNoptimized;
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * moreover, it is sub-optimal due to initial conditions passed
2094e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org * to Lloyd's algorithm (the interpolation modes are even worse).
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com\***************************************************************************/
2114e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_COMP 4 /* ever needed maximum number of components in texel */
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_VECT 4 /* ever needed maximum number of base vectors to find */
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define N_TEXELS 32 /* number of texels in a block (always 32) */
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define LL_N_REP 50 /* number of iterations in lloyd's vq */
2174e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org#define LL_RMS_D 10 /* fault tolerance (maximum delta) */
2184e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org#define LL_RMS_E 255 /* fault tolerance (maximum error) */
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define ALPHA_TS 2 /* alpha threshold: (255 - ALPHA_TS) deemed opaque */
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define ISTBLACK(v) (*((GLuint *)(v)) == 0)
2214e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2234e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org/*
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Define a 64-bit unsigned integer type and macros
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 1
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_NATIVE 1
2294e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef uint64_t Fx64;
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_MOV32(a, b) a = b
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_OR32(a, b)  a |= b
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_SHL(a, c)   a <<= c
2354e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_NATIVE 0
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef struct {
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLuint lo, hi;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} Fx64;
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2444e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org#define FX64_MOV32(a, b) a.lo = b
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_OR32(a, b)  a.lo |= b
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define FX64_SHL(a, c)                                 \
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   do {                                                \
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       if ((c) >= 32) {                                \
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          a.hi = a.lo << ((c) - 32);                   \
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          a.lo = 0;                                    \
2524e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org       } else {                                        \
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          a.hi = (a.hi << (c)) | (a.lo >> (32 - (c))); \
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          a.lo <<= (c);                                \
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com       }                                               \
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   } while (0)
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2614e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org#define F(i) (GLfloat)1 /* can be used to obtain an oblong metric: 0.30 / 0.59 / 0.11 */
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SAFECDOT 1 /* for paranoids */
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAKEIVEC(NV, NC, IV, B, V0, V1)  \
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   do {                                  \
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      /* compute interpolation vector */ \
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLfloat d2 = 0.0F;                 \
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLfloat rd2;                       \
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                         \
2704e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (i = 0; i < NC; i++) {         \
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         IV[i] = (V1[i] - V0[i]) * F(i); \
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         d2 += IV[i] * IV[i];            \
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }                                  \
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      rd2 = (GLfloat)NV / d2;            \
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      B = 0;                             \
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < NC; i++) {         \
2774e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         IV[i] *= F(i);                  \
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         B -= IV[i] * V0[i];             \
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         IV[i] *= rd2;                   \
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }                                  \
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      B = B * rd2 + 0.5f;                \
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   } while (0)
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define CALCCDOT(TEXEL, NV, NC, IV, B, V)\
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   do {                                  \
2864e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLfloat dot = 0.0F;                \
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < NC; i++) {         \
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         dot += V[i] * IV[i];            \
2894e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }                                  \
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      TEXEL = (GLint)(dot + B);          \
2914e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      if (SAFECDOT) {                    \
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         if (TEXEL < 0) {                \
2934e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            TEXEL = 0;                   \
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         } else if (TEXEL > NV) {        \
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            TEXEL = NV;                  \
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }                               \
2974e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }                                  \
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   } while (0)
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3014e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.orgstatic GLint
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_bestcol (GLfloat vec[][MAX_COMP], GLint nv,
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com              GLubyte input[MAX_COMP], GLint nc)
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3054e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint i, j, best = -1;
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLfloat err = 1e9; /* big enough */
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (j = 0; j < nv; j++) {
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLfloat e = 0.0F;
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < nc; i++) {
3114e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         e += (vec[j][i] - input[i]) * (vec[j][i] - input[i]);
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (e < err) {
3144e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         err = e;
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         best = j;
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return best;
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
321fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com
322fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com
323fc296295257a9300098df56a1e3975580e13d329bsalomon@google.comstatic GLint
324fc296295257a9300098df56a1e3975580e13d329bsalomon@google.comfxt1_worst (GLfloat vec[MAX_COMP],
325fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com            GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
326fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com{
327fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com   GLint i, k, worst = -1;
328fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com   GLfloat err = -1.0F; /* small enough */
329fc296295257a9300098df56a1e3975580e13d329bsalomon@google.com
3304e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   for (k = 0; k < n; k++) {
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLfloat e = 0.0F;
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < nc; i++) {
3334e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         e += (vec[i] - input[k][i]) * (vec[i] - input[k][i]);
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3354e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      if (e > err) {
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         err = e;
3374e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         worst = k;
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return worst;
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic GLint
3464e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.orgfxt1_variance (GLdouble variance[MAX_COMP],
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3494e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint i, k, best = 0;
3504e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint sx, sx2;
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLdouble var, maxvar = -1; /* small enough */
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLdouble teenth = 1.0 / n;
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (i = 0; i < nc; i++) {
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      sx = sx2 = 0;
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (k = 0; k < n; k++) {
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         GLint t = input[k][i];
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         sx += t;
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         sx2 += t * t;
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3614e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      var = sx2 * teenth - sx * sx * teenth * teenth;
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (maxvar < var) {
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         maxvar = var;
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         best = i;
3654e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }
3664e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      if (variance) {
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         variance[i] = var;
3684e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }
3694e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   }
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return best;
3724e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org}
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3744e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic GLint
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_choose (GLfloat vec[][MAX_COMP], GLint nv,
3774e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org             GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0
3804e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   /* Choose colors from a grid.
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3824e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint i, j;
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (j = 0; j < nv; j++) {
3854e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint m = j * (n - 1) / (nv - 1);
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < nc; i++) {
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         vec[j][i] = input[m][i];
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
3914e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   /* Our solution here is to find the darkest and brightest colors in
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * the 8x4 tile and use those as the two representative colors.
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * There are probably better algorithms to use (histogram-based).
3944e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    */
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLint i, j, k;
3964e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint minSum = 2000; /* big enough */
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLint maxSum = -1; /* small enough */
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLint minCol = 0; /* phoudoin: silent compiler! */
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLint maxCol = 0; /* phoudoin: silent compiler! */
4004e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
4014e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   struct {
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLint flag;
4034e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint key;
4044e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint freq;
4054e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint idx;
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   } hist[N_TEXELS];
4074e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint lenh = 0;
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4094e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   memset(hist, 0, sizeof(hist));
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4114e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   for (k = 0; k < n; k++) {
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      GLint l;
4134e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint key = 0;
4144e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      GLint sum = 0;
4154e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (i = 0; i < nc; i++) {
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         key <<= 8;
4174e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         key |= input[k][i];
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         sum += input[k][i];
4194e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (l = 0; l < n; l++) {
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         if (!hist[l].flag) {
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            /* alloc new slot */
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            hist[l].flag = !0;
4244e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            hist[l].key = key;
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            hist[l].freq = 1;
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            hist[l].idx = k;
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lenh = l + 1;
4284e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            break;
4294e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         } else if (hist[l].key == key) {
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            hist[l].freq++;
4314e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            break;
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }
4334e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      }
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (minSum > sum) {
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         minSum = sum;
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         minCol = k;
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if (maxSum < sum) {
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         maxSum = sum;
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         maxCol = k;
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   if (lenh <= nv) {
4454e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (j = 0; j < lenh; j++) {
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         for (i = 0; i < nc; i++) {
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            vec[j][i] = (GLfloat)input[hist[j].idx][i];
4484e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         }
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
4504e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (; j < nv; j++) {
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         for (i = 0; i < nc; i++) {
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            vec[j][i] = vec[0][i];
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
4554e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      return 0;
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (j = 0; j < nv; j++) {
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (i = 0; i < nc; i++) {
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         vec[j][i] = ((nv - 1 - j) * input[minCol][i] + j * input[maxCol][i] + (nv - 1) / 2) / (GLfloat)(nv - 1);
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
4624e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   }
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
4644e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return !0;
4664e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org}
4674e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
4684e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
4694e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.orgstatic GLint
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_lloyd (GLfloat vec[][MAX_COMP], GLint nv,
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   /* Use the generalized lloyd's algorithm for VQ:
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *     find 4 color vectors.
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *
4764e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    *     for each sample color
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *         sort to nearest vector.
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *     replace each vector with the centroid of its matching colors.
4804e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    *
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *     repeat until RMS doesn't improve.
4824e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    *
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *     if a color vector has no samples, or becomes the same as another
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *     vector, replace it with the color which is farthest from a sample.
4854e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    *
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * vec[][MAX_COMP]           initial vectors and resulting colors
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * nv                        number of resulting colors required
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * input[N_TEXELS][MAX_COMP] input texels
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * nc                        number of components in input / vec
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    * n                         number of input samples
4914e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org    */
492d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
493d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   GLint sum[MAX_VECT][MAX_COMP]; /* used to accumulate closest texels */
494d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   GLint cnt[MAX_VECT]; /* how many times a certain vector was chosen */
495d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org   GLfloat error, lasterror = 1e9;
496d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org
4974e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint i, j, k, rep;
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
499fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com   /* the quantizer */
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (rep = 0; rep < LL_N_REP; rep++) {
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      /* reset sums & counters */
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (j = 0; j < nv; j++) {
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         for (i = 0; i < nc; i++) {
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            sum[j][i] = 0;
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         cnt[j] = 0;
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      error = 0;
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5104e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      /* scan whole block */
5114e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (k = 0; k < n; k++) {
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 1
5134e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         GLint best = -1;
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         GLfloat err = 1e9; /* big enough */
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         /* determine best vector */
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         for (j = 0; j < nv; j++) {
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            GLfloat e = (vec[j][0] - input[k][0]) * (vec[j][0] - input[k][0]) +
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                      (vec[j][1] - input[k][1]) * (vec[j][1] - input[k][1]) +
5194e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org                      (vec[j][2] - input[k][2]) * (vec[j][2] - input[k][2]);
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nc == 4) {
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               e += (vec[j][3] - input[k][3]) * (vec[j][3] - input[k][3]);
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (e < err) {
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               err = e;
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               best = j;
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         GLint best = fxt1_bestcol(vec, nv, input[k], nc, &err);
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         assert(best >= 0);
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         /* add in closest color */
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         for (i = 0; i < nc; i++) {
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            sum[best][i] += input[k][i];
535fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com         }
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         /* mark this vector as used */
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         cnt[best]++;
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         /* accumulate error */
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         error += err;
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
542fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com      /* check RMS */
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      if ((error < LL_RMS_E) ||
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com          ((error < lasterror) && ((lasterror - error) < LL_RMS_D))) {
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         return !0; /* good match */
546fa06e528035dd9c4d01c1d1e17e9df1cfe99b855reed@google.com      }
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      lasterror = error;
5484e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      /* move each vector to the barycenter of its closest colors */
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      for (j = 0; j < nv; j++) {
5514e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org         if (cnt[j]) {
5524e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            GLfloat div = 1.0F / cnt[j];
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (i = 0; i < nc; i++) {
5544e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org               vec[j][i] = div * sum[j][i];
5554e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            }
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         } else {
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            /* this vec has no samples or is identical with a previous vec */
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            GLint worst = fxt1_worst(vec[j], input, nc, n);
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (i = 0; i < nc; i++) {
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com               vec[j][i] = input[worst][i];
5614e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org            }
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         }
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   return 0; /* could not converge fast enough */
5674e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org}
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfxt1_quantize_CHROMA (GLuint *cc,
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                      GLubyte input[N_TEXELS][MAX_COMP])
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   const GLint n_vect = 4; /* 4 base vectors to find */
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   const GLint n_comp = 3; /* 3 components: R, G, B */
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLfloat vec[MAX_VECT][MAX_COMP];
5774e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org   GLint i, j, k;
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   Fx64 hi; /* high quadword */
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   if (fxt1_choose(vec, n_vect, input, n_comp, N_TEXELS) != 0) {
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      fxt1_lloyd(vec, n_vect, input, n_comp, N_TEXELS);
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   FX64_MOV32(hi, 4); /* cc-chroma = "010" + unused bit */
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (j = n_vect - 1; j >= 0; j--) {
5874e1d3acc16edb0b502cff157978235f5af627a5amike@reedtribe.org      for (i = 0; i < n_comp; i++) {
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         /* add in colors */
589d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org         FX64_SHL(hi, 5);
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      }
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   ((Fx64 *)cc)[1] = hi;
594d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org
595d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org   lohi = lolo = 0;
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   /* right microtile */
597d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org   for (k = N_TEXELS - 1; k >= N_TEXELS/2; k--) {
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      lohi <<= 2;
599d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org      lohi |= fxt1_bestcol(vec, n_vect, input[k], n_comp);
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   }
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   /* left microtile */
6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   for (; k >= 0; k--) {
6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      lolo <<= 2;
604d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org      lolo |= fxt1_bestcol(vec, n_vect, input[k], n_comp);
605d5e05d428647c164080e38dabee94db52c8c4544mike@reedtribe.org   }
6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   cc[1] = lohi;
6073a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com   cc[0] = lolo;
6083a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com}
6093a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com
6103a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com
6113a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.comstatic void
6123a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.comfxt1_quantize_ALPHA0 (GLuint *cc,
6133a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com                      GLubyte input[N_TEXELS][MAX_COMP],
6143a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com                      GLubyte reord[N_TEXELS][MAX_COMP], GLint n)
6153a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com{
6163a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com   const GLint n_vect = 3; /* 3 base vectors to find */
6173a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com   const GLint n_comp = 4; /* 4 components: R, G, B, A */
6183a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com   GLfloat vec[MAX_VECT][MAX_COMP];
61947e0a09052eb4c93a4506ebf3c64070fafc3d4b3tomhudson@google.com   GLint i, j, k;
6203a1f6a06cc706b35d9d6086ffbf5135cbf42bf8atomhudson@google.com   Fx64 hi; /* high quadword */
621   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
622
623   /* the last vector indicates zero */
624   for (i = 0; i < n_comp; i++) {
625      vec[n_vect][i] = 0;
626   }
627
628   /* the first n texels in reord are guaranteed to be non-zero */
629   if (fxt1_choose(vec, n_vect, reord, n_comp, n) != 0) {
630      fxt1_lloyd(vec, n_vect, reord, n_comp, n);
631   }
632
633   FX64_MOV32(hi, 6); /* alpha = "011" + lerp = 0 */
634   for (j = n_vect - 1; j >= 0; j--) {
635      /* add in alphas */
636      FX64_SHL(hi, 5);
637      FX64_OR32(hi, (GLuint)(vec[j][ACOMP] / 8.0F));
638   }
639   for (j = n_vect - 1; j >= 0; j--) {
640      for (i = 0; i < n_comp - 1; i++) {
641         /* add in colors */
642         FX64_SHL(hi, 5);
643         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
644      }
645   }
646   ((Fx64 *)cc)[1] = hi;
647
648   lohi = lolo = 0;
649   /* right microtile */
650   for (k = N_TEXELS - 1; k >= N_TEXELS/2; k--) {
651      lohi <<= 2;
652      lohi |= fxt1_bestcol(vec, n_vect + 1, input[k], n_comp);
653   }
654   /* left microtile */
655   for (; k >= 0; k--) {
656      lolo <<= 2;
657      lolo |= fxt1_bestcol(vec, n_vect + 1, input[k], n_comp);
658   }
659   cc[1] = lohi;
660   cc[0] = lolo;
661}
662
663
664static void
665fxt1_quantize_ALPHA1 (GLuint *cc,
666                      GLubyte input[N_TEXELS][MAX_COMP])
667{
668   const GLint n_vect = 3; /* highest vector number in each microtile */
669   const GLint n_comp = 4; /* 4 components: R, G, B, A */
670   GLfloat vec[1 + 1 + 1][MAX_COMP]; /* 1.5 extrema for each sub-block */
671   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
672   GLint i, j, k;
673   Fx64 hi; /* high quadword */
674   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
675
676   GLint minSum;
677   GLint maxSum;
678   GLint minColL = 0, maxColL = 0;
679   GLint minColR = 0, maxColR = 0;
680   GLint sumL = 0, sumR = 0;
681   GLint nn_comp;
682   /* Our solution here is to find the darkest and brightest colors in
683    * the 4x4 tile and use those as the two representative colors.
684    * There are probably better algorithms to use (histogram-based).
685    */
686   nn_comp = n_comp;
687   while ((minColL == maxColL) && nn_comp) {
688       minSum = 2000; /* big enough */
689       maxSum = -1; /* small enough */
690       for (k = 0; k < N_TEXELS / 2; k++) {
691           GLint sum = 0;
692           for (i = 0; i < nn_comp; i++) {
693               sum += input[k][i];
694           }
695           if (minSum > sum) {
696               minSum = sum;
697               minColL = k;
698           }
699           if (maxSum < sum) {
700               maxSum = sum;
701               maxColL = k;
702           }
703           sumL += sum;
704       }
705
706       nn_comp--;
707   }
708
709   nn_comp = n_comp;
710   while ((minColR == maxColR) && nn_comp) {
711       minSum = 2000; /* big enough */
712       maxSum = -1; /* small enough */
713       for (k = N_TEXELS / 2; k < N_TEXELS; k++) {
714           GLint sum = 0;
715           for (i = 0; i < nn_comp; i++) {
716               sum += input[k][i];
717           }
718           if (minSum > sum) {
719               minSum = sum;
720               minColR = k;
721           }
722           if (maxSum < sum) {
723               maxSum = sum;
724               maxColR = k;
725           }
726           sumR += sum;
727       }
728
729       nn_comp--;
730   }
731
732   /* choose the common vector (yuck!) */
733   {
734      GLint j1, j2;
735      GLint v1 = 0, v2 = 0;
736      GLfloat err = 1e9; /* big enough */
737      GLfloat tv[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
738      for (i = 0; i < n_comp; i++) {
739         tv[0][i] = input[minColL][i];
740         tv[1][i] = input[maxColL][i];
741         tv[2][i] = input[minColR][i];
742         tv[3][i] = input[maxColR][i];
743      }
744      for (j1 = 0; j1 < 2; j1++) {
745         for (j2 = 2; j2 < 4; j2++) {
746            GLfloat e = 0.0F;
747            for (i = 0; i < n_comp; i++) {
748               e += (tv[j1][i] - tv[j2][i]) * (tv[j1][i] - tv[j2][i]);
749            }
750            if (e < err) {
751               err = e;
752               v1 = j1;
753               v2 = j2;
754            }
755         }
756      }
757      for (i = 0; i < n_comp; i++) {
758         vec[0][i] = tv[1 - v1][i];
759         vec[1][i] = (tv[v1][i] * sumL + tv[v2][i] * sumR) / (sumL + sumR);
760         vec[2][i] = tv[5 - v2][i];
761      }
762   }
763
764   /* left microtile */
765   cc[0] = 0;
766   if (minColL != maxColL) {
767      /* compute interpolation vector */
768      MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
769
770      /* add in texels */
771      lolo = 0;
772      for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
773         GLint texel;
774         /* interpolate color */
775         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
776         /* add in texel */
777         lolo <<= 2;
778         lolo |= texel;
779      }
780
781      cc[0] = lolo;
782   }
783
784   /* right microtile */
785   cc[1] = 0;
786   if (minColR != maxColR) {
787      /* compute interpolation vector */
788      MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[1]);
789
790      /* add in texels */
791      lohi = 0;
792      for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
793         GLint texel;
794         /* interpolate color */
795         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
796         /* add in texel */
797         lohi <<= 2;
798         lohi |= texel;
799      }
800
801      cc[1] = lohi;
802   }
803
804   FX64_MOV32(hi, 7); /* alpha = "011" + lerp = 1 */
805   for (j = n_vect - 1; j >= 0; j--) {
806      /* add in alphas */
807      FX64_SHL(hi, 5);
808      FX64_OR32(hi, (GLuint)(vec[j][ACOMP] / 8.0F));
809   }
810   for (j = n_vect - 1; j >= 0; j--) {
811      for (i = 0; i < n_comp - 1; i++) {
812         /* add in colors */
813         FX64_SHL(hi, 5);
814         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
815      }
816   }
817   ((Fx64 *)cc)[1] = hi;
818}
819
820
821static void
822fxt1_quantize_HI (GLuint *cc,
823                  GLubyte input[N_TEXELS][MAX_COMP],
824                  GLubyte reord[N_TEXELS][MAX_COMP], GLint n)
825{
826   const GLint n_vect = 6; /* highest vector number */
827   const GLint n_comp = 3; /* 3 components: R, G, B */
828   GLfloat b = 0.0F;       /* phoudoin: silent compiler! */
829   GLfloat iv[MAX_COMP];   /* interpolation vector */
830   GLint i, k;
831   GLuint hihi; /* high quadword: hi dword */
832
833   GLint minSum = 2000; /* big enough */
834   GLint maxSum = -1; /* small enough */
835   GLint minCol = 0; /* phoudoin: silent compiler! */
836   GLint maxCol = 0; /* phoudoin: silent compiler! */
837
838   /* Our solution here is to find the darkest and brightest colors in
839    * the 8x4 tile and use those as the two representative colors.
840    * There are probably better algorithms to use (histogram-based).
841    */
842   for (k = 0; k < n; k++) {
843      GLint sum = 0;
844      for (i = 0; i < n_comp; i++) {
845         sum += reord[k][i];
846      }
847      if (minSum > sum) {
848         minSum = sum;
849         minCol = k;
850      }
851      if (maxSum < sum) {
852         maxSum = sum;
853         maxCol = k;
854      }
855   }
856
857   hihi = 0; /* cc-hi = "00" */
858   for (i = 0; i < n_comp; i++) {
859      /* add in colors */
860      hihi <<= 5;
861      hihi |= reord[maxCol][i] >> 3;
862   }
863   for (i = 0; i < n_comp; i++) {
864      /* add in colors */
865      hihi <<= 5;
866      hihi |= reord[minCol][i] >> 3;
867   }
868   cc[3] = hihi;
869   cc[0] = cc[1] = cc[2] = 0;
870
871   /* compute interpolation vector */
872   if (minCol != maxCol) {
873      MAKEIVEC(n_vect, n_comp, iv, b, reord[minCol], reord[maxCol]);
874   }
875
876   /* add in texels */
877   for (k = N_TEXELS - 1; k >= 0; k--) {
878      GLint t = k * 3;
879      GLuint *kk = (GLuint *)((char *)cc + t / 8);
880      GLint texel = n_vect + 1; /* transparent black */
881
882      if (!ISTBLACK(input[k])) {
883         if (minCol != maxCol) {
884            /* interpolate color */
885            CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
886            /* add in texel */
887            kk[0] |= texel << (t & 7);
888         }
889      } else {
890         /* add in texel */
891         kk[0] |= texel << (t & 7);
892      }
893   }
894}
895
896
897static void
898fxt1_quantize_MIXED1 (GLuint *cc,
899                      GLubyte input[N_TEXELS][MAX_COMP])
900{
901   const GLint n_vect = 2; /* highest vector number in each microtile */
902   const GLint n_comp = 3; /* 3 components: R, G, B */
903   GLubyte vec[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
904   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
905   GLint i, j, k;
906   Fx64 hi; /* high quadword */
907   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
908
909   GLint minSum;
910   GLint maxSum;
911   GLint minColL = 0, maxColL = -1;
912   GLint minColR = 0, maxColR = -1;
913
914   /* Our solution here is to find the darkest and brightest colors in
915    * the 4x4 tile and use those as the two representative colors.
916    * There are probably better algorithms to use (histogram-based).
917    */
918   minSum = 2000; /* big enough */
919   maxSum = -1; /* small enough */
920   for (k = 0; k < N_TEXELS / 2; k++) {
921      if (!ISTBLACK(input[k])) {
922         GLint sum = 0;
923         for (i = 0; i < n_comp; i++) {
924            sum += input[k][i];
925         }
926         if (minSum > sum) {
927            minSum = sum;
928            minColL = k;
929         }
930         if (maxSum < sum) {
931            maxSum = sum;
932            maxColL = k;
933         }
934      }
935   }
936   minSum = 2000; /* big enough */
937   maxSum = -1; /* small enough */
938   for (; k < N_TEXELS; k++) {
939      if (!ISTBLACK(input[k])) {
940         GLint sum = 0;
941         for (i = 0; i < n_comp; i++) {
942            sum += input[k][i];
943         }
944         if (minSum > sum) {
945            minSum = sum;
946            minColR = k;
947         }
948         if (maxSum < sum) {
949            maxSum = sum;
950            maxColR = k;
951         }
952      }
953   }
954
955   /* left microtile */
956   if (maxColL == -1) {
957      /* all transparent black */
958      cc[0] = ~0u;
959      for (i = 0; i < n_comp; i++) {
960         vec[0][i] = 0;
961         vec[1][i] = 0;
962      }
963   } else {
964      cc[0] = 0;
965      for (i = 0; i < n_comp; i++) {
966         vec[0][i] = input[minColL][i];
967         vec[1][i] = input[maxColL][i];
968      }
969      if (minColL != maxColL) {
970         /* compute interpolation vector */
971         MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
972
973         /* add in texels */
974         lolo = 0;
975         for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
976            GLint texel = n_vect + 1; /* transparent black */
977            if (!ISTBLACK(input[k])) {
978               /* interpolate color */
979               CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
980            }
981            /* add in texel */
982            lolo <<= 2;
983            lolo |= texel;
984         }
985         cc[0] = lolo;
986      }
987   }
988
989   /* right microtile */
990   if (maxColR == -1) {
991      /* all transparent black */
992      cc[1] = ~0u;
993      for (i = 0; i < n_comp; i++) {
994         vec[2][i] = 0;
995         vec[3][i] = 0;
996      }
997   } else {
998      cc[1] = 0;
999      for (i = 0; i < n_comp; i++) {
1000         vec[2][i] = input[minColR][i];
1001         vec[3][i] = input[maxColR][i];
1002      }
1003      if (minColR != maxColR) {
1004         /* compute interpolation vector */
1005         MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[3]);
1006
1007         /* add in texels */
1008         lohi = 0;
1009         for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
1010            GLint texel = n_vect + 1; /* transparent black */
1011            if (!ISTBLACK(input[k])) {
1012               /* interpolate color */
1013               CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1014            }
1015            /* add in texel */
1016            lohi <<= 2;
1017            lohi |= texel;
1018         }
1019         cc[1] = lohi;
1020      }
1021   }
1022
1023   FX64_MOV32(hi, 9 | (vec[3][GCOMP] & 4) | ((vec[1][GCOMP] >> 1) & 2)); /* chroma = "1" */
1024   for (j = 2 * 2 - 1; j >= 0; j--) {
1025      for (i = 0; i < n_comp; i++) {
1026         /* add in colors */
1027         FX64_SHL(hi, 5);
1028         FX64_OR32(hi, vec[j][i] >> 3);
1029      }
1030   }
1031   ((Fx64 *)cc)[1] = hi;
1032}
1033
1034
1035static void
1036fxt1_quantize_MIXED0 (GLuint *cc,
1037                      GLubyte input[N_TEXELS][MAX_COMP])
1038{
1039   const GLint n_vect = 3; /* highest vector number in each microtile */
1040   const GLint n_comp = 3; /* 3 components: R, G, B */
1041   GLubyte vec[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
1042   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
1043   GLint i, j, k;
1044   Fx64 hi; /* high quadword */
1045   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
1046
1047   GLint minColL = 0, maxColL = 0;
1048   GLint minColR = 0, maxColR = 0;
1049#if 0
1050   GLint minSum;
1051   GLint maxSum;
1052
1053   /* Our solution here is to find the darkest and brightest colors in
1054    * the 4x4 tile and use those as the two representative colors.
1055    * There are probably better algorithms to use (histogram-based).
1056    */
1057   minSum = 2000; /* big enough */
1058   maxSum = -1; /* small enough */
1059   for (k = 0; k < N_TEXELS / 2; k++) {
1060      GLint sum = 0;
1061      for (i = 0; i < n_comp; i++) {
1062         sum += input[k][i];
1063      }
1064      if (minSum > sum) {
1065         minSum = sum;
1066         minColL = k;
1067      }
1068      if (maxSum < sum) {
1069         maxSum = sum;
1070         maxColL = k;
1071      }
1072   }
1073   minSum = 2000; /* big enough */
1074   maxSum = -1; /* small enough */
1075   for (; k < N_TEXELS; k++) {
1076      GLint sum = 0;
1077      for (i = 0; i < n_comp; i++) {
1078         sum += input[k][i];
1079      }
1080      if (minSum > sum) {
1081         minSum = sum;
1082         minColR = k;
1083      }
1084      if (maxSum < sum) {
1085         maxSum = sum;
1086         maxColR = k;
1087      }
1088   }
1089#else
1090   GLint minVal;
1091   GLint maxVal;
1092   GLint maxVarL = fxt1_variance(NULL, input, n_comp, N_TEXELS / 2);
1093   GLint maxVarR = fxt1_variance(NULL, &input[N_TEXELS / 2], n_comp, N_TEXELS / 2);
1094
1095   /* Scan the channel with max variance for lo & hi
1096    * and use those as the two representative colors.
1097    */
1098   minVal = 2000; /* big enough */
1099   maxVal = -1; /* small enough */
1100   for (k = 0; k < N_TEXELS / 2; k++) {
1101      GLint t = input[k][maxVarL];
1102      if (minVal > t) {
1103         minVal = t;
1104         minColL = k;
1105      }
1106      if (maxVal < t) {
1107         maxVal = t;
1108         maxColL = k;
1109      }
1110   }
1111   minVal = 2000; /* big enough */
1112   maxVal = -1; /* small enough */
1113   for (; k < N_TEXELS; k++) {
1114      GLint t = input[k][maxVarR];
1115      if (minVal > t) {
1116         minVal = t;
1117         minColR = k;
1118      }
1119      if (maxVal < t) {
1120         maxVal = t;
1121         maxColR = k;
1122      }
1123   }
1124#endif
1125
1126   /* left microtile */
1127   cc[0] = 0;
1128   for (i = 0; i < n_comp; i++) {
1129      vec[0][i] = input[minColL][i];
1130      vec[1][i] = input[maxColL][i];
1131   }
1132   if (minColL != maxColL) {
1133      /* compute interpolation vector */
1134      MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
1135
1136      /* add in texels */
1137      lolo = 0;
1138      for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
1139         GLint texel;
1140         /* interpolate color */
1141         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1142         /* add in texel */
1143         lolo <<= 2;
1144         lolo |= texel;
1145      }
1146
1147      /* funky encoding for LSB of green */
1148      if ((GLint)((lolo >> 1) & 1) != (((vec[1][GCOMP] ^ vec[0][GCOMP]) >> 2) & 1)) {
1149         for (i = 0; i < n_comp; i++) {
1150            vec[1][i] = input[minColL][i];
1151            vec[0][i] = input[maxColL][i];
1152         }
1153         lolo = ~lolo;
1154      }
1155
1156      cc[0] = lolo;
1157   }
1158
1159   /* right microtile */
1160   cc[1] = 0;
1161   for (i = 0; i < n_comp; i++) {
1162      vec[2][i] = input[minColR][i];
1163      vec[3][i] = input[maxColR][i];
1164   }
1165   if (minColR != maxColR) {
1166      /* compute interpolation vector */
1167      MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[3]);
1168
1169      /* add in texels */
1170      lohi = 0;
1171      for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
1172         GLint texel;
1173         /* interpolate color */
1174         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1175         /* add in texel */
1176         lohi <<= 2;
1177         lohi |= texel;
1178      }
1179
1180      /* funky encoding for LSB of green */
1181      if ((GLint)((lohi >> 1) & 1) != (((vec[3][GCOMP] ^ vec[2][GCOMP]) >> 2) & 1)) {
1182         for (i = 0; i < n_comp; i++) {
1183            vec[3][i] = input[minColR][i];
1184            vec[2][i] = input[maxColR][i];
1185         }
1186         lohi = ~lohi;
1187      }
1188
1189      cc[1] = lohi;
1190   }
1191
1192   FX64_MOV32(hi, 8 | (vec[3][GCOMP] & 4) | ((vec[1][GCOMP] >> 1) & 2)); /* chroma = "1" */
1193   for (j = 2 * 2 - 1; j >= 0; j--) {
1194      for (i = 0; i < n_comp; i++) {
1195         /* add in colors */
1196         FX64_SHL(hi, 5);
1197         FX64_OR32(hi, vec[j][i] >> 3);
1198      }
1199   }
1200   ((Fx64 *)cc)[1] = hi;
1201}
1202
1203
1204static void
1205fxt1_quantize (GLuint *cc, const GLubyte *lines[], GLint comps)
1206{
1207   GLint trualpha;
1208   GLubyte reord[N_TEXELS][MAX_COMP];
1209
1210   GLubyte input[N_TEXELS][MAX_COMP];
1211   GLint i, k, l;
1212
1213   if (comps == 3) {
1214      /* make the whole block opaque */
1215      memset(input, -1, sizeof(input));
1216   }
1217
1218   /* 8 texels each line */
1219   for (l = 0; l < 4; l++) {
1220      for (k = 0; k < 4; k++) {
1221         for (i = 0; i < comps; i++) {
1222            input[k + l * 4][i] = *lines[l]++;
1223         }
1224      }
1225      for (; k < 8; k++) {
1226         for (i = 0; i < comps; i++) {
1227            input[k + l * 4 + 12][i] = *lines[l]++;
1228         }
1229      }
1230   }
1231
1232   /* block layout:
1233    * 00, 01, 02, 03, 08, 09, 0a, 0b
1234    * 10, 11, 12, 13, 18, 19, 1a, 1b
1235    * 04, 05, 06, 07, 0c, 0d, 0e, 0f
1236    * 14, 15, 16, 17, 1c, 1d, 1e, 1f
1237    */
1238
1239   /* [dBorca]
1240    * stupidity flows forth from this
1241    */
1242   l = N_TEXELS;
1243   trualpha = 0;
1244   if (comps == 4) {
1245      /* skip all transparent black texels */
1246      l = 0;
1247      for (k = 0; k < N_TEXELS; k++) {
1248         /* test all components against 0 */
1249         if (!ISTBLACK(input[k])) {
1250            /* texel is not transparent black */
1251            COPY_4UBV(reord[l], input[k]);
1252            if (reord[l][ACOMP] < (255 - ALPHA_TS)) {
1253               /* non-opaque texel */
1254               trualpha = !0;
1255            }
1256            l++;
1257         }
1258      }
1259   }
1260
1261#if 0
1262   if (trualpha) {
1263      fxt1_quantize_ALPHA0(cc, input, reord, l);
1264   } else if (l == 0) {
1265      cc[0] = cc[1] = cc[2] = -1;
1266      cc[3] = 0;
1267   } else if (l < N_TEXELS) {
1268      fxt1_quantize_HI(cc, input, reord, l);
1269   } else {
1270      fxt1_quantize_CHROMA(cc, input);
1271   }
1272   (void)fxt1_quantize_ALPHA1;
1273   (void)fxt1_quantize_MIXED1;
1274   (void)fxt1_quantize_MIXED0;
1275#else
1276   if (trualpha) {
1277      fxt1_quantize_ALPHA1(cc, input);
1278   } else if (l == 0) {
1279      cc[0] = cc[1] = cc[2] = ~0u;
1280      cc[3] = 0;
1281   } else if (l < N_TEXELS) {
1282      fxt1_quantize_MIXED1(cc, input);
1283   } else {
1284      fxt1_quantize_MIXED0(cc, input);
1285   }
1286   (void)fxt1_quantize_ALPHA0;
1287   (void)fxt1_quantize_HI;
1288   (void)fxt1_quantize_CHROMA;
1289#endif
1290}
1291
1292
1293static void
1294fxt1_encode (GLuint width, GLuint height, GLint comps,
1295             const void *source, GLint srcRowStride,
1296             void *dest, GLint destRowStride)
1297{
1298   GLuint x, y;
1299   const GLubyte *data;
1300   GLuint *encoded = (GLuint *)dest;
1301   void *newSource = NULL;
1302
1303   assert(comps == 3 || comps == 4);
1304
1305   /* Replicate image if width is not M8 or height is not M4 */
1306   if ((width & 7) | (height & 3)) {
1307      GLint newWidth = (width + 7) & ~7;
1308      GLint newHeight = (height + 3) & ~3;
1309      newSource = malloc(comps * newWidth * newHeight * sizeof(GLchan));
1310      if (!newSource) {
1311         GET_CURRENT_CONTEXT(ctx);
1312         _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture compression");
1313         goto cleanUp;
1314      }
1315      _mesa_upscale_teximage2d(width, height, newWidth, newHeight,
1316                               comps, (const GLchan *) source,
1317                               srcRowStride, (GLchan *) newSource);
1318      source = newSource;
1319      width = newWidth;
1320      height = newHeight;
1321      srcRowStride = comps * newWidth;
1322   }
1323
1324   /* convert from 16/32-bit channels to GLubyte if needed */
1325   if (CHAN_TYPE != GL_UNSIGNED_BYTE) {
1326      const GLuint n = width * height * comps;
1327      const GLchan *src = (const GLchan *) source;
1328      GLubyte *dest = (GLubyte *) malloc(n * sizeof(GLubyte));
1329      GLuint i;
1330      if (!dest) {
1331         GET_CURRENT_CONTEXT(ctx);
1332         _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture compression");
1333         goto cleanUp;
1334      }
1335      for (i = 0; i < n; i++) {
1336         dest[i] = CHAN_TO_UBYTE(src[i]);
1337      }
1338      if (newSource != NULL) {
1339         free(newSource);
1340      }
1341      newSource = dest;  /* we'll free this buffer before returning */
1342      source = dest;  /* the new, GLubyte incoming image */
1343   }
1344
1345   data = (const GLubyte *) source;
1346   destRowStride = (destRowStride - width * 2) / 4;
1347   for (y = 0; y < height; y += 4) {
1348      GLuint offs = 0 + (y + 0) * srcRowStride;
1349      for (x = 0; x < width; x += 8) {
1350         const GLubyte *lines[4];
1351         lines[0] = &data[offs];
1352         lines[1] = lines[0] + srcRowStride;
1353         lines[2] = lines[1] + srcRowStride;
1354         lines[3] = lines[2] + srcRowStride;
1355         offs += 8 * comps;
1356         fxt1_quantize(encoded, lines, comps);
1357         /* 128 bits per 8x4 block */
1358         encoded += 4;
1359      }
1360      encoded += destRowStride;
1361   }
1362
1363 cleanUp:
1364   if (newSource != NULL) {
1365      free(newSource);
1366   }
1367}
1368
1369
1370/***************************************************************************\
1371 * FXT1 decoder
1372 *
1373 * The decoder is based on GL_3DFX_texture_compression_FXT1
1374 * specification and serves as a concept for the encoder.
1375\***************************************************************************/
1376
1377
1378/* lookup table for scaling 5 bit colors up to 8 bits */
1379static const GLubyte _rgb_scale_5[] = {
1380   0,   8,   16,  25,  33,  41,  49,  58,
1381   66,  74,  82,  90,  99,  107, 115, 123,
1382   132, 140, 148, 156, 165, 173, 181, 189,
1383   197, 206, 214, 222, 230, 239, 247, 255
1384};
1385
1386/* lookup table for scaling 6 bit colors up to 8 bits */
1387static const GLubyte _rgb_scale_6[] = {
1388   0,   4,   8,   12,  16,  20,  24,  28,
1389   32,  36,  40,  45,  49,  53,  57,  61,
1390   65,  69,  73,  77,  81,  85,  89,  93,
1391   97,  101, 105, 109, 113, 117, 121, 125,
1392   130, 134, 138, 142, 146, 150, 154, 158,
1393   162, 166, 170, 174, 178, 182, 186, 190,
1394   194, 198, 202, 206, 210, 215, 219, 223,
1395   227, 231, 235, 239, 243, 247, 251, 255
1396};
1397
1398
1399#define CC_SEL(cc, which) (((GLuint *)(cc))[(which) / 32] >> ((which) & 31))
1400#define UP5(c) _rgb_scale_5[(c) & 31]
1401#define UP6(c, b) _rgb_scale_6[(((c) & 31) << 1) | ((b) & 1)]
1402#define LERP(n, t, c0, c1) (((n) - (t)) * (c0) + (t) * (c1) + (n) / 2) / (n)
1403
1404
1405static void
1406fxt1_decode_1HI (const GLubyte *code, GLint t, GLchan *rgba)
1407{
1408   const GLuint *cc;
1409
1410   t *= 3;
1411   cc = (const GLuint *)(code + t / 8);
1412   t = (cc[0] >> (t & 7)) & 7;
1413
1414   if (t == 7) {
1415      rgba[RCOMP] = rgba[GCOMP] = rgba[BCOMP] = rgba[ACOMP] = 0;
1416   } else {
1417      GLubyte r, g, b;
1418      cc = (const GLuint *)(code + 12);
1419      if (t == 0) {
1420         b = UP5(CC_SEL(cc, 0));
1421         g = UP5(CC_SEL(cc, 5));
1422         r = UP5(CC_SEL(cc, 10));
1423      } else if (t == 6) {
1424         b = UP5(CC_SEL(cc, 15));
1425         g = UP5(CC_SEL(cc, 20));
1426         r = UP5(CC_SEL(cc, 25));
1427      } else {
1428         b = LERP(6, t, UP5(CC_SEL(cc, 0)), UP5(CC_SEL(cc, 15)));
1429         g = LERP(6, t, UP5(CC_SEL(cc, 5)), UP5(CC_SEL(cc, 20)));
1430         r = LERP(6, t, UP5(CC_SEL(cc, 10)), UP5(CC_SEL(cc, 25)));
1431      }
1432      rgba[RCOMP] = UBYTE_TO_CHAN(r);
1433      rgba[GCOMP] = UBYTE_TO_CHAN(g);
1434      rgba[BCOMP] = UBYTE_TO_CHAN(b);
1435      rgba[ACOMP] = CHAN_MAX;
1436   }
1437}
1438
1439
1440static void
1441fxt1_decode_1CHROMA (const GLubyte *code, GLint t, GLchan *rgba)
1442{
1443   const GLuint *cc;
1444   GLuint kk;
1445
1446   cc = (const GLuint *)code;
1447   if (t & 16) {
1448      cc++;
1449      t &= 15;
1450   }
1451   t = (cc[0] >> (t * 2)) & 3;
1452
1453   t *= 15;
1454   cc = (const GLuint *)(code + 8 + t / 8);
1455   kk = cc[0] >> (t & 7);
1456   rgba[BCOMP] = UBYTE_TO_CHAN( UP5(kk) );
1457   rgba[GCOMP] = UBYTE_TO_CHAN( UP5(kk >> 5) );
1458   rgba[RCOMP] = UBYTE_TO_CHAN( UP5(kk >> 10) );
1459   rgba[ACOMP] = CHAN_MAX;
1460}
1461
1462
1463static void
1464fxt1_decode_1MIXED (const GLubyte *code, GLint t, GLchan *rgba)
1465{
1466   const GLuint *cc;
1467   GLuint col[2][3];
1468   GLint glsb, selb;
1469
1470   cc = (const GLuint *)code;
1471   if (t & 16) {
1472      t &= 15;
1473      t = (cc[1] >> (t * 2)) & 3;
1474      /* col 2 */
1475      col[0][BCOMP] = (*(const GLuint *)(code + 11)) >> 6;
1476      col[0][GCOMP] = CC_SEL(cc, 99);
1477      col[0][RCOMP] = CC_SEL(cc, 104);
1478      /* col 3 */
1479      col[1][BCOMP] = CC_SEL(cc, 109);
1480      col[1][GCOMP] = CC_SEL(cc, 114);
1481      col[1][RCOMP] = CC_SEL(cc, 119);
1482      glsb = CC_SEL(cc, 126);
1483      selb = CC_SEL(cc, 33);
1484   } else {
1485      t = (cc[0] >> (t * 2)) & 3;
1486      /* col 0 */
1487      col[0][BCOMP] = CC_SEL(cc, 64);
1488      col[0][GCOMP] = CC_SEL(cc, 69);
1489      col[0][RCOMP] = CC_SEL(cc, 74);
1490      /* col 1 */
1491      col[1][BCOMP] = CC_SEL(cc, 79);
1492      col[1][GCOMP] = CC_SEL(cc, 84);
1493      col[1][RCOMP] = CC_SEL(cc, 89);
1494      glsb = CC_SEL(cc, 125);
1495      selb = CC_SEL(cc, 1);
1496   }
1497
1498   if (CC_SEL(cc, 124) & 1) {
1499      /* alpha[0] == 1 */
1500
1501      if (t == 3) {
1502         /* zero */
1503         rgba[RCOMP] = rgba[BCOMP] = rgba[GCOMP] = rgba[ACOMP] = 0;
1504      } else {
1505         GLubyte r, g, b;
1506         if (t == 0) {
1507            b = UP5(col[0][BCOMP]);
1508            g = UP5(col[0][GCOMP]);
1509            r = UP5(col[0][RCOMP]);
1510         } else if (t == 2) {
1511            b = UP5(col[1][BCOMP]);
1512            g = UP6(col[1][GCOMP], glsb);
1513            r = UP5(col[1][RCOMP]);
1514         } else {
1515            b = (UP5(col[0][BCOMP]) + UP5(col[1][BCOMP])) / 2;
1516            g = (UP5(col[0][GCOMP]) + UP6(col[1][GCOMP], glsb)) / 2;
1517            r = (UP5(col[0][RCOMP]) + UP5(col[1][RCOMP])) / 2;
1518         }
1519         rgba[RCOMP] = UBYTE_TO_CHAN(r);
1520         rgba[GCOMP] = UBYTE_TO_CHAN(g);
1521         rgba[BCOMP] = UBYTE_TO_CHAN(b);
1522         rgba[ACOMP] = CHAN_MAX;
1523      }
1524   } else {
1525      /* alpha[0] == 0 */
1526      GLubyte r, g, b;
1527      if (t == 0) {
1528         b = UP5(col[0][BCOMP]);
1529         g = UP6(col[0][GCOMP], glsb ^ selb);
1530         r = UP5(col[0][RCOMP]);
1531      } else if (t == 3) {
1532         b = UP5(col[1][BCOMP]);
1533         g = UP6(col[1][GCOMP], glsb);
1534         r = UP5(col[1][RCOMP]);
1535      } else {
1536         b = LERP(3, t, UP5(col[0][BCOMP]), UP5(col[1][BCOMP]));
1537         g = LERP(3, t, UP6(col[0][GCOMP], glsb ^ selb),
1538                        UP6(col[1][GCOMP], glsb));
1539         r = LERP(3, t, UP5(col[0][RCOMP]), UP5(col[1][RCOMP]));
1540      }
1541      rgba[RCOMP] = UBYTE_TO_CHAN(r);
1542      rgba[GCOMP] = UBYTE_TO_CHAN(g);
1543      rgba[BCOMP] = UBYTE_TO_CHAN(b);
1544      rgba[ACOMP] = CHAN_MAX;
1545   }
1546}
1547
1548
1549static void
1550fxt1_decode_1ALPHA (const GLubyte *code, GLint t, GLchan *rgba)
1551{
1552   const GLuint *cc;
1553   GLubyte r, g, b, a;
1554
1555   cc = (const GLuint *)code;
1556   if (CC_SEL(cc, 124) & 1) {
1557      /* lerp == 1 */
1558      GLuint col0[4];
1559
1560      if (t & 16) {
1561         t &= 15;
1562         t = (cc[1] >> (t * 2)) & 3;
1563         /* col 2 */
1564         col0[BCOMP] = (*(const GLuint *)(code + 11)) >> 6;
1565         col0[GCOMP] = CC_SEL(cc, 99);
1566         col0[RCOMP] = CC_SEL(cc, 104);
1567         col0[ACOMP] = CC_SEL(cc, 119);
1568      } else {
1569         t = (cc[0] >> (t * 2)) & 3;
1570         /* col 0 */
1571         col0[BCOMP] = CC_SEL(cc, 64);
1572         col0[GCOMP] = CC_SEL(cc, 69);
1573         col0[RCOMP] = CC_SEL(cc, 74);
1574         col0[ACOMP] = CC_SEL(cc, 109);
1575      }
1576
1577      if (t == 0) {
1578         b = UP5(col0[BCOMP]);
1579         g = UP5(col0[GCOMP]);
1580         r = UP5(col0[RCOMP]);
1581         a = UP5(col0[ACOMP]);
1582      } else if (t == 3) {
1583         b = UP5(CC_SEL(cc, 79));
1584         g = UP5(CC_SEL(cc, 84));
1585         r = UP5(CC_SEL(cc, 89));
1586         a = UP5(CC_SEL(cc, 114));
1587      } else {
1588         b = LERP(3, t, UP5(col0[BCOMP]), UP5(CC_SEL(cc, 79)));
1589         g = LERP(3, t, UP5(col0[GCOMP]), UP5(CC_SEL(cc, 84)));
1590         r = LERP(3, t, UP5(col0[RCOMP]), UP5(CC_SEL(cc, 89)));
1591         a = LERP(3, t, UP5(col0[ACOMP]), UP5(CC_SEL(cc, 114)));
1592      }
1593   } else {
1594      /* lerp == 0 */
1595
1596      if (t & 16) {
1597         cc++;
1598         t &= 15;
1599      }
1600      t = (cc[0] >> (t * 2)) & 3;
1601
1602      if (t == 3) {
1603         /* zero */
1604         r = g = b = a = 0;
1605      } else {
1606         GLuint kk;
1607         cc = (const GLuint *)code;
1608         a = UP5(cc[3] >> (t * 5 + 13));
1609         t *= 15;
1610         cc = (const GLuint *)(code + 8 + t / 8);
1611         kk = cc[0] >> (t & 7);
1612         b = UP5(kk);
1613         g = UP5(kk >> 5);
1614         r = UP5(kk >> 10);
1615      }
1616   }
1617   rgba[RCOMP] = UBYTE_TO_CHAN(r);
1618   rgba[GCOMP] = UBYTE_TO_CHAN(g);
1619   rgba[BCOMP] = UBYTE_TO_CHAN(b);
1620   rgba[ACOMP] = UBYTE_TO_CHAN(a);
1621}
1622
1623
1624void
1625fxt1_decode_1 (const void *texture, GLint stride, /* in pixels */
1626               GLint i, GLint j, GLchan *rgba)
1627{
1628   static void (*decode_1[]) (const GLubyte *, GLint, GLchan *) = {
1629      fxt1_decode_1HI,     /* cc-high   = "00?" */
1630      fxt1_decode_1HI,     /* cc-high   = "00?" */
1631      fxt1_decode_1CHROMA, /* cc-chroma = "010" */
1632      fxt1_decode_1ALPHA,  /* alpha     = "011" */
1633      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1634      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1635      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1636      fxt1_decode_1MIXED   /* mixed     = "1??" */
1637   };
1638
1639   const GLubyte *code = (const GLubyte *)texture +
1640                         ((j / 4) * (stride / 8) + (i / 8)) * 16;
1641   GLint mode = CC_SEL(code, 125);
1642   GLint t = i & 7;
1643
1644   if (t & 4) {
1645      t += 12;
1646   }
1647   t += (j & 3) * 4;
1648
1649   decode_1[mode](code, t, rgba);
1650}
1651
1652
1653#endif /* FEATURE_texture_fxt1 */
1654