OSDN Git Service

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