2 * Copyright (C) 2011 Rudolf Polzer All Rights Reserved.
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:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
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.
21 #define S2TC_LICENSE_IDENTIFIER s2tc_compress_license
22 #include "s2tc_license.h"
30 #include "s2tc_common.h"
32 #ifdef ENABLE_RUNTIME_LINKING
37 typedef void (tx_compress_dxtn_t)(GLint srccomps, GLint width, GLint height,
38 const GLubyte *srcPixData, GLenum destformat,
39 GLubyte *dest, GLint dstRowStride);
41 tx_compress_dxtn_t *tx_compress_dxtn = NULL;
42 inline bool load_libraries(const char *n)
44 void *l = dlopen(n, RTLD_NOW);
47 fprintf(stderr, "Cannot load library: %s\n", dlerror());
50 tx_compress_dxtn = (tx_compress_dxtn_t *) dlsym(l, "tx_compress_dxtn");
53 fprintf(stderr, "The selected libtxc_dxtn.so does not contain all required symbols.");
66 /* START stuff that originates from image.c in DarkPlaces */
68 Thu Jul 14 21:58:02 CEST 2011
69 21:25:25 @divVerent | LordHavoc: http://paste.pocoo.org/show/438804/
70 21:25:31 @divVerent | can I have this code under a MIT-style license?
71 21:59:58 @LordHavoc | divVerent: yeah, have them under any license you want
72 22:00:11 @LordHavoc | divVerent: my attitude toward licenses is generally "WTFPL would be preferably if I could use it" :P
73 22:04:01 @divVerent | LordHavoc: okay, thanks
76 int image_width, image_height;
78 typedef struct _TargaHeader
80 unsigned char id_length, colormap_type, image_type;
81 unsigned short colormap_index, colormap_length;
82 unsigned char colormap_size;
83 unsigned short x_origin, y_origin, width, height;
84 unsigned char pixel_size, attributes;
88 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize)
90 int x, y, pix_inc, row_inci, runlen, alphabits;
91 unsigned char *image_buffer;
92 unsigned int *pixbufi;
93 const unsigned char *fin, *enddata;
94 TargaHeader targa_header;
95 unsigned int palettei[256];
106 enddata = f + filesize;
108 targa_header.id_length = f[0];
109 targa_header.colormap_type = f[1];
110 targa_header.image_type = f[2];
112 targa_header.colormap_index = f[3] + f[4] * 256;
113 targa_header.colormap_length = f[5] + f[6] * 256;
114 targa_header.colormap_size = f[7];
115 targa_header.x_origin = f[8] + f[9] * 256;
116 targa_header.y_origin = f[10] + f[11] * 256;
117 targa_header.width = image_width = f[12] + f[13] * 256;
118 targa_header.height = image_height = f[14] + f[15] * 256;
119 targa_header.pixel_size = f[16];
120 targa_header.attributes = f[17];
122 if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
124 printf("LoadTGA: invalid size\n");
128 /* advance to end of header */
131 /* skip TARGA image comment (usually 0 bytes) */
132 fin += targa_header.id_length;
134 /* read/skip the colormap if present (note: according to the TARGA spec it */
135 /* can be present even on 1color or greyscale images, just not used by */
136 /* the image data) */
137 if (targa_header.colormap_type)
139 if (targa_header.colormap_length > 256)
141 printf("LoadTGA: only up to 256 colormap_length supported\n");
144 if (targa_header.colormap_index)
146 printf("LoadTGA: colormap_index not supported\n");
149 if (targa_header.colormap_size == 24)
151 for (x = 0;x < targa_header.colormap_length;x++)
157 palettei[x] = bgra.i;
160 else if (targa_header.colormap_size == 32)
162 memcpy(palettei, fin, targa_header.colormap_length*4);
163 fin += targa_header.colormap_length * 4;
167 printf("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
172 /* check our pixel_size restrictions according to image_type */
173 switch (targa_header.image_type & ~8)
176 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
178 printf("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
183 /* set up a palette to make the loader easier */
184 for (x = 0;x < 256;x++)
186 bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
188 palettei[x] = bgra.i;
190 /* fall through to colormap case */
192 if (targa_header.pixel_size != 8)
194 printf("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
199 printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
203 if (targa_header.attributes & 0x10)
205 printf("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
209 /* number of attribute bits per pixel, we only support 0 or 8 */
210 alphabits = targa_header.attributes & 0x0F;
211 if (alphabits != 8 && alphabits != 0)
213 printf("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
217 image_buffer = (unsigned char *)malloc(image_width * image_height * 4);
220 printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
224 /* If bit 5 of attributes isn't set, the image has been stored from bottom to top */
225 if ((targa_header.attributes & 0x20) == 0)
227 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
228 row_inci = -image_width*2;
232 pixbufi = (unsigned int*)image_buffer;
239 if ((targa_header.image_type & ~8) == 2)
240 pix_inc = (targa_header.pixel_size + 7) / 8;
241 switch (targa_header.image_type)
243 case 1: /* colormapped, uncompressed */
244 case 3: /* greyscale, uncompressed */
245 if (fin + image_width * image_height * pix_inc > enddata)
247 for (y = 0;y < image_height;y++, pixbufi += row_inci)
248 for (x = 0;x < image_width;x++)
249 *pixbufi++ = palettei[*fin++];
252 /* BGR or BGRA, uncompressed */
253 if (fin + image_width * image_height * pix_inc > enddata)
255 if (targa_header.pixel_size == 32 && alphabits)
257 for (y = 0;y < image_height;y++)
258 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
262 for (y = 0;y < image_height;y++, pixbufi += row_inci)
264 for (x = 0;x < image_width;x++, fin += pix_inc)
275 case 9: /* colormapped, RLE */
276 case 11: /* greyscale, RLE */
277 for (y = 0;y < image_height;y++, pixbufi += row_inci)
279 for (x = 0;x < image_width;)
282 break; /* error - truncated file */
286 /* RLE - all pixels the same color */
288 if (fin + pix_inc > enddata)
289 break; /* error - truncated file */
290 if (x + runlen > image_width)
291 break; /* error - line exceeds width */
292 bgra.i = palettei[*fin++];
298 /* uncompressed - all pixels different color */
300 if (fin + pix_inc * runlen > enddata)
301 break; /* error - truncated file */
302 if (x + runlen > image_width)
303 break; /* error - line exceeds width */
305 *pixbufi++ = palettei[*fin++];
309 if (x != image_width)
311 /* pixbufi is useless now */
312 printf("LoadTGA: corrupt file\n");
318 /* BGR or BGRA, RLE */
319 if (targa_header.pixel_size == 32 && alphabits)
321 for (y = 0;y < image_height;y++, pixbufi += row_inci)
323 for (x = 0;x < image_width;)
326 break; /* error - truncated file */
330 /* RLE - all pixels the same color */
332 if (fin + pix_inc > enddata)
333 break; /* error - truncated file */
334 if (x + runlen > image_width)
335 break; /* error - line exceeds width */
346 /* uncompressed - all pixels different color */
348 if (fin + pix_inc * runlen > enddata)
349 break; /* error - truncated file */
350 if (x + runlen > image_width)
351 break; /* error - line exceeds width */
364 if (x != image_width)
366 /* pixbufi is useless now */
367 printf("LoadTGA: corrupt file\n");
374 for (y = 0;y < image_height;y++, pixbufi += row_inci)
376 for (x = 0;x < image_width;)
379 break; /* error - truncated file */
383 /* RLE - all pixels the same color */
385 if (fin + pix_inc > enddata)
386 break; /* error - truncated file */
387 if (x + runlen > image_width)
388 break; /* error - line exceeds width */
399 /* uncompressed - all pixels different color */
401 if (fin + pix_inc * runlen > enddata)
402 break; /* error - truncated file */
403 if (x + runlen > image_width)
404 break; /* error - line exceeds width */
417 if (x != image_width)
419 /* pixbufi is useless now */
420 printf("LoadTGA: corrupt file\n");
427 /* unknown image_type */
434 // in can be the same as out
435 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int destwidth, int destheight)
437 const unsigned char *inrow;
439 // note: if given odd width/height this discards the last row/column of
440 // pixels, rather than doing a proper box-filter scale down
442 nextrow = *width * 4;
443 if (*width > destwidth)
446 if (*height > destheight)
450 for (y = 0;y < *height;y++, inrow += nextrow * 2)
452 for (in = inrow, x = 0;x < *width;x++)
454 out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2);
455 out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
456 out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
457 out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
466 for (y = 0;y < *height;y++, inrow += nextrow)
468 for (in = inrow, x = 0;x < *width;x++)
470 out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
471 out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
472 out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
473 out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
482 if (*height > destheight)
486 for (y = 0;y < *height;y++, inrow += nextrow * 2)
488 for (in = inrow, x = 0;x < *width;x++)
490 out[0] = (unsigned char) ((in[0] + in[nextrow ]) >> 1);
491 out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
492 out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
493 out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
501 unsigned char *FS_LoadFile(const char *fn, int *len)
503 unsigned char *buf = NULL;
505 FILE *f = fn ? fopen(fn, "rb") : stdin;
511 buf = (unsigned char *) realloc(buf, *len + 65536);
520 n = fread(buf + *len, 1, 65536, f);
537 /* END of darkplaces stuff */
539 uint32_t LittleLong(uint32_t w)
554 int usage(const char *me)
556 fprintf(stderr, "usage:\n"
559 " [-o outfile.dds]\n"
560 " [-t {DXT1|DXT3|DXT5}]\n"
561 #ifdef ENABLE_RUNTIME_LINKING
562 " [-l path_to_libtxc_dxtn.so]\n"
569 int main(int argc, char **argv)
571 GLenum dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
572 const char *infile = NULL, *outfile = NULL;
574 #ifdef ENABLE_RUNTIME_LINKING
575 const char *library = "libtxc_dxtn.so";
579 while((opt = getopt(argc, argv, "i:o:t:"
580 #ifdef ENABLE_RUNTIME_LINKING
594 if(!strcasecmp(optarg, "DXT1"))
595 dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
596 else if(!strcasecmp(optarg, "DXT3"))
597 dxt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
598 else if(!strcasecmp(optarg, "DXT5"))
599 dxt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
601 return usage(argv[0]);
603 #ifdef ENABLE_RUNTIME_LINKING
609 return usage(argv[0]);
613 #ifdef ENABLE_RUNTIME_LINKING
614 if(!load_libraries(library))
618 FILE *outfh = outfile ? fopen(outfile, "wb") : stdout;
621 printf("opening output failed\n");
626 unsigned char *picdata = FS_LoadFile(infile, &piclen);
629 printf("FS_LoadFile failed\n");
633 unsigned char *pic = LoadTGA_BGRA(picdata, piclen);
634 for(int x = 0; x < image_width*image_height; ++x)
635 std::swap(pic[4*x], pic[4*x+2]);
637 while(image_width >= (1 << mipcount) || image_height >= (1 << mipcount))
639 // now, (1 << mipcount) >= width, height
645 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
649 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
654 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
661 bool alphapixels = false;
662 for(int y = 0; y < image_height; ++y)
663 for(int x = 0; x < image_width; ++x)
664 if(pic[(y*image_width+x)*4+3] != 255)
670 uint32_t zero = LittleLong(0);
671 uint32_t dds_picsize = LittleLong(((image_width+3)/4) * ((image_height+3)/4) * blocksize);
672 uint32_t dds_mipcount = LittleLong(mipcount);
673 uint32_t dds_width = LittleLong(image_width);
674 uint32_t dds_height = LittleLong(image_height);
677 fwrite("DDS ", 4, 1, outfh);
678 fwrite("\x7c\x00\x00\x00", 4, 1, outfh);
679 fwrite("\x07\x10\x0a\x00", 4, 1, outfh);
680 fwrite(&dds_height, 4, 1, outfh);
681 fwrite(&dds_width, 4, 1, outfh);
682 fwrite(&dds_picsize, 4, 1, outfh);
683 fwrite(&zero, 4, 1, outfh);
684 fwrite(&dds_mipcount, 4, 1, outfh);
687 fwrite(&zero, 4, 1, outfh);
688 fwrite(&zero, 4, 1, outfh);
689 fwrite(&zero, 4, 1, outfh);
690 fwrite(&zero, 4, 1, outfh);
691 fwrite(&zero, 4, 1, outfh);
692 fwrite(&zero, 4, 1, outfh);
693 fwrite(&zero, 4, 1, outfh);
694 fwrite(&zero, 4, 1, outfh);
697 fwrite(&zero, 4, 1, outfh);
698 fwrite(&zero, 4, 1, outfh);
699 fwrite(&zero, 4, 1, outfh);
700 fwrite("\x20\x00\x00\x00", 4, 1, outfh);
701 fwrite(alphapixels ? "\x05\x00\x00\x00" : "\x04\x00\x00\x00", 4, 1, outfh);
702 fwrite(fourcc, 4, 1, outfh);
703 fwrite(&zero, 4, 1, outfh);
704 fwrite(&zero, 4, 1, outfh);
707 fwrite(&zero, 4, 1, outfh);
708 fwrite(&zero, 4, 1, outfh);
709 fwrite(&zero, 4, 1, outfh);
710 fwrite("\x08\x10\x40\x00", 4, 1, outfh);
711 fwrite(&zero, 4, 1, outfh);
712 fwrite(&zero, 4, 1, outfh);
713 fwrite(&zero, 4, 1, outfh);
714 fwrite(&zero, 4, 1, outfh);
719 int blocks_w = (image_width + 3) / 4;
720 int blocks_h = (image_height + 3) / 4;
721 GLubyte *obuf = (GLubyte *) malloc(blocksize * blocks_w * blocks_h);
722 tx_compress_dxtn(4, image_width, image_height, pic, dxt, obuf, blocks_w * blocksize);
723 fwrite(obuf, blocksize * blocks_w * blocks_h, 1, outfh);
725 if(image_width == 1 && image_height == 1)
727 Image_MipReduce32(pic, pic, &image_width, &image_height, 1, 1);