• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libtxc_dxtn
3  * Version:  1.0
4  *
5  * Copyright (C) 2004  Roland Scheidegger   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 #ifdef __APPLE__
26 #include <OpenGL/gl.h>
27 #else
28 #include <GL/gl.h>
29 #endif
30 
31 typedef GLubyte GLchan;
32 #define UBYTE_TO_CHAN(b)  (b)
33 #define CHAN_MAX 255
34 #define RCOMP 0
35 #define GCOMP 1
36 #define BCOMP 2
37 #define ACOMP 3
38 
39 #define EXP5TO8R(packedcol)					\
40    ((((packedcol) >> 8) & 0xf8) | (((packedcol) >> 13) & 0x7))
41 
42 #define EXP6TO8G(packedcol)					\
43    ((((packedcol) >> 3) & 0xfc) | (((packedcol) >>  9) & 0x3))
44 
45 #define EXP5TO8B(packedcol)					\
46    ((((packedcol) << 3) & 0xf8) | (((packedcol) >>  2) & 0x7))
47 
48 #define EXP4TO8(col)						\
49    ((col) | ((col) << 4))
50 
51 /* inefficient. To be efficient, it would be necessary to decode 16 pixels at once */
52 
dxt135_decode_imageblock(const GLubyte * img_block_src,GLint i,GLint j,GLuint dxt_type,GLvoid * texel)53 static void dxt135_decode_imageblock ( const GLubyte *img_block_src,
54                          GLint i, GLint j, GLuint dxt_type, GLvoid *texel ) {
55    GLchan *rgba = (GLchan *) texel;
56    const GLushort color0 = img_block_src[0] | (img_block_src[1] << 8);
57    const GLushort color1 = img_block_src[2] | (img_block_src[3] << 8);
58    const GLuint bits = img_block_src[4] | (img_block_src[5] << 8) |
59       (img_block_src[6] << 16) | (img_block_src[7] << 24);
60    /* What about big/little endian? */
61    GLubyte bit_pos = 2 * (j * 4 + i) ;
62    GLubyte code = (GLubyte) ((bits >> bit_pos) & 3);
63 
64    rgba[ACOMP] = CHAN_MAX;
65    switch (code) {
66    case 0:
67       rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color0) );
68       rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color0) );
69       rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color0) );
70       break;
71    case 1:
72       rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color1) );
73       rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color1) );
74       rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color1) );
75       break;
76    case 2:
77       if ((dxt_type > 1) || (color0 > color1)) {
78          rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) * 2 + EXP5TO8R(color1)) / 3) );
79          rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) * 2 + EXP6TO8G(color1)) / 3) );
80          rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) * 2 + EXP5TO8B(color1)) / 3) );
81       }
82       else {
83          rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1)) / 2) );
84          rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1)) / 2) );
85          rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1)) / 2) );
86       }
87       break;
88    case 3:
89       if ((dxt_type > 1) || (color0 > color1)) {
90          rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1) * 2) / 3) );
91          rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1) * 2) / 3) );
92          rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1) * 2) / 3) );
93       }
94       else {
95          rgba[RCOMP] = 0;
96          rgba[GCOMP] = 0;
97          rgba[BCOMP] = 0;
98          if (dxt_type == 1) rgba[ACOMP] = UBYTE_TO_CHAN(0);
99       }
100       break;
101    default:
102    /* CANNOT happen (I hope) */
103       break;
104    }
105 }
106 
107 
fetch_2d_texel_rgb_dxt1(GLint srcRowStride,const GLubyte * pixdata,GLint i,GLint j,GLvoid * texel)108 static void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata,
109                          GLint i, GLint j, GLvoid *texel)
110 {
111    /* Extract the (i,j) pixel from pixdata and return it
112     * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP].
113     */
114 
115    const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8);
116    dxt135_decode_imageblock(blksrc, (i&3), (j&3), 0, texel);
117 }
118 
119 
fetch_2d_texel_rgba_dxt1(GLint srcRowStride,const GLubyte * pixdata,GLint i,GLint j,GLvoid * texel)120 static void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata,
121                          GLint i, GLint j, GLvoid *texel)
122 {
123    /* Extract the (i,j) pixel from pixdata and return it
124     * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP].
125     */
126 
127    const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8);
128    dxt135_decode_imageblock(blksrc, (i&3), (j&3), 1, texel);
129 }
130 
fetch_2d_texel_rgba_dxt3(GLint srcRowStride,const GLubyte * pixdata,GLint i,GLint j,GLvoid * texel)131 static void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata,
132                          GLint i, GLint j, GLvoid *texel) {
133 
134    /* Extract the (i,j) pixel from pixdata and return it
135     * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP].
136     */
137 
138    GLchan *rgba = (GLchan *) texel;
139    const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16);
140    const GLubyte anibble = (blksrc[((j&3) * 4 + (i&3)) / 2] >> (4 * (i&1))) & 0xf;
141    dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel);
142    rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8(anibble)) );
143 }
144 
fetch_2d_texel_rgba_dxt5(GLint srcRowStride,const GLubyte * pixdata,GLint i,GLint j,GLvoid * texel)145 static void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata,
146                          GLint i, GLint j, GLvoid *texel) {
147 
148    /* Extract the (i,j) pixel from pixdata and return it
149     * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP].
150     */
151 
152    GLchan *rgba = (GLchan *) texel;
153    const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16);
154    const GLubyte alpha0 = blksrc[0];
155    const GLubyte alpha1 = blksrc[1];
156    const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3;
157    const GLubyte acodelow = blksrc[2 + bit_pos / 8];
158    const GLubyte acodehigh = blksrc[3 + bit_pos / 8];
159    const GLubyte code = (acodelow >> (bit_pos & 0x7) |
160       (acodehigh  << (8 - (bit_pos & 0x7)))) & 0x7;
161    dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel);
162    if (code == 0)
163       rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 );
164    else if (code == 1)
165       rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 );
166    else if (alpha0 > alpha1)
167       rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) );
168    else if (code < 6)
169       rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) );
170    else if (code == 6)
171       rgba[ACOMP] = 0;
172    else
173       rgba[ACOMP] = CHAN_MAX;
174 }
175 
176 
177 /* weights used for error function, basically weights (unsquared 2/4/1) according to rgb->luminance conversion
178    not sure if this really reflects visual perception */
179 #define REDWEIGHT 4
180 #define GREENWEIGHT 16
181 #define BLUEWEIGHT 1
182 
183 #define ALPHACUT 127
184 
fancybasecolorsearch(UNUSED GLubyte * blkaddr,GLubyte srccolors[4][4][4],GLubyte * bestcolor[2],GLint numxpixels,GLint numypixels,UNUSED GLint type,UNUSED GLboolean haveAlpha)185 static void fancybasecolorsearch( UNUSED GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2],
186                            GLint numxpixels, GLint numypixels, UNUSED GLint type, UNUSED GLboolean haveAlpha)
187 {
188    /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */
189 
190    /* TODO could also try to find a better encoding for the 3-color-encoding type, this really should be done
191       if it's rgba_dxt1 and we have alpha in the block, currently even values which will be mapped to black
192       due to their alpha value will influence the result */
193    GLint i, j, colors, z;
194    GLuint pixerror, pixerrorred, pixerrorgreen, pixerrorblue, pixerrorbest;
195    GLint colordist, blockerrlin[2][3];
196    GLubyte nrcolor[2];
197    GLint pixerrorcolorbest[3];
198    GLubyte enc = 0;
199    GLubyte cv[4][4];
200    GLubyte testcolor[2][3];
201 
202 /*   fprintf(stderr, "color begin 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n",
203       bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/
204    if (((bestcolor[0][0] & 0xf8) << 8 | (bestcolor[0][1] & 0xfc) << 3 | bestcolor[0][2] >> 3) <
205       ((bestcolor[1][0] & 0xf8) << 8 | (bestcolor[1][1] & 0xfc) << 3 | bestcolor[1][2] >> 3)) {
206       testcolor[0][0] = bestcolor[0][0];
207       testcolor[0][1] = bestcolor[0][1];
208       testcolor[0][2] = bestcolor[0][2];
209       testcolor[1][0] = bestcolor[1][0];
210       testcolor[1][1] = bestcolor[1][1];
211       testcolor[1][2] = bestcolor[1][2];
212    }
213    else {
214       testcolor[1][0] = bestcolor[0][0];
215       testcolor[1][1] = bestcolor[0][1];
216       testcolor[1][2] = bestcolor[0][2];
217       testcolor[0][0] = bestcolor[1][0];
218       testcolor[0][1] = bestcolor[1][1];
219       testcolor[0][2] = bestcolor[1][2];
220    }
221 
222    for (i = 0; i < 3; i ++) {
223       cv[0][i] = testcolor[0][i];
224       cv[1][i] = testcolor[1][i];
225       cv[2][i] = (testcolor[0][i] * 2 + testcolor[1][i]) / 3;
226       cv[3][i] = (testcolor[0][i] + testcolor[1][i] * 2) / 3;
227    }
228 
229    blockerrlin[0][0] = 0;
230    blockerrlin[0][1] = 0;
231    blockerrlin[0][2] = 0;
232    blockerrlin[1][0] = 0;
233    blockerrlin[1][1] = 0;
234    blockerrlin[1][2] = 0;
235 
236    nrcolor[0] = 0;
237    nrcolor[1] = 0;
238 
239    for (j = 0; j < numypixels; j++) {
240       for (i = 0; i < numxpixels; i++) {
241          pixerrorbest = 0xffffffff;
242          for (colors = 0; colors < 4; colors++) {
243             colordist = srccolors[j][i][0] - (cv[colors][0]);
244             pixerror = colordist * colordist * REDWEIGHT;
245             pixerrorred = colordist;
246             colordist = srccolors[j][i][1] - (cv[colors][1]);
247             pixerror += colordist * colordist * GREENWEIGHT;
248             pixerrorgreen = colordist;
249             colordist = srccolors[j][i][2] - (cv[colors][2]);
250             pixerror += colordist * colordist * BLUEWEIGHT;
251             pixerrorblue = colordist;
252             if (pixerror < pixerrorbest) {
253                enc = colors;
254                pixerrorbest = pixerror;
255                pixerrorcolorbest[0] = pixerrorred;
256                pixerrorcolorbest[1] = pixerrorgreen;
257                pixerrorcolorbest[2] = pixerrorblue;
258             }
259          }
260          if (enc == 0) {
261             for (z = 0; z < 3; z++) {
262                blockerrlin[0][z] += 3 * pixerrorcolorbest[z];
263             }
264             nrcolor[0] += 3;
265          }
266          else if (enc == 2) {
267             for (z = 0; z < 3; z++) {
268                blockerrlin[0][z] += 2 * pixerrorcolorbest[z];
269             }
270             nrcolor[0] += 2;
271             for (z = 0; z < 3; z++) {
272                blockerrlin[1][z] += 1 * pixerrorcolorbest[z];
273             }
274             nrcolor[1] += 1;
275          }
276          else if (enc == 3) {
277             for (z = 0; z < 3; z++) {
278                blockerrlin[0][z] += 1 * pixerrorcolorbest[z];
279             }
280             nrcolor[0] += 1;
281             for (z = 0; z < 3; z++) {
282                blockerrlin[1][z] += 2 * pixerrorcolorbest[z];
283             }
284             nrcolor[1] += 2;
285          }
286          else if (enc == 1) {
287             for (z = 0; z < 3; z++) {
288                blockerrlin[1][z] += 3 * pixerrorcolorbest[z];
289             }
290             nrcolor[1] += 3;
291          }
292       }
293    }
294    if (nrcolor[0] == 0) nrcolor[0] = 1;
295    if (nrcolor[1] == 0) nrcolor[1] = 1;
296    for (j = 0; j < 2; j++) {
297       for (i = 0; i < 3; i++) {
298 	 GLint newvalue = testcolor[j][i] + blockerrlin[j][i] / nrcolor[j];
299 	 if (newvalue <= 0)
300 	    testcolor[j][i] = 0;
301 	 else if (newvalue >= 255)
302 	    testcolor[j][i] = 255;
303 	 else testcolor[j][i] = newvalue;
304       }
305    }
306 
307    if ((abs(testcolor[0][0] - testcolor[1][0]) < 8) &&
308        (abs(testcolor[0][1] - testcolor[1][1]) < 4) &&
309        (abs(testcolor[0][2] - testcolor[1][2]) < 8)) {
310        /* both colors are so close they might get encoded as the same 16bit values */
311       GLubyte coldiffred, coldiffgreen, coldiffblue, coldiffmax, factor, ind0, ind1;
312 
313       coldiffred = abs(testcolor[0][0] - testcolor[1][0]);
314       coldiffgreen = 2 * abs(testcolor[0][1] - testcolor[1][1]);
315       coldiffblue = abs(testcolor[0][2] - testcolor[1][2]);
316       coldiffmax = coldiffred;
317       if (coldiffmax < coldiffgreen) coldiffmax = coldiffgreen;
318       if (coldiffmax < coldiffblue) coldiffmax = coldiffblue;
319       if (coldiffmax > 0) {
320          if (coldiffmax > 4) factor = 2;
321          else if (coldiffmax > 2) factor = 3;
322          else factor = 4;
323          /* Won't do much if the color value is near 255... */
324          /* argh so many ifs */
325          if (testcolor[1][1] >= testcolor[0][1]) {
326             ind1 = 1; ind0 = 0;
327          }
328          else {
329             ind1 = 0; ind0 = 1;
330          }
331          if ((testcolor[ind1][1] + factor * coldiffgreen) <= 255)
332             testcolor[ind1][1] += factor * coldiffgreen;
333          else testcolor[ind1][1] = 255;
334          if ((testcolor[ind1][0] - testcolor[ind0][1]) > 0) {
335             if ((testcolor[ind1][0] + factor * coldiffred) <= 255)
336                testcolor[ind1][0] += factor * coldiffred;
337             else testcolor[ind1][0] = 255;
338          }
339          else {
340             if ((testcolor[ind0][0] + factor * coldiffred) <= 255)
341                testcolor[ind0][0] += factor * coldiffred;
342             else testcolor[ind0][0] = 255;
343          }
344          if ((testcolor[ind1][2] - testcolor[ind0][2]) > 0) {
345             if ((testcolor[ind1][2] + factor * coldiffblue) <= 255)
346                testcolor[ind1][2] += factor * coldiffblue;
347             else testcolor[ind1][2] = 255;
348          }
349          else {
350             if ((testcolor[ind0][2] + factor * coldiffblue) <= 255)
351                testcolor[ind0][2] += factor * coldiffblue;
352             else testcolor[ind0][2] = 255;
353          }
354       }
355    }
356 
357    if (((testcolor[0][0] & 0xf8) << 8 | (testcolor[0][1] & 0xfc) << 3 | testcolor[0][2] >> 3) <
358       ((testcolor[1][0] & 0xf8) << 8 | (testcolor[1][1] & 0xfc) << 3 | testcolor[1][2]) >> 3) {
359       for (i = 0; i < 3; i++) {
360          bestcolor[0][i] = testcolor[0][i];
361          bestcolor[1][i] = testcolor[1][i];
362       }
363    }
364    else {
365       for (i = 0; i < 3; i++) {
366          bestcolor[0][i] = testcolor[1][i];
367          bestcolor[1][i] = testcolor[0][i];
368       }
369    }
370 
371 /*     fprintf(stderr, "color end 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n",
372      bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/
373 }
374 
375 
376 
storedxtencodedblock(GLubyte * blkaddr,GLubyte srccolors[4][4][4],GLubyte * bestcolor[2],GLint numxpixels,GLint numypixels,GLuint type,GLboolean haveAlpha)377 static void storedxtencodedblock( GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2],
378                            GLint numxpixels, GLint numypixels, GLuint type, GLboolean haveAlpha)
379 {
380    /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */
381 
382    GLint i, j, colors;
383    GLuint testerror, testerror2, pixerror, pixerrorbest;
384    GLint colordist;
385    GLushort color0, color1, tempcolor;
386    GLuint bits = 0, bits2 = 0;
387    GLubyte *colorptr;
388    GLubyte enc = 0;
389    GLubyte cv[4][4];
390 
391    bestcolor[0][0] = bestcolor[0][0] & 0xf8;
392    bestcolor[0][1] = bestcolor[0][1] & 0xfc;
393    bestcolor[0][2] = bestcolor[0][2] & 0xf8;
394    bestcolor[1][0] = bestcolor[1][0] & 0xf8;
395    bestcolor[1][1] = bestcolor[1][1] & 0xfc;
396    bestcolor[1][2] = bestcolor[1][2] & 0xf8;
397 
398    color0 = bestcolor[0][0] << 8 | bestcolor[0][1] << 3 | bestcolor[0][2] >> 3;
399    color1 = bestcolor[1][0] << 8 | bestcolor[1][1] << 3 | bestcolor[1][2] >> 3;
400    if (color0 < color1) {
401       tempcolor = color0; color0 = color1; color1 = tempcolor;
402       colorptr = bestcolor[0]; bestcolor[0] = bestcolor[1]; bestcolor[1] = colorptr;
403    }
404 
405 
406    for (i = 0; i < 3; i++) {
407       cv[0][i] = bestcolor[0][i];
408       cv[1][i] = bestcolor[1][i];
409       cv[2][i] = (bestcolor[0][i] * 2 + bestcolor[1][i]) / 3;
410       cv[3][i] = (bestcolor[0][i] + bestcolor[1][i] * 2) / 3;
411    }
412 
413    testerror = 0;
414    for (j = 0; j < numypixels; j++) {
415       for (i = 0; i < numxpixels; i++) {
416          pixerrorbest = 0xffffffff;
417          for (colors = 0; colors < 4; colors++) {
418             colordist = srccolors[j][i][0] - cv[colors][0];
419             pixerror = colordist * colordist * REDWEIGHT;
420             colordist = srccolors[j][i][1] - cv[colors][1];
421             pixerror += colordist * colordist * GREENWEIGHT;
422             colordist = srccolors[j][i][2] - cv[colors][2];
423             pixerror += colordist * colordist * BLUEWEIGHT;
424             if (pixerror < pixerrorbest) {
425                pixerrorbest = pixerror;
426                enc = colors;
427             }
428          }
429          testerror += pixerrorbest;
430          bits |= enc << (2 * (j * 4 + i));
431       }
432    }
433    /* some hw might disagree but actually decoding should always use 4-color encoding
434       for non-dxt1 formats */
435    if (type == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) {
436       for (i = 0; i < 3; i++) {
437          cv[2][i] = (bestcolor[0][i] + bestcolor[1][i]) / 2;
438          /* this isn't used. Looks like the black color constant can only be used
439             with RGB_DXT1 if I read the spec correctly (note though that the radeon gpu disagrees,
440             it will decode 3 to black even with DXT3/5), and due to how the color searching works
441             it won't get used even then */
442          cv[3][i] = 0;
443       }
444       testerror2 = 0;
445       for (j = 0; j < numypixels; j++) {
446          for (i = 0; i < numxpixels; i++) {
447             pixerrorbest = 0xffffffff;
448             if ((type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) && (srccolors[j][i][3] <= ALPHACUT)) {
449                enc = 3;
450                pixerrorbest = 0; /* don't calculate error */
451             }
452             else {
453                /* we're calculating the same what we have done already for colors 0-1 above... */
454                for (colors = 0; colors < 3; colors++) {
455                   colordist = srccolors[j][i][0] - cv[colors][0];
456                   pixerror = colordist * colordist * REDWEIGHT;
457                   colordist = srccolors[j][i][1] - cv[colors][1];
458                   pixerror += colordist * colordist * GREENWEIGHT;
459                   colordist = srccolors[j][i][2] - cv[colors][2];
460                   pixerror += colordist * colordist * BLUEWEIGHT;
461                   if (pixerror < pixerrorbest) {
462                      pixerrorbest = pixerror;
463                      /* need to exchange colors later */
464                      if (colors > 1) enc = colors;
465                      else enc = colors ^ 1;
466                   }
467                }
468             }
469             testerror2 += pixerrorbest;
470             bits2 |= enc << (2 * (j * 4 + i));
471          }
472       }
473    } else {
474       testerror2 = 0xffffffff;
475    }
476 
477    /* finally we're finished, write back colors and bits */
478    if ((testerror > testerror2) || (haveAlpha)) {
479       *blkaddr++ = color1 & 0xff;
480       *blkaddr++ = color1 >> 8;
481       *blkaddr++ = color0 & 0xff;
482       *blkaddr++ = color0 >> 8;
483       *blkaddr++ = bits2 & 0xff;
484       *blkaddr++ = ( bits2 >> 8) & 0xff;
485       *blkaddr++ = ( bits2 >> 16) & 0xff;
486       *blkaddr = bits2 >> 24;
487    }
488    else {
489       *blkaddr++ = color0 & 0xff;
490       *blkaddr++ = color0 >> 8;
491       *blkaddr++ = color1 & 0xff;
492       *blkaddr++ = color1 >> 8;
493       *blkaddr++ = bits & 0xff;
494       *blkaddr++ = ( bits >> 8) & 0xff;
495       *blkaddr++ = ( bits >> 16) & 0xff;
496       *blkaddr = bits >> 24;
497    }
498 }
499 
encodedxtcolorblockfaster(GLubyte * blkaddr,GLubyte srccolors[4][4][4],GLint numxpixels,GLint numypixels,GLuint type)500 static void encodedxtcolorblockfaster( GLubyte *blkaddr, GLubyte srccolors[4][4][4],
501                          GLint numxpixels, GLint numypixels, GLuint type )
502 {
503 /* simplistic approach. We need two base colors, simply use the "highest" and the "lowest" color
504    present in the picture as base colors */
505 
506    /* define lowest and highest color as shortest and longest vector to 0/0/0, though the
507       vectors are weighted similar to their importance in rgb-luminance conversion
508       doesn't work too well though...
509       This seems to be a rather difficult problem */
510 
511    GLubyte *bestcolor[2];
512    GLubyte basecolors[2][3];
513    GLubyte i, j;
514    GLuint lowcv, highcv, testcv;
515    GLboolean haveAlpha = GL_FALSE;
516 
517    lowcv = highcv = srccolors[0][0][0] * srccolors[0][0][0] * REDWEIGHT +
518                           srccolors[0][0][1] * srccolors[0][0][1] * GREENWEIGHT +
519                           srccolors[0][0][2] * srccolors[0][0][2] * BLUEWEIGHT;
520    bestcolor[0] = bestcolor[1] = srccolors[0][0];
521    for (j = 0; j < numypixels; j++) {
522       for (i = 0; i < numxpixels; i++) {
523          /* don't use this as a base color if the pixel will get black/transparent anyway */
524          if ((type != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (srccolors[j][i][3] > ALPHACUT)) {
525             testcv = srccolors[j][i][0] * srccolors[j][i][0] * REDWEIGHT +
526                      srccolors[j][i][1] * srccolors[j][i][1] * GREENWEIGHT +
527                      srccolors[j][i][2] * srccolors[j][i][2] * BLUEWEIGHT;
528             if (testcv > highcv) {
529                highcv = testcv;
530                bestcolor[1] = srccolors[j][i];
531             }
532             else if (testcv < lowcv) {
533                lowcv = testcv;
534                bestcolor[0] = srccolors[j][i];
535             }
536          }
537          else haveAlpha = GL_TRUE;
538       }
539    }
540    /* make sure the original color values won't get touched... */
541    for (j = 0; j < 2; j++) {
542       for (i = 0; i < 3; i++) {
543          basecolors[j][i] = bestcolor[j][i];
544       }
545    }
546    bestcolor[0] = basecolors[0];
547    bestcolor[1] = basecolors[1];
548 
549    /* try to find better base colors */
550    fancybasecolorsearch(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha);
551    /* find the best encoding for these colors, and store the result */
552    storedxtencodedblock(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha);
553 }
554 
writedxt5encodedalphablock(GLubyte * blkaddr,GLubyte alphabase1,GLubyte alphabase2,GLubyte alphaenc[16])555 static void writedxt5encodedalphablock( GLubyte *blkaddr, GLubyte alphabase1, GLubyte alphabase2,
556                          GLubyte alphaenc[16])
557 {
558    *blkaddr++ = alphabase1;
559    *blkaddr++ = alphabase2;
560    *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6);
561    *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7);
562    *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5);
563    *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6);
564    *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7);
565    *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5);
566 }
567 
encodedxt5alpha(GLubyte * blkaddr,GLubyte srccolors[4][4][4],GLint numxpixels,GLint numypixels)568 static void encodedxt5alpha(GLubyte *blkaddr, GLubyte srccolors[4][4][4],
569                             GLint numxpixels, GLint numypixels)
570 {
571    GLubyte alphabase[2], alphause[2];
572    GLshort alphatest[2];
573    GLuint alphablockerror1, alphablockerror2, alphablockerror3;
574    GLubyte i, j, aindex, acutValues[7];
575    GLubyte alphaenc1[16], alphaenc2[16], alphaenc3[16];
576    GLboolean alphaabsmin = GL_FALSE;
577    GLboolean alphaabsmax = GL_FALSE;
578    GLshort alphadist;
579 
580    /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */
581    alphabase[0] = 0xff; alphabase[1] = 0x0;
582    for (j = 0; j < numypixels; j++) {
583       for (i = 0; i < numxpixels; i++) {
584          if (srccolors[j][i][3] == 0)
585             alphaabsmin = GL_TRUE;
586          else if (srccolors[j][i][3] == 255)
587             alphaabsmax = GL_TRUE;
588          else {
589             if (srccolors[j][i][3] > alphabase[1])
590                alphabase[1] = srccolors[j][i][3];
591             if (srccolors[j][i][3] < alphabase[0])
592                alphabase[0] = srccolors[j][i][3];
593          }
594       }
595    }
596 
597 
598    if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */
599       /* shortcut here since it is a very common case (and also avoids later problems) */
600       /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */
601       /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */
602 
603       *blkaddr++ = srccolors[0][0][3];
604       blkaddr++;
605       *blkaddr++ = 0;
606       *blkaddr++ = 0;
607       *blkaddr++ = 0;
608       *blkaddr++ = 0;
609       *blkaddr++ = 0;
610       *blkaddr++ = 0;
611 /*      fprintf(stderr, "enc0 used\n");*/
612       return;
613    }
614 
615    /* find best encoding for alpha0 > alpha1 */
616    /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */
617    alphablockerror1 = 0x0;
618    alphablockerror2 = 0xffffffff;
619    alphablockerror3 = 0xffffffff;
620    if (alphaabsmin) alphause[0] = 0;
621    else alphause[0] = alphabase[0];
622    if (alphaabsmax) alphause[1] = 255;
623    else alphause[1] = alphabase[1];
624    /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */
625    for (aindex = 0; aindex < 7; aindex++) {
626       /* don't forget here is always rounded down */
627       acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14;
628    }
629 
630    for (j = 0; j < numypixels; j++) {
631       for (i = 0; i < numxpixels; i++) {
632          /* maybe it's overkill to have the most complicated calculation just for the error
633             calculation which we only need to figure out if encoding1 or encoding2 is better... */
634          if (srccolors[j][i][3] > acutValues[0]) {
635             alphaenc1[4*j + i] = 0;
636             alphadist = srccolors[j][i][3] - alphause[1];
637          }
638          else if (srccolors[j][i][3] > acutValues[1]) {
639             alphaenc1[4*j + i] = 2;
640             alphadist = srccolors[j][i][3] - (alphause[1] * 6 + alphause[0] * 1) / 7;
641          }
642          else if (srccolors[j][i][3] > acutValues[2]) {
643             alphaenc1[4*j + i] = 3;
644             alphadist = srccolors[j][i][3] - (alphause[1] * 5 + alphause[0] * 2) / 7;
645          }
646          else if (srccolors[j][i][3] > acutValues[3]) {
647             alphaenc1[4*j + i] = 4;
648             alphadist = srccolors[j][i][3] - (alphause[1] * 4 + alphause[0] * 3) / 7;
649          }
650          else if (srccolors[j][i][3] > acutValues[4]) {
651             alphaenc1[4*j + i] = 5;
652             alphadist = srccolors[j][i][3] - (alphause[1] * 3 + alphause[0] * 4) / 7;
653          }
654          else if (srccolors[j][i][3] > acutValues[5]) {
655             alphaenc1[4*j + i] = 6;
656             alphadist = srccolors[j][i][3] - (alphause[1] * 2 + alphause[0] * 5) / 7;
657          }
658          else if (srccolors[j][i][3] > acutValues[6]) {
659             alphaenc1[4*j + i] = 7;
660             alphadist = srccolors[j][i][3] - (alphause[1] * 1 + alphause[0] * 6) / 7;
661          }
662          else {
663             alphaenc1[4*j + i] = 1;
664             alphadist = srccolors[j][i][3] - alphause[0];
665          }
666          alphablockerror1 += alphadist * alphadist;
667       }
668    }
669 /*      for (i = 0; i < 16; i++) {
670          fprintf(stderr, "%d ", alphaenc1[i]);
671       }
672       fprintf(stderr, "cutVals ");
673       for (i = 0; i < 8; i++) {
674          fprintf(stderr, "%d ", acutValues[i]);
675       }
676       fprintf(stderr, "srcVals ");
677       for (j = 0; j < numypixels; j++)
678          for (i = 0; i < numxpixels; i++) {
679             fprintf(stderr, "%d ", srccolors[j][i][3]);
680          }
681 
682       fprintf(stderr, "\n");
683    }*/
684    /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax
685       are false but try it anyway */
686    if (alphablockerror1 >= 32) {
687 
688       /* don't bother if encoding is already very good, this condition should also imply
689       we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */
690       alphablockerror2 = 0;
691       for (aindex = 0; aindex < 5; aindex++) {
692          /* don't forget here is always rounded down */
693          acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10;
694       }
695       for (j = 0; j < numypixels; j++) {
696          for (i = 0; i < numxpixels; i++) {
697              /* maybe it's overkill to have the most complicated calculation just for the error
698                calculation which we only need to figure out if encoding1 or encoding2 is better... */
699             if (srccolors[j][i][3] == 0) {
700                alphaenc2[4*j + i] = 6;
701                alphadist = 0;
702             }
703             else if (srccolors[j][i][3] == 255) {
704                alphaenc2[4*j + i] = 7;
705                alphadist = 0;
706             }
707             else if (srccolors[j][i][3] <= acutValues[0]) {
708                alphaenc2[4*j + i] = 0;
709                alphadist = srccolors[j][i][3] - alphabase[0];
710             }
711             else if (srccolors[j][i][3] <= acutValues[1]) {
712                alphaenc2[4*j + i] = 2;
713                alphadist = srccolors[j][i][3] - (alphabase[0] * 4 + alphabase[1] * 1) / 5;
714             }
715             else if (srccolors[j][i][3] <= acutValues[2]) {
716                alphaenc2[4*j + i] = 3;
717                alphadist = srccolors[j][i][3] - (alphabase[0] * 3 + alphabase[1] * 2) / 5;
718             }
719             else if (srccolors[j][i][3] <= acutValues[3]) {
720                alphaenc2[4*j + i] = 4;
721                alphadist = srccolors[j][i][3] - (alphabase[0] * 2 + alphabase[1] * 3) / 5;
722             }
723             else if (srccolors[j][i][3] <= acutValues[4]) {
724                alphaenc2[4*j + i] = 5;
725                alphadist = srccolors[j][i][3] - (alphabase[0] * 1 + alphabase[1] * 4) / 5;
726             }
727             else {
728                alphaenc2[4*j + i] = 1;
729                alphadist = srccolors[j][i][3] - alphabase[1];
730             }
731             alphablockerror2 += alphadist * alphadist;
732          }
733       }
734 
735 
736       /* skip this if the error is already very small
737          this encoding is MUCH better on average than #2 though, but expensive! */
738       if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) {
739          GLshort blockerrlin1 = 0;
740          GLshort blockerrlin2 = 0;
741          GLubyte nralphainrangelow = 0;
742          GLubyte nralphainrangehigh = 0;
743          alphatest[0] = 0xff;
744          alphatest[1] = 0x0;
745          /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */
746          for (j = 0; j < numypixels; j++) {
747             for (i = 0; i < numxpixels; i++) {
748                if ((srccolors[j][i][3] > alphatest[1]) && (srccolors[j][i][3] < (255 -(alphabase[1] - alphabase[0]) / 28)))
749                   alphatest[1] = srccolors[j][i][3];
750                if ((srccolors[j][i][3] < alphatest[0]) && (srccolors[j][i][3] > (alphabase[1] - alphabase[0]) / 28))
751                   alphatest[0] = srccolors[j][i][3];
752             }
753          }
754           /* shouldn't happen too often, don't really care about those degenerated cases */
755           if (alphatest[1] <= alphatest[0]) {
756              alphatest[0] = 1;
757              alphatest[1] = 254;
758 /*             fprintf(stderr, "only 1 or 0 colors for encoding!\n");*/
759          }
760          for (aindex = 0; aindex < 5; aindex++) {
761          /* don't forget here is always rounded down */
762             acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10;
763          }
764 
765          /* find the "average" difference between the alpha values and the next encoded value.
766             This is then used to calculate new base values.
767             Should there be some weighting, i.e. those values closer to alphatest[x] have more weight,
768             since they will see more improvement, and also because the values in the middle are somewhat
769             likely to get no improvement at all (because the base values might move in different directions)?
770             OTOH it would mean the values in the middle are even less likely to get an improvement
771          */
772          for (j = 0; j < numypixels; j++) {
773             for (i = 0; i < numxpixels; i++) {
774                if (srccolors[j][i][3] <= alphatest[0] / 2) {
775                }
776                else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) {
777                }
778                else if (srccolors[j][i][3] <= acutValues[0]) {
779                   blockerrlin1 += (srccolors[j][i][3] - alphatest[0]);
780                   nralphainrangelow += 1;
781                }
782                else if (srccolors[j][i][3] <= acutValues[1]) {
783                   blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5);
784                   blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5);
785                   nralphainrangelow += 1;
786                   nralphainrangehigh += 1;
787                }
788                else if (srccolors[j][i][3] <= acutValues[2]) {
789                   blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5);
790                   blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5);
791                   nralphainrangelow += 1;
792                   nralphainrangehigh += 1;
793                }
794                else if (srccolors[j][i][3] <= acutValues[3]) {
795                   blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5);
796                   blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5);
797                   nralphainrangelow += 1;
798                   nralphainrangehigh += 1;
799                }
800                else if (srccolors[j][i][3] <= acutValues[4]) {
801                   blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5);
802                   blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5);
803                   nralphainrangelow += 1;
804                   nralphainrangehigh += 1;
805                   }
806                else {
807                   blockerrlin2 += (srccolors[j][i][3] - alphatest[1]);
808                   nralphainrangehigh += 1;
809                }
810             }
811          }
812          /* shouldn't happen often, needed to avoid div by zero */
813          if (nralphainrangelow == 0) nralphainrangelow = 1;
814          if (nralphainrangehigh == 0) nralphainrangehigh = 1;
815          alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow);
816 /*         fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow);
817          fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh);*/
818          /* again shouldn't really happen often... */
819          if (alphatest[0] < 0) {
820             alphatest[0] = 0;
821 /*            fprintf(stderr, "adj alpha base val to 0\n");*/
822          }
823          alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh);
824          if (alphatest[1] > 255) {
825             alphatest[1] = 255;
826 /*            fprintf(stderr, "adj alpha base val to 255\n");*/
827          }
828 
829          alphablockerror3 = 0;
830          for (aindex = 0; aindex < 5; aindex++) {
831          /* don't forget here is always rounded down */
832             acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10;
833          }
834          for (j = 0; j < numypixels; j++) {
835             for (i = 0; i < numxpixels; i++) {
836                 /* maybe it's overkill to have the most complicated calculation just for the error
837                   calculation which we only need to figure out if encoding1 or encoding2 is better... */
838                if (srccolors[j][i][3] <= alphatest[0] / 2) {
839                   alphaenc3[4*j + i] = 6;
840                   alphadist = srccolors[j][i][3];
841                }
842                else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) {
843                   alphaenc3[4*j + i] = 7;
844                   alphadist = 255 - srccolors[j][i][3];
845                }
846                else if (srccolors[j][i][3] <= acutValues[0]) {
847                   alphaenc3[4*j + i] = 0;
848                   alphadist = srccolors[j][i][3] - alphatest[0];
849                }
850                else if (srccolors[j][i][3] <= acutValues[1]) {
851                  alphaenc3[4*j + i] = 2;
852                  alphadist = srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5;
853                }
854                else if (srccolors[j][i][3] <= acutValues[2]) {
855                   alphaenc3[4*j + i] = 3;
856                   alphadist = srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5;
857                }
858                else if (srccolors[j][i][3] <= acutValues[3]) {
859                   alphaenc3[4*j + i] = 4;
860                   alphadist = srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5;
861                }
862                else if (srccolors[j][i][3] <= acutValues[4]) {
863                   alphaenc3[4*j + i] = 5;
864                   alphadist = srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5;
865                }
866                else {
867                   alphaenc3[4*j + i] = 1;
868                   alphadist = srccolors[j][i][3] - alphatest[1];
869                }
870                alphablockerror3 += alphadist * alphadist;
871             }
872          }
873       }
874    }
875   /* write the alpha values and encoding back. */
876    if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) {
877 /*      if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1);*/
878       writedxt5encodedalphablock( blkaddr, alphause[1], alphause[0], alphaenc1 );
879    }
880    else if (alphablockerror2 <= alphablockerror3) {
881 /*      if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2);*/
882       writedxt5encodedalphablock( blkaddr, alphabase[0], alphabase[1], alphaenc2 );
883    }
884    else {
885 /*      fprintf(stderr, "enc3 used, error %d\n", alphablockerror3);*/
886       writedxt5encodedalphablock( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 );
887    }
888 }
889 
extractsrccolors(GLubyte srcpixels[4][4][4],const GLchan * srcaddr,GLint srcRowStride,GLint numxpixels,GLint numypixels,GLint comps)890 static void extractsrccolors( GLubyte srcpixels[4][4][4], const GLchan *srcaddr,
891                          GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps)
892 {
893    GLubyte i, j, c;
894    const GLchan *curaddr;
895    for (j = 0; j < numypixels; j++) {
896       curaddr = srcaddr + j * srcRowStride * comps;
897       for (i = 0; i < numxpixels; i++) {
898          for (c = 0; c < comps; c++) {
899             srcpixels[j][i][c] = *curaddr++ / (CHAN_MAX / 255);
900          }
901       }
902    }
903 }
904 
905 
tx_compress_dxtn(GLint srccomps,GLint width,GLint height,const GLubyte * srcPixData,GLenum destFormat,GLubyte * dest,GLint dstRowStride)906 static void tx_compress_dxtn(GLint srccomps, GLint width, GLint height, const GLubyte *srcPixData,
907                      GLenum destFormat, GLubyte *dest, GLint dstRowStride)
908 {
909       GLubyte *blkaddr = dest;
910       GLubyte srcpixels[4][4][4];
911       const GLchan *srcaddr = srcPixData;
912       GLint numxpixels, numypixels;
913       GLint i, j;
914       GLint dstRowDiff;
915 
916    switch (destFormat) {
917    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
918    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
919       /* hmm we used to get called without dstRowStride... */
920       dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0;
921 /*      fprintf(stderr, "dxt1 tex width %d tex height %d dstRowStride %d\n",
922               width, height, dstRowStride); */
923       for (j = 0; j < height; j += 4) {
924          if (height > j + 3) numypixels = 4;
925          else numypixels = height - j;
926          srcaddr = srcPixData + j * width * srccomps;
927          for (i = 0; i < width; i += 4) {
928             if (width > i + 3) numxpixels = 4;
929             else numxpixels = width - i;
930             extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps);
931             encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat);
932             srcaddr += srccomps * numxpixels;
933             blkaddr += 8;
934          }
935          blkaddr += dstRowDiff;
936       }
937       break;
938    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
939       dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
940 /*      fprintf(stderr, "dxt3 tex width %d tex height %d dstRowStride %d\n",
941               width, height, dstRowStride); */
942       for (j = 0; j < height; j += 4) {
943          if (height > j + 3) numypixels = 4;
944          else numypixels = height - j;
945          srcaddr = srcPixData + j * width * srccomps;
946          for (i = 0; i < width; i += 4) {
947             if (width > i + 3) numxpixels = 4;
948             else numxpixels = width - i;
949             extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps);
950             *blkaddr++ = (srcpixels[0][0][3] >> 4) | (srcpixels[0][1][3] & 0xf0);
951             *blkaddr++ = (srcpixels[0][2][3] >> 4) | (srcpixels[0][3][3] & 0xf0);
952             *blkaddr++ = (srcpixels[1][0][3] >> 4) | (srcpixels[1][1][3] & 0xf0);
953             *blkaddr++ = (srcpixels[1][2][3] >> 4) | (srcpixels[1][3][3] & 0xf0);
954             *blkaddr++ = (srcpixels[2][0][3] >> 4) | (srcpixels[2][1][3] & 0xf0);
955             *blkaddr++ = (srcpixels[2][2][3] >> 4) | (srcpixels[2][3][3] & 0xf0);
956             *blkaddr++ = (srcpixels[3][0][3] >> 4) | (srcpixels[3][1][3] & 0xf0);
957             *blkaddr++ = (srcpixels[3][2][3] >> 4) | (srcpixels[3][3][3] & 0xf0);
958             encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat);
959             srcaddr += srccomps * numxpixels;
960             blkaddr += 8;
961          }
962          blkaddr += dstRowDiff;
963       }
964       break;
965    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
966       dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
967 /*      fprintf(stderr, "dxt5 tex width %d tex height %d dstRowStride %d\n",
968               width, height, dstRowStride); */
969       for (j = 0; j < height; j += 4) {
970          if (height > j + 3) numypixels = 4;
971          else numypixels = height - j;
972          srcaddr = srcPixData + j * width * srccomps;
973          for (i = 0; i < width; i += 4) {
974             if (width > i + 3) numxpixels = 4;
975             else numxpixels = width - i;
976             extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps);
977             encodedxt5alpha(blkaddr, srcpixels, numxpixels, numypixels);
978             encodedxtcolorblockfaster(blkaddr + 8, srcpixels, numxpixels, numypixels, destFormat);
979             srcaddr += srccomps * numxpixels;
980             blkaddr += 16;
981          }
982          blkaddr += dstRowDiff;
983       }
984       break;
985    default:
986       assert(false);
987       return;
988    }
989 }
990