OSDN Git Service

implement tx_compress_dxtn
[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
8 #include "s2tc_compressor.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                         "    [-r randomcount]\n"
498                         "    [-c {RGB|YUV|SRGB|SRGB_MIXED|LAB|AVG|NORMALMAP}]\n",
499                         me);
500         return 1;
501 }
502
503 int main(int argc, char **argv)
504 {
505         int x, y;
506         unsigned char *pic, *picdata;
507         int piclen;
508         const char *fourcc;
509         int blocksize, alpharange;
510         DxtMode dxt = DXT1;
511         ColorDistMode cd = RGB;
512         int nrandom = 0;
513         const char *infile = NULL, *outfile = NULL;
514         FILE *outfh;
515
516         int opt;
517         while((opt = getopt(argc, argv, "i:o:t:r:c:")) != -1)
518         {
519                 switch(opt)
520                 {
521                         case 'i':
522                                 infile = optarg;
523                                 break;
524                         case 'o':
525                                 outfile = optarg;
526                                 break;
527                         case 't':
528                                 if(!strcasecmp(optarg, "DXT1"))
529                                         dxt = DXT1;
530                                 else if(!strcasecmp(optarg, "DXT3"))
531                                         dxt = DXT3;
532                                 else if(!strcasecmp(optarg, "DXT5"))
533                                         dxt = DXT5;
534                                 else
535                                         return usage(argv[0]);
536                                 break;
537                         case 'r':
538                                 nrandom = atoi(optarg);
539                                 break;
540                         case 'c':
541                                 if(!strcasecmp(optarg, "RGB"))
542                                         cd = RGB;
543                                 else if(!strcasecmp(optarg, "YUV"))
544                                         cd = YUV;
545                                 else if(!strcasecmp(optarg, "SRGB"))
546                                         cd = SRGB;
547                                 else if(!strcasecmp(optarg, "SRGB_MIXED"))
548                                         cd = SRGB_MIXED;
549                                 else if(!strcasecmp(optarg, "LAB"))
550                                         cd = LAB;
551                                 else if(!strcasecmp(optarg, "AVG"))
552                                         cd = AVG;
553                                 else if(!strcasecmp(optarg, "NORMALMAP"))
554                                         cd = NORMALMAP;
555                                 else
556                                         return usage(argv[0]);
557                                 break;
558                         default:
559                                 return usage(argv[0]);
560                                 break;
561                 }
562         }
563
564         outfh = outfile ? fopen(outfile, "wb") : stdout;
565         if(!outfh)
566         {
567                 printf("opening output failed\n");
568                 return 2;
569         }
570
571         picdata = FS_LoadFile(infile, &piclen);
572         if(!picdata)
573         {
574                 printf("FS_LoadFile failed\n");
575                 return 2;
576         }
577         pic = LoadTGA_BGRA(picdata, piclen);
578
579         int mipcount = 0;
580         while(image_width >= (1 << mipcount) || image_height >= (1 << mipcount))
581                 ++mipcount;
582         // now, (1 << mipcount) >= width, height
583
584         switch(dxt)
585         {
586                 case DXT1:
587                         blocksize = 8;
588                         alpharange = 1;
589                         fourcc = "DXT1";
590                         break;
591                 case DXT3:
592                         blocksize = 16;
593                         alpharange = 15;
594                         fourcc = "DXT3";
595                         break;
596                 default:
597                 case DXT5:
598                         blocksize = 16;
599                         alpharange = 255;
600                         fourcc = "DXT5";
601                         break;
602         }
603
604         {
605                 uint32_t picsize = LittleLong(((image_width+3)/4) * ((image_height+3)/4) * blocksize);
606                 uint32_t ddssize = LittleLong(0x7c);
607                 uint32_t dds_flags = LittleLong(0xa1007);
608                 uint32_t one = LittleLong(1);
609                 uint32_t zero = LittleLong(0);
610                 uint32_t dds_format_flags = LittleLong(0x04);
611                 uint32_t dds_caps1 = LittleLong(0x401008);
612                 uint32_t dds_caps2 = LittleLong(0);
613                 uint32_t dds_format_size = LittleLong(32);
614                 uint32_t dds_mipcount = LittleLong(mipcount);
615
616                 //0
617                 fwrite("DDS ", 4, 1, outfh);
618                 fwrite(&ddssize, 4, 1, outfh);
619                 fwrite(&dds_flags, 4, 1, outfh);
620                 fwrite(&image_height, 4, 1, outfh);
621                 fwrite(&image_width, 4, 1, outfh);
622                 fwrite(&picsize, 4, 1, outfh);
623                 fwrite(&one, 4, 1, outfh);
624                 fwrite(&dds_mipcount, 4, 1, outfh);
625
626                 //32
627                 fwrite(&zero, 4, 1, outfh);
628                 fwrite(&zero, 4, 1, outfh);
629                 fwrite(&zero, 4, 1, outfh);
630                 fwrite(&zero, 4, 1, outfh);
631                 fwrite(&zero, 4, 1, outfh);
632                 fwrite(&zero, 4, 1, outfh);
633                 fwrite(&zero, 4, 1, outfh);
634                 fwrite(&zero, 4, 1, outfh);
635
636                 //64
637                 fwrite(&zero, 4, 1, outfh);
638                 fwrite(&zero, 4, 1, outfh);
639                 fwrite(&zero, 4, 1, outfh);
640                 fwrite(&dds_format_size, 4, 1, outfh);
641                 fwrite(&dds_format_flags, 4, 1, outfh);
642                 fwrite(fourcc, 4, 1, outfh);
643                 fwrite("\x18\x00\x00\x00", 4, 1, outfh);
644                 fwrite("\x00\x00\xff\x00", 4, 1, outfh);
645
646                 //96
647                 fwrite("\x00\xff\x00\x00", 4, 1, outfh);
648                 fwrite("\xff\x00\x00\x00", 4, 1, outfh);
649                 fwrite(&zero, 4, 1, outfh);
650                 fwrite(&dds_caps1, 4, 1, outfh);
651                 fwrite(&dds_caps2, 4, 1, outfh);
652                 fwrite(&zero, 4, 1, outfh);
653                 fwrite(&zero, 4, 1, outfh);
654                 fwrite(&zero, 4, 1, outfh);
655         }
656
657         unsigned char *opic = (unsigned char *) malloc(image_width * image_height * 4);
658         for(;;)
659         {
660                 rgb565_image(opic, pic, image_width, image_height, 4, 1, alpharange);
661                 for(y = 0; y < image_height; y += 4)
662                         for(x = 0; x < image_width; x += 4)
663                         {
664                                 unsigned char block[16];
665                                 s2tc_encode_block(block, opic + (x + y * image_width) * 4, image_width, min(4, image_width - x), min(4, image_height - y), dxt, cd, nrandom);
666                                 fwrite(block, blocksize, 1, outfh);
667                         }
668                 if(image_width == 1 && image_height == 1)
669                         break;
670                 Image_MipReduce32(pic, pic, &image_width, &image_height, 1, 1);
671         }
672
673         if(outfile)
674                 fclose(outfh);
675
676         return 0;
677 }