swrast: s/Data/Map/ in swrast_texture_image
[profile/ivi/mesa.git] / src / mesa / main / texcompress_fxt1.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25
26 /**
27  * \file texcompress_fxt1.c
28  * GL_3DFX_texture_compression_FXT1 support.
29  */
30
31
32 #include "glheader.h"
33 #include "imports.h"
34 #include "colormac.h"
35 #include "image.h"
36 #include "macros.h"
37 #include "mfeatures.h"
38 #include "mipmap.h"
39 #include "texcompress.h"
40 #include "texcompress_fxt1.h"
41 #include "texstore.h"
42 #include "swrast/s_context.h"
43
44
45 #if FEATURE_texture_fxt1
46
47
48 static void
49 fxt1_encode (GLuint width, GLuint height, GLint comps,
50              const void *source, GLint srcRowStride,
51              void *dest, GLint destRowStride);
52
53 void
54 fxt1_decode_1 (const void *texture, GLint stride,
55                GLint i, GLint j, GLubyte *rgba);
56
57
58 /**
59  * Store user's image in rgb_fxt1 format.
60  */
61 GLboolean
62 _mesa_texstore_rgb_fxt1(TEXSTORE_PARAMS)
63 {
64    const GLubyte *pixels;
65    GLint srcRowStride;
66    GLubyte *dst;
67    const GLubyte *tempImage = NULL;
68
69    ASSERT(dstFormat == MESA_FORMAT_RGB_FXT1);
70
71    if (srcFormat != GL_RGB ||
72        srcType != GL_UNSIGNED_BYTE ||
73        ctx->_ImageTransferState ||
74        srcPacking->RowLength != srcWidth ||
75        srcPacking->SwapBytes) {
76       /* convert image to RGB/GLubyte */
77       tempImage = _mesa_make_temp_ubyte_image(ctx, dims,
78                                              baseInternalFormat,
79                                              _mesa_get_format_base_format(dstFormat),
80                                              srcWidth, srcHeight, srcDepth,
81                                              srcFormat, srcType, srcAddr,
82                                              srcPacking);
83       if (!tempImage)
84          return GL_FALSE; /* out of memory */
85       pixels = tempImage;
86       srcRowStride = 3 * srcWidth;
87       srcFormat = GL_RGB;
88    }
89    else {
90       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
91                                      srcFormat, srcType, 0, 0);
92
93       srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
94                                             srcType) / sizeof(GLubyte);
95    }
96
97    dst = dstSlices[0];
98
99    fxt1_encode(srcWidth, srcHeight, 3, pixels, srcRowStride,
100                dst, dstRowStride);
101
102    if (tempImage)
103       free((void*) tempImage);
104
105    return GL_TRUE;
106 }
107
108
109 /**
110  * Store user's image in rgba_fxt1 format.
111  */
112 GLboolean
113 _mesa_texstore_rgba_fxt1(TEXSTORE_PARAMS)
114 {
115    const GLubyte *pixels;
116    GLint srcRowStride;
117    GLubyte *dst;
118    const GLubyte *tempImage = NULL;
119
120    ASSERT(dstFormat == MESA_FORMAT_RGBA_FXT1);
121
122    if (srcFormat != GL_RGBA ||
123        srcType != GL_UNSIGNED_BYTE ||
124        ctx->_ImageTransferState ||
125        srcPacking->SwapBytes) {
126       /* convert image to RGBA/GLubyte */
127       tempImage = _mesa_make_temp_ubyte_image(ctx, dims,
128                                              baseInternalFormat,
129                                              _mesa_get_format_base_format(dstFormat),
130                                              srcWidth, srcHeight, srcDepth,
131                                              srcFormat, srcType, srcAddr,
132                                              srcPacking);
133       if (!tempImage)
134          return GL_FALSE; /* out of memory */
135       pixels = tempImage;
136       srcRowStride = 4 * srcWidth;
137       srcFormat = GL_RGBA;
138    }
139    else {
140       pixels = _mesa_image_address2d(srcPacking, srcAddr, srcWidth, srcHeight,
141                                      srcFormat, srcType, 0, 0);
142
143       srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat,
144                                             srcType) / sizeof(GLubyte);
145    }
146
147    dst = dstSlices[0];
148
149    fxt1_encode(srcWidth, srcHeight, 4, pixels, srcRowStride,
150                dst, dstRowStride);
151
152    if (tempImage)
153       free((void*) tempImage);
154
155    return GL_TRUE;
156 }
157
158
159 void
160 _mesa_fetch_texel_2d_f_rgba_fxt1( const struct swrast_texture_image *texImage,
161                                   GLint i, GLint j, GLint k, GLfloat *texel )
162 {
163    /* just sample as GLubyte and convert to float here */
164    GLubyte rgba[4];
165    (void) k;
166    fxt1_decode_1(texImage->Map, texImage->RowStride, i, j, rgba);
167    texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]);
168    texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]);
169    texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]);
170    texel[ACOMP] = UBYTE_TO_FLOAT(rgba[ACOMP]);
171 }
172
173
174 void
175 _mesa_fetch_texel_2d_f_rgb_fxt1( const struct swrast_texture_image *texImage,
176                                  GLint i, GLint j, GLint k, GLfloat *texel )
177 {
178    /* just sample as GLubyte and convert to float here */
179    GLubyte rgba[4];
180    (void) k;
181    fxt1_decode_1(texImage->Map, texImage->RowStride, i, j, rgba);
182    texel[RCOMP] = UBYTE_TO_FLOAT(rgba[RCOMP]);
183    texel[GCOMP] = UBYTE_TO_FLOAT(rgba[GCOMP]);
184    texel[BCOMP] = UBYTE_TO_FLOAT(rgba[BCOMP]);
185    texel[ACOMP] = 1.0F;
186 }
187
188
189
190 /***************************************************************************\
191  * FXT1 encoder
192  *
193  * The encoder was built by reversing the decoder,
194  * and is vaguely based on Texus2 by 3dfx. Note that this code
195  * is merely a proof of concept, since it is highly UNoptimized;
196  * moreover, it is sub-optimal due to initial conditions passed
197  * to Lloyd's algorithm (the interpolation modes are even worse).
198 \***************************************************************************/
199
200
201 #define MAX_COMP 4 /* ever needed maximum number of components in texel */
202 #define MAX_VECT 4 /* ever needed maximum number of base vectors to find */
203 #define N_TEXELS 32 /* number of texels in a block (always 32) */
204 #define LL_N_REP 50 /* number of iterations in lloyd's vq */
205 #define LL_RMS_D 10 /* fault tolerance (maximum delta) */
206 #define LL_RMS_E 255 /* fault tolerance (maximum error) */
207 #define ALPHA_TS 2 /* alpha threshold: (255 - ALPHA_TS) deemed opaque */
208 #define ISTBLACK(v) (*((GLuint *)(v)) == 0)
209
210
211 /*
212  * Define a 64-bit unsigned integer type and macros
213  */
214 #if 1
215
216 #define FX64_NATIVE 1
217
218 typedef uint64_t Fx64;
219
220 #define FX64_MOV32(a, b) a = b
221 #define FX64_OR32(a, b)  a |= b
222 #define FX64_SHL(a, c)   a <<= c
223
224 #else
225
226 #define FX64_NATIVE 0
227
228 typedef struct {
229    GLuint lo, hi;
230 } Fx64;
231
232 #define FX64_MOV32(a, b) a.lo = b
233 #define FX64_OR32(a, b)  a.lo |= b
234
235 #define FX64_SHL(a, c)                                 \
236    do {                                                \
237        if ((c) >= 32) {                                \
238           a.hi = a.lo << ((c) - 32);                   \
239           a.lo = 0;                                    \
240        } else {                                        \
241           a.hi = (a.hi << (c)) | (a.lo >> (32 - (c))); \
242           a.lo <<= (c);                                \
243        }                                               \
244    } while (0)
245
246 #endif
247
248
249 #define F(i) (GLfloat)1 /* can be used to obtain an oblong metric: 0.30 / 0.59 / 0.11 */
250 #define SAFECDOT 1 /* for paranoids */
251
252 #define MAKEIVEC(NV, NC, IV, B, V0, V1)  \
253    do {                                  \
254       /* compute interpolation vector */ \
255       GLfloat d2 = 0.0F;                 \
256       GLfloat rd2;                       \
257                                          \
258       for (i = 0; i < NC; i++) {         \
259          IV[i] = (V1[i] - V0[i]) * F(i); \
260          d2 += IV[i] * IV[i];            \
261       }                                  \
262       rd2 = (GLfloat)NV / d2;            \
263       B = 0;                             \
264       for (i = 0; i < NC; i++) {         \
265          IV[i] *= F(i);                  \
266          B -= IV[i] * V0[i];             \
267          IV[i] *= rd2;                   \
268       }                                  \
269       B = B * rd2 + 0.5f;                \
270    } while (0)
271
272 #define CALCCDOT(TEXEL, NV, NC, IV, B, V)\
273    do {                                  \
274       GLfloat dot = 0.0F;                \
275       for (i = 0; i < NC; i++) {         \
276          dot += V[i] * IV[i];            \
277       }                                  \
278       TEXEL = (GLint)(dot + B);          \
279       if (SAFECDOT) {                    \
280          if (TEXEL < 0) {                \
281             TEXEL = 0;                   \
282          } else if (TEXEL > NV) {        \
283             TEXEL = NV;                  \
284          }                               \
285       }                                  \
286    } while (0)
287
288
289 static GLint
290 fxt1_bestcol (GLfloat vec[][MAX_COMP], GLint nv,
291               GLubyte input[MAX_COMP], GLint nc)
292 {
293    GLint i, j, best = -1;
294    GLfloat err = 1e9; /* big enough */
295
296    for (j = 0; j < nv; j++) {
297       GLfloat e = 0.0F;
298       for (i = 0; i < nc; i++) {
299          e += (vec[j][i] - input[i]) * (vec[j][i] - input[i]);
300       }
301       if (e < err) {
302          err = e;
303          best = j;
304       }
305    }
306
307    return best;
308 }
309
310
311 static GLint
312 fxt1_worst (GLfloat vec[MAX_COMP],
313             GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
314 {
315    GLint i, k, worst = -1;
316    GLfloat err = -1.0F; /* small enough */
317
318    for (k = 0; k < n; k++) {
319       GLfloat e = 0.0F;
320       for (i = 0; i < nc; i++) {
321          e += (vec[i] - input[k][i]) * (vec[i] - input[k][i]);
322       }
323       if (e > err) {
324          err = e;
325          worst = k;
326       }
327    }
328
329    return worst;
330 }
331
332
333 static GLint
334 fxt1_variance (GLdouble variance[MAX_COMP],
335                GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
336 {
337    GLint i, k, best = 0;
338    GLint sx, sx2;
339    GLdouble var, maxvar = -1; /* small enough */
340    GLdouble teenth = 1.0 / n;
341
342    for (i = 0; i < nc; i++) {
343       sx = sx2 = 0;
344       for (k = 0; k < n; k++) {
345          GLint t = input[k][i];
346          sx += t;
347          sx2 += t * t;
348       }
349       var = sx2 * teenth - sx * sx * teenth * teenth;
350       if (maxvar < var) {
351          maxvar = var;
352          best = i;
353       }
354       if (variance) {
355          variance[i] = var;
356       }
357    }
358
359    return best;
360 }
361
362
363 static GLint
364 fxt1_choose (GLfloat vec[][MAX_COMP], GLint nv,
365              GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
366 {
367 #if 0
368    /* Choose colors from a grid.
369     */
370    GLint i, j;
371
372    for (j = 0; j < nv; j++) {
373       GLint m = j * (n - 1) / (nv - 1);
374       for (i = 0; i < nc; i++) {
375          vec[j][i] = input[m][i];
376       }
377    }
378 #else
379    /* Our solution here is to find the darkest and brightest colors in
380     * the 8x4 tile and use those as the two representative colors.
381     * There are probably better algorithms to use (histogram-based).
382     */
383    GLint i, j, k;
384    GLint minSum = 2000; /* big enough */
385    GLint maxSum = -1; /* small enough */
386    GLint minCol = 0; /* phoudoin: silent compiler! */
387    GLint maxCol = 0; /* phoudoin: silent compiler! */
388
389    struct {
390       GLint flag;
391       GLint key;
392       GLint freq;
393       GLint idx;
394    } hist[N_TEXELS];
395    GLint lenh = 0;
396
397    memset(hist, 0, sizeof(hist));
398
399    for (k = 0; k < n; k++) {
400       GLint l;
401       GLint key = 0;
402       GLint sum = 0;
403       for (i = 0; i < nc; i++) {
404          key <<= 8;
405          key |= input[k][i];
406          sum += input[k][i];
407       }
408       for (l = 0; l < n; l++) {
409          if (!hist[l].flag) {
410             /* alloc new slot */
411             hist[l].flag = !0;
412             hist[l].key = key;
413             hist[l].freq = 1;
414             hist[l].idx = k;
415             lenh = l + 1;
416             break;
417          } else if (hist[l].key == key) {
418             hist[l].freq++;
419             break;
420          }
421       }
422       if (minSum > sum) {
423          minSum = sum;
424          minCol = k;
425       }
426       if (maxSum < sum) {
427          maxSum = sum;
428          maxCol = k;
429       }
430    }
431
432    if (lenh <= nv) {
433       for (j = 0; j < lenh; j++) {
434          for (i = 0; i < nc; i++) {
435             vec[j][i] = (GLfloat)input[hist[j].idx][i];
436          }
437       }
438       for (; j < nv; j++) {
439          for (i = 0; i < nc; i++) {
440             vec[j][i] = vec[0][i];
441          }
442       }
443       return 0;
444    }
445
446    for (j = 0; j < nv; j++) {
447       for (i = 0; i < nc; i++) {
448          vec[j][i] = ((nv - 1 - j) * input[minCol][i] + j * input[maxCol][i] + (nv - 1) / 2) / (GLfloat)(nv - 1);
449       }
450    }
451 #endif
452
453    return !0;
454 }
455
456
457 static GLint
458 fxt1_lloyd (GLfloat vec[][MAX_COMP], GLint nv,
459             GLubyte input[N_TEXELS][MAX_COMP], GLint nc, GLint n)
460 {
461    /* Use the generalized lloyd's algorithm for VQ:
462     *     find 4 color vectors.
463     *
464     *     for each sample color
465     *         sort to nearest vector.
466     *
467     *     replace each vector with the centroid of its matching colors.
468     *
469     *     repeat until RMS doesn't improve.
470     *
471     *     if a color vector has no samples, or becomes the same as another
472     *     vector, replace it with the color which is farthest from a sample.
473     *
474     * vec[][MAX_COMP]           initial vectors and resulting colors
475     * nv                        number of resulting colors required
476     * input[N_TEXELS][MAX_COMP] input texels
477     * nc                        number of components in input / vec
478     * n                         number of input samples
479     */
480
481    GLint sum[MAX_VECT][MAX_COMP]; /* used to accumulate closest texels */
482    GLint cnt[MAX_VECT]; /* how many times a certain vector was chosen */
483    GLfloat error, lasterror = 1e9;
484
485    GLint i, j, k, rep;
486
487    /* the quantizer */
488    for (rep = 0; rep < LL_N_REP; rep++) {
489       /* reset sums & counters */
490       for (j = 0; j < nv; j++) {
491          for (i = 0; i < nc; i++) {
492             sum[j][i] = 0;
493          }
494          cnt[j] = 0;
495       }
496       error = 0;
497
498       /* 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
558 static void
559 fxt1_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
599 static void
600 fxt1_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
652 static void
653 fxt1_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
809 static void
810 fxt1_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
885 static void
886 fxt1_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
1023 static void
1024 fxt1_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
1192 static void
1193 fxt1_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  */
1287 static void
1288 upscale_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
1316 static void
1317 fxt1_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 */
1381 static 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 */
1389 static 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
1407 static void
1408 fxt1_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
1442 static void
1443 fxt1_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
1465 static void
1466 fxt1_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
1551 static void
1552 fxt1_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
1626 void
1627 fxt1_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 */