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_decompress_license
22 #include "s2tc_license.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <getopt.h>
30 
31 #ifdef ENABLE_RUNTIME_LINKING
32 #include <dlfcn.h>
33 #include <GL/gl.h>
34 typedef void (fetch_2d_texel_rgb_dxt1_t)(GLint srcRowStride, const GLubyte *pixdata,
35 		     GLint i, GLint j, GLvoid *texel);
36 typedef void (fetch_2d_texel_rgba_dxt1_t)(GLint srcRowStride, const GLubyte *pixdata,
37 		     GLint i, GLint j, GLvoid *texel);
38 typedef void (fetch_2d_texel_rgba_dxt3_t)(GLint srcRowStride, const GLubyte *pixdata,
39 		     GLint i, GLint j, GLvoid *texel);
40 typedef void (fetch_2d_texel_rgba_dxt5_t)(GLint srcRowStride, const GLubyte *pixdata,
41 			     GLint i, GLint j, GLvoid *texel);
42 fetch_2d_texel_rgb_dxt1_t *fetch_2d_texel_rgb_dxt1 = NULL;
43 fetch_2d_texel_rgba_dxt1_t *fetch_2d_texel_rgba_dxt1 = NULL;
44 fetch_2d_texel_rgba_dxt3_t *fetch_2d_texel_rgba_dxt3 = NULL;
45 fetch_2d_texel_rgba_dxt5_t *fetch_2d_texel_rgba_dxt5 = NULL;
load_libraries(const char * n)46 bool load_libraries(const char *n)
47 {
48 	void *l = dlopen(n, RTLD_NOW);
49 	if(!l)
50 	{
51 		fprintf(stderr, "Cannot load library: %s\n", dlerror());
52 		return false;
53 	}
54 	fetch_2d_texel_rgb_dxt1 = (fetch_2d_texel_rgb_dxt1_t *) dlsym(l, "fetch_2d_texel_rgb_dxt1");
55 	fetch_2d_texel_rgba_dxt1 = (fetch_2d_texel_rgba_dxt1_t *) dlsym(l, "fetch_2d_texel_rgba_dxt1");
56 	fetch_2d_texel_rgba_dxt3 = (fetch_2d_texel_rgba_dxt3_t *) dlsym(l, "fetch_2d_texel_rgba_dxt3");
57 	fetch_2d_texel_rgba_dxt5 = (fetch_2d_texel_rgba_dxt5_t *) dlsym(l, "fetch_2d_texel_rgba_dxt5");
58 	if(!fetch_2d_texel_rgb_dxt1 || !fetch_2d_texel_rgba_dxt1 || !fetch_2d_texel_rgba_dxt3 || !fetch_2d_texel_rgba_dxt5)
59 	{
60 		fprintf(stderr, "The selected libtxc_dxtn.so does not contain all required symbols.");
61 		dlclose(l);
62 		return false;
63 	}
64 	return true;
65 }
66 #else
67 #include "txc_dxtn.h"
68 #endif
69 
LittleLong(uint32_t w)70 uint32_t LittleLong(uint32_t w)
71 {
72 	union
73 	{
74 		unsigned char c[4];
75 		uint32_t u;
76 	}
77 	un;
78 	un.c[0] = w;
79 	un.c[1] = w >> 8;
80 	un.c[2] = w >> 16;
81 	un.c[3] = w >> 24;
82 	return un.u;
83 }
84 
usage(const char * me)85 int usage(const char *me)
86 {
87 	fprintf(stderr, "usage:\n"
88 			"%s \n"
89 			"    [-i infile.tga]\n"
90 			"    [-o outfile.dds]\n"
91 #ifdef ENABLE_RUNTIME_LINKING
92 			"    [-l path_to_libtxc_dxtn.so]\n"
93 #endif
94 			,
95 			me);
96 	return 1;
97 }
98 
main(int argc,char ** argv)99 int main(int argc, char **argv)
100 {
101 	const char *infile = NULL, *outfile = NULL;
102 	FILE *infh, *outfh;
103 	uint32_t h[32];
104 	int x, y, width, height, n;
105 	unsigned char t[18];
106 	unsigned char *buf;
107 
108 #ifdef ENABLE_RUNTIME_LINKING
109 	const char *library = "libtxc_dxtn.so";
110 #endif
111 
112 	int opt;
113 	while((opt = getopt(argc, argv, "i:o:"
114 #ifdef ENABLE_RUNTIME_LINKING
115 					"l:"
116 #endif
117 					)) != -1)
118 	{
119 		switch(opt)
120 		{
121 			case 'i':
122 				infile = optarg;
123 				break;
124 			case 'o':
125 				outfile = optarg;
126 				break;
127 #ifdef ENABLE_RUNTIME_LINKING
128 			case 'l':
129 				library = optarg;
130 				break;
131 #endif
132 			default:
133 				return usage(argv[0]);
134 				break;
135 		}
136 	}
137 #ifdef ENABLE_RUNTIME_LINKING
138 	if(!load_libraries(library))
139 		return 1;
140 #endif
141 
142 	infh = infile ? fopen(infile, "rb") : stdin;
143 	if(!infh)
144 	{
145 		printf("opening input failed\n");
146 		return 2;
147 	}
148 
149 	outfh = outfile ? fopen(outfile, "wb") : stdout;
150 	if(!outfh)
151 	{
152 		printf("opening output failed\n");
153 		return 2;
154 	}
155 
156 	fread(h, sizeof(h), 1, infh);
157 	height = LittleLong(h[3]);
158 	width = LittleLong(h[4]);
159 
160 	void (*fetch)(GLint srcRowStride, const GLubyte *pixdata, GLint i, GLint j, GLvoid *texel) = NULL;
161 	int fourcc = LittleLong(h[21]);
162 	int blocksize;
163 	switch(fourcc)
164 	{
165 		case 0x31545844:
166 			fetch = fetch_2d_texel_rgba_dxt1;
167 			blocksize = 8;
168 			break;
169 		case 0x33545844:
170 			fetch = fetch_2d_texel_rgba_dxt3;
171 			blocksize = 16;
172 			break;
173 		case 0x35545844:
174 			fetch = fetch_2d_texel_rgba_dxt5;
175 			blocksize = 16;
176 			break;
177 		default:
178 			fprintf(stderr, "Only DXT1, DXT3, DXT5 are supported!\n");
179 			return 1;
180 	}
181 
182 	memset(t, 0, 18);
183 	t[2]  = 2;
184 	t[12] = width % 256;
185 	t[13] = width / 256;
186 	t[14] = height % 256;
187 	t[15] = height / 256;
188 	t[16] = 32;
189 	t[17] = 0x28;
190 	fwrite(t, 18, 1, outfh);
191 
192 	n = ((width + 3) / 4) * ((height + 3) / 4);
193 	buf = (unsigned char *) malloc(n * blocksize);
194 	fread(buf, blocksize, n, infh);
195 
196 	for(y = 0; y < height; ++y)
197 		for(x = 0; x < width; ++x)
198 		{
199 			char data[4];
200 			char h;
201 			fetch(width, buf, x, y, &data);
202 			h = data[0];
203 			data[0] = data[2];
204 			data[2] = h;
205 			fwrite(data, 4, 1, outfh);
206 		}
207 
208 	if(infile)
209 		fclose(infh);
210 	if(outfile)
211 		fclose(outfh);
212 
213 	return 0;
214 }
215