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_from_s3tc_license
22 #include "s2tc_license.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdint.h>
28 #include <getopt.h>
29 #include <algorithm>
30 #include "s2tc_common.h"
31
LittleLong(uint32_t w)32 uint32_t LittleLong(uint32_t w)
33 {
34 union
35 {
36 unsigned char c[4];
37 uint32_t u;
38 }
39 un;
40 un.c[0] = w;
41 un.c[1] = w >> 8;
42 un.c[2] = w >> 16;
43 un.c[3] = w >> 24;
44 return un.u;
45 }
46
usage(const char * me)47 int usage(const char *me)
48 {
49 fprintf(stderr, "usage:\n"
50 "%s \n"
51 " [-i infile.dds]\n"
52 " [-o outfile.dds]\n"
53 ,
54 me);
55 return 1;
56 }
57
58 enum DxtConversion
59 {
60 DXT1,
61 DXT3,
62 DXT5
63 };
64
65 //pixels = (pixels & ~((~pixels & 0x55555555) << 1)) | ((pixels & 0x22882288) >> 1);
66 // 00 -> 00
67 // 01 -> 01
68 // 10 -> 00 or 01
69 // 11 -> 11
70
71 //pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1);
72 // 00 -> 00
73 // 01 -> 01
74 // 10 -> 00 or 01
75 // 11 -> 00 or 01
76
convert_dxt1(unsigned char * buf)77 void convert_dxt1(unsigned char *buf)
78 {
79 unsigned int c = buf[0] + 256*buf[1];
80 unsigned int c1 = buf[2] + 256*buf[3];
81 uint32_t pixels = buf[4] | (((uint32_t)buf[5]) << 8) | (((uint32_t)buf[6]) << 16) | (((uint32_t)buf[7]) << 24);
82 if(c1 >= c)
83 {
84 // we have 10, 11 "cannot be", but we better treat 11 the same way as 10 here
85 pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1);
86
87 // S2TC conformance: always use the same order of c, c1
88 // swap
89 std::swap(c1, c);
90 // invert
91 pixels ^= 0x55555555;
92 }
93 else
94 {
95 // we have no alpha
96 pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1);
97 // alternatively: collapse
98 //pixels = pixels & 0x55555555;
99 }
100 buf[0] = c & 0xFF;
101 buf[1] = c >> 8;
102 buf[2] = c1 & 0xFF;
103 buf[3] = c1 >> 8;
104 buf[4] = pixels & 0xFF;
105 buf[5] = (pixels >> 8) & 0xFF;
106 buf[6] = (pixels >> 16) & 0xFF;
107 buf[7] = (pixels >> 24) & 0xFF;
108 }
109
convert_dxt1a(unsigned char * buf)110 void convert_dxt1a(unsigned char *buf)
111 {
112 unsigned int c = buf[0] + 256*buf[1];
113 unsigned int c1 = buf[2] + 256*buf[3];
114 uint32_t pixels = buf[4] | (((uint32_t)buf[5]) << 8) | (((uint32_t)buf[6]) << 16) | (((uint32_t)buf[7]) << 24);
115 if(c1 >= c)
116 {
117 // we have alpha, don't break it
118 pixels = (pixels & ~((~pixels & 0x55555555) << 1)) | ((pixels & 0x22882288) >> 1);
119 }
120 else
121 {
122 // we have no alpha
123 pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1);
124 // alternatively: collapse
125 //pixels = pixels & 0x55555555;
126
127 // S2TC conformance: always use the same order of c, c1
128 // swap
129 std::swap(c1, c);
130 // invert
131 pixels ^= 0x55555555;
132 }
133 buf[0] = c & 0xFF;
134 buf[1] = c >> 8;
135 buf[2] = c1 & 0xFF;
136 buf[3] = c1 >> 8;
137 buf[4] = pixels & 0xFF;
138 buf[5] = (pixels >> 8) & 0xFF;
139 buf[6] = (pixels >> 16) & 0xFF;
140 buf[7] = (pixels >> 24) & 0xFF;
141 }
142
convert_dxt5(unsigned char * buf)143 void convert_dxt5(unsigned char *buf)
144 {
145 unsigned int a = buf[0];
146 unsigned int a1 = buf[1];
147 uint64_t pixels = buf[2] | (((uint32_t)buf[3]) << 8) | (((uint32_t)buf[4]) << 16) | (((uint32_t)buf[5]) << 24) | (((uint64_t)buf[6]) << 32) | (((uint64_t)buf[7]) << 40);
148 if(a1 >= a)
149 {
150 // we want to map:
151 // 000 -> 000
152 // 001 -> 001
153 // 010 -> 000 or 001
154 // 011 -> 000 or 001
155 // 100 -> 001 or 000
156 // 101 -> 001 or 000
157 // 110 -> 110
158 // 111 -> 111
159
160 pixels = (pixels & ~((((pixels >> 1) ^ (pixels >> 2)) & 01111111111111111ull) * 7)) | (((pixels >> 1) ^ (pixels >> 2)) & 00101101001011010ull);
161 }
162 else
163 {
164 // we want to map:
165 // 000 -> 000
166 // 001 -> 001
167 // 010 -> 000 or 001
168 // 011 -> 000 or 001
169 // 100 -> 000 or 001
170 // 101 -> 001 or 000
171 // 110 -> 001 or 000
172 // 111 -> 001 or 000
173
174 pixels = (pixels & ~((((pixels >> 1) | (pixels >> 2)) & 01111111111111111ull) * 7)) | (((pixels >> 1) | (pixels >> 2)) & 00101101001011010ull);
175
176 // S2TC conformance: always use the same order of a, a1
177 // swap
178 std::swap(a1, a);
179 // invert
180 pixels ^= 01111111111111111ull;
181 }
182 buf[0] = a;
183 buf[1] = a1;
184 buf[2] = pixels & 0xFF;
185 buf[3] = (pixels >> 8) & 0xFF;
186 buf[4] = (pixels >> 16) & 0xFF;
187 buf[5] = (pixels >> 24) & 0xFF;
188 buf[6] = (pixels >> 32) & 0xFF;
189 buf[7] = (pixels >> 40) & 0xFF;
190 }
191
main(int argc,char ** argv)192 int main(int argc, char **argv)
193 {
194 const char *infile = NULL, *outfile = NULL;
195
196 int opt;
197 while((opt = getopt(argc, argv, "i:o:")) != -1)
198 {
199 switch(opt)
200 {
201 case 'i':
202 infile = optarg;
203 break;
204 case 'o':
205 outfile = optarg;
206 break;
207 default:
208 return usage(argv[0]);
209 break;
210 }
211 }
212
213 FILE *infh = infile ? fopen(infile, "rb") : stdin;
214 if(!infh)
215 {
216 printf("opening input failed\n");
217 return 2;
218 }
219
220 FILE *outfh = outfile ? fopen(outfile, "wb") : stdout;
221 if(!outfh)
222 {
223 printf("opening output failed\n");
224 return 2;
225 }
226
227 uint32_t h[32];
228 fread(h, sizeof(h), 1, infh);
229
230 int fourcc = LittleLong(h[21]);
231 int blocksize;
232 DxtConversion mode;
233 switch(fourcc)
234 {
235 case 0x31545844:
236 blocksize = 8;
237 mode = DXT1;
238 break;
239 case 0x33545844:
240 blocksize = 16;
241 mode = DXT3;
242 break;
243 case 0x35545844:
244 blocksize = 16;
245 mode = DXT5;
246 break;
247 default:
248 fprintf(stderr, "Only DXT1, DXT3, DXT5 are supported!\n");
249 return 1;
250 }
251
252 fwrite(h, sizeof(h), 1, outfh);
253 unsigned char buf[16];
254 while(fread(buf, blocksize, 1, infh) > 0)
255 {
256 if(mode == DXT1)
257 convert_dxt1a(buf);
258 else
259 convert_dxt1(buf + 8);
260 if(mode == DXT5)
261 convert_dxt5(buf);
262 fwrite(buf, blocksize, 1, outfh);
263 }
264
265 if(infile)
266 fclose(infh);
267 if(outfile)
268 fclose(outfh);
269
270 return 0;
271 }
272