130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/*
230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Mesa 3-D graphics library
3efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Version:  7.1
430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * Permission is hereby granted, free of charge, to any person obtaining a
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * copy of this software and associated documentation files (the "Software"),
930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * to deal in the Software without restriction, including without limitation
1030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * and/or sell copies of the Software, and to permit persons to whom the
1230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Software is furnished to do so, subject to the following conditions:
1330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
1430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * The above copyright notice and this permission notice shall be included
1530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * in all copies or substantial portions of the Software.
1630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
1730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o */
2430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o
2630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/**
2730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * \file texcompress_fxt1.c
28819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o * GL_3DFX_texture_compression_FXT1 support.
29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
30e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
3130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "glheader.h"
3330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "imports.h"
340f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#include "colormac.h"
350f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#include "image.h"
36a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o#include "macros.h"
37a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o#include "mfeatures.h"
38a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o#include "mipmap.h"
3930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "texcompress.h"
4030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "texcompress_fxt1.h"
4130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "texstore.h"
4230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include "swrast/s_context.h"
4330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#if FEATURE_texture_fxt1
4630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'ostatic void
4930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'ofxt1_encode (GLuint width, GLuint height, GLint comps,
5030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o             const void *source, GLint srcRowStride,
51c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o             void *dest, GLint destRowStride);
527b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
537b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'ovoid
54efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ofxt1_decode_1 (const void *texture, GLint stride,
5530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o               GLint i, GLint j, GLubyte *rgba);
5630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
5730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
5830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/**
5930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Store user's image in rgb_fxt1 format.
6030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o */
61a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'oGLboolean
62a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o_mesa_texstore_rgb_fxt1(TEXSTORE_PARAMS)
63a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o{
64a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   const GLubyte *pixels;
65a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   GLint srcRowStride;
66a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   GLubyte *dst;
67a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   const GLubyte *tempImage = NULL;
68efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
69ee01079a17bfecd17292ccd60058056fb3a8ba6cTheodore Ts'o   ASSERT(dstFormat == MESA_FORMAT_RGB_FXT1);
707b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
7130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   if (srcFormat != GL_RGB ||
7230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       srcType != GL_UNSIGNED_BYTE ||
7330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       ctx->_ImageTransferState ||
7430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       srcPacking->RowLength != srcWidth ||
75efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o       srcPacking->SwapBytes) {
7630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      /* convert image to RGB/GLubyte */
7730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      tempImage = _mesa_make_temp_ubyte_image(ctx, dims,
78c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o                                             baseInternalFormat,
79c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o                                             _mesa_get_format_base_format(dstFormat),
8030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcWidth, srcHeight, srcDepth,
8130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcFormat, srcType, srcAddr,
8230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcPacking);
83a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o      if (!tempImage)
84a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o         return GL_FALSE; /* out of memory */
85a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o      pixels = tempImage;
86a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o      srcRowStride = 3 * srcWidth;
87a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o      srcFormat = GL_RGB;
88a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   }
8930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   else {
9079a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
9179a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o                                     srcFormat, srcType, 0, 0);
9279a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o
9379a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
9479a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o                                            srcType) / sizeof(GLubyte);
9579a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   }
9679a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o
9779a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   dst = dstSlices[0];
9879a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o
9979a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   fxt1_encode(srcWidth, srcHeight, 3, pixels, srcRowStride,
100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall               dst, dstRowStride);
101e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
102e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   if (tempImage)
103e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      free((void*) tempImage);
104e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   return GL_TRUE;
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
108e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/**
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Store user's image in rgba_fxt1 format.
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
112e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP AbgrallGLboolean
113e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall_mesa_texstore_rgba_fxt1(TEXSTORE_PARAMS)
114e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
115e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   const GLubyte *pixels;
116e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   GLint srcRowStride;
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   GLubyte *dst;
11830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   const GLubyte *tempImage = NULL;
11930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
12030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   ASSERT(dstFormat == MESA_FORMAT_RGBA_FXT1);
121f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
12230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   if (srcFormat != GL_RGBA ||
12330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       srcType != GL_UNSIGNED_BYTE ||
1240f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o       ctx->_ImageTransferState ||
125efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o       srcPacking->SwapBytes) {
12630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      /* convert image to RGBA/GLubyte */
1270f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      tempImage = _mesa_make_temp_ubyte_image(ctx, dims,
12830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             baseInternalFormat,
12930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             _mesa_get_format_base_format(dstFormat),
13030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcWidth, srcHeight, srcDepth,
13130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcFormat, srcType, srcAddr,
13230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                             srcPacking);
13330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      if (!tempImage)
13430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         return GL_FALSE; /* out of memory */
13530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      pixels = tempImage;
13630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      srcRowStride = 4 * srcWidth;
13730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      srcFormat = GL_RGBA;
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   }
139a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   else {
140e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
14130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                     srcFormat, srcType, 0, 0);
14230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
14330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
14430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o                                            srcType) / sizeof(GLubyte);
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   }
14630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
14730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   dst = dstSlices[0];
14830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
14930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   fxt1_encode(srcWidth, srcHeight, 4, pixels, srcRowStride,
15030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o               dst, dstRowStride);
15130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
15230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   if (tempImage)
15330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      free((void*) tempImage);
1540f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1550f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   return GL_TRUE;
1560f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o}
1570f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1580f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1590f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'ovoid
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall_mesa_fetch_texel_2d_f_rgba_fxt1( const struct swrast_texture_image *texImage,
1610f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o                                  GLint i, GLint j, GLint k, GLfloat *texel )
1620f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o{
1630f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   /* just sample as GLubyte and convert to float here */
1640f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLubyte rgba[4];
1650f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   (void) k;
1660f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   fxt1_decode_1(texImage->Map, texImage->RowStride, i, j, rgba);
1670f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]);
1680f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]);
1690f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]);
1700f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]);
1710f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o}
1720f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1730f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1740f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'ovoid
1750f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o_mesa_fetch_texel_2d_f_rgb_fxt1( const struct swrast_texture_image *texImage,
1760f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o                                 GLint i, GLint j, GLint k, GLfloat *texel )
1770f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o{
1780f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   /* just sample as GLubyte and convert to float here */
1790f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLubyte rgba[4];
1800f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   (void) k;
1810f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   fxt1_decode_1(texImage->Map, texImage->RowStride, i, j, rgba);
1820f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]);
1830f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]);
1840f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]);
1850f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   texel[ACOMP] = 1.0F;
1860f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o}
1870f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
1880f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
189e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
190e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/***************************************************************************\
1910f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o * FXT1 encoder
1920f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o *
1930f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o * The encoder was built by reversing the decoder,
1940f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o * and is vaguely based on Texus2 by 3dfx. Note that this code
1950f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o * is merely a proof of concept, since it is highly UNoptimized;
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * moreover, it is sub-optimal due to initial conditions passed
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * to Lloyd's algorithm (the interpolation modes are even worse).
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall\***************************************************************************/
1990f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2000f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2010f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define MAX_COMP 4 /* ever needed maximum number of components in texel */
2020f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define MAX_VECT 4 /* ever needed maximum number of base vectors to find */
2030f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define N_TEXELS 32 /* number of texels in a block (always 32) */
2040f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define LL_N_REP 50 /* number of iterations in lloyd's vq */
2050f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define LL_RMS_D 10 /* fault tolerance (maximum delta) */
2060f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define LL_RMS_E 255 /* fault tolerance (maximum error) */
2070f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define ALPHA_TS 2 /* alpha threshold: (255 - ALPHA_TS) deemed opaque */
208efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#define ISTBLACK(v) (*((GLuint *)(v)) == 0)
2090f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
21030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
21130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/*
21230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Define a 64-bit unsigned integer type and macros
213efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o */
21430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#if 1
21530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
21630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define FX64_NATIVE 1
217efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
21830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'otypedef uint64_t Fx64;
219c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o
220c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o#define FX64_MOV32(a, b) a = b
22130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define FX64_OR32(a, b)  a |= b
22230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define FX64_SHL(a, c)   a <<= c
22330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
22430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#else
22530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
22630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define FX64_NATIVE 0
22779a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o
22830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'otypedef struct {
22930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   GLuint lo, hi;
2300f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o} Fx64;
231819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o
232819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#define FX64_MOV32(a, b) a.lo = b
233b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#define FX64_OR32(a, b)  a.lo |= b
23430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
23530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define FX64_SHL(a, c)                                 \
23630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   do {                                                \
23730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       if ((c) >= 32) {                                \
238819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o          a.hi = a.lo << ((c) - 32);                   \
2390f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o          a.lo = 0;                                    \
24030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       } else {                                        \
24130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o          a.hi = (a.hi << (c)) | (a.lo >> (32 - (c))); \
2420f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o          a.lo <<= (c);                                \
24330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o       }                                               \
24430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   } while (0)
2450f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2460f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#endif
2470f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2480f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2490f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define F(i) (GLfloat)1 /* can be used to obtain an oblong metric: 0.30 / 0.59 / 0.11 */
250819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#define SAFECDOT 1 /* for paranoids */
2510f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2520f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define MAKEIVEC(NV, NC, IV, B, V0, V1)  \
253efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o   do {                                  \
2540f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      /* compute interpolation vector */ \
2550f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      GLfloat d2 = 0.0F;                 \
2560f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      GLfloat rd2;                       \
2570f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o                                         \
2580f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      for (i = 0; i < NC; i++) {         \
25930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         IV[i] = (V1[i] - V0[i]) * F(i); \
260efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o         d2 += IV[i] * IV[i];            \
2610f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      }                                  \
26230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      rd2 = (GLfloat)NV / d2;            \
26330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      B = 0;                             \
26430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      for (i = 0; i < NC; i++) {         \
26530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         IV[i] *= F(i);                  \
26630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         B -= IV[i] * V0[i];             \
26730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         IV[i] *= rd2;                   \
268f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o      }                                  \
26979a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      B = B * rd2 + 0.5f;                \
27030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   } while (0)
27130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2720f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o#define CALCCDOT(TEXEL, NV, NC, IV, B, V)\
2730f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   do {                                  \
274546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'o      GLfloat dot = 0.0F;                \
27530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      for (i = 0; i < NC; i++) {         \
27630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         dot += V[i] * IV[i];            \
27730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      }                                  \
27830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      TEXEL = (GLint)(dot + B);          \
27930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      if (SAFECDOT) {                    \
2801f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o         if (TEXEL < 0) {                \
28130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o            TEXEL = 0;                   \
2820f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o         } else if (TEXEL > NV) {        \
2830f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o            TEXEL = NV;                  \
28430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         }                               \
28530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      }                                  \
286efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o   } while (0)
2870f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2880f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2890f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'ostatic GLint
2900f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'ofxt1_bestcol (GLfloat vec[][MAX_COMP], GLint nv,
2910f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o              GLubyte input[MAX_COMP], GLint nc)
2920f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o{
2930f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLint i, j, best = -1;
2940f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLfloat err = 1e9; /* big enough */
2950f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
2960f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   for (j = 0; j < nv; j++) {
29730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      GLfloat e = 0.0F;
29830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      for (i = 0; i < nc; i++) {
2990f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o         e += (vec[j][i] - input[i]) * (vec[j][i] - input[i]);
300e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
301e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      if (e < err) {
302e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         err = e;
303e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         best = j;
304e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
305e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   }
306e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
307e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   return best;
308e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
309e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
310e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
311e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic GLint
312e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallfxt1_worst (GLfloat vec[MAX_COMP],
313e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
3140f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o{
3150f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLint i, k, worst = -1;
3160f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   GLfloat err = -1.0F; /* small enough */
3170f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o
3180f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o   for (k = 0; k < n; k++) {
3190f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      GLfloat e = 0.0F;
32030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      for (i = 0; i < nc; i++) {
321efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o         e += (vec[i] - input[k][i]) * (vec[i] - input[k][i]);
3220f6794591edf238825f8ab80c885e83d1efbf203Theodore Ts'o      }
323e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      if (e > err) {
324e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         err = e;
325e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         worst = k;
326e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
327e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   }
328e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
329e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   return worst;
330e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
331e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
33230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
33330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'ostatic GLint
33430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'ofxt1_variance (GLdouble variance[MAX_COMP],
33530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o               GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
33630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
337819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint i, k, best = 0;
338819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint sx, sx2;
33930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   GLdouble var, maxvar = -1; /* small enough */
34030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   GLdouble teenth = 1.0 / n;
34130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
34230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   for (i = 0; i < nc; i++) {
34330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      sx = sx2 = 0;
34430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      for (k = 0; k < n; k++) {
34530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         GLint t = input[k][i];
34630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         sx += t;
347819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o         sx2 += t * t;
34830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      }
3491f0b6c1f895d189fea6999d0c07a7fee936a4baaTheodore Ts'o      var = sx2 * teenth - sx * sx * teenth * teenth;
35030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      if (maxvar < var) {
35130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         maxvar = var;
35230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         best = i;
35330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      }
35430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      if (variance) {
35530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o         variance[i] = var;
35630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o      }
357819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   }
358819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o
359819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   return best;
360819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o}
361819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o
362efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
363819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'ostatic GLint
364819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'ofxt1_choose (GLfloat vec[][MAX_COMP], GLint nv,
36520754488a228fed766126a2788bce523154a48f0Theodore Ts'o             GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
36620754488a228fed766126a2788bce523154a48f0Theodore Ts'o{
367819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#if 0
368819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   /* Choose colors from a grid.
369819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o    */
370819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint i, j;
37179a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o
37279a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   for (j = 0; j < nv; j++) {
37379a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      GLint m = j * (n - 1) / (nv - 1);
374819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o      for (i = 0; i < nc; i++) {
37579a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o         vec[j][i] = input[m][i];
37679a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      }
377819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   }
378819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o#else
379819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   /* Our solution here is to find the darkest and brightest colors in
380819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o    * the 8x4 tile and use those as the two representative colors.
381819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o    * There are probably better algorithms to use (histogram-based).
382819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o    */
383819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint i, j, k;
384819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint minSum = 2000; /* big enough */
385819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint maxSum = -1; /* small enough */
386819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint minCol = 0; /* phoudoin: silent compiler! */
387819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   GLint maxCol = 0; /* phoudoin: silent compiler! */
388819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o
389819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o   struct {
390819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o      GLint flag;
391819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o      GLint key;
39279a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      GLint freq;
393819157db798cd514aa2f3ae421d64e2e0c9b7fa8Theodore Ts'o      GLint idx;
39479a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   } hist[N_TEXELS];
39530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o   GLint lenh = 0;
396e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
397e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   memset(hist, 0, sizeof(hist));
398e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
399e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   for (k = 0; k < n; k++) {
400e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      GLint l;
401e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      GLint key = 0;
402e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      GLint sum = 0;
403e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (i = 0; i < nc; i++) {
404e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         key <<= 8;
405e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         key |= input[k][i];
406e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         sum += input[k][i];
407e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
408e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (l = 0; l < n; l++) {
409e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         if (!hist[l].flag) {
410e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            /* alloc new slot */
411e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            hist[l].flag = !0;
412e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            hist[l].key = key;
413e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            hist[l].freq = 1;
414e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            hist[l].idx = k;
415e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            lenh = l + 1;
416e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            break;
417e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         } else if (hist[l].key == key) {
418e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            hist[l].freq++;
419e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            break;
420e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         }
421e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
422e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      if (minSum > sum) {
423e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         minSum = sum;
424e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         minCol = k;
425e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
426e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      if (maxSum < sum) {
427e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         maxSum = sum;
428e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         maxCol = k;
429e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
430e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   }
431e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
432e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   if (lenh <= nv) {
433e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (j = 0; j < lenh; j++) {
434e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         for (i = 0; i < nc; i++) {
435e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            vec[j][i] = (GLfloat)input[hist[j].idx][i];
436e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         }
437e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
438e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (; j < nv; j++) {
439e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         for (i = 0; i < nc; i++) {
440e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            vec[j][i] = vec[0][i];
441e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         }
442e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
44379a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      return 0;
44479a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   }
445efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
44679a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   for (j = 0; j < nv; j++) {
447e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (i = 0; i < nc; i++) {
44879a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o         vec[j][i] = ((nv - 1 - j) * input[minCol][i] + j * input[maxCol][i] + (nv - 1) / 2) / (GLfloat)(nv - 1);
449e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
45079a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   }
451e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
452e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
45379a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   return !0;
454efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o}
455e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
456e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
457e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic GLint
458e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallfxt1_lloyd (GLfloat vec[][MAX_COMP], GLint nv,
459e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
460e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
461e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   /* Use the generalized lloyd's algorithm for VQ:
462e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     find 4 color vectors.
463e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *
464e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     for each sample color
465e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *         sort to nearest vector.
466e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *
467e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     replace each vector with the centroid of its matching colors.
468e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *
469e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     repeat until RMS doesn't improve.
470e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *
471e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     if a color vector has no samples, or becomes the same as another
472e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *     vector, replace it with the color which is farthest from a sample.
473e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    *
474e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    * vec[][MAX_COMP]           initial vectors and resulting colors
475e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    * nv                        number of resulting colors required
476e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    * input[N_TEXELS][MAX_COMP] input texels
477e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall    * nc                        number of components in input / vec
478a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o    * n                         number of input samples
479a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o    */
480a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o
481a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   GLint sum[MAX_VECT][MAX_COMP]; /* used to accumulate closest texels */
482a435ec3449694a8fa299337197cc09624960a3a6Theodore Ts'o   GLint cnt[MAX_VECT]; /* how many times a certain vector was chosen */
48379a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o   GLfloat error, lasterror = 1e9;
484e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
485e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   GLint i, j, k, rep;
486e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
48727a0e958e619c3ca105e575670416a964fa2678fTheodore Ts'o   /* the quantizer */
488e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall   for (rep = 0; rep < LL_N_REP; rep++) {
489e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      /* reset sums & counters */
490e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      for (j = 0; j < nv; j++) {
491e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         for (i = 0; i < nc; i++) {
492e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall            sum[j][i] = 0;
493e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         }
494e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall         cnt[j] = 0;
495e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      }
496e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall      error = 0;
497e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
49879a90bdad033e101c38bb3c3207c8f4be47a2de7Theodore Ts'o      /* scan whole block */
499      for (k = 0; k < n; k++) {
500#if 1
501         GLint best = -1;
502         GLfloat err = 1e9; /* big enough */
503         /* determine best vector */
504         for (j = 0; j < nv; j++) {
505            GLfloat e = (vec[j][0] - input[k][0]) * (vec[j][0] - input[k][0]) +
506                      (vec[j][1] - input[k][1]) * (vec[j][1] - input[k][1]) +
507                      (vec[j][2] - input[k][2]) * (vec[j][2] - input[k][2]);
508            if (nc == 4) {
509               e += (vec[j][3] - input[k][3]) * (vec[j][3] - input[k][3]);
510            }
511            if (e < err) {
512               err = e;
513               best = j;
514            }
515         }
516#else
517         GLint best = fxt1_bestcol(vec, nv, input[k], nc, &err);
518#endif
519         assert(best >= 0);
520         /* add in closest color */
521         for (i = 0; i < nc; i++) {
522            sum[best][i] += input[k][i];
523         }
524         /* mark this vector as used */
525         cnt[best]++;
526         /* accumulate error */
527         error += err;
528      }
529
530      /* check RMS */
531      if ((error < LL_RMS_E) ||
532          ((error < lasterror) && ((lasterror - error) < LL_RMS_D))) {
533         return !0; /* good match */
534      }
535      lasterror = error;
536
537      /* move each vector to the barycenter of its closest colors */
538      for (j = 0; j < nv; j++) {
539         if (cnt[j]) {
540            GLfloat div = 1.0F / cnt[j];
541            for (i = 0; i < nc; i++) {
542               vec[j][i] = div * sum[j][i];
543            }
544         } else {
545            /* this vec has no samples or is identical with a previous vec */
546            GLint worst = fxt1_worst(vec[j], input, nc, n);
547            for (i = 0; i < nc; i++) {
548               vec[j][i] = input[worst][i];
549            }
550         }
551      }
552   }
553
554   return 0; /* could not converge fast enough */
555}
556
557
558static void
559fxt1_quantize_CHROMA (GLuint *cc,
560                      GLubyte input[N_TEXELS][MAX_COMP])
561{
562   const GLint n_vect = 4; /* 4 base vectors to find */
563   const GLint n_comp = 3; /* 3 components: R, G, B */
564   GLfloat vec[MAX_VECT][MAX_COMP];
565   GLint i, j, k;
566   Fx64 hi; /* high quadword */
567   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
568
569   if (fxt1_choose(vec, n_vect, input, n_comp, N_TEXELS) != 0) {
570      fxt1_lloyd(vec, n_vect, input, n_comp, N_TEXELS);
571   }
572
573   FX64_MOV32(hi, 4); /* cc-chroma = "010" + unused bit */
574   for (j = n_vect - 1; j >= 0; j--) {
575      for (i = 0; i < n_comp; i++) {
576         /* add in colors */
577         FX64_SHL(hi, 5);
578         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
579      }
580   }
581   ((Fx64 *)cc)[1] = hi;
582
583   lohi = lolo = 0;
584   /* right microtile */
585   for (k = N_TEXELS - 1; k >= N_TEXELS/2; k--) {
586      lohi <<= 2;
587      lohi |= fxt1_bestcol(vec, n_vect, input[k], n_comp);
588   }
589   /* left microtile */
590   for (; k >= 0; k--) {
591      lolo <<= 2;
592      lolo |= fxt1_bestcol(vec, n_vect, input[k], n_comp);
593   }
594   cc[1] = lohi;
595   cc[0] = lolo;
596}
597
598
599static void
600fxt1_quantize_ALPHA0 (GLuint *cc,
601                      GLubyte input[N_TEXELS][MAX_COMP],
602                      GLubyte reord[N_TEXELS][MAX_COMP], GLint n)
603{
604   const GLint n_vect = 3; /* 3 base vectors to find */
605   const GLint n_comp = 4; /* 4 components: R, G, B, A */
606   GLfloat vec[MAX_VECT][MAX_COMP];
607   GLint i, j, k;
608   Fx64 hi; /* high quadword */
609   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
610
611   /* the last vector indicates zero */
612   for (i = 0; i < n_comp; i++) {
613      vec[n_vect][i] = 0;
614   }
615
616   /* the first n texels in reord are guaranteed to be non-zero */
617   if (fxt1_choose(vec, n_vect, reord, n_comp, n) != 0) {
618      fxt1_lloyd(vec, n_vect, reord, n_comp, n);
619   }
620
621   FX64_MOV32(hi, 6); /* alpha = "011" + lerp = 0 */
622   for (j = n_vect - 1; j >= 0; j--) {
623      /* add in alphas */
624      FX64_SHL(hi, 5);
625      FX64_OR32(hi, (GLuint)(vec[j][ACOMP] / 8.0F));
626   }
627   for (j = n_vect - 1; j >= 0; j--) {
628      for (i = 0; i < n_comp - 1; i++) {
629         /* add in colors */
630         FX64_SHL(hi, 5);
631         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
632      }
633   }
634   ((Fx64 *)cc)[1] = hi;
635
636   lohi = lolo = 0;
637   /* right microtile */
638   for (k = N_TEXELS - 1; k >= N_TEXELS/2; k--) {
639      lohi <<= 2;
640      lohi |= fxt1_bestcol(vec, n_vect + 1, input[k], n_comp);
641   }
642   /* left microtile */
643   for (; k >= 0; k--) {
644      lolo <<= 2;
645      lolo |= fxt1_bestcol(vec, n_vect + 1, input[k], n_comp);
646   }
647   cc[1] = lohi;
648   cc[0] = lolo;
649}
650
651
652static void
653fxt1_quantize_ALPHA1 (GLuint *cc,
654                      GLubyte input[N_TEXELS][MAX_COMP])
655{
656   const GLint n_vect = 3; /* highest vector number in each microtile */
657   const GLint n_comp = 4; /* 4 components: R, G, B, A */
658   GLfloat vec[1 + 1 + 1][MAX_COMP]; /* 1.5 extrema for each sub-block */
659   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
660   GLint i, j, k;
661   Fx64 hi; /* high quadword */
662   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
663
664   GLint minSum;
665   GLint maxSum;
666   GLint minColL = 0, maxColL = 0;
667   GLint minColR = 0, maxColR = 0;
668   GLint sumL = 0, sumR = 0;
669   GLint nn_comp;
670   /* Our solution here is to find the darkest and brightest colors in
671    * the 4x4 tile and use those as the two representative colors.
672    * There are probably better algorithms to use (histogram-based).
673    */
674   nn_comp = n_comp;
675   while ((minColL == maxColL) && nn_comp) {
676       minSum = 2000; /* big enough */
677       maxSum = -1; /* small enough */
678       for (k = 0; k < N_TEXELS / 2; k++) {
679           GLint sum = 0;
680           for (i = 0; i < nn_comp; i++) {
681               sum += input[k][i];
682           }
683           if (minSum > sum) {
684               minSum = sum;
685               minColL = k;
686           }
687           if (maxSum < sum) {
688               maxSum = sum;
689               maxColL = k;
690           }
691           sumL += sum;
692       }
693
694       nn_comp--;
695   }
696
697   nn_comp = n_comp;
698   while ((minColR == maxColR) && nn_comp) {
699       minSum = 2000; /* big enough */
700       maxSum = -1; /* small enough */
701       for (k = N_TEXELS / 2; k < N_TEXELS; k++) {
702           GLint sum = 0;
703           for (i = 0; i < nn_comp; i++) {
704               sum += input[k][i];
705           }
706           if (minSum > sum) {
707               minSum = sum;
708               minColR = k;
709           }
710           if (maxSum < sum) {
711               maxSum = sum;
712               maxColR = k;
713           }
714           sumR += sum;
715       }
716
717       nn_comp--;
718   }
719
720   /* choose the common vector (yuck!) */
721   {
722      GLint j1, j2;
723      GLint v1 = 0, v2 = 0;
724      GLfloat err = 1e9; /* big enough */
725      GLfloat tv[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
726      for (i = 0; i < n_comp; i++) {
727         tv[0][i] = input[minColL][i];
728         tv[1][i] = input[maxColL][i];
729         tv[2][i] = input[minColR][i];
730         tv[3][i] = input[maxColR][i];
731      }
732      for (j1 = 0; j1 < 2; j1++) {
733         for (j2 = 2; j2 < 4; j2++) {
734            GLfloat e = 0.0F;
735            for (i = 0; i < n_comp; i++) {
736               e += (tv[j1][i] - tv[j2][i]) * (tv[j1][i] - tv[j2][i]);
737            }
738            if (e < err) {
739               err = e;
740               v1 = j1;
741               v2 = j2;
742            }
743         }
744      }
745      for (i = 0; i < n_comp; i++) {
746         vec[0][i] = tv[1 - v1][i];
747         vec[1][i] = (tv[v1][i] * sumL + tv[v2][i] * sumR) / (sumL + sumR);
748         vec[2][i] = tv[5 - v2][i];
749      }
750   }
751
752   /* left microtile */
753   cc[0] = 0;
754   if (minColL != maxColL) {
755      /* compute interpolation vector */
756      MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
757
758      /* add in texels */
759      lolo = 0;
760      for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
761         GLint texel;
762         /* interpolate color */
763         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
764         /* add in texel */
765         lolo <<= 2;
766         lolo |= texel;
767      }
768
769      cc[0] = lolo;
770   }
771
772   /* right microtile */
773   cc[1] = 0;
774   if (minColR != maxColR) {
775      /* compute interpolation vector */
776      MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[1]);
777
778      /* add in texels */
779      lohi = 0;
780      for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
781         GLint texel;
782         /* interpolate color */
783         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
784         /* add in texel */
785         lohi <<= 2;
786         lohi |= texel;
787      }
788
789      cc[1] = lohi;
790   }
791
792   FX64_MOV32(hi, 7); /* alpha = "011" + lerp = 1 */
793   for (j = n_vect - 1; j >= 0; j--) {
794      /* add in alphas */
795      FX64_SHL(hi, 5);
796      FX64_OR32(hi, (GLuint)(vec[j][ACOMP] / 8.0F));
797   }
798   for (j = n_vect - 1; j >= 0; j--) {
799      for (i = 0; i < n_comp - 1; i++) {
800         /* add in colors */
801         FX64_SHL(hi, 5);
802         FX64_OR32(hi, (GLuint)(vec[j][i] / 8.0F));
803      }
804   }
805   ((Fx64 *)cc)[1] = hi;
806}
807
808
809static void
810fxt1_quantize_HI (GLuint *cc,
811                  GLubyte input[N_TEXELS][MAX_COMP],
812                  GLubyte reord[N_TEXELS][MAX_COMP], GLint n)
813{
814   const GLint n_vect = 6; /* highest vector number */
815   const GLint n_comp = 3; /* 3 components: R, G, B */
816   GLfloat b = 0.0F;       /* phoudoin: silent compiler! */
817   GLfloat iv[MAX_COMP];   /* interpolation vector */
818   GLint i, k;
819   GLuint hihi; /* high quadword: hi dword */
820
821   GLint minSum = 2000; /* big enough */
822   GLint maxSum = -1; /* small enough */
823   GLint minCol = 0; /* phoudoin: silent compiler! */
824   GLint maxCol = 0; /* phoudoin: silent compiler! */
825
826   /* Our solution here is to find the darkest and brightest colors in
827    * the 8x4 tile and use those as the two representative colors.
828    * There are probably better algorithms to use (histogram-based).
829    */
830   for (k = 0; k < n; k++) {
831      GLint sum = 0;
832      for (i = 0; i < n_comp; i++) {
833         sum += reord[k][i];
834      }
835      if (minSum > sum) {
836         minSum = sum;
837         minCol = k;
838      }
839      if (maxSum < sum) {
840         maxSum = sum;
841         maxCol = k;
842      }
843   }
844
845   hihi = 0; /* cc-hi = "00" */
846   for (i = 0; i < n_comp; i++) {
847      /* add in colors */
848      hihi <<= 5;
849      hihi |= reord[maxCol][i] >> 3;
850   }
851   for (i = 0; i < n_comp; i++) {
852      /* add in colors */
853      hihi <<= 5;
854      hihi |= reord[minCol][i] >> 3;
855   }
856   cc[3] = hihi;
857   cc[0] = cc[1] = cc[2] = 0;
858
859   /* compute interpolation vector */
860   if (minCol != maxCol) {
861      MAKEIVEC(n_vect, n_comp, iv, b, reord[minCol], reord[maxCol]);
862   }
863
864   /* add in texels */
865   for (k = N_TEXELS - 1; k >= 0; k--) {
866      GLint t = k * 3;
867      GLuint *kk = (GLuint *)((char *)cc + t / 8);
868      GLint texel = n_vect + 1; /* transparent black */
869
870      if (!ISTBLACK(input[k])) {
871         if (minCol != maxCol) {
872            /* interpolate color */
873            CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
874            /* add in texel */
875            kk[0] |= texel << (t & 7);
876         }
877      } else {
878         /* add in texel */
879         kk[0] |= texel << (t & 7);
880      }
881   }
882}
883
884
885static void
886fxt1_quantize_MIXED1 (GLuint *cc,
887                      GLubyte input[N_TEXELS][MAX_COMP])
888{
889   const GLint n_vect = 2; /* highest vector number in each microtile */
890   const GLint n_comp = 3; /* 3 components: R, G, B */
891   GLubyte vec[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
892   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
893   GLint i, j, k;
894   Fx64 hi; /* high quadword */
895   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
896
897   GLint minSum;
898   GLint maxSum;
899   GLint minColL = 0, maxColL = -1;
900   GLint minColR = 0, maxColR = -1;
901
902   /* Our solution here is to find the darkest and brightest colors in
903    * the 4x4 tile and use those as the two representative colors.
904    * There are probably better algorithms to use (histogram-based).
905    */
906   minSum = 2000; /* big enough */
907   maxSum = -1; /* small enough */
908   for (k = 0; k < N_TEXELS / 2; k++) {
909      if (!ISTBLACK(input[k])) {
910         GLint sum = 0;
911         for (i = 0; i < n_comp; i++) {
912            sum += input[k][i];
913         }
914         if (minSum > sum) {
915            minSum = sum;
916            minColL = k;
917         }
918         if (maxSum < sum) {
919            maxSum = sum;
920            maxColL = k;
921         }
922      }
923   }
924   minSum = 2000; /* big enough */
925   maxSum = -1; /* small enough */
926   for (; k < N_TEXELS; k++) {
927      if (!ISTBLACK(input[k])) {
928         GLint sum = 0;
929         for (i = 0; i < n_comp; i++) {
930            sum += input[k][i];
931         }
932         if (minSum > sum) {
933            minSum = sum;
934            minColR = k;
935         }
936         if (maxSum < sum) {
937            maxSum = sum;
938            maxColR = k;
939         }
940      }
941   }
942
943   /* left microtile */
944   if (maxColL == -1) {
945      /* all transparent black */
946      cc[0] = ~0u;
947      for (i = 0; i < n_comp; i++) {
948         vec[0][i] = 0;
949         vec[1][i] = 0;
950      }
951   } else {
952      cc[0] = 0;
953      for (i = 0; i < n_comp; i++) {
954         vec[0][i] = input[minColL][i];
955         vec[1][i] = input[maxColL][i];
956      }
957      if (minColL != maxColL) {
958         /* compute interpolation vector */
959         MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
960
961         /* add in texels */
962         lolo = 0;
963         for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
964            GLint texel = n_vect + 1; /* transparent black */
965            if (!ISTBLACK(input[k])) {
966               /* interpolate color */
967               CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
968            }
969            /* add in texel */
970            lolo <<= 2;
971            lolo |= texel;
972         }
973         cc[0] = lolo;
974      }
975   }
976
977   /* right microtile */
978   if (maxColR == -1) {
979      /* all transparent black */
980      cc[1] = ~0u;
981      for (i = 0; i < n_comp; i++) {
982         vec[2][i] = 0;
983         vec[3][i] = 0;
984      }
985   } else {
986      cc[1] = 0;
987      for (i = 0; i < n_comp; i++) {
988         vec[2][i] = input[minColR][i];
989         vec[3][i] = input[maxColR][i];
990      }
991      if (minColR != maxColR) {
992         /* compute interpolation vector */
993         MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[3]);
994
995         /* add in texels */
996         lohi = 0;
997         for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
998            GLint texel = n_vect + 1; /* transparent black */
999            if (!ISTBLACK(input[k])) {
1000               /* interpolate color */
1001               CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1002            }
1003            /* add in texel */
1004            lohi <<= 2;
1005            lohi |= texel;
1006         }
1007         cc[1] = lohi;
1008      }
1009   }
1010
1011   FX64_MOV32(hi, 9 | (vec[3][GCOMP] & 4) | ((vec[1][GCOMP] >> 1) & 2)); /* chroma = "1" */
1012   for (j = 2 * 2 - 1; j >= 0; j--) {
1013      for (i = 0; i < n_comp; i++) {
1014         /* add in colors */
1015         FX64_SHL(hi, 5);
1016         FX64_OR32(hi, vec[j][i] >> 3);
1017      }
1018   }
1019   ((Fx64 *)cc)[1] = hi;
1020}
1021
1022
1023static void
1024fxt1_quantize_MIXED0 (GLuint *cc,
1025                      GLubyte input[N_TEXELS][MAX_COMP])
1026{
1027   const GLint n_vect = 3; /* highest vector number in each microtile */
1028   const GLint n_comp = 3; /* 3 components: R, G, B */
1029   GLubyte vec[2 * 2][MAX_COMP]; /* 2 extrema for each sub-block */
1030   GLfloat b, iv[MAX_COMP]; /* interpolation vector */
1031   GLint i, j, k;
1032   Fx64 hi; /* high quadword */
1033   GLuint lohi, lolo; /* low quadword: hi dword, lo dword */
1034
1035   GLint minColL = 0, maxColL = 0;
1036   GLint minColR = 0, maxColR = 0;
1037#if 0
1038   GLint minSum;
1039   GLint maxSum;
1040
1041   /* Our solution here is to find the darkest and brightest colors in
1042    * the 4x4 tile and use those as the two representative colors.
1043    * There are probably better algorithms to use (histogram-based).
1044    */
1045   minSum = 2000; /* big enough */
1046   maxSum = -1; /* small enough */
1047   for (k = 0; k < N_TEXELS / 2; k++) {
1048      GLint sum = 0;
1049      for (i = 0; i < n_comp; i++) {
1050         sum += input[k][i];
1051      }
1052      if (minSum > sum) {
1053         minSum = sum;
1054         minColL = k;
1055      }
1056      if (maxSum < sum) {
1057         maxSum = sum;
1058         maxColL = k;
1059      }
1060   }
1061   minSum = 2000; /* big enough */
1062   maxSum = -1; /* small enough */
1063   for (; k < N_TEXELS; k++) {
1064      GLint sum = 0;
1065      for (i = 0; i < n_comp; i++) {
1066         sum += input[k][i];
1067      }
1068      if (minSum > sum) {
1069         minSum = sum;
1070         minColR = k;
1071      }
1072      if (maxSum < sum) {
1073         maxSum = sum;
1074         maxColR = k;
1075      }
1076   }
1077#else
1078   GLint minVal;
1079   GLint maxVal;
1080   GLint maxVarL = fxt1_variance(NULL, input, n_comp, N_TEXELS / 2);
1081   GLint maxVarR = fxt1_variance(NULL, &input[N_TEXELS / 2], n_comp, N_TEXELS / 2);
1082
1083   /* Scan the channel with max variance for lo & hi
1084    * and use those as the two representative colors.
1085    */
1086   minVal = 2000; /* big enough */
1087   maxVal = -1; /* small enough */
1088   for (k = 0; k < N_TEXELS / 2; k++) {
1089      GLint t = input[k][maxVarL];
1090      if (minVal > t) {
1091         minVal = t;
1092         minColL = k;
1093      }
1094      if (maxVal < t) {
1095         maxVal = t;
1096         maxColL = k;
1097      }
1098   }
1099   minVal = 2000; /* big enough */
1100   maxVal = -1; /* small enough */
1101   for (; k < N_TEXELS; k++) {
1102      GLint t = input[k][maxVarR];
1103      if (minVal > t) {
1104         minVal = t;
1105         minColR = k;
1106      }
1107      if (maxVal < t) {
1108         maxVal = t;
1109         maxColR = k;
1110      }
1111   }
1112#endif
1113
1114   /* left microtile */
1115   cc[0] = 0;
1116   for (i = 0; i < n_comp; i++) {
1117      vec[0][i] = input[minColL][i];
1118      vec[1][i] = input[maxColL][i];
1119   }
1120   if (minColL != maxColL) {
1121      /* compute interpolation vector */
1122      MAKEIVEC(n_vect, n_comp, iv, b, vec[0], vec[1]);
1123
1124      /* add in texels */
1125      lolo = 0;
1126      for (k = N_TEXELS / 2 - 1; k >= 0; k--) {
1127         GLint texel;
1128         /* interpolate color */
1129         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1130         /* add in texel */
1131         lolo <<= 2;
1132         lolo |= texel;
1133      }
1134
1135      /* funky encoding for LSB of green */
1136      if ((GLint)((lolo >> 1) & 1) != (((vec[1][GCOMP] ^ vec[0][GCOMP]) >> 2) & 1)) {
1137         for (i = 0; i < n_comp; i++) {
1138            vec[1][i] = input[minColL][i];
1139            vec[0][i] = input[maxColL][i];
1140         }
1141         lolo = ~lolo;
1142      }
1143
1144      cc[0] = lolo;
1145   }
1146
1147   /* right microtile */
1148   cc[1] = 0;
1149   for (i = 0; i < n_comp; i++) {
1150      vec[2][i] = input[minColR][i];
1151      vec[3][i] = input[maxColR][i];
1152   }
1153   if (minColR != maxColR) {
1154      /* compute interpolation vector */
1155      MAKEIVEC(n_vect, n_comp, iv, b, vec[2], vec[3]);
1156
1157      /* add in texels */
1158      lohi = 0;
1159      for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) {
1160         GLint texel;
1161         /* interpolate color */
1162         CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]);
1163         /* add in texel */
1164         lohi <<= 2;
1165         lohi |= texel;
1166      }
1167
1168      /* funky encoding for LSB of green */
1169      if ((GLint)((lohi >> 1) & 1) != (((vec[3][GCOMP] ^ vec[2][GCOMP]) >> 2) & 1)) {
1170         for (i = 0; i < n_comp; i++) {
1171            vec[3][i] = input[minColR][i];
1172            vec[2][i] = input[maxColR][i];
1173         }
1174         lohi = ~lohi;
1175      }
1176
1177      cc[1] = lohi;
1178   }
1179
1180   FX64_MOV32(hi, 8 | (vec[3][GCOMP] & 4) | ((vec[1][GCOMP] >> 1) & 2)); /* chroma = "1" */
1181   for (j = 2 * 2 - 1; j >= 0; j--) {
1182      for (i = 0; i < n_comp; i++) {
1183         /* add in colors */
1184         FX64_SHL(hi, 5);
1185         FX64_OR32(hi, vec[j][i] >> 3);
1186      }
1187   }
1188   ((Fx64 *)cc)[1] = hi;
1189}
1190
1191
1192static void
1193fxt1_quantize (GLuint *cc, const GLubyte *lines[], GLint comps)
1194{
1195   GLint trualpha;
1196   GLubyte reord[N_TEXELS][MAX_COMP];
1197
1198   GLubyte input[N_TEXELS][MAX_COMP];
1199   GLint i, k, l;
1200
1201   if (comps == 3) {
1202      /* make the whole block opaque */
1203      memset(input, -1, sizeof(input));
1204   }
1205
1206   /* 8 texels each line */
1207   for (l = 0; l < 4; l++) {
1208      for (k = 0; k < 4; k++) {
1209         for (i = 0; i < comps; i++) {
1210            input[k + l * 4][i] = *lines[l]++;
1211         }
1212      }
1213      for (; k < 8; k++) {
1214         for (i = 0; i < comps; i++) {
1215            input[k + l * 4 + 12][i] = *lines[l]++;
1216         }
1217      }
1218   }
1219
1220   /* block layout:
1221    * 00, 01, 02, 03, 08, 09, 0a, 0b
1222    * 10, 11, 12, 13, 18, 19, 1a, 1b
1223    * 04, 05, 06, 07, 0c, 0d, 0e, 0f
1224    * 14, 15, 16, 17, 1c, 1d, 1e, 1f
1225    */
1226
1227   /* [dBorca]
1228    * stupidity flows forth from this
1229    */
1230   l = N_TEXELS;
1231   trualpha = 0;
1232   if (comps == 4) {
1233      /* skip all transparent black texels */
1234      l = 0;
1235      for (k = 0; k < N_TEXELS; k++) {
1236         /* test all components against 0 */
1237         if (!ISTBLACK(input[k])) {
1238            /* texel is not transparent black */
1239            COPY_4UBV(reord[l], input[k]);
1240            if (reord[l][ACOMP] < (255 - ALPHA_TS)) {
1241               /* non-opaque texel */
1242               trualpha = !0;
1243            }
1244            l++;
1245         }
1246      }
1247   }
1248
1249#if 0
1250   if (trualpha) {
1251      fxt1_quantize_ALPHA0(cc, input, reord, l);
1252   } else if (l == 0) {
1253      cc[0] = cc[1] = cc[2] = -1;
1254      cc[3] = 0;
1255   } else if (l < N_TEXELS) {
1256      fxt1_quantize_HI(cc, input, reord, l);
1257   } else {
1258      fxt1_quantize_CHROMA(cc, input);
1259   }
1260   (void)fxt1_quantize_ALPHA1;
1261   (void)fxt1_quantize_MIXED1;
1262   (void)fxt1_quantize_MIXED0;
1263#else
1264   if (trualpha) {
1265      fxt1_quantize_ALPHA1(cc, input);
1266   } else if (l == 0) {
1267      cc[0] = cc[1] = cc[2] = ~0u;
1268      cc[3] = 0;
1269   } else if (l < N_TEXELS) {
1270      fxt1_quantize_MIXED1(cc, input);
1271   } else {
1272      fxt1_quantize_MIXED0(cc, input);
1273   }
1274   (void)fxt1_quantize_ALPHA0;
1275   (void)fxt1_quantize_HI;
1276   (void)fxt1_quantize_CHROMA;
1277#endif
1278}
1279
1280
1281
1282/**
1283 * Upscale an image by replication, not (typical) stretching.
1284 * We use this when the image width or height is less than a
1285 * certain size (4, 8) and we need to upscale an image.
1286 */
1287static void
1288upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
1289                   GLsizei outWidth, GLsizei outHeight,
1290                   GLint comps, const GLubyte *src, GLint srcRowStride,
1291                   GLubyte *dest )
1292{
1293   GLint i, j, k;
1294
1295   ASSERT(outWidth >= inWidth);
1296   ASSERT(outHeight >= inHeight);
1297#if 0
1298   ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
1299   ASSERT((outWidth & 3) == 0);
1300   ASSERT((outHeight & 3) == 0);
1301#endif
1302
1303   for (i = 0; i < outHeight; i++) {
1304      const GLint ii = i % inHeight;
1305      for (j = 0; j < outWidth; j++) {
1306         const GLint jj = j % inWidth;
1307         for (k = 0; k < comps; k++) {
1308            dest[(i * outWidth + j) * comps + k]
1309               = src[ii * srcRowStride + jj * comps + k];
1310         }
1311      }
1312   }
1313}
1314
1315
1316static void
1317fxt1_encode (GLuint width, GLuint height, GLint comps,
1318             const void *source, GLint srcRowStride,
1319             void *dest, GLint destRowStride)
1320{
1321   GLuint x, y;
1322   const GLubyte *data;
1323   GLuint *encoded = (GLuint *)dest;
1324   void *newSource = NULL;
1325
1326   assert(comps == 3 || comps == 4);
1327
1328   /* Replicate image if width is not M8 or height is not M4 */
1329   if ((width & 7) | (height & 3)) {
1330      GLint newWidth = (width + 7) & ~7;
1331      GLint newHeight = (height + 3) & ~3;
1332      newSource = malloc(comps * newWidth * newHeight * sizeof(GLubyte));
1333      if (!newSource) {
1334         GET_CURRENT_CONTEXT(ctx);
1335         _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture compression");
1336         goto cleanUp;
1337      }
1338      upscale_teximage2d(width, height, newWidth, newHeight,
1339                         comps, (const GLubyte *) source,
1340                         srcRowStride, (GLubyte *) newSource);
1341      source = newSource;
1342      width = newWidth;
1343      height = newHeight;
1344      srcRowStride = comps * newWidth;
1345   }
1346
1347   data = (const GLubyte *) source;
1348   destRowStride = (destRowStride - width * 2) / 4;
1349   for (y = 0; y < height; y += 4) {
1350      GLuint offs = 0 + (y + 0) * srcRowStride;
1351      for (x = 0; x < width; x += 8) {
1352         const GLubyte *lines[4];
1353         lines[0] = &data[offs];
1354         lines[1] = lines[0] + srcRowStride;
1355         lines[2] = lines[1] + srcRowStride;
1356         lines[3] = lines[2] + srcRowStride;
1357         offs += 8 * comps;
1358         fxt1_quantize(encoded, lines, comps);
1359         /* 128 bits per 8x4 block */
1360         encoded += 4;
1361      }
1362      encoded += destRowStride;
1363   }
1364
1365 cleanUp:
1366   if (newSource != NULL) {
1367      free(newSource);
1368   }
1369}
1370
1371
1372/***************************************************************************\
1373 * FXT1 decoder
1374 *
1375 * The decoder is based on GL_3DFX_texture_compression_FXT1
1376 * specification and serves as a concept for the encoder.
1377\***************************************************************************/
1378
1379
1380/* lookup table for scaling 5 bit colors up to 8 bits */
1381static const GLubyte _rgb_scale_5[] = {
1382   0,   8,   16,  25,  33,  41,  49,  58,
1383   66,  74,  82,  90,  99,  107, 115, 123,
1384   132, 140, 148, 156, 165, 173, 181, 189,
1385   197, 206, 214, 222, 230, 239, 247, 255
1386};
1387
1388/* lookup table for scaling 6 bit colors up to 8 bits */
1389static const GLubyte _rgb_scale_6[] = {
1390   0,   4,   8,   12,  16,  20,  24,  28,
1391   32,  36,  40,  45,  49,  53,  57,  61,
1392   65,  69,  73,  77,  81,  85,  89,  93,
1393   97,  101, 105, 109, 113, 117, 121, 125,
1394   130, 134, 138, 142, 146, 150, 154, 158,
1395   162, 166, 170, 174, 178, 182, 186, 190,
1396   194, 198, 202, 206, 210, 215, 219, 223,
1397   227, 231, 235, 239, 243, 247, 251, 255
1398};
1399
1400
1401#define CC_SEL(cc, which) (((GLuint *)(cc))[(which) / 32] >> ((which) & 31))
1402#define UP5(c) _rgb_scale_5[(c) & 31]
1403#define UP6(c, b) _rgb_scale_6[(((c) & 31) << 1) | ((b) & 1)]
1404#define LERP(n, t, c0, c1) (((n) - (t)) * (c0) + (t) * (c1) + (n) / 2) / (n)
1405
1406
1407static void
1408fxt1_decode_1HI (const GLubyte *code, GLint t, GLubyte *rgba)
1409{
1410   const GLuint *cc;
1411
1412   t *= 3;
1413   cc = (const GLuint *)(code + t / 8);
1414   t = (cc[0] >> (t & 7)) & 7;
1415
1416   if (t == 7) {
1417      rgba[RCOMP] = rgba[GCOMP] = rgba[BCOMP] = rgba[ACOMP] = 0;
1418   } else {
1419      GLubyte r, g, b;
1420      cc = (const GLuint *)(code + 12);
1421      if (t == 0) {
1422         b = UP5(CC_SEL(cc, 0));
1423         g = UP5(CC_SEL(cc, 5));
1424         r = UP5(CC_SEL(cc, 10));
1425      } else if (t == 6) {
1426         b = UP5(CC_SEL(cc, 15));
1427         g = UP5(CC_SEL(cc, 20));
1428         r = UP5(CC_SEL(cc, 25));
1429      } else {
1430         b = LERP(6, t, UP5(CC_SEL(cc, 0)), UP5(CC_SEL(cc, 15)));
1431         g = LERP(6, t, UP5(CC_SEL(cc, 5)), UP5(CC_SEL(cc, 20)));
1432         r = LERP(6, t, UP5(CC_SEL(cc, 10)), UP5(CC_SEL(cc, 25)));
1433      }
1434      rgba[RCOMP] = r;
1435      rgba[GCOMP] = g;
1436      rgba[BCOMP] = b;
1437      rgba[ACOMP] = 255;
1438   }
1439}
1440
1441
1442static void
1443fxt1_decode_1CHROMA (const GLubyte *code, GLint t, GLubyte *rgba)
1444{
1445   const GLuint *cc;
1446   GLuint kk;
1447
1448   cc = (const GLuint *)code;
1449   if (t & 16) {
1450      cc++;
1451      t &= 15;
1452   }
1453   t = (cc[0] >> (t * 2)) & 3;
1454
1455   t *= 15;
1456   cc = (const GLuint *)(code + 8 + t / 8);
1457   kk = cc[0] >> (t & 7);
1458   rgba[BCOMP] = UP5(kk);
1459   rgba[GCOMP] = UP5(kk >> 5);
1460   rgba[RCOMP] = UP5(kk >> 10);
1461   rgba[ACOMP] = 255;
1462}
1463
1464
1465static void
1466fxt1_decode_1MIXED (const GLubyte *code, GLint t, GLubyte *rgba)
1467{
1468   const GLuint *cc;
1469   GLuint col[2][3];
1470   GLint glsb, selb;
1471
1472   cc = (const GLuint *)code;
1473   if (t & 16) {
1474      t &= 15;
1475      t = (cc[1] >> (t * 2)) & 3;
1476      /* col 2 */
1477      col[0][BCOMP] = (*(const GLuint *)(code + 11)) >> 6;
1478      col[0][GCOMP] = CC_SEL(cc, 99);
1479      col[0][RCOMP] = CC_SEL(cc, 104);
1480      /* col 3 */
1481      col[1][BCOMP] = CC_SEL(cc, 109);
1482      col[1][GCOMP] = CC_SEL(cc, 114);
1483      col[1][RCOMP] = CC_SEL(cc, 119);
1484      glsb = CC_SEL(cc, 126);
1485      selb = CC_SEL(cc, 33);
1486   } else {
1487      t = (cc[0] >> (t * 2)) & 3;
1488      /* col 0 */
1489      col[0][BCOMP] = CC_SEL(cc, 64);
1490      col[0][GCOMP] = CC_SEL(cc, 69);
1491      col[0][RCOMP] = CC_SEL(cc, 74);
1492      /* col 1 */
1493      col[1][BCOMP] = CC_SEL(cc, 79);
1494      col[1][GCOMP] = CC_SEL(cc, 84);
1495      col[1][RCOMP] = CC_SEL(cc, 89);
1496      glsb = CC_SEL(cc, 125);
1497      selb = CC_SEL(cc, 1);
1498   }
1499
1500   if (CC_SEL(cc, 124) & 1) {
1501      /* alpha[0] == 1 */
1502
1503      if (t == 3) {
1504         /* zero */
1505         rgba[RCOMP] = rgba[BCOMP] = rgba[GCOMP] = rgba[ACOMP] = 0;
1506      } else {
1507         GLubyte r, g, b;
1508         if (t == 0) {
1509            b = UP5(col[0][BCOMP]);
1510            g = UP5(col[0][GCOMP]);
1511            r = UP5(col[0][RCOMP]);
1512         } else if (t == 2) {
1513            b = UP5(col[1][BCOMP]);
1514            g = UP6(col[1][GCOMP], glsb);
1515            r = UP5(col[1][RCOMP]);
1516         } else {
1517            b = (UP5(col[0][BCOMP]) + UP5(col[1][BCOMP])) / 2;
1518            g = (UP5(col[0][GCOMP]) + UP6(col[1][GCOMP], glsb)) / 2;
1519            r = (UP5(col[0][RCOMP]) + UP5(col[1][RCOMP])) / 2;
1520         }
1521         rgba[RCOMP] = r;
1522         rgba[GCOMP] = g;
1523         rgba[BCOMP] = b;
1524         rgba[ACOMP] = 255;
1525      }
1526   } else {
1527      /* alpha[0] == 0 */
1528      GLubyte r, g, b;
1529      if (t == 0) {
1530         b = UP5(col[0][BCOMP]);
1531         g = UP6(col[0][GCOMP], glsb ^ selb);
1532         r = UP5(col[0][RCOMP]);
1533      } else if (t == 3) {
1534         b = UP5(col[1][BCOMP]);
1535         g = UP6(col[1][GCOMP], glsb);
1536         r = UP5(col[1][RCOMP]);
1537      } else {
1538         b = LERP(3, t, UP5(col[0][BCOMP]), UP5(col[1][BCOMP]));
1539         g = LERP(3, t, UP6(col[0][GCOMP], glsb ^ selb),
1540                        UP6(col[1][GCOMP], glsb));
1541         r = LERP(3, t, UP5(col[0][RCOMP]), UP5(col[1][RCOMP]));
1542      }
1543      rgba[RCOMP] = r;
1544      rgba[GCOMP] = g;
1545      rgba[BCOMP] = b;
1546      rgba[ACOMP] = 255;
1547   }
1548}
1549
1550
1551static void
1552fxt1_decode_1ALPHA (const GLubyte *code, GLint t, GLubyte *rgba)
1553{
1554   const GLuint *cc;
1555   GLubyte r, g, b, a;
1556
1557   cc = (const GLuint *)code;
1558   if (CC_SEL(cc, 124) & 1) {
1559      /* lerp == 1 */
1560      GLuint col0[4];
1561
1562      if (t & 16) {
1563         t &= 15;
1564         t = (cc[1] >> (t * 2)) & 3;
1565         /* col 2 */
1566         col0[BCOMP] = (*(const GLuint *)(code + 11)) >> 6;
1567         col0[GCOMP] = CC_SEL(cc, 99);
1568         col0[RCOMP] = CC_SEL(cc, 104);
1569         col0[ACOMP] = CC_SEL(cc, 119);
1570      } else {
1571         t = (cc[0] >> (t * 2)) & 3;
1572         /* col 0 */
1573         col0[BCOMP] = CC_SEL(cc, 64);
1574         col0[GCOMP] = CC_SEL(cc, 69);
1575         col0[RCOMP] = CC_SEL(cc, 74);
1576         col0[ACOMP] = CC_SEL(cc, 109);
1577      }
1578
1579      if (t == 0) {
1580         b = UP5(col0[BCOMP]);
1581         g = UP5(col0[GCOMP]);
1582         r = UP5(col0[RCOMP]);
1583         a = UP5(col0[ACOMP]);
1584      } else if (t == 3) {
1585         b = UP5(CC_SEL(cc, 79));
1586         g = UP5(CC_SEL(cc, 84));
1587         r = UP5(CC_SEL(cc, 89));
1588         a = UP5(CC_SEL(cc, 114));
1589      } else {
1590         b = LERP(3, t, UP5(col0[BCOMP]), UP5(CC_SEL(cc, 79)));
1591         g = LERP(3, t, UP5(col0[GCOMP]), UP5(CC_SEL(cc, 84)));
1592         r = LERP(3, t, UP5(col0[RCOMP]), UP5(CC_SEL(cc, 89)));
1593         a = LERP(3, t, UP5(col0[ACOMP]), UP5(CC_SEL(cc, 114)));
1594      }
1595   } else {
1596      /* lerp == 0 */
1597
1598      if (t & 16) {
1599         cc++;
1600         t &= 15;
1601      }
1602      t = (cc[0] >> (t * 2)) & 3;
1603
1604      if (t == 3) {
1605         /* zero */
1606         r = g = b = a = 0;
1607      } else {
1608         GLuint kk;
1609         cc = (const GLuint *)code;
1610         a = UP5(cc[3] >> (t * 5 + 13));
1611         t *= 15;
1612         cc = (const GLuint *)(code + 8 + t / 8);
1613         kk = cc[0] >> (t & 7);
1614         b = UP5(kk);
1615         g = UP5(kk >> 5);
1616         r = UP5(kk >> 10);
1617      }
1618   }
1619   rgba[RCOMP] = r;
1620   rgba[GCOMP] = g;
1621   rgba[BCOMP] = b;
1622   rgba[ACOMP] = a;
1623}
1624
1625
1626void
1627fxt1_decode_1 (const void *texture, GLint stride, /* in pixels */
1628               GLint i, GLint j, GLubyte *rgba)
1629{
1630   static void (*decode_1[]) (const GLubyte *, GLint, GLubyte *) = {
1631      fxt1_decode_1HI,     /* cc-high   = "00?" */
1632      fxt1_decode_1HI,     /* cc-high   = "00?" */
1633      fxt1_decode_1CHROMA, /* cc-chroma = "010" */
1634      fxt1_decode_1ALPHA,  /* alpha     = "011" */
1635      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1636      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1637      fxt1_decode_1MIXED,  /* mixed     = "1??" */
1638      fxt1_decode_1MIXED   /* mixed     = "1??" */
1639   };
1640
1641   const GLubyte *code = (const GLubyte *)texture +
1642                         ((j / 4) * (stride / 8) + (i / 8)) * 16;
1643   GLint mode = CC_SEL(code, 125);
1644   GLint t = i & 7;
1645
1646   if (t & 4) {
1647      t += 12;
1648   }
1649   t += (j & 3) * 4;
1650
1651   decode_1[mode](code, t, rgba);
1652}
1653
1654
1655#endif /* FEATURE_texture_fxt1 */
1656