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