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