OSDN Git Service

aaef04016e2c33fb5e93c3dd7144ef25159c5827
[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 template <class T> inline T min(const T &a, const T &b)
9 {
10         if(b < a)
11                 return b;
12         return a;
13 }
14
15 template <class T> inline T max(const T &a, const T &b)
16 {
17         if(b > a)
18                 return b;
19         return a;
20 }
21
22 /* START stuff that originates from image.c in DarkPlaces */
23 int image_width, image_height;
24
25 typedef struct _TargaHeader
26 {
27         unsigned char   id_length, colormap_type, image_type;
28         unsigned short  colormap_index, colormap_length;
29         unsigned char   colormap_size;
30         unsigned short  x_origin, y_origin, width, height;
31         unsigned char   pixel_size, attributes;
32 }
33 TargaHeader;
34
35 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize)
36 {
37         int x, y, pix_inc, row_inci, runlen, alphabits;
38         unsigned char *image_buffer;
39         unsigned int *pixbufi;
40         const unsigned char *fin, *enddata;
41         TargaHeader targa_header;
42         unsigned int palettei[256];
43         union
44         {
45                 unsigned int i;
46                 unsigned char b[4];
47         }
48         bgra;
49
50         if (filesize < 19)
51                 return NULL;
52
53         enddata = f + filesize;
54
55         targa_header.id_length = f[0];
56         targa_header.colormap_type = f[1];
57         targa_header.image_type = f[2];
58
59         targa_header.colormap_index = f[3] + f[4] * 256;
60         targa_header.colormap_length = f[5] + f[6] * 256;
61         targa_header.colormap_size = f[7];
62         targa_header.x_origin = f[8] + f[9] * 256;
63         targa_header.y_origin = f[10] + f[11] * 256;
64         targa_header.width = image_width = f[12] + f[13] * 256;
65         targa_header.height = image_height = f[14] + f[15] * 256;
66         targa_header.pixel_size = f[16];
67         targa_header.attributes = f[17];
68
69         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
70         {
71                 printf("LoadTGA: invalid size\n");
72                 return NULL;
73         }
74
75         /* advance to end of header */
76         fin = f + 18;
77
78         /* skip TARGA image comment (usually 0 bytes) */
79         fin += targa_header.id_length;
80
81         /* read/skip the colormap if present (note: according to the TARGA spec it */
82         /* can be present even on 1color or greyscale images, just not used by */
83         /* the image data) */
84         if (targa_header.colormap_type)
85         {
86                 if (targa_header.colormap_length > 256)
87                 {
88                         printf("LoadTGA: only up to 256 colormap_length supported\n");
89                         return NULL;
90                 }
91                 if (targa_header.colormap_index)
92                 {
93                         printf("LoadTGA: colormap_index not supported\n");
94                         return NULL;
95                 }
96                 if (targa_header.colormap_size == 24)
97                 {
98                         for (x = 0;x < targa_header.colormap_length;x++)
99                         {
100                                 bgra.b[0] = *fin++;
101                                 bgra.b[1] = *fin++;
102                                 bgra.b[2] = *fin++;
103                                 bgra.b[3] = 255;
104                                 palettei[x] = bgra.i;
105                         }
106                 }
107                 else if (targa_header.colormap_size == 32)
108                 {
109                         memcpy(palettei, fin, targa_header.colormap_length*4);
110                         fin += targa_header.colormap_length * 4;
111                 }
112                 else
113                 {
114                         printf("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
115                         return NULL;
116                 }
117         }
118
119         /* check our pixel_size restrictions according to image_type */
120         switch (targa_header.image_type & ~8)
121         {
122         case 2:
123                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
124                 {
125                         printf("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
126                         return NULL;
127                 }
128                 break;
129         case 3:
130                 /* set up a palette to make the loader easier */
131                 for (x = 0;x < 256;x++)
132                 {
133                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
134                         bgra.b[3] = 255;
135                         palettei[x] = bgra.i;
136                 }
137                 /* fall through to colormap case */
138         case 1:
139                 if (targa_header.pixel_size != 8)
140                 {
141                         printf("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
142                         return NULL;
143                 }
144                 break;
145         default:
146                 printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
147                 return NULL;
148         }
149
150         if (targa_header.attributes & 0x10)
151         {
152                 printf("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
153                 return NULL;
154         }
155
156         /* number of attribute bits per pixel, we only support 0 or 8 */
157         alphabits = targa_header.attributes & 0x0F;
158         if (alphabits != 8 && alphabits != 0)
159         {
160                 printf("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
161                 return NULL;
162         }
163
164         image_buffer = (unsigned char *)malloc(image_width * image_height * 4);
165         if (!image_buffer)
166         {
167                 printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
168                 return NULL;
169         }
170
171         /* If bit 5 of attributes isn't set, the image has been stored from bottom to top */
172         if ((targa_header.attributes & 0x20) == 0)
173         {
174                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
175                 row_inci = -image_width*2;
176         }
177         else
178         {
179                 pixbufi = (unsigned int*)image_buffer;
180                 row_inci = 0;
181         }
182
183         x = 0;
184         y = 0;
185         pix_inc = 1;
186         if ((targa_header.image_type & ~8) == 2)
187                 pix_inc = (targa_header.pixel_size + 7) / 8;
188         switch (targa_header.image_type)
189         {
190         case 1: /* colormapped, uncompressed */
191         case 3: /* greyscale, uncompressed */
192                 if (fin + image_width * image_height * pix_inc > enddata)
193                         break;
194                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
195                         for (x = 0;x < image_width;x++)
196                                 *pixbufi++ = palettei[*fin++];
197                 break;
198         case 2:
199                 /* BGR or BGRA, uncompressed */
200                 if (fin + image_width * image_height * pix_inc > enddata)
201                         break;
202                 if (targa_header.pixel_size == 32 && alphabits)
203                 {
204                         for (y = 0;y < image_height;y++)
205                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
206                 }
207                 else
208                 {
209                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
210                         {
211                                 for (x = 0;x < image_width;x++, fin += pix_inc)
212                                 {
213                                         bgra.b[0] = fin[0];
214                                         bgra.b[1] = fin[1];
215                                         bgra.b[2] = fin[2];
216                                         bgra.b[3] = 255;
217                                         *pixbufi++ = bgra.i;
218                                 }
219                         }
220                 }
221                 break;
222         case 9: /* colormapped, RLE */
223         case 11: /* greyscale, RLE */
224                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
225                 {
226                         for (x = 0;x < image_width;)
227                         {
228                                 if (fin >= enddata)
229                                         break; /* error - truncated file */
230                                 runlen = *fin++;
231                                 if (runlen & 0x80)
232                                 {
233                                         /* RLE - all pixels the same color */
234                                         runlen += 1 - 0x80;
235                                         if (fin + pix_inc > enddata)
236                                                 break; /* error - truncated file */
237                                         if (x + runlen > image_width)
238                                                 break; /* error - line exceeds width */
239                                         bgra.i = palettei[*fin++];
240                                         for (;runlen--;x++)
241                                                 *pixbufi++ = bgra.i;
242                                 }
243                                 else
244                                 {
245                                         /* uncompressed - all pixels different color */
246                                         runlen++;
247                                         if (fin + pix_inc * runlen > enddata)
248                                                 break; /* error - truncated file */
249                                         if (x + runlen > image_width)
250                                                 break; /* error - line exceeds width */
251                                         for (;runlen--;x++)
252                                                 *pixbufi++ = palettei[*fin++];
253                                 }
254                         }
255
256                         if (x != image_width)
257                         {
258                                 /* pixbufi is useless now */
259                                 printf("LoadTGA: corrupt file\n");
260                                 break;
261                         }
262                 }
263                 break;
264         case 10:
265                 /* BGR or BGRA, RLE */
266                 if (targa_header.pixel_size == 32 && alphabits)
267                 {
268                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
269                         {
270                                 for (x = 0;x < image_width;)
271                                 {
272                                         if (fin >= enddata)
273                                                 break; /* error - truncated file */
274                                         runlen = *fin++;
275                                         if (runlen & 0x80)
276                                         {
277                                                 /* RLE - all pixels the same color */
278                                                 runlen += 1 - 0x80;
279                                                 if (fin + pix_inc > enddata)
280                                                         break; /* error - truncated file */
281                                                 if (x + runlen > image_width)
282                                                         break; /* error - line exceeds width */
283                                                 bgra.b[0] = fin[0];
284                                                 bgra.b[1] = fin[1];
285                                                 bgra.b[2] = fin[2];
286                                                 bgra.b[3] = fin[3];
287                                                 fin += pix_inc;
288                                                 for (;runlen--;x++)
289                                                         *pixbufi++ = bgra.i;
290                                         }
291                                         else
292                                         {
293                                                 /* uncompressed - all pixels different color */
294                                                 runlen++;
295                                                 if (fin + pix_inc * runlen > enddata)
296                                                         break; /* error - truncated file */
297                                                 if (x + runlen > image_width)
298                                                         break; /* error - line exceeds width */
299                                                 for (;runlen--;x++)
300                                                 {
301                                                         bgra.b[0] = fin[0];
302                                                         bgra.b[1] = fin[1];
303                                                         bgra.b[2] = fin[2];
304                                                         bgra.b[3] = fin[3];
305                                                         fin += pix_inc;
306                                                         *pixbufi++ = bgra.i;
307                                                 }
308                                         }
309                                 }
310
311                                 if (x != image_width)
312                                 {
313                                         /* pixbufi is useless now */
314                                         printf("LoadTGA: corrupt file\n");
315                                         break;
316                                 }
317                         }
318                 }
319                 else
320                 {
321                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
322                         {
323                                 for (x = 0;x < image_width;)
324                                 {
325                                         if (fin >= enddata)
326                                                 break; /* error - truncated file */
327                                         runlen = *fin++;
328                                         if (runlen & 0x80)
329                                         {
330                                                 /* RLE - all pixels the same color */
331                                                 runlen += 1 - 0x80;
332                                                 if (fin + pix_inc > enddata)
333                                                         break; /* error - truncated file */
334                                                 if (x + runlen > image_width)
335                                                         break; /* error - line exceeds width */
336                                                 bgra.b[0] = fin[0];
337                                                 bgra.b[1] = fin[1];
338                                                 bgra.b[2] = fin[2];
339                                                 bgra.b[3] = 255;
340                                                 fin += pix_inc;
341                                                 for (;runlen--;x++)
342                                                         *pixbufi++ = bgra.i;
343                                         }
344                                         else
345                                         {
346                                                 /* uncompressed - all pixels different color */
347                                                 runlen++;
348                                                 if (fin + pix_inc * runlen > enddata)
349                                                         break; /* error - truncated file */
350                                                 if (x + runlen > image_width)
351                                                         break; /* error - line exceeds width */
352                                                 for (;runlen--;x++)
353                                                 {
354                                                         bgra.b[0] = fin[0];
355                                                         bgra.b[1] = fin[1];
356                                                         bgra.b[2] = fin[2];
357                                                         bgra.b[3] = 255;
358                                                         fin += pix_inc;
359                                                         *pixbufi++ = bgra.i;
360                                                 }
361                                         }
362                                 }
363
364                                 if (x != image_width)
365                                 {
366                                         /* pixbufi is useless now */
367                                         printf("LoadTGA: corrupt file\n");
368                                         break;
369                                 }
370                         }
371                 }
372                 break;
373         default:
374                 /* unknown image_type */
375                 break;
376         }
377
378         return image_buffer;
379 }
380
381 // in can be the same as out
382 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int destwidth, int destheight)
383 {
384         const unsigned char *inrow;
385         int x, y, nextrow;
386         // note: if given odd width/height this discards the last row/column of
387         // pixels, rather than doing a proper box-filter scale down
388         inrow = in;
389         nextrow = *width * 4;
390         if (*width > destwidth)
391         {
392                 *width >>= 1;
393                 if (*height > destheight)
394                 {
395                         // reduce both
396                         *height >>= 1;
397                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
398                         {
399                                 for (in = inrow, x = 0;x < *width;x++)
400                                 {
401                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
402                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
403                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
404                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
405                                         out += 4;
406                                         in += 8;
407                                 }
408                         }
409                 }
410                 else
411                 {
412                         // reduce width
413                         for (y = 0;y < *height;y++, inrow += nextrow)
414                         {
415                                 for (in = inrow, x = 0;x < *width;x++)
416                                 {
417                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
418                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
419                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
420                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
421                                         out += 4;
422                                         in += 8;
423                                 }
424                         }
425                 }
426         }
427         else
428         {
429                 if (*height > destheight)
430                 {
431                         // reduce height
432                         *height >>= 1;
433                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
434                         {
435                                 for (in = inrow, x = 0;x < *width;x++)
436                                 {
437                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
438                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
439                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
440                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
441                                         out += 4;
442                                         in += 4;
443                                 }
444                         }
445                 }
446         }
447 }
448 unsigned char *FS_LoadFile(const char *fn, int *len)
449 {
450         unsigned char *buf = NULL;
451         int n;
452         FILE *f = fn ? fopen(fn, "rb") : stdin;
453         *len = 0;
454         if(!f)
455                 return NULL;
456         for(;;)
457         {
458                 buf = (unsigned char *) realloc(buf, *len + 65536);
459                 if(!buf)
460                 {
461                         if(fn)
462                                 fclose(f);
463                         free(buf);
464                         *len = 0;
465                         return NULL;
466                 }
467                 n = fread(buf + *len, 1, 65536, f);
468                 if(n < 0)
469                 {
470                         if(fn)
471                                 fclose(f);
472                         free(buf);
473                         *len = 0;
474                         return NULL;
475                 }
476                 *len += n;
477                 if(n < 65536)
478                         break;
479         }
480         if(fn)
481                 fclose(f);
482         return buf;
483 }
484 /* end of darkplaces stuff */
485
486
487
488
489 typedef struct
490 {
491         signed char r, g, b;
492 }
493 color_t;
494 inline bool operator<(const color_t &a, const color_t &b)
495 {
496         signed char d;
497         d = a.r - b.r;
498         if(d)
499                 return d < 0;
500         d = a.g - b.g;
501         if(d)
502                 return d < 0;
503         d = a.b - b.b;
504         return d < 0;
505 }
506
507 // 16 differences must fit in int
508 // i.e. a difference must be lower than 2^27
509
510 // shift right, rounded
511 #define SHRR(a,n) (((a) + (1 << ((n)-1))) >> (n))
512
513 inline int color_dist_avg(const color_t &a, const color_t &b)
514 {
515         int dr = a.r - b.r; // multiplier: 31 (-1..1)
516         int dg = a.g - b.g; // multiplier: 63 (-1..1)
517         int db = a.b - b.b; // multiplier: 31 (-1..1)
518         return ((dr*dr) << 2) + dg*dg + ((db*db) << 2);
519 }
520
521 inline int color_dist_yuv(const color_t &a, const color_t &b)
522 {
523         int dr = a.r - b.r; // multiplier: 31 (-1..1)
524         int dg = a.g - b.g; // multiplier: 63 (-1..1)
525         int db = a.b - b.b; // multiplier: 31 (-1..1)
526         int y = dr * 30*2 + dg * 59 + db * 11*2; // multiplier: 6259
527         int u = dr * 202 - y; // * 0.5 / (1 - 0.30)
528         int v = db * 202 - y; // * 0.5 / (1 - 0.11)
529         return ((y*y) << 1) + SHRR(u*u, 3) + SHRR(v*v, 4);
530         // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.30)) = 0.350
531         // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.11)) = 0.315
532 }
533
534 inline int color_dist_rgb(const color_t &a, const color_t &b)
535 {
536         int dr = a.r - b.r; // multiplier: 31 (-1..1)
537         int dg = a.g - b.g; // multiplier: 63 (-1..1)
538         int db = a.b - b.b; // multiplier: 31 (-1..1)
539         int y = dr * 21*2 + dg * 72 + db * 7*2; // multiplier: 6272
540         int u = dr * 202 - y; // * 0.5 / (1 - 0.21)
541         int v = db * 202 - y; // * 0.5 / (1 - 0.07)
542         return ((y*y) << 1) + SHRR(u*u, 3) + SHRR(v*v, 4);
543         // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.21)) = 0.395
544         // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.07)) = 0.328
545 }
546
547 inline int color_dist_srgb(const color_t &a, const color_t &b)
548 {
549         int dr = a.r * (int) a.r - b.r * (int) b.r; // multiplier: 31*31
550         int dg = a.g * (int) a.g - b.g * (int) b.g; // multiplier: 63*63
551         int db = a.b * (int) a.b - b.b * (int) b.b; // multiplier: 31*31
552         int y = dr * 21*2*2 + dg * 72 + db * 7*2*2; // multiplier: 393400
553         int u = dr * 409 - y; // * 0.5 / (1 - 0.30)
554         int v = db * 409 - y; // * 0.5 / (1 - 0.11)
555         int sy = SHRR(y, 3) * SHRR(y, 4);
556         int su = SHRR(u, 3) * SHRR(u, 4);
557         int sv = SHRR(v, 3) * SHRR(v, 4);
558         return SHRR(sy, 4) + SHRR(su, 8) + SHRR(sv, 9);
559         // weight for u: sqrt(2^-4) / (0.5 / (1 - 0.30)) = 0.350
560         // weight for v: sqrt(2^-5) / (0.5 / (1 - 0.11)) = 0.315
561 }
562
563 inline int srgb_get_y(const color_t &a)
564 {
565         // convert to linear
566         int r = a.r * (int) a.r;
567         int g = a.g * (int) a.g;
568         int b = a.b * (int) a.b;
569         // find luminance
570         int y = 37 * (r * 21*2*2 + g * 72 + b * 7*2*2); // multiplier: 14555800
571         // square root it (!)
572         y = sqrt(y); // now in range 0 to 3815
573         return y;
574 }
575
576 inline int color_dist_srgb_mixed(const color_t &a, const color_t &b)
577 {
578         // get Y
579         int ay = srgb_get_y(a);
580         int by = srgb_get_y(b);
581         // get UV
582         int au = a.r * 191 - ay;
583         int av = a.b * 191 - ay;
584         int bu = b.r * 191 - by;
585         int bv = b.b * 191 - by;
586         // get differences
587         int y = ay - by;
588         int u = au - bu;
589         int v = av - bv;
590         return ((y*y) << 3) + SHRR(u*u, 1) + SHRR(v*v, 2);
591         // weight for u: ???
592         // weight for v: ???
593 }
594
595 // FIXME this is likely broken
596 inline int color_dist_lab_srgb(const color_t &a, const color_t &b)
597 {
598         // undo sRGB
599         float ar = powf(a.r / 31.0f, 2.4f);
600         float ag = powf(a.g / 63.0f, 2.4f);
601         float ab = powf(a.b / 31.0f, 2.4f);
602         float br = powf(b.r / 31.0f, 2.4f);
603         float bg = powf(b.g / 63.0f, 2.4f);
604         float bb = powf(b.b / 31.0f, 2.4f);
605         // convert to CIE XYZ
606         float aX = 0.4124f * ar + 0.3576f * ag + 0.1805f * ab;
607         float aY = 0.2126f * ar + 0.7152f * ag + 0.0722f * ab;
608         float aZ = 0.0193f * ar + 0.1192f * ag + 0.9505f * ab;
609         float bX = 0.4124f * br + 0.3576f * bg + 0.1805f * bb;
610         float bY = 0.2126f * br + 0.7152f * bg + 0.0722f * bb;
611         float bZ = 0.0193f * br + 0.1192f * bg + 0.9505f * bb;
612         // convert to CIE Lab
613         float Xn = 0.3127f;
614         float Yn = 0.3290f;
615         float Zn = 0.3583f;
616         float aL = 116 * cbrtf(aY / Yn) - 16;
617         float aA = 500 * (cbrtf(aX / Xn) - cbrtf(aY / Yn));
618         float aB = 200 * (cbrtf(aY / Yn) - cbrtf(aZ / Zn));
619         float bL = 116 * cbrtf(bY / Yn) - 16;
620         float bA = 500 * (cbrtf(bX / Xn) - cbrtf(bY / Yn));
621         float bB = 200 * (cbrtf(bY / Yn) - cbrtf(bZ / Zn));
622         // euclidean distance, but moving weight away from A and B
623         return 1000 * ((aL - bL) * (aL - bL) + (aA - bA) * (aA - bA) + (aB - bB) * (aB - bB));
624 }
625
626 inline int color_dist_normalmap(const color_t &a, const color_t &b)
627 {
628         float ca[3], cb[3];
629         ca[0] = a.r / 31.0 * 2 - 1;
630         ca[1] = a.g / 63.0 * 2 - 1;
631         ca[2] = a.b / 31.0 * 2 - 1;
632         cb[0] = b.r / 31.0 * 2 - 1;
633         cb[1] = b.g / 63.0 * 2 - 1;
634         cb[2] = b.b / 31.0 * 2 - 1;
635
636         return
637                 500 *
638                 (
639                         (cb[0] - ca[0]) * (cb[0] - ca[0])
640                         +
641                         (cb[1] - ca[1]) * (cb[1] - ca[1])
642                         +
643                         (cb[2] - ca[2]) * (cb[2] - ca[2])
644                 )
645                 ;
646         // max value: 500 * (4 + 4 + 4) = 6000
647 }
648
649 typedef int ColorDistFunc(const color_t &a, const color_t &b);
650
651 inline int alpha_dist(unsigned char a, unsigned char b)
652 {
653         return (a - (int) b) * (a - (int) b);
654 }
655
656 template <class T, class F>
657 // n: input count
658 // m: total color count (including non-counted inputs)
659 // m >= n
660 void reduce_colors_inplace(T *c, int n, int m, F dist)
661 {
662         int i, j, k;
663         int bestsum = -1;
664         int besti = 0;
665         int bestj = 1;
666         int dists[m][n];
667         // first the square
668         for(i = 0; i < n; ++i)
669         {
670                 dists[i][i] = 0;
671                 for(j = i+1; j < n; ++j)
672                 {
673                         int d = dist(c[i], c[j]);
674                         dists[i][j] = dists[j][i] = d;
675                 }
676         }
677         // then the box
678         for(; i < m; ++i)
679         {
680                 for(j = 0; j < n; ++j)
681                 {
682                         int d = dist(c[i], c[j]);
683                         dists[i][j] = d;
684                 }
685         }
686         for(i = 0; i < m; ++i)
687                 for(j = i+1; j < m; ++j)
688                 {
689                         int sum = 0;
690                         for(k = 0; k < n; ++k)
691                         {
692                                 int di = dists[i][k];
693                                 int dj = dists[j][k];
694                                 int m  = min(di, dj);
695                                 sum += m;
696                         }
697                         if(bestsum < 0 || sum < bestsum)
698                         {
699                                 bestsum = sum;
700                                 besti = i;
701                                 bestj = j;
702                         }
703                 }
704         if(besti != 0)
705                 c[0] = c[besti];
706         if(bestj != 1)
707                 c[1] = c[bestj];
708 }
709 template <class T, class F>
710 void reduce_colors_inplace_2fixpoints(T *c, int n, int m, F dist, const T &fix0, const T &fix1)
711 {
712         int i, j, k;
713         int bestsum = -1;
714         int besti = 0;
715         int bestj = 1;
716         int dists[m+2][n];
717         // first the square
718         for(i = 0; i < n; ++i)
719         {
720                 dists[i][i] = 0;
721                 for(j = i+1; j < n; ++j)
722                 {
723                         int d = dist(c[i], c[j]);
724                         dists[i][j] = dists[j][i] = d;
725                 }
726         }
727         // then the box
728         for(; i < m; ++i)
729         {
730                 for(j = 0; j < n; ++j)
731                 {
732                         int d = dist(c[i], c[j]);
733                         dists[i][j] = d;
734                 }
735         }
736         // then the two extra rows
737         for(j = 0; j < n; ++j)
738         {
739                 int d = dist(fix0, c[j]);
740                 dists[m][j] = d;
741         }
742         for(j = 0; j < n; ++j)
743         {
744                 int d = dist(fix1, c[j]);
745                 dists[m+1][j] = d;
746         }
747         for(i = 0; i < m; ++i)
748                 for(j = i+1; j < m; ++j)
749                 {
750                         int sum = 0;
751                         for(k = 0; k < n; ++k)
752                         {
753                                 int di = dists[i][k];
754                                 int dj = dists[j][k];
755                                 int d0 = dists[m][k];
756                                 int d1 = dists[m+1][k];
757                                 int m  = min(min(di, dj), min(d0, d1));
758                                 sum += m;
759                         }
760                         if(bestsum < 0 || sum < bestsum)
761                         {
762                                 bestsum = sum;
763                                 besti = i;
764                                 bestj = j;
765                         }
766                 }
767         if(besti != 0)
768                 c[0] = c[besti];
769         if(bestj != 1)
770                 c[1] = c[bestj];
771 }
772
773 inline int diffuse(float *diff, float src)
774 {
775         int ret;
776         src += *diff;
777         ret = src;
778         *diff = (src - ret);
779         return ret;
780 }
781
782 void rgb565_image(unsigned char *out, const unsigned char *rgba, int w, int h, int alpharange)
783 {
784         int x, y;
785         float diffuse_r = 0;
786         float diffuse_g = 0;
787         float diffuse_b = 0;
788         float diffuse_a = 0;
789         for(y = 0; y < h; ++y)
790                 for(x = 0; x < w; ++x)
791                 {
792                         out[(x + y * w) * 4 + 2] = diffuse(&diffuse_r, rgba[(x + y * w) * 4 + 2] * 31.0 / 255.0);
793                         out[(x + y * w) * 4 + 1] = diffuse(&diffuse_g, rgba[(x + y * w) * 4 + 1] * 63.0 / 255.0);
794                         out[(x + y * w) * 4 + 0] = diffuse(&diffuse_b, rgba[(x + y * w) * 4 + 0] * 31.0 / 255.0);
795                         out[(x + y * w) * 4 + 3] = diffuse(&diffuse_a, rgba[(x + y * w) * 4 + 3] * (alpharange / 255.0));
796                 }
797 }
798
799 enum DxtMode
800 {
801         DXT1,
802         DXT3,
803         DXT5
804 };
805 enum ColorDistMode
806 {
807         RGB,
808         YUV,
809         SRGB,
810         SRGB_MIXED,
811         LAB,
812         AVG,
813         NORMALMAP
814 };
815
816 template<DxtMode dxt, ColorDistFunc ColorDist, bool userandom>
817 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, int nrandom)
818 {
819         color_t c[16 + (userandom ? nrandom : 0)];
820
821         unsigned char ca[16];
822         int n = 0, m = 0;
823         int x, y;
824
825         for(x = 0; x < w; ++x)
826                 for(y = 0; y < h; ++y)
827                 {
828                         c[n].r = rgba[(x + y * iw) * 4 + 2];
829                         c[n].g = rgba[(x + y * iw) * 4 + 1];
830                         c[n].b = rgba[(x + y * iw) * 4 + 0];
831                         if(dxt == DXT5)
832                                 ca[n]  = rgba[(x + y * iw) * 4 + 3];
833                         ++n;
834                 }
835
836         m = n;
837
838         if(userandom)
839         {
840                 color_t mins = c[0];
841                 color_t maxs = c[0];
842                 for(x = 1; x < n; ++x)
843                 {
844                         mins.r = min(mins.r, c[x].r);
845                         mins.g = min(mins.g, c[x].g);
846                         mins.b = min(mins.b, c[x].b);
847                         maxs.r = max(maxs.r, c[x].r);
848                         maxs.g = max(maxs.g, c[x].g);
849                         maxs.b = max(maxs.b, c[x].b);
850                 }
851                 color_t len = { maxs.r - mins.r + 1, maxs.g - mins.g + 1, maxs.b - mins.b + 1 };
852                 for(x = 0; x < nrandom; ++x)
853                 {
854                         c[m].r = mins.r + rand() % len.r;
855                         c[m].g = mins.g + rand() % len.g;
856                         c[m].b = mins.b + rand() % len.b;
857                         ++m;
858                 }
859         }
860
861         reduce_colors_inplace(c, n, m, ColorDist);
862         if(dxt == DXT5)
863         {
864                 reduce_colors_inplace_2fixpoints(ca, n, n, alpha_dist, (unsigned char) 0, (unsigned char) 255);
865                 if(ca[1] < ca[0])
866                 {
867                         ca[2] = ca[0];
868                         ca[0] = ca[1];
869                         ca[1] = ca[2];
870                 }
871         }
872         if(c[1] < c[0])
873         {
874                 c[2] = c[0];
875                 c[0] = c[1];
876                 c[1] = c[2];
877         }
878
879         memset(out, 0, 16);
880         switch(dxt)
881         {
882                 case DXT5:
883                         out[0] = ca[0];
884                         out[1] = ca[1];
885                 case DXT3:
886                         out[8] = ((c[0].g & 0x07) << 5) | c[0].b;
887                         out[9] = (c[0].r << 3) | (c[0].g >> 3);
888                         out[10] = ((c[1].g & 0x07) << 5) | c[1].b;
889                         out[11] = (c[1].r << 3) | (c[1].g >> 3);
890                         break;
891                 case DXT1:
892                         out[0] = ((c[0].g & 0x07) << 5) | c[0].b;
893                         out[1] = (c[0].r << 3) | (c[0].g >> 3);
894                         out[2] = ((c[1].g & 0x07) << 5) | c[1].b;
895                         out[3] = (c[1].r << 3) | (c[1].g >> 3);
896                         break;
897         }
898         for(x = 0; x < w; ++x)
899                 for(y = 0; y < h; ++y)
900                 {
901                         int pindex = (x+y*4);
902                         c[2].r = rgba[(x + y * iw) * 4 + 2];
903                         c[2].g = rgba[(x + y * iw) * 4 + 1];
904                         c[2].b = rgba[(x + y * iw) * 4 + 0];
905                         ca[2]  = rgba[(x + y * iw) * 4 + 3];
906                         switch(dxt)
907                         {
908                                 case DXT5:
909                                         {
910                                                 int da[4];
911                                                 int bitindex = pindex * 3;
912                                                 da[0] = alpha_dist(ca[0], ca[2]);
913                                                 da[1] = alpha_dist(ca[1], ca[2]);
914                                                 da[2] = alpha_dist(0, ca[2]);
915                                                 da[3] = alpha_dist(255, ca[2]);
916                                                 if(da[2] <= da[0] && da[2] <= da[1] && da[2] <= da[3])
917                                                 {
918                                                         // 6
919                                                         ++bitindex;
920                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
921                                                         ++bitindex;
922                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
923                                                 }
924                                                 else if(da[3] <= da[0] && da[3] <= da[1])
925                                                 {
926                                                         // 7
927                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
928                                                         ++bitindex;
929                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
930                                                         ++bitindex;
931                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
932                                                 }
933                                                 else if(da[0] <= da[1])
934                                                 {
935                                                         // 0
936                                                 }
937                                                 else
938                                                 {
939                                                         // 1
940                                                         out[bitindex / 8 + 2] |= (1 << (bitindex % 8));
941                                                 }
942                                         }
943                                         if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
944                                         {
945                                                 int bitindex = pindex * 2;
946                                                 out[bitindex / 8 + 12] |= (1 << (bitindex % 8));
947                                         }
948                                         break;
949                                 case DXT3:
950                                         {
951                                                 int bitindex = pindex * 4;
952                                                 out[bitindex / 8 + 0] |= (ca[2] << (bitindex % 8));
953                                         }
954                                         if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
955                                         {
956                                                 int bitindex = pindex * 2;
957                                                 out[bitindex / 8 + 12] |= (1 << (bitindex % 8));
958                                         }
959                                         break;
960                                 case DXT1:
961                                         {
962                                                 int bitindex = pindex * 2;
963                                                 if(!ca[2])
964                                                         out[bitindex / 8 + 4] |= (3 << (bitindex % 8));
965                                                 else if(ColorDist(c[0], c[2]) > ColorDist(c[1], c[2]))
966                                                         out[bitindex / 8 + 4] |= (1 << (bitindex % 8));
967                                         }
968                                         break;
969                         }
970                 }
971 }
972
973 // compile time dispatch magic
974 template<DxtMode dxt, ColorDistFunc ColorDist>
975 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, int nrandom)
976 {
977         if(nrandom)
978                 s2tc_encode_block<dxt, ColorDist, true>(out, rgba, iw, w, h, nrandom);
979         else
980                 s2tc_encode_block<dxt, ColorDist, false>(out, rgba, iw, w, h, nrandom);
981 }
982
983 template<ColorDistFunc ColorDist>
984 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, DxtMode dxt, int nrandom)
985 {
986         switch(dxt)
987         {
988                 case DXT1:
989                         s2tc_encode_block<DXT1, ColorDist>(out, rgba, iw, w, h, nrandom);
990                         break;
991                 case DXT3:
992                         s2tc_encode_block<DXT3, ColorDist>(out, rgba, iw, w, h, nrandom);
993                         break;
994                 default:
995                 case DXT5:
996                         s2tc_encode_block<DXT5, ColorDist>(out, rgba, iw, w, h, nrandom);
997                         break;
998         }
999 }
1000
1001 void s2tc_encode_block(unsigned char *out, const unsigned char *rgba, int iw, int w, int h, DxtMode dxt, ColorDistMode cd, int nrandom)
1002 {
1003         switch(cd)
1004         {
1005                 case RGB:
1006                         s2tc_encode_block<color_dist_rgb>(out, rgba, iw, w, h, dxt, nrandom);
1007                         break;
1008                 case YUV:
1009                         s2tc_encode_block<color_dist_yuv>(out, rgba, iw, w, h, dxt, nrandom);
1010                         break;
1011                 case SRGB:
1012                         s2tc_encode_block<color_dist_srgb>(out, rgba, iw, w, h, dxt, nrandom);
1013                         break;
1014                 case SRGB_MIXED:
1015                         s2tc_encode_block<color_dist_srgb_mixed>(out, rgba, iw, w, h, dxt, nrandom);
1016                         break;
1017                 case LAB:
1018                         s2tc_encode_block<color_dist_lab_srgb>(out, rgba, iw, w, h, dxt, nrandom);
1019                         break;
1020                 case AVG:
1021                         s2tc_encode_block<color_dist_avg>(out, rgba, iw, w, h, dxt, nrandom);
1022                         break;
1023                 case NORMALMAP:
1024                         s2tc_encode_block<color_dist_normalmap>(out, rgba, iw, w, h, dxt, nrandom);
1025                         break;
1026         }
1027 }
1028
1029 uint32_t LittleLong(uint32_t w)
1030 {
1031         union
1032         {
1033                 unsigned char c[4];
1034                 uint32_t u;
1035         }
1036         un;
1037         un.c[0] = w;
1038         un.c[1] = w >> 8;
1039         un.c[2] = w >> 16;
1040         un.c[3] = w >> 24;
1041         return un.u;
1042 }
1043
1044 int usage(const char *me)
1045 {
1046         fprintf(stderr, "usage:\n"
1047                         "%s \n"
1048                         "    [-i infile.tga]\n"
1049                         "    [-o outfile.dds]\n"
1050                         "    [-t {DXT1|DXT3|DXT5}]\n"
1051                         "    [-r randomcount]\n"
1052                         "    [-c {RGB|YUV|SRGB|SRGB_MIXED|LAB|AVG|NORMALMAP}]\n",
1053                         me);
1054         return 1;
1055 }
1056
1057 int main(int argc, char **argv)
1058 {
1059         int x, y;
1060         unsigned char *pic, *picdata;
1061         int piclen;
1062         const char *fourcc;
1063         int blocksize, alpharange;
1064         DxtMode dxt = DXT1;
1065         ColorDistMode cd = RGB;
1066         int nrandom = 0;
1067         const char *infile = NULL, *outfile = NULL;
1068         FILE *outfh;
1069
1070         int opt;
1071         while((opt = getopt(argc, argv, "i:o:t:r:c:")) != -1)
1072         {
1073                 switch(opt)
1074                 {
1075                         case 'i':
1076                                 infile = optarg;
1077                                 break;
1078                         case 'o':
1079                                 outfile = optarg;
1080                                 break;
1081                         case 't':
1082                                 if(!strcasecmp(optarg, "DXT1"))
1083                                         dxt = DXT1;
1084                                 else if(!strcasecmp(optarg, "DXT3"))
1085                                         dxt = DXT3;
1086                                 else if(!strcasecmp(optarg, "DXT5"))
1087                                         dxt = DXT5;
1088                                 else
1089                                         return usage(argv[0]);
1090                                 break;
1091                         case 'r':
1092                                 nrandom = atoi(optarg);
1093                                 break;
1094                         case 'c':
1095                                 if(!strcasecmp(optarg, "RGB"))
1096                                         cd = RGB;
1097                                 else if(!strcasecmp(optarg, "YUV"))
1098                                         cd = YUV;
1099                                 else if(!strcasecmp(optarg, "SRGB"))
1100                                         cd = SRGB;
1101                                 else if(!strcasecmp(optarg, "SRGB_MIXED"))
1102                                         cd = SRGB_MIXED;
1103                                 else if(!strcasecmp(optarg, "LAB"))
1104                                         cd = LAB;
1105                                 else if(!strcasecmp(optarg, "AVG"))
1106                                         cd = AVG;
1107                                 else if(!strcasecmp(optarg, "NORMALMAP"))
1108                                         cd = NORMALMAP;
1109                                 else
1110                                         return usage(argv[0]);
1111                                 break;
1112                         default:
1113                                 return usage(argv[0]);
1114                                 break;
1115                 }
1116         }
1117
1118         outfh = outfile ? fopen(outfile, "wb") : stdout;
1119         if(!outfh)
1120         {
1121                 printf("opening output failed\n");
1122                 return 2;
1123         }
1124
1125         picdata = FS_LoadFile(infile, &piclen);
1126         if(!picdata)
1127         {
1128                 printf("FS_LoadFile failed\n");
1129                 return 2;
1130         }
1131         pic = LoadTGA_BGRA(picdata, piclen);
1132
1133         int mipcount = 0;
1134         while(image_width >= (1 << mipcount) || image_height >= (1 << mipcount))
1135                 ++mipcount;
1136         // now, (1 << mipcount) >= width, height
1137
1138         switch(dxt)
1139         {
1140                 case DXT1:
1141                         blocksize = 8;
1142                         alpharange = 1;
1143                         fourcc = "DXT1";
1144                         break;
1145                 case DXT3:
1146                         blocksize = 16;
1147                         alpharange = 15;
1148                         fourcc = "DXT3";
1149                         break;
1150                 default:
1151                 case DXT5:
1152                         blocksize = 16;
1153                         alpharange = 255;
1154                         fourcc = "DXT5";
1155                         break;
1156         }
1157
1158         {
1159                 uint32_t picsize = LittleLong(((image_width+3)/4) * ((image_height+3)/4) * blocksize);
1160                 uint32_t ddssize = LittleLong(0x7c);
1161                 uint32_t dds_flags = LittleLong(0xa1007);
1162                 uint32_t one = LittleLong(1);
1163                 uint32_t zero = LittleLong(0);
1164                 uint32_t dds_format_flags = LittleLong(0x04);
1165                 uint32_t dds_caps1 = LittleLong(0x401008);
1166                 uint32_t dds_caps2 = LittleLong(0);
1167                 uint32_t dds_format_size = LittleLong(32);
1168                 uint32_t dds_mipcount = LittleLong(mipcount);
1169
1170                 //0
1171                 fwrite("DDS ", 4, 1, outfh);
1172                 fwrite(&ddssize, 4, 1, outfh);
1173                 fwrite(&dds_flags, 4, 1, outfh);
1174                 fwrite(&image_height, 4, 1, outfh);
1175                 fwrite(&image_width, 4, 1, outfh);
1176                 fwrite(&picsize, 4, 1, outfh);
1177                 fwrite(&one, 4, 1, outfh);
1178                 fwrite(&dds_mipcount, 4, 1, outfh);
1179
1180                 //32
1181                 fwrite(&zero, 4, 1, outfh);
1182                 fwrite(&zero, 4, 1, outfh);
1183                 fwrite(&zero, 4, 1, outfh);
1184                 fwrite(&zero, 4, 1, outfh);
1185                 fwrite(&zero, 4, 1, outfh);
1186                 fwrite(&zero, 4, 1, outfh);
1187                 fwrite(&zero, 4, 1, outfh);
1188                 fwrite(&zero, 4, 1, outfh);
1189
1190                 //64
1191                 fwrite(&zero, 4, 1, outfh);
1192                 fwrite(&zero, 4, 1, outfh);
1193                 fwrite(&zero, 4, 1, outfh);
1194                 fwrite(&dds_format_size, 4, 1, outfh);
1195                 fwrite(&dds_format_flags, 4, 1, outfh);
1196                 fwrite(fourcc, 4, 1, outfh);
1197                 fwrite("\x18\x00\x00\x00", 4, 1, outfh);
1198                 fwrite("\x00\x00\xff\x00", 4, 1, outfh);
1199
1200                 //96
1201                 fwrite("\x00\xff\x00\x00", 4, 1, outfh);
1202                 fwrite("\xff\x00\x00\x00", 4, 1, outfh);
1203                 fwrite(&zero, 4, 1, outfh);
1204                 fwrite(&dds_caps1, 4, 1, outfh);
1205                 fwrite(&dds_caps2, 4, 1, outfh);
1206                 fwrite(&zero, 4, 1, outfh);
1207                 fwrite(&zero, 4, 1, outfh);
1208                 fwrite(&zero, 4, 1, outfh);
1209         }
1210
1211         unsigned char *opic = (unsigned char *) malloc(image_width * image_height * 4);
1212         for(;;)
1213         {
1214                 rgb565_image(opic, pic, image_width, image_height, alpharange);
1215                 for(y = 0; y < image_height; y += 4)
1216                         for(x = 0; x < image_width; x += 4)
1217                         {
1218                                 unsigned char block[16];
1219                                 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);
1220                                 fwrite(block, blocksize, 1, outfh);
1221                         }
1222                 if(image_width == 1 && image_height == 1)
1223                         break;
1224                 Image_MipReduce32(pic, pic, &image_width, &image_height, 1, 1);
1225         }
1226
1227         if(outfile)
1228                 fclose(outfh);
1229
1230         return 0;
1231 }