OSDN Git Service

Avoid the case c0 == c1 when encoding
[android-x86/external-s2tc.git] / s2tc_libtxc_dxtn.cpp
1 /*
2  * Copyright (C) 2011  Rudolf Polzer   All Rights Reserved.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
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.
20  */
21 #define S2TC_LICENSE_IDENTIFIER s2tc_libtxc_dxtn_license
22 #include "s2tc_license.h"
23
24 extern "C"
25 {
26 #include "txc_dxtn.h"
27 };
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include "s2tc_algorithm.h"
33 #include "s2tc_common.h"
34
35 void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata,
36                              GLint i, GLint j, GLvoid *texel)
37 {
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;
44         switch(b)
45         {
46                 case 0:                        break;
47                 case 1:  c = c1;               break;
48                 case 3:  if(c1 >= c) { c = 0;  break; }
49                 default: if((i^j) & 1) c = c1; break;
50         }
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);
54         t[3] = 255;
55 }
56
57 void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata,
58                              GLint i, GLint j, GLvoid *texel)
59 {
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;
66         switch(b)
67         {
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;
72         }
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);
76 }
77
78 void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata,
79                              GLint i, GLint j, GLvoid *texel)
80 {
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;
87         switch(b)
88         {
89                 case 0:                        break;
90                 case 1:  c = c1;               break;
91                 default: if((i^j) & 1) c = c1; break;
92         }
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;
97         t[3] = a | (a << 4);
98 }
99
100 void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata,
101                              GLint i, GLint j, GLvoid *texel)
102 {
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;
109         switch(b)
110         {
111                 case 0:                        break;
112                 case 1:  c = c1;               break;
113                 default: if((i^j) & 1) c = c1; break;
114         }
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);
118
119         unsigned int a  = blksrc[0];
120         unsigned int a1 = blksrc[1];
121         int abit = ((j & 3) * 4 + (i & 3)) * 3;
122         int ab = 0;
123         if(testbit(&blksrc[2], abit))
124                 ab |= 1;
125         ++abit;
126         if(testbit(&blksrc[2], abit))
127                 ab |= 2;
128         ++abit;
129         if(testbit(&blksrc[2], abit))
130                 ab |= 4;
131         switch(ab)
132         {
133                 case 0:                         break;
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;
138         }
139         t[3] = a;
140 }
141
142 void tx_compress_dxtn(GLint srccomps, GLint width, GLint height,
143                       const GLubyte *srcPixData, GLenum destformat,
144                       GLubyte *dest, GLint dstRowStride)
145 {
146         // compresses width*height pixels (RGB or RGBA depending on srccomps) at srcPixData (packed) to destformat (dest, dstRowStride)
147
148         GLubyte *blkaddr = dest;
149         GLint numxpixels, numypixels;
150         GLint i, j;
151         GLint dstRowDiff;
152         unsigned char *rgba = (unsigned char *) malloc(width * height * 4);
153         unsigned char *srcaddr;
154         DxtMode dxt;
155
156         ColorDistMode cd = WAVG;
157         int nrandom = -1;
158         RefinementMode refine = REFINE_ALWAYS;
159         DitherMode dither = DITHER_SIMPLE;
160         {
161                 const char *v = getenv("S2TC_DITHER_MODE");
162                 if(v)
163                 {
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;
170                         else
171                                 fprintf(stderr, "Invalid dither mode: %s\n", v);
172                 }
173         }
174         {
175                 const char *v = getenv("S2TC_COLORDIST_MODE");
176                 if(v)
177                 {
178                         if(!strcasecmp(v, "RGB"))
179                                 cd = RGB;
180                         else if(!strcasecmp(v, "YUV"))
181                                 cd = YUV;
182                         else if(!strcasecmp(v, "SRGB"))
183                                 cd = SRGB;
184                         else if(!strcasecmp(v, "SRGB_MIXED"))
185                                 cd = SRGB_MIXED;
186                         else if(!strcasecmp(v, "AVG"))
187                                 cd = AVG;
188                         else if(!strcasecmp(v, "WAVG"))
189                                 cd = WAVG;
190                         else if(!strcasecmp(v, "NORMALMAP"))
191                                 cd = NORMALMAP;
192                         else
193                                 fprintf(stderr, "Invalid color dist mode: %s\n", v);
194                 }
195         }
196         {
197                 const char *v = getenv("S2TC_RANDOM_COLORS");
198                 if(v)
199                         nrandom = atoi(v);
200         }
201         {
202                 const char *v = getenv("S2TC_REFINE_COLORS");
203                 if(v)
204                 {
205                         if(!strcasecmp(v, "NEVER"))
206                                 refine = REFINE_NEVER;
207                         else if(!strcasecmp(v, "ALWAYS"))
208                                 refine = REFINE_ALWAYS;
209                         else if(!strcasecmp(v, "LOOP"))
210                                 refine = REFINE_LOOP;
211                         else
212                                 fprintf(stderr, "Invalid refinement mode: %s\n", v);
213                 }
214         }
215
216         switch (destformat) {
217                 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
218                 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
219                         dxt = DXT1;
220                         rgb565_image(rgba, srcPixData, width, height, srccomps, 1, dither);
221                         break;
222                 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
223                         dxt = DXT3;
224                         rgb565_image(rgba, srcPixData, width, height, srccomps, 4, dither);
225                         break;
226                 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
227                         dxt = DXT5;
228                         rgb565_image(rgba, srcPixData, width, height, srccomps, 8, dither);
229                         break;
230                 default:
231                         free(rgba);
232                         fprintf(stderr, "libdxtn: Bad dstFormat %d in tx_compress_dxtn\n", destformat);
233                         return;
234         }
235
236         s2tc_encode_block_func_t encode_block = s2tc_encode_block_func(dxt, cd, nrandom, refine);
237         switch (destformat) {
238                 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
239                 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
240                         /* hmm we used to get called without dstRowStride... */
241                         dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0;
242                         /*      fprintf(stderr, "dxt1 tex width %d tex height %d dstRowStride %d\n",
243                                 width, height, dstRowStride); */
244                         for (j = 0; j < height; j += 4) {
245                                 if (height > j + 3) numypixels = 4;
246                                 else numypixels = height - j;
247                                 srcaddr = rgba + j * width * 4;
248                                 for (i = 0; i < width; i += 4) {
249                                         if (width > i + 3) numxpixels = 4;
250                                         else numxpixels = width - i;
251                                         encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
252                                         srcaddr += 4 * numxpixels;
253                                         blkaddr += 8;
254                                 }
255                                 blkaddr += dstRowDiff;
256                         }
257                         break;
258                 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
259                         dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
260                         /*      fprintf(stderr, "dxt3 tex width %d tex height %d dstRowStride %d\n",
261                                 width, height, dstRowStride); */
262                         for (j = 0; j < height; j += 4) {
263                                 if (height > j + 3) numypixels = 4;
264                                 else numypixels = height - j;
265                                 srcaddr = rgba + j * width * 4;
266                                 for (i = 0; i < width; i += 4) {
267                                         if (width > i + 3) numxpixels = 4;
268                                         else numxpixels = width - i;
269                                         encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
270                                         srcaddr += 4 * numxpixels;
271                                         blkaddr += 16;
272                                 }
273                                 blkaddr += dstRowDiff;
274                         }
275                         break;
276                 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
277                         dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0;
278                         /*      fprintf(stderr, "dxt5 tex width %d tex height %d dstRowStride %d\n",
279                                 width, height, dstRowStride); */
280                         for (j = 0; j < height; j += 4) {
281                                 if (height > j + 3) numypixels = 4;
282                                 else numypixels = height - j;
283                                 srcaddr = rgba + j * width * 4;
284                                 for (i = 0; i < width; i += 4) {
285                                         if (width > i + 3) numxpixels = 4;
286                                         else numxpixels = width - i;
287                                         encode_block(blkaddr, srcaddr, width, numxpixels, numypixels, nrandom);
288                                         srcaddr += 4 * numxpixels;
289                                         blkaddr += 16;
290                                 }
291                                 blkaddr += dstRowDiff;
292                         }
293                         break;
294         }
295
296         free(rgba);
297 }