OSDN Git Service

add Android.mk to build for android
[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, "W0AVG"))
191                                 cd = W0AVG;
192                         else if(!strcasecmp(v, "NORMALMAP"))
193                                 cd = NORMALMAP;
194                         else
195                                 fprintf(stderr, "Invalid color dist mode: %s\n", v);
196                 }
197         }
198         {
199                 const char *v = getenv("S2TC_RANDOM_COLORS");
200                 if(v)
201                         nrandom = atoi(v);
202         }
203         {
204                 const char *v = getenv("S2TC_REFINE_COLORS");
205                 if(v)
206                 {
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;
213                         else
214                                 fprintf(stderr, "Invalid refinement mode: %s\n", v);
215                 }
216         }
217
218         switch (destformat) {
219                 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
220                 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
221                         dxt = DXT1;
222                         rgb565_image(rgba, srcPixData, width, height, srccomps, 1, dither);
223                         break;
224                 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
225                         dxt = DXT3;
226                         rgb565_image(rgba, srcPixData, width, height, srccomps, 4, dither);
227                         break;
228                 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
229                         dxt = DXT5;
230                         rgb565_image(rgba, srcPixData, width, height, srccomps, 8, dither);
231                         break;
232                 default:
233                         free(rgba);
234                         fprintf(stderr, "libdxtn: Bad dstFormat %d in tx_compress_dxtn\n", destformat);
235                         return;
236         }
237
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;
255                                         blkaddr += 8;
256                                 }
257                                 blkaddr += dstRowDiff;
258                         }
259                         break;
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;
273                                         blkaddr += 16;
274                                 }
275                                 blkaddr += dstRowDiff;
276                         }
277                         break;
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;
291                                         blkaddr += 16;
292                                 }
293                                 blkaddr += dstRowDiff;
294                         }
295                         break;
296         }
297
298         free(rgba);
299 }