/* * Copyright (C) 2011 Rudolf Polzer All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * RUDOLF POLZER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define S2TC_LICENSE_IDENTIFIER s2tc_from_s3tc_license #include "s2tc_license.h" #include #include #include #include #include #include #include "s2tc_common.h" uint32_t LittleLong(uint32_t w) { union { unsigned char c[4]; uint32_t u; } un; un.c[0] = w; un.c[1] = w >> 8; un.c[2] = w >> 16; un.c[3] = w >> 24; return un.u; } int usage(const char *me) { fprintf(stderr, "usage:\n" "%s \n" " [-i infile.dds]\n" " [-o outfile.dds]\n" , me); return 1; } enum DxtConversion { DXT1, DXT3, DXT5 }; //pixels = (pixels & ~((~pixels & 0x55555555) << 1)) | ((pixels & 0x22882288) >> 1); // 00 -> 00 // 01 -> 01 // 10 -> 00 or 01 // 11 -> 11 //pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1); // 00 -> 00 // 01 -> 01 // 10 -> 00 or 01 // 11 -> 00 or 01 void convert_dxt1(unsigned char *buf) { unsigned int c = buf[0] + 256*buf[1]; unsigned int c1 = buf[2] + 256*buf[3]; uint32_t pixels = buf[4] | (((uint32_t)buf[5]) << 8) | (((uint32_t)buf[6]) << 16) | (((uint32_t)buf[7]) << 24); if(c1 >= c) { // we have 10, 11 "cannot be", but we better treat 11 the same way as 10 here pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1); // S2TC conformance: always use the same order of c, c1 // swap std::swap(c1, c); // invert pixels ^= 0x55555555; } else { // we have no alpha pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1); // alternatively: collapse //pixels = pixels & 0x55555555; } buf[0] = c & 0xFF; buf[1] = c >> 8; buf[2] = c1 & 0xFF; buf[3] = c1 >> 8; buf[4] = pixels & 0xFF; buf[5] = (pixels >> 8) & 0xFF; buf[6] = (pixels >> 16) & 0xFF; buf[7] = (pixels >> 24) & 0xFF; } void convert_dxt1a(unsigned char *buf) { unsigned int c = buf[0] + 256*buf[1]; unsigned int c1 = buf[2] + 256*buf[3]; uint32_t pixels = buf[4] | (((uint32_t)buf[5]) << 8) | (((uint32_t)buf[6]) << 16) | (((uint32_t)buf[7]) << 24); if(c1 >= c) { // we have alpha, don't break it pixels = (pixels & ~((~pixels & 0x55555555) << 1)) | ((pixels & 0x22882288) >> 1); } else { // we have no alpha pixels = (pixels & ((~pixels & 0xAAAAAAAA) >> 1)) | ((pixels & 0x22882288) >> 1); // alternatively: collapse //pixels = pixels & 0x55555555; // S2TC conformance: always use the same order of c, c1 // swap std::swap(c1, c); // invert pixels ^= 0x55555555; } buf[0] = c & 0xFF; buf[1] = c >> 8; buf[2] = c1 & 0xFF; buf[3] = c1 >> 8; buf[4] = pixels & 0xFF; buf[5] = (pixels >> 8) & 0xFF; buf[6] = (pixels >> 16) & 0xFF; buf[7] = (pixels >> 24) & 0xFF; } void convert_dxt5(unsigned char *buf) { unsigned int a = buf[0]; unsigned int a1 = buf[1]; 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); if(a1 >= a) { // we want to map: // 000 -> 000 // 001 -> 001 // 010 -> 000 or 001 // 011 -> 000 or 001 // 100 -> 001 or 000 // 101 -> 001 or 000 // 110 -> 110 // 111 -> 111 pixels = (pixels & ~((((pixels >> 1) ^ (pixels >> 2)) & 01111111111111111ull) * 7)) | (((pixels >> 1) ^ (pixels >> 2)) & 00101101001011010ull); } else { // we want to map: // 000 -> 000 // 001 -> 001 // 010 -> 000 or 001 // 011 -> 000 or 001 // 100 -> 000 or 001 // 101 -> 001 or 000 // 110 -> 001 or 000 // 111 -> 001 or 000 pixels = (pixels & ~((((pixels >> 1) | (pixels >> 2)) & 01111111111111111ull) * 7)) | (((pixels >> 1) | (pixels >> 2)) & 00101101001011010ull); // S2TC conformance: always use the same order of a, a1 // swap std::swap(a1, a); // invert pixels ^= 01111111111111111ull; } buf[0] = a; buf[1] = a1; buf[2] = pixels & 0xFF; buf[3] = (pixels >> 8) & 0xFF; buf[4] = (pixels >> 16) & 0xFF; buf[5] = (pixels >> 24) & 0xFF; buf[6] = (pixels >> 32) & 0xFF; buf[7] = (pixels >> 40) & 0xFF; } int main(int argc, char **argv) { const char *infile = NULL, *outfile = NULL; int opt; while((opt = getopt(argc, argv, "i:o:")) != -1) { switch(opt) { case 'i': infile = optarg; break; case 'o': outfile = optarg; break; default: return usage(argv[0]); break; } } FILE *infh = infile ? fopen(infile, "rb") : stdin; if(!infh) { printf("opening input failed\n"); return 2; } FILE *outfh = outfile ? fopen(outfile, "wb") : stdout; if(!outfh) { printf("opening output failed\n"); return 2; } uint32_t h[32]; fread(h, sizeof(h), 1, infh); int fourcc = LittleLong(h[21]); int blocksize; DxtConversion mode; switch(fourcc) { case 0x31545844: blocksize = 8; mode = DXT1; break; case 0x33545844: blocksize = 16; mode = DXT3; break; case 0x35545844: blocksize = 16; mode = DXT5; break; default: fprintf(stderr, "Only DXT1, DXT3, DXT5 are supported!\n"); return 1; } fwrite(h, sizeof(h), 1, outfh); unsigned char buf[16]; while(fread(buf, blocksize, 1, infh) > 0) { if(mode == DXT1) convert_dxt1a(buf); else convert_dxt1(buf + 8); if(mode == DXT5) convert_dxt5(buf); fwrite(buf, blocksize, 1, outfh); } if(infile) fclose(infh); if(outfile) fclose(outfh); return 0; }