2 * Copyright (C) 2011 Rudolf Polzer All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * RUDOLF POLZER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 #define S2TC_LICENSE_IDENTIFIER s2tc_libtxc_dxtn_license
22 #include "s2tc_license.h"
32 #include "s2tc_algorithm.h"
33 #include "s2tc_common.h"
35 void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata,
36 GLint i, GLint j, GLvoid *texel)
38 // fetches a single texel (i,j) into pixdata (RGB)
39 GLubyte *t = (GLubyte *) texel;
40 const GLubyte *blksrc = (pixdata + (((srcRowStride + 3) >> 2) * (j >> 2) + (i >> 2)) * 8);
41 unsigned int c = blksrc[0] + 256*blksrc[1];
42 unsigned int c1 = blksrc[2] + 256*blksrc[3];
43 int b = (blksrc[4 + (j & 3)] >> (2 * (i & 3))) & 0x03;
47 case 1: c = c1; break;
48 case 3: if(c1 >= c) { c = 0; break; }
49 default: if((i^j) & 1) c = c1; break;
51 t[0] = ((c >> 11) & 0x1F); t[0] = (t[0] << 3) | (t[0] >> 2);
52 t[1] = ((c >> 5) & 0x3F); t[1] = (t[1] << 2) | (t[1] >> 4);
53 t[2] = ((c ) & 0x1F); t[2] = (t[2] << 3) | (t[2] >> 2);
57 void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata,
58 GLint i, GLint j, GLvoid *texel)
60 // fetches a single texel (i,j) into pixdata (RGBA)
61 GLubyte *t = (GLubyte *) texel;
62 const GLubyte *blksrc = (pixdata + (((srcRowStride + 3) >> 2) * (j >> 2) + (i >> 2)) * 8);
63 unsigned int c = blksrc[0] + 256*blksrc[1];
64 unsigned int c1 = blksrc[2] + 256*blksrc[3];
65 int b = (blksrc[4 + (j & 3)] >> (2 * (i & 3))) & 0x03;
68 case 0: t[3] = 255; break;
69 case 1: c = c1; t[3] = 255; break;
70 case 3: if(c1 >= c) { c = 0; t[3] = 0; break; }
71 default: if((i^j) & 1) c = c1; t[3] = 255; break;
73 t[0] = ((c >> 11) & 0x1F); t[0] = (t[0] << 3) | (t[0] >> 2);
74 t[1] = ((c >> 5) & 0x3F); t[1] = (t[1] << 2) | (t[1] >> 4);
75 t[2] = ((c ) & 0x1F); t[2] = (t[2] << 3) | (t[2] >> 2);
78 void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata,
79 GLint i, GLint j, GLvoid *texel)
81 // fetches a single texel (i,j) into pixdata (RGBA)
82 GLubyte *t = (GLubyte *) texel;
83 const GLubyte *blksrc = (pixdata + (((srcRowStride + 3) >> 2) * (j >> 2) + (i >> 2)) * 16);
84 unsigned int c = blksrc[8] + 256*blksrc[9];
85 unsigned int c1 = blksrc[10] + 256*blksrc[11];
86 int b = (blksrc[12 + (j & 3)] >> (2 * (i & 3))) & 0x03;
90 case 1: c = c1; break;
91 default: if((i^j) & 1) c = c1; break;
93 t[0] = ((c >> 11) & 0x1F); t[0] = (t[0] << 3) | (t[0] >> 2);
94 t[1] = ((c >> 5) & 0x3F); t[1] = (t[1] << 2) | (t[1] >> 4);
95 t[2] = ((c ) & 0x1F); t[2] = (t[2] << 3) | (t[2] >> 2);
96 int a = (blksrc[(j & 3) * 2 + ((i & 3) >> 1)] >> (4 * (i & 1))) & 0x0F;
100 void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata,
101 GLint i, GLint j, GLvoid *texel)
103 // fetches a single texel (i,j) into pixdata (RGBA)
104 GLubyte *t = (GLubyte *) texel;
105 const GLubyte *blksrc = (pixdata + (((srcRowStride + 3) >> 2) * (j >> 2) + (i >> 2)) * 16);
106 unsigned int c = blksrc[8] + 256*blksrc[9];
107 unsigned int c1 = blksrc[10] + 256*blksrc[11];
108 int b = (blksrc[12 + (j & 3)] >> (2 * (i & 3))) & 0x03;
112 case 1: c = c1; break;
113 default: if((i^j) & 1) c = c1; break;
115 t[0] = ((c >> 11) & 0x1F); t[0] = (t[0] << 3) | (t[0] >> 2);
116 t[1] = ((c >> 5) & 0x3F); t[1] = (t[1] << 2) | (t[1] >> 4);
117 t[2] = ((c ) & 0x1F); t[2] = (t[2] << 3) | (t[2] >> 2);
119 unsigned int a = blksrc[0];
120 unsigned int a1 = blksrc[1];
121 int abit = ((j & 3) * 4 + (i & 3)) * 3;
123 if(testbit(&blksrc[2], abit))
126 if(testbit(&blksrc[2], abit))
129 if(testbit(&blksrc[2], abit))
134 case 1: a = a1; break;
135 case 6: if(a1 >= a) { a = 0; break; }
136 case 7: if(a1 >= a) { a = 255; break; }
137 default: if((i^j) & 1) a = a1; break;
142 void tx_compress_dxtn(GLint srccomps, GLint width, GLint height,
143 const GLubyte *srcPixData, GLenum destformat,
144 GLubyte *dest, GLint dstRowStride)
146 // compresses width*height pixels (RGB or RGBA depending on srccomps) at srcPixData (packed) to destformat (dest, dstRowStride)
148 GLubyte *blkaddr = dest;
149 GLint numxpixels, numypixels;
152 unsigned char *rgba = (unsigned char *) malloc(width * height * 4);
153 unsigned char *srcaddr;
156 ColorDistMode cd = WAVG;
158 RefinementMode refine = REFINE_ALWAYS;
159 DitherMode dither = DITHER_SIMPLE;
161 const char *v = getenv("S2TC_DITHER_MODE");
164 if(!strcasecmp(v, "NONE"))
165 dither = DITHER_NONE;
166 else if(!strcasecmp(v, "SIMPLE"))
167 dither = DITHER_SIMPLE;
168 else if(!strcasecmp(v, "FLOYDSTEINBERG"))
169 dither = DITHER_FLOYDSTEINBERG;
171 fprintf(stderr, "Invalid dither mode: %s\n", v);
175 const char *v = getenv("S2TC_COLORDIST_MODE");
178 if(!strcasecmp(v, "RGB"))
180 else if(!strcasecmp(v, "YUV"))
182 else if(!strcasecmp(v, "SRGB"))
184 else if(!strcasecmp(v, "SRGB_MIXED"))
186 else if(!strcasecmp(v, "AVG"))
188 else if(!strcasecmp(v, "WAVG"))
190 else if(!strcasecmp(v, "W0AVG"))
192 else if(!strcasecmp(v, "NORMALMAP"))
195 fprintf(stderr, "Invalid color dist mode: %s\n", v);
199 const char *v = getenv("S2TC_RANDOM_COLORS");
204 const char *v = getenv("S2TC_REFINE_COLORS");
207 if(!strcasecmp(v, "NEVER"))
208 refine = REFINE_NEVER;
209 else if(!strcasecmp(v, "ALWAYS"))
210 refine = REFINE_ALWAYS;
211 else if(!strcasecmp(v, "LOOP"))
212 refine = REFINE_LOOP;
214 fprintf(stderr, "Invalid refinement mode: %s\n", v);
218 switch (destformat) {
219 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
220 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
222 rgb565_image(rgba, srcPixData, width, height, srccomps, 1, dither);
224 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
226 rgb565_image(rgba, srcPixData, width, height, srccomps, 4, dither);
228 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
230 rgb565_image(rgba, srcPixData, width, height, srccomps, 8, dither);
234 fprintf(stderr, "libdxtn: Bad dstFormat %d in tx_compress_dxtn\n", destformat);
238 s2tc_encode_block_func_t encode_block = s2tc_encode_block_func(dxt, cd, nrandom, refine);
239 switch (destformat) {
240 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
241 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
242 /* hmm we used to get called without dstRowStride... */
243 dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0;
244 /* fprintf(stderr, "dxt1 tex width %d tex height %d dstRowStride %d\n",
245 width, height, dstRowStride); */
246 for (j = 0; j < height; j += 4) {
247 if (height > j + 3) numypixels = 4;
248 else numypixels = height - j;
249 srcaddr = rgba + j * width * 4;
250 for (i = 0; i < width; i += 4) {
251 if (width > i + 3) numxpixels = 4;
252 else numxpixels = width - i;
253 encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
254 srcaddr += 4 * numxpixels;
257 blkaddr += dstRowDiff;
260 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
261 dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
262 /* fprintf(stderr, "dxt3 tex width %d tex height %d dstRowStride %d\n",
263 width, height, dstRowStride); */
264 for (j = 0; j < height; j += 4) {
265 if (height > j + 3) numypixels = 4;
266 else numypixels = height - j;
267 srcaddr = rgba + j * width * 4;
268 for (i = 0; i < width; i += 4) {
269 if (width > i + 3) numxpixels = 4;
270 else numxpixels = width - i;
271 encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
272 srcaddr += 4 * numxpixels;
275 blkaddr += dstRowDiff;
278 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
279 dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
280 /* fprintf(stderr, "dxt5 tex width %d tex height %d dstRowStride %d\n",
281 width, height, dstRowStride); */
282 for (j = 0; j < height; j += 4) {
283 if (height > j + 3) numypixels = 4;
284 else numypixels = height - j;
285 srcaddr = rgba + j * width * 4;
286 for (i = 0; i < width; i += 4) {
287 if (width > i + 3) numxpixels = 4;
288 else numxpixels = width - i;
289 encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
290 srcaddr += 4 * numxpixels;
293 blkaddr += dstRowDiff;