OSDN Git Service

082f7d745a6bd172b26c87f544107fdd0f4dae54
[android-x86/external-s2tc.git] / s2tc.cpp
1 #include <math.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <getopt.h>
7 #include "libtxc_dxtn.h"
8 #include "s2tc_common.h"
9
10 /* START stuff that originates from image.c in DarkPlaces */
11 int image_width, image_height;
12
13 typedef struct _TargaHeader
14 {
15         unsigned char   id_length, colormap_type, image_type;
16         unsigned short  colormap_index, colormap_length;
17         unsigned char   colormap_size;
18         unsigned short  x_origin, y_origin, width, height;
19         unsigned char   pixel_size, attributes;
20 }
21 TargaHeader;
22
23 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize)
24 {
25         int x, y, pix_inc, row_inci, runlen, alphabits;
26         unsigned char *image_buffer;
27         unsigned int *pixbufi;
28         const unsigned char *fin, *enddata;
29         TargaHeader targa_header;
30         unsigned int palettei[256];
31         union
32         {
33                 unsigned int i;
34                 unsigned char b[4];
35         }
36         bgra;
37
38         if (filesize < 19)
39                 return NULL;
40
41         enddata = f + filesize;
42
43         targa_header.id_length = f[0];
44         targa_header.colormap_type = f[1];
45         targa_header.image_type = f[2];
46
47         targa_header.colormap_index = f[3] + f[4] * 256;
48         targa_header.colormap_length = f[5] + f[6] * 256;
49         targa_header.colormap_size = f[7];
50         targa_header.x_origin = f[8] + f[9] * 256;
51         targa_header.y_origin = f[10] + f[11] * 256;
52         targa_header.width = image_width = f[12] + f[13] * 256;
53         targa_header.height = image_height = f[14] + f[15] * 256;
54         targa_header.pixel_size = f[16];
55         targa_header.attributes = f[17];
56
57         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
58         {
59                 printf("LoadTGA: invalid size\n");
60                 return NULL;
61         }
62
63         /* advance to end of header */
64         fin = f + 18;
65
66         /* skip TARGA image comment (usually 0 bytes) */
67         fin += targa_header.id_length;
68
69         /* read/skip the colormap if present (note: according to the TARGA spec it */
70         /* can be present even on 1color or greyscale images, just not used by */
71         /* the image data) */
72         if (targa_header.colormap_type)
73         {
74                 if (targa_header.colormap_length > 256)
75                 {
76                         printf("LoadTGA: only up to 256 colormap_length supported\n");
77                         return NULL;
78                 }
79                 if (targa_header.colormap_index)
80                 {
81                         printf("LoadTGA: colormap_index not supported\n");
82                         return NULL;
83                 }
84                 if (targa_header.colormap_size == 24)
85                 {
86                         for (x = 0;x < targa_header.colormap_length;x++)
87                         {
88                                 bgra.b[0] = *fin++;
89                                 bgra.b[1] = *fin++;
90                                 bgra.b[2] = *fin++;
91                                 bgra.b[3] = 255;
92                                 palettei[x] = bgra.i;
93                         }
94                 }
95                 else if (targa_header.colormap_size == 32)
96                 {
97                         memcpy(palettei, fin, targa_header.colormap_length*4);
98                         fin += targa_header.colormap_length * 4;
99                 }
100                 else
101                 {
102                         printf("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
103                         return NULL;
104                 }
105         }
106
107         /* check our pixel_size restrictions according to image_type */
108         switch (targa_header.image_type & ~8)
109         {
110         case 2:
111                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
112                 {
113                         printf("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
114                         return NULL;
115                 }
116                 break;
117         case 3:
118                 /* set up a palette to make the loader easier */
119                 for (x = 0;x < 256;x++)
120                 {
121                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
122                         bgra.b[3] = 255;
123                         palettei[x] = bgra.i;
124                 }
125                 /* fall through to colormap case */
126         case 1:
127                 if (targa_header.pixel_size != 8)
128                 {
129                         printf("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
130                         return NULL;
131                 }
132                 break;
133         default:
134                 printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
135                 return NULL;
136         }
137
138         if (targa_header.attributes & 0x10)
139         {
140                 printf("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
141                 return NULL;
142         }
143
144         /* number of attribute bits per pixel, we only support 0 or 8 */
145         alphabits = targa_header.attributes & 0x0F;
146         if (alphabits != 8 && alphabits != 0)
147         {
148                 printf("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
149                 return NULL;
150         }
151
152         image_buffer = (unsigned char *)malloc(image_width * image_height * 4);
153         if (!image_buffer)
154         {
155                 printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
156                 return NULL;
157         }
158
159         /* If bit 5 of attributes isn't set, the image has been stored from bottom to top */
160         if ((targa_header.attributes & 0x20) == 0)
161         {
162                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
163                 row_inci = -image_width*2;
164         }
165         else
166         {
167                 pixbufi = (unsigned int*)image_buffer;
168                 row_inci = 0;
169         }
170
171         x = 0;
172         y = 0;
173         pix_inc = 1;
174         if ((targa_header.image_type & ~8) == 2)
175                 pix_inc = (targa_header.pixel_size + 7) / 8;
176         switch (targa_header.image_type)
177         {
178         case 1: /* colormapped, uncompressed */
179         case 3: /* greyscale, uncompressed */
180                 if (fin + image_width * image_height * pix_inc > enddata)
181                         break;
182                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
183                         for (x = 0;x < image_width;x++)
184                                 *pixbufi++ = palettei[*fin++];
185                 break;
186         case 2:
187                 /* BGR or BGRA, uncompressed */
188                 if (fin + image_width * image_height * pix_inc > enddata)
189                         break;
190                 if (targa_header.pixel_size == 32 && alphabits)
191                 {
192                         for (y = 0;y < image_height;y++)
193                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
194                 }
195                 else
196                 {
197                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
198                         {
199                                 for (x = 0;x < image_width;x++, fin += pix_inc)
200                                 {
201                                         bgra.b[0] = fin[0];
202                                         bgra.b[1] = fin[1];
203                                         bgra.b[2] = fin[2];
204                                         bgra.b[3] = 255;
205                                         *pixbufi++ = bgra.i;
206                                 }
207                         }
208                 }
209                 break;
210         case 9: /* colormapped, RLE */
211         case 11: /* greyscale, RLE */
212                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
213                 {
214                         for (x = 0;x < image_width;)
215                         {
216                                 if (fin >= enddata)
217                                         break; /* error - truncated file */
218                                 runlen = *fin++;
219                                 if (runlen & 0x80)
220                                 {
221                                         /* RLE - all pixels the same color */
222                                         runlen += 1 - 0x80;
223                                         if (fin + pix_inc > enddata)
224                                                 break; /* error - truncated file */
225                                         if (x + runlen > image_width)
226                                                 break; /* error - line exceeds width */
227                                         bgra.i = palettei[*fin++];
228                                         for (;runlen--;x++)
229                                                 *pixbufi++ = bgra.i;
230                                 }
231                                 else
232                                 {
233                                         /* uncompressed - all pixels different color */
234                                         runlen++;
235                                         if (fin + pix_inc * runlen > enddata)
236                                                 break; /* error - truncated file */
237                                         if (x + runlen > image_width)
238                                                 break; /* error - line exceeds width */
239                                         for (;runlen--;x++)
240                                                 *pixbufi++ = palettei[*fin++];
241                                 }
242                         }
243
244                         if (x != image_width)
245                         {
246                                 /* pixbufi is useless now */
247                                 printf("LoadTGA: corrupt file\n");
248                                 break;
249                         }
250                 }
251                 break;
252         case 10:
253                 /* BGR or BGRA, RLE */
254                 if (targa_header.pixel_size == 32 && alphabits)
255                 {
256                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
257                         {
258                                 for (x = 0;x < image_width;)
259                                 {
260                                         if (fin >= enddata)
261                                                 break; /* error - truncated file */
262                                         runlen = *fin++;
263                                         if (runlen & 0x80)
264                                         {
265                                                 /* RLE - all pixels the same color */
266                                                 runlen += 1 - 0x80;
267                                                 if (fin + pix_inc > enddata)
268                                                         break; /* error - truncated file */
269                                                 if (x + runlen > image_width)
270                                                         break; /* error - line exceeds width */
271                                                 bgra.b[0] = fin[0];
272                                                 bgra.b[1] = fin[1];
273                                                 bgra.b[2] = fin[2];
274                                                 bgra.b[3] = fin[3];
275                                                 fin += pix_inc;
276                                                 for (;runlen--;x++)
277                                                         *pixbufi++ = bgra.i;
278                                         }
279                                         else
280                                         {
281                                                 /* uncompressed - all pixels different color */
282                                                 runlen++;
283                                                 if (fin + pix_inc * runlen > enddata)
284                                                         break; /* error - truncated file */
285                                                 if (x + runlen > image_width)
286                                                         break; /* error - line exceeds width */
287                                                 for (;runlen--;x++)
288                                                 {
289                                                         bgra.b[0] = fin[0];
290                                                         bgra.b[1] = fin[1];
291                                                         bgra.b[2] = fin[2];
292                                                         bgra.b[3] = fin[3];
293                                                         fin += pix_inc;
294                                                         *pixbufi++ = bgra.i;
295                                                 }
296                                         }
297                                 }
298
299                                 if (x != image_width)
300                                 {
301                                         /* pixbufi is useless now */
302                                         printf("LoadTGA: corrupt file\n");
303                                         break;
304                                 }
305                         }
306                 }
307                 else
308                 {
309                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
310                         {
311                                 for (x = 0;x < image_width;)
312                                 {
313                                         if (fin >= enddata)
314                                                 break; /* error - truncated file */
315                                         runlen = *fin++;
316                                         if (runlen & 0x80)
317                                         {
318                                                 /* RLE - all pixels the same color */
319                                                 runlen += 1 - 0x80;
320                                                 if (fin + pix_inc > enddata)
321                                                         break; /* error - truncated file */
322                                                 if (x + runlen > image_width)
323                                                         break; /* error - line exceeds width */
324                                                 bgra.b[0] = fin[0];
325                                                 bgra.b[1] = fin[1];
326                                                 bgra.b[2] = fin[2];
327                                                 bgra.b[3] = 255;
328                                                 fin += pix_inc;
329                                                 for (;runlen--;x++)
330                                                         *pixbufi++ = bgra.i;
331                                         }
332                                         else
333                                         {
334                                                 /* uncompressed - all pixels different color */
335                                                 runlen++;
336                                                 if (fin + pix_inc * runlen > enddata)
337                                                         break; /* error - truncated file */
338                                                 if (x + runlen > image_width)
339                                                         break; /* error - line exceeds width */
340                                                 for (;runlen--;x++)
341                                                 {
342                                                         bgra.b[0] = fin[0];
343                                                         bgra.b[1] = fin[1];
344                                                         bgra.b[2] = fin[2];
345                                                         bgra.b[3] = 255;
346                                                         fin += pix_inc;
347                                                         *pixbufi++ = bgra.i;
348                                                 }
349                                         }
350                                 }
351
352                                 if (x != image_width)
353                                 {
354                                         /* pixbufi is useless now */
355                                         printf("LoadTGA: corrupt file\n");
356                                         break;
357                                 }
358                         }
359                 }
360                 break;
361         default:
362                 /* unknown image_type */
363                 break;
364         }
365
366         return image_buffer;
367 }
368
369 // in can be the same as out
370 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int destwidth, int destheight)
371 {
372         const unsigned char *inrow;
373         int x, y, nextrow;
374         // note: if given odd width/height this discards the last row/column of
375         // pixels, rather than doing a proper box-filter scale down
376         inrow = in;
377         nextrow = *width * 4;
378         if (*width > destwidth)
379         {
380                 *width >>= 1;
381                 if (*height > destheight)
382                 {
383                         // reduce both
384                         *height >>= 1;
385                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
386                         {
387                                 for (in = inrow, x = 0;x < *width;x++)
388                                 {
389                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
390                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
391                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
392                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
393                                         out += 4;
394                                         in += 8;
395                                 }
396                         }
397                 }
398                 else
399                 {
400                         // reduce width
401                         for (y = 0;y < *height;y++, inrow += nextrow)
402                         {
403                                 for (in = inrow, x = 0;x < *width;x++)
404                                 {
405                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
406                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
407                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
408                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
409                                         out += 4;
410                                         in += 8;
411                                 }
412                         }
413                 }
414         }
415         else
416         {
417                 if (*height > destheight)
418                 {
419                         // reduce height
420                         *height >>= 1;
421                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
422                         {
423                                 for (in = inrow, x = 0;x < *width;x++)
424                                 {
425                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
426                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
427                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
428                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
429                                         out += 4;
430                                         in += 4;
431                                 }
432                         }
433                 }
434         }
435 }
436 unsigned char *FS_LoadFile(const char *fn, int *len)
437 {
438         unsigned char *buf = NULL;
439         int n;
440         FILE *f = fn ? fopen(fn, "rb") : stdin;
441         *len = 0;
442         if(!f)
443                 return NULL;
444         for(;;)
445         {
446                 buf = (unsigned char *) realloc(buf, *len + 65536);
447                 if(!buf)
448                 {
449                         if(fn)
450                                 fclose(f);
451                         free(buf);
452                         *len = 0;
453                         return NULL;
454                 }
455                 n = fread(buf + *len, 1, 65536, f);
456                 if(n < 0)
457                 {
458                         if(fn)
459                                 fclose(f);
460                         free(buf);
461                         *len = 0;
462                         return NULL;
463                 }
464                 *len += n;
465                 if(n < 65536)
466                         break;
467         }
468         if(fn)
469                 fclose(f);
470         return buf;
471 }
472 /* end of darkplaces stuff */
473
474 uint32_t LittleLong(uint32_t w)
475 {
476         union
477         {
478                 unsigned char c[4];
479                 uint32_t u;
480         }
481         un;
482         un.c[0] = w;
483         un.c[1] = w >> 8;
484         un.c[2] = w >> 16;
485         un.c[3] = w >> 24;
486         return un.u;
487 }
488
489 int usage(const char *me)
490 {
491         fprintf(stderr, "usage:\n"
492                         "%s \n"
493                         "    [-i infile.tga]\n"
494                         "    [-o outfile.dds]\n"
495                         "    [-t {DXT1|DXT3|DXT5}]\n"
496                         "    [-r randomcount]\n"
497                         "    [-c {RGB|YUV|SRGB|SRGB_MIXED|LAB|AVG|WAVG|NORMALMAP}]\n",
498                         me);
499         return 1;
500 }
501
502 int main(int argc, char **argv)
503 {
504         unsigned char *pic, *picdata;
505         int piclen;
506         const char *fourcc;
507         int blocksize;
508         GLenum dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
509         const char *infile = NULL, *outfile = NULL;
510         FILE *outfh;
511         char buf[80];
512
513         int opt;
514         while((opt = getopt(argc, argv, "i:o:t:r:c:")) != -1)
515         {
516                 switch(opt)
517                 {
518                         case 'i':
519                                 infile = optarg;
520                                 break;
521                         case 'o':
522                                 outfile = optarg;
523                                 break;
524                         case 't':
525                                 if(!strcasecmp(optarg, "DXT1"))
526                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
527                                 else if(!strcasecmp(optarg, "DXT3"))
528                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
529                                 else if(!strcasecmp(optarg, "DXT5"))
530                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
531                                 else
532                                         return usage(argv[0]);
533                                 break;
534                         case 'r':
535                                 snprintf(buf, sizeof(buf), "S2TC_RANDOM_COLORS=%d", atoi(optarg));
536                                 buf[sizeof(buf)-1] = 0;
537                                 putenv(buf);
538                                 break;
539                         case 'c':
540                                 snprintf(buf, sizeof(buf), "S2TC_COLORDIST_MODE=%s", optarg);
541                                 buf[sizeof(buf)-1] = 0;
542                                 putenv(buf);
543                                 break;
544                         default:
545                                 return usage(argv[0]);
546                                 break;
547                 }
548         }
549
550         outfh = outfile ? fopen(outfile, "wb") : stdout;
551         if(!outfh)
552         {
553                 printf("opening output failed\n");
554                 return 2;
555         }
556
557         picdata = FS_LoadFile(infile, &piclen);
558         if(!picdata)
559         {
560                 printf("FS_LoadFile failed\n");
561                 return 2;
562         }
563         pic = LoadTGA_BGRA(picdata, piclen);
564
565         int mipcount = 0;
566         while(image_width >= (1 << mipcount) || image_height >= (1 << mipcount))
567                 ++mipcount;
568         // now, (1 << mipcount) >= width, height
569
570         switch(dxt)
571         {
572                 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
573                         blocksize = 8;
574                         fourcc = "DXT1";
575                         break;
576                 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
577                         blocksize = 16;
578                         fourcc = "DXT3";
579                         break;
580                 default:
581                 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
582                         blocksize = 16;
583                         fourcc = "DXT5";
584                         break;
585         }
586
587         {
588                 uint32_t picsize = LittleLong(((image_width+3)/4) * ((image_height+3)/4) * blocksize);
589                 uint32_t ddssize = LittleLong(0x7c);
590                 uint32_t dds_flags = LittleLong(0xa1007);
591                 uint32_t one = LittleLong(1);
592                 uint32_t zero = LittleLong(0);
593                 uint32_t dds_format_flags = LittleLong(0x04);
594                 uint32_t dds_caps1 = LittleLong(0x401008);
595                 uint32_t dds_caps2 = LittleLong(0);
596                 uint32_t dds_format_size = LittleLong(32);
597                 uint32_t dds_mipcount = LittleLong(mipcount);
598
599                 //0
600                 fwrite("DDS ", 4, 1, outfh);
601                 fwrite(&ddssize, 4, 1, outfh);
602                 fwrite(&dds_flags, 4, 1, outfh);
603                 fwrite(&image_height, 4, 1, outfh);
604                 fwrite(&image_width, 4, 1, outfh);
605                 fwrite(&picsize, 4, 1, outfh);
606                 fwrite(&one, 4, 1, outfh);
607                 fwrite(&dds_mipcount, 4, 1, outfh);
608
609                 //32
610                 fwrite(&zero, 4, 1, outfh);
611                 fwrite(&zero, 4, 1, outfh);
612                 fwrite(&zero, 4, 1, outfh);
613                 fwrite(&zero, 4, 1, outfh);
614                 fwrite(&zero, 4, 1, outfh);
615                 fwrite(&zero, 4, 1, outfh);
616                 fwrite(&zero, 4, 1, outfh);
617                 fwrite(&zero, 4, 1, outfh);
618
619                 //64
620                 fwrite(&zero, 4, 1, outfh);
621                 fwrite(&zero, 4, 1, outfh);
622                 fwrite(&zero, 4, 1, outfh);
623                 fwrite(&dds_format_size, 4, 1, outfh);
624                 fwrite(&dds_format_flags, 4, 1, outfh);
625                 fwrite(fourcc, 4, 1, outfh);
626                 fwrite("\x18\x00\x00\x00", 4, 1, outfh);
627                 fwrite("\x00\x00\xff\x00", 4, 1, outfh);
628
629                 //96
630                 fwrite("\x00\xff\x00\x00", 4, 1, outfh);
631                 fwrite("\xff\x00\x00\x00", 4, 1, outfh);
632                 fwrite(&zero, 4, 1, outfh);
633                 fwrite(&dds_caps1, 4, 1, outfh);
634                 fwrite(&dds_caps2, 4, 1, outfh);
635                 fwrite(&zero, 4, 1, outfh);
636                 fwrite(&zero, 4, 1, outfh);
637                 fwrite(&zero, 4, 1, outfh);
638         }
639
640         for(;;)
641         {
642                 int blocks_w = (image_width + 3) / 4;
643                 int blocks_h = (image_height + 3) / 4;
644                 GLubyte *obuf = (GLubyte *) malloc(blocksize * blocks_w * blocks_h);
645                 tx_compress_dxtn(4, image_width, image_height, pic, dxt, obuf, blocks_w * blocksize);
646                 fwrite(obuf, blocksize * blocks_w * blocks_h, 1, outfh);
647                 free(obuf);
648                 if(image_width == 1 && image_height == 1)
649                         break;
650                 Image_MipReduce32(pic, pic, &image_width, &image_height, 1, 1);
651         }
652
653         if(outfile)
654                 fclose(outfh);
655
656         return 0;
657 }