OSDN Git Service

add Android.mk to build for android
[android-x86/external-s2tc.git] / s2tc_compress.c
1 /*
2  * Copyright (C) 2011  Rudolf Polzer   All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * RUDOLF POLZER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  */
21 #define S2TC_LICENSE_IDENTIFIER s2tc_compress_license
22 #include "s2tc_license.h"
23
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31
32 #ifdef ENABLE_RUNTIME_LINKING
33 #include <dlfcn.h>
34 #include <GL/gl.h>
35 typedef void (tx_compress_dxtn_t)(GLint srccomps, GLint width, GLint height,
36                       const GLubyte *srcPixData, GLenum destformat,
37                       GLubyte *dest, GLint dstRowStride);
38 tx_compress_dxtn_t *tx_compress_dxtn = NULL;
39 bool load_libraries(const char *n)
40 {
41         void *l = dlopen(n, RTLD_NOW);
42         if(!l)
43         {
44                 fprintf(stderr, "Cannot load library: %s\n", dlerror());
45                 return false;
46         }
47         tx_compress_dxtn = (tx_compress_dxtn_t *) dlsym(l, "tx_compress_dxtn");
48         if(!tx_compress_dxtn)
49         {
50                 fprintf(stderr, "The selected libtxc_dxtn.so does not contain all required symbols.");
51                 dlclose(l);
52                 return false;
53         }
54         return true;
55 }
56 #else
57 #include "txc_dxtn.h"
58 #endif
59
60 /* START stuff that originates from image.c in DarkPlaces */
61 /*
62         Thu Jul 14 21:58:02 CEST 2011
63         21:25:25        @divVerent | LordHavoc: http://paste.pocoo.org/show/438804/
64         21:25:31        @divVerent | can I have this code under a MIT-style license?
65         21:59:58        @LordHavoc | divVerent: yeah, have them under any license you want
66         22:00:11        @LordHavoc | divVerent: my attitude toward licenses is generally "WTFPL would be preferably if I could use it" :P
67         22:04:01        @divVerent | LordHavoc: okay, thanks
68 */
69
70 int image_width, image_height;
71
72 typedef struct _TargaHeader
73 {
74         unsigned char   id_length, colormap_type, image_type;
75         unsigned short  colormap_index, colormap_length;
76         unsigned char   colormap_size;
77         unsigned short  x_origin, y_origin, width, height;
78         unsigned char   pixel_size, attributes;
79 }
80 TargaHeader;
81
82 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize)
83 {
84         int x, y, pix_inc, row_inci, runlen, alphabits;
85         unsigned char *image_buffer;
86         unsigned int *pixbufi;
87         const unsigned char *fin, *enddata;
88         TargaHeader targa_header;
89         unsigned int palettei[256];
90         union
91         {
92                 unsigned int i;
93                 unsigned char b[4];
94         }
95         bgra;
96
97         if (filesize < 19)
98                 return NULL;
99
100         enddata = f + filesize;
101
102         targa_header.id_length = f[0];
103         targa_header.colormap_type = f[1];
104         targa_header.image_type = f[2];
105
106         targa_header.colormap_index = f[3] + f[4] * 256;
107         targa_header.colormap_length = f[5] + f[6] * 256;
108         targa_header.colormap_size = f[7];
109         targa_header.x_origin = f[8] + f[9] * 256;
110         targa_header.y_origin = f[10] + f[11] * 256;
111         targa_header.width = image_width = f[12] + f[13] * 256;
112         targa_header.height = image_height = f[14] + f[15] * 256;
113         targa_header.pixel_size = f[16];
114         targa_header.attributes = f[17];
115
116         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
117         {
118                 printf("LoadTGA: invalid size\n");
119                 return NULL;
120         }
121
122         /* advance to end of header */
123         fin = f + 18;
124
125         /* skip TARGA image comment (usually 0 bytes) */
126         fin += targa_header.id_length;
127
128         /* read/skip the colormap if present (note: according to the TARGA spec it */
129         /* can be present even on 1color or greyscale images, just not used by */
130         /* the image data) */
131         if (targa_header.colormap_type)
132         {
133                 if (targa_header.colormap_length > 256)
134                 {
135                         printf("LoadTGA: only up to 256 colormap_length supported\n");
136                         return NULL;
137                 }
138                 if (targa_header.colormap_index)
139                 {
140                         printf("LoadTGA: colormap_index not supported\n");
141                         return NULL;
142                 }
143                 if (targa_header.colormap_size == 24)
144                 {
145                         for (x = 0;x < targa_header.colormap_length;x++)
146                         {
147                                 bgra.b[0] = *fin++;
148                                 bgra.b[1] = *fin++;
149                                 bgra.b[2] = *fin++;
150                                 bgra.b[3] = 255;
151                                 palettei[x] = bgra.i;
152                         }
153                 }
154                 else if (targa_header.colormap_size == 32)
155                 {
156                         memcpy(palettei, fin, targa_header.colormap_length*4);
157                         fin += targa_header.colormap_length * 4;
158                 }
159                 else
160                 {
161                         printf("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
162                         return NULL;
163                 }
164         }
165
166         /* check our pixel_size restrictions according to image_type */
167         switch (targa_header.image_type & ~8)
168         {
169         case 2:
170                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
171                 {
172                         printf("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
173                         return NULL;
174                 }
175                 break;
176         case 3:
177                 /* set up a palette to make the loader easier */
178                 for (x = 0;x < 256;x++)
179                 {
180                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
181                         bgra.b[3] = 255;
182                         palettei[x] = bgra.i;
183                 }
184                 /* fall through to colormap case */
185         case 1:
186                 if (targa_header.pixel_size != 8)
187                 {
188                         printf("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
189                         return NULL;
190                 }
191                 break;
192         default:
193                 printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
194                 return NULL;
195         }
196
197         if (targa_header.attributes & 0x10)
198         {
199                 printf("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
200                 return NULL;
201         }
202
203         /* number of attribute bits per pixel, we only support 0 or 8 */
204         alphabits = targa_header.attributes & 0x0F;
205         if (alphabits != 8 && alphabits != 0)
206         {
207                 printf("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
208                 return NULL;
209         }
210
211         image_buffer = (unsigned char *)malloc(image_width * image_height * 4);
212         if (!image_buffer)
213         {
214                 printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
215                 return NULL;
216         }
217
218         /* If bit 5 of attributes isn't set, the image has been stored from bottom to top */
219         if ((targa_header.attributes & 0x20) == 0)
220         {
221                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
222                 row_inci = -image_width*2;
223         }
224         else
225         {
226                 pixbufi = (unsigned int*)image_buffer;
227                 row_inci = 0;
228         }
229
230         pix_inc = 1;
231         if ((targa_header.image_type & ~8) == 2)
232                 pix_inc = (targa_header.pixel_size + 7) / 8;
233         switch (targa_header.image_type)
234         {
235         case 1: /* colormapped, uncompressed */
236         case 3: /* greyscale, uncompressed */
237                 if (fin + image_width * image_height * pix_inc > enddata)
238                         break;
239                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
240                         for (x = 0;x < image_width;x++)
241                                 *pixbufi++ = palettei[*fin++];
242                 break;
243         case 2:
244                 /* BGR or BGRA, uncompressed */
245                 if (fin + image_width * image_height * pix_inc > enddata)
246                         break;
247                 if (targa_header.pixel_size == 32 && alphabits)
248                 {
249                         for (y = 0;y < image_height;y++)
250                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
251                 }
252                 else
253                 {
254                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
255                         {
256                                 for (x = 0;x < image_width;x++, fin += pix_inc)
257                                 {
258                                         bgra.b[0] = fin[0];
259                                         bgra.b[1] = fin[1];
260                                         bgra.b[2] = fin[2];
261                                         bgra.b[3] = 255;
262                                         *pixbufi++ = bgra.i;
263                                 }
264                         }
265                 }
266                 break;
267         case 9: /* colormapped, RLE */
268         case 11: /* greyscale, RLE */
269                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
270                 {
271                         for (x = 0;x < image_width;)
272                         {
273                                 if (fin >= enddata)
274                                         break; /* error - truncated file */
275                                 runlen = *fin++;
276                                 if (runlen & 0x80)
277                                 {
278                                         /* RLE - all pixels the same color */
279                                         runlen += 1 - 0x80;
280                                         if (fin + pix_inc > enddata)
281                                                 break; /* error - truncated file */
282                                         if (x + runlen > image_width)
283                                                 break; /* error - line exceeds width */
284                                         bgra.i = palettei[*fin++];
285                                         for (;runlen--;x++)
286                                                 *pixbufi++ = bgra.i;
287                                 }
288                                 else
289                                 {
290                                         /* uncompressed - all pixels different color */
291                                         runlen++;
292                                         if (fin + pix_inc * runlen > enddata)
293                                                 break; /* error - truncated file */
294                                         if (x + runlen > image_width)
295                                                 break; /* error - line exceeds width */
296                                         for (;runlen--;x++)
297                                                 *pixbufi++ = palettei[*fin++];
298                                 }
299                         }
300
301                         if (x != image_width)
302                         {
303                                 /* pixbufi is useless now */
304                                 printf("LoadTGA: corrupt file\n");
305                                 break;
306                         }
307                 }
308                 break;
309         case 10:
310                 /* BGR or BGRA, RLE */
311                 if (targa_header.pixel_size == 32 && alphabits)
312                 {
313                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
314                         {
315                                 for (x = 0;x < image_width;)
316                                 {
317                                         if (fin >= enddata)
318                                                 break; /* error - truncated file */
319                                         runlen = *fin++;
320                                         if (runlen & 0x80)
321                                         {
322                                                 /* RLE - all pixels the same color */
323                                                 runlen += 1 - 0x80;
324                                                 if (fin + pix_inc > enddata)
325                                                         break; /* error - truncated file */
326                                                 if (x + runlen > image_width)
327                                                         break; /* error - line exceeds width */
328                                                 bgra.b[0] = fin[0];
329                                                 bgra.b[1] = fin[1];
330                                                 bgra.b[2] = fin[2];
331                                                 bgra.b[3] = fin[3];
332                                                 fin += pix_inc;
333                                                 for (;runlen--;x++)
334                                                         *pixbufi++ = bgra.i;
335                                         }
336                                         else
337                                         {
338                                                 /* uncompressed - all pixels different color */
339                                                 runlen++;
340                                                 if (fin + pix_inc * runlen > enddata)
341                                                         break; /* error - truncated file */
342                                                 if (x + runlen > image_width)
343                                                         break; /* error - line exceeds width */
344                                                 for (;runlen--;x++)
345                                                 {
346                                                         bgra.b[0] = fin[0];
347                                                         bgra.b[1] = fin[1];
348                                                         bgra.b[2] = fin[2];
349                                                         bgra.b[3] = fin[3];
350                                                         fin += pix_inc;
351                                                         *pixbufi++ = bgra.i;
352                                                 }
353                                         }
354                                 }
355
356                                 if (x != image_width)
357                                 {
358                                         /* pixbufi is useless now */
359                                         printf("LoadTGA: corrupt file\n");
360                                         break;
361                                 }
362                         }
363                 }
364                 else
365                 {
366                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
367                         {
368                                 for (x = 0;x < image_width;)
369                                 {
370                                         if (fin >= enddata)
371                                                 break; /* error - truncated file */
372                                         runlen = *fin++;
373                                         if (runlen & 0x80)
374                                         {
375                                                 /* RLE - all pixels the same color */
376                                                 runlen += 1 - 0x80;
377                                                 if (fin + pix_inc > enddata)
378                                                         break; /* error - truncated file */
379                                                 if (x + runlen > image_width)
380                                                         break; /* error - line exceeds width */
381                                                 bgra.b[0] = fin[0];
382                                                 bgra.b[1] = fin[1];
383                                                 bgra.b[2] = fin[2];
384                                                 bgra.b[3] = 255;
385                                                 fin += pix_inc;
386                                                 for (;runlen--;x++)
387                                                         *pixbufi++ = bgra.i;
388                                         }
389                                         else
390                                         {
391                                                 /* uncompressed - all pixels different color */
392                                                 runlen++;
393                                                 if (fin + pix_inc * runlen > enddata)
394                                                         break; /* error - truncated file */
395                                                 if (x + runlen > image_width)
396                                                         break; /* error - line exceeds width */
397                                                 for (;runlen--;x++)
398                                                 {
399                                                         bgra.b[0] = fin[0];
400                                                         bgra.b[1] = fin[1];
401                                                         bgra.b[2] = fin[2];
402                                                         bgra.b[3] = 255;
403                                                         fin += pix_inc;
404                                                         *pixbufi++ = bgra.i;
405                                                 }
406                                         }
407                                 }
408
409                                 if (x != image_width)
410                                 {
411                                         /* pixbufi is useless now */
412                                         printf("LoadTGA: corrupt file\n");
413                                         break;
414                                 }
415                         }
416                 }
417                 break;
418         default:
419                 /* unknown image_type */
420                 break;
421         }
422
423         return image_buffer;
424 }
425
426 /* in can be the same as out */
427 void Image_MipReduce32(const unsigned char *in, unsigned char *out, int *width, int *height, int destwidth, int destheight)
428 {
429         const unsigned char *inrow;
430         int x, y, nextrow;
431         /* note: if given odd width/height this discards the last row/column of
432          * pixels, rather than doing a proper box-filter scale down
433          */
434         inrow = in;
435         nextrow = *width * 4;
436         if (*width > destwidth)
437         {
438                 *width >>= 1;
439                 if (*height > destheight)
440                 {
441                         /* reduce both */
442                         *height >>= 1;
443                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
444                         {
445                                 for (in = inrow, x = 0;x < *width;x++)
446                                 {
447                                         out[0] = (unsigned char) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
448                                         out[1] = (unsigned char) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
449                                         out[2] = (unsigned char) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
450                                         out[3] = (unsigned char) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
451                                         out += 4;
452                                         in += 8;
453                                 }
454                         }
455                 }
456                 else
457                 {
458                         /* reduce width */
459                         for (y = 0;y < *height;y++, inrow += nextrow)
460                         {
461                                 for (in = inrow, x = 0;x < *width;x++)
462                                 {
463                                         out[0] = (unsigned char) ((in[0] + in[4]) >> 1);
464                                         out[1] = (unsigned char) ((in[1] + in[5]) >> 1);
465                                         out[2] = (unsigned char) ((in[2] + in[6]) >> 1);
466                                         out[3] = (unsigned char) ((in[3] + in[7]) >> 1);
467                                         out += 4;
468                                         in += 8;
469                                 }
470                         }
471                 }
472         }
473         else
474         {
475                 if (*height > destheight)
476                 {
477                         /* reduce height */
478                         *height >>= 1;
479                         for (y = 0;y < *height;y++, inrow += nextrow * 2)
480                         {
481                                 for (in = inrow, x = 0;x < *width;x++)
482                                 {
483                                         out[0] = (unsigned char) ((in[0] + in[nextrow  ]) >> 1);
484                                         out[1] = (unsigned char) ((in[1] + in[nextrow+1]) >> 1);
485                                         out[2] = (unsigned char) ((in[2] + in[nextrow+2]) >> 1);
486                                         out[3] = (unsigned char) ((in[3] + in[nextrow+3]) >> 1);
487                                         out += 4;
488                                         in += 4;
489                                 }
490                         }
491                 }
492         }
493 }
494 unsigned char *FS_LoadFile(const char *fn, int *len)
495 {
496         unsigned char *buf = NULL;
497         int n;
498         FILE *f = fn ? fopen(fn, "rb") : stdin;
499         *len = 0;
500         if(!f)
501                 return NULL;
502         for(;;)
503         {
504                 unsigned char *newbuf = (unsigned char *) realloc(buf, *len + 65536);
505                 if(newbuf)
506                 {
507                         buf = newbuf;
508                 }
509                 else
510                 {
511                         if(fn)
512                                 fclose(f);
513                         free(buf);
514                         *len = 0;
515                         return NULL;
516                 }
517                 n = fread(buf + *len, 1, 65536, f);
518                 if(n < 0)
519                 {
520                         if(fn)
521                                 fclose(f);
522                         free(buf);
523                         *len = 0;
524                         return NULL;
525                 }
526                 *len += n;
527                 if(n < 65536)
528                         break;
529         }
530         if(fn)
531                 fclose(f);
532         return buf;
533 }
534 /* END of darkplaces stuff */
535
536 uint32_t LittleLong(uint32_t w)
537 {
538         union
539         {
540                 unsigned char c[4];
541                 uint32_t u;
542         }
543         un;
544         un.c[0] = w;
545         un.c[1] = w >> 8;
546         un.c[2] = w >> 16;
547         un.c[3] = w >> 24;
548         return un.u;
549 }
550
551 int usage(const char *me)
552 {
553         fprintf(stderr, "usage:\n"
554                         "%s \n"
555                         "    [-i infile.tga]\n"
556                         "    [-o outfile.dds]\n"
557                         "    [-t {DXT1|DXT3|DXT5}]\n"
558 #ifdef ENABLE_RUNTIME_LINKING
559                         "    [-l path_to_libtxc_dxtn.so]\n"
560 #endif
561                         ,
562                         me);
563         return 1;
564 }
565
566 int main(int argc, char **argv)
567 {
568         const char *infile = NULL, *outfile = NULL;
569         FILE *outfh;
570         unsigned char *picdata, *pic;
571         int x, mipcount, piclen;
572         const char *fourcc;
573         int blocksize;
574         GLenum dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
575
576 #ifdef ENABLE_RUNTIME_LINKING
577         const char *library = "libtxc_dxtn.so";
578 #endif
579
580         int opt;
581         while((opt = getopt(argc, argv, "i:o:t:"
582 #ifdef ENABLE_RUNTIME_LINKING
583                                         "l:"
584 #endif
585                                         )) != -1)
586         {
587                 switch(opt)
588                 {
589                         case 'i':
590                                 infile = optarg;
591                                 break;
592                         case 'o':
593                                 outfile = optarg;
594                                 break;
595                         case 't':
596                                 if(!strcasecmp(optarg, "DXT1"))
597                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
598                                 else if(!strcasecmp(optarg, "DXT3"))
599                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
600                                 else if(!strcasecmp(optarg, "DXT5"))
601                                         dxt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
602                                 else
603                                         return usage(argv[0]);
604                                 break;
605 #ifdef ENABLE_RUNTIME_LINKING
606                         case 'l':
607                                 library = optarg;
608                                 break;
609 #endif
610                         default:
611                                 return usage(argv[0]);
612                                 break;
613                 }
614         }
615 #ifdef ENABLE_RUNTIME_LINKING
616         if(!load_libraries(library))
617                 return 1;
618 #endif
619
620         outfh = outfile ? fopen(outfile, "wb") : stdout;
621         if(!outfh)
622         {
623                 printf("opening output failed\n");
624                 return 2;
625         }
626
627         picdata = FS_LoadFile(infile, &piclen);
628         if(!picdata)
629         {
630                 printf("FS_LoadFile failed\n");
631                 return 2;
632         }
633
634         pic = LoadTGA_BGRA(picdata, piclen);
635         for(x = 0; x < image_width*image_height; ++x) {
636                 unsigned char h = pic[4*x];
637                 pic[4*x] = pic[4*x+2];
638                 pic[4*x+2] = h;
639         }
640         mipcount = 0;
641         while(image_width >= (1 << mipcount) || image_height >= (1 << mipcount))
642                 ++mipcount;
643         /* now, (1 << mipcount) >= width, height */
644
645         switch(dxt)
646         {
647                 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
648                         blocksize = 8;
649                         fourcc = "DXT1";
650                         break;
651                 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
652                         blocksize = 16;
653                         fourcc = "DXT3";
654                         break;
655                 default:
656                 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
657                         blocksize = 16;
658                         fourcc = "DXT5";
659                         break;
660         }
661
662         {
663                 uint32_t zero = LittleLong(0);
664                 bool alphapixels = false;
665                 int x, y;
666                 uint32_t dds_picsize, dds_mipcount, dds_width, dds_height;
667
668                 for(y = 0; y < image_height; ++y)
669                         for(x = 0; x < image_width; ++x)
670                                 if(pic[(y*image_width+x)*4+3] != 255)
671                                 {
672                                         alphapixels = true;
673                                         break;
674                                 }
675
676                 dds_picsize = LittleLong(((image_width+3)/4) * ((image_height+3)/4) * blocksize);
677                 dds_mipcount = LittleLong(mipcount);
678                 dds_width = LittleLong(image_width);
679                 dds_height = LittleLong(image_height);
680
681                 /* 0 */
682                 fwrite("DDS ", 4, 1, outfh);
683                 fwrite("\x7c\x00\x00\x00", 4, 1, outfh);
684                 fwrite("\x07\x10\x0a\x00", 4, 1, outfh);
685                 fwrite(&dds_height, 4, 1, outfh);
686                 fwrite(&dds_width, 4, 1, outfh);
687                 fwrite(&dds_picsize, 4, 1, outfh);
688                 fwrite(&zero, 4, 1, outfh);
689                 fwrite(&dds_mipcount, 4, 1, outfh);
690
691                 /* 32 */
692                 fwrite(&zero, 4, 1, outfh);
693                 fwrite(&zero, 4, 1, outfh);
694                 fwrite(&zero, 4, 1, outfh);
695                 fwrite(&zero, 4, 1, outfh);
696                 fwrite(&zero, 4, 1, outfh);
697                 fwrite(&zero, 4, 1, outfh);
698                 fwrite(&zero, 4, 1, outfh);
699                 fwrite(&zero, 4, 1, outfh);
700
701                 /* 64 */
702                 fwrite(&zero, 4, 1, outfh);
703                 fwrite(&zero, 4, 1, outfh);
704                 fwrite(&zero, 4, 1, outfh);
705                 fwrite("\x20\x00\x00\x00", 4, 1, outfh);
706                 fwrite(alphapixels ? "\x05\x00\x00\x00" : "\x04\x00\x00\x00", 4, 1, outfh);
707                 fwrite(fourcc, 4, 1, outfh);
708                 fwrite(&zero, 4, 1, outfh);
709                 fwrite(&zero, 4, 1, outfh);
710
711                 /* 96 */
712                 fwrite(&zero, 4, 1, outfh);
713                 fwrite(&zero, 4, 1, outfh);
714                 fwrite(&zero, 4, 1, outfh);
715                 fwrite("\x08\x10\x40\x00", 4, 1, outfh);
716                 fwrite(&zero, 4, 1, outfh);
717                 fwrite(&zero, 4, 1, outfh);
718                 fwrite(&zero, 4, 1, outfh);
719                 fwrite(&zero, 4, 1, outfh);
720         }
721
722         for(;;)
723         {
724                 int blocks_w = (image_width + 3) / 4;
725                 int blocks_h = (image_height + 3) / 4;
726                 GLubyte *obuf = (GLubyte *) malloc(blocksize * blocks_w * blocks_h);
727                 tx_compress_dxtn(4, image_width, image_height, pic, dxt, obuf, blocks_w * blocksize);
728                 fwrite(obuf, blocksize * blocks_w * blocks_h, 1, outfh);
729                 free(obuf);
730                 if(image_width == 1 && image_height == 1)
731                         break;
732                 Image_MipReduce32(pic, pic, &image_width, &image_height, 1, 1);
733         }
734
735         if(outfile)
736                 fclose(outfh);
737
738         return 0;
739 }