OSDN Git Service

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