OSDN Git Service

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