Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / GlideHQ / TxImage.cpp
1 /*
2  * Texture Filtering
3  * Version:  1.0
4  *
5  * Copyright (C) 2007  Hiroshi Morii   All Rights Reserved.
6  * Email koolsmoky(at)users.sourceforge.net
7  * Web   http://www.3dfxzone.it/koolsmoky
8  *
9  * this is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * this is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with GNU Make; see the file COPYING.  If not, write to
21  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 /* use power of 2 texture size
25  * (0:disable, 1:enable, 2:3dfx) */
26 #define POW2_TEXTURES 0
27
28 /* check 8 bytes. use a larger value if needed. */
29 #define PNG_CHK_BYTES 8
30
31 #include "TxImage.h"
32 #include "TxReSample.h"
33 #include "TxDbg.h"
34 #include <stdlib.h>
35 #include "../Glide64/Gfx_1.3.h"
36
37 boolean
38 TxImage::getPNGInfo(FILE *fp, png_structp *png_ptr, png_infop *info_ptr)
39 {
40   unsigned char sig[PNG_CHK_BYTES];
41
42   /* check for valid file pointer */
43   if (!fp)
44     return 0;
45
46   /* check if file is PNG */
47   if (fread(sig, 1, PNG_CHK_BYTES, fp) != PNG_CHK_BYTES)
48     return 0;
49
50   if (png_sig_cmp(sig, 0, PNG_CHK_BYTES) != 0)
51     return 0;
52
53   /* get PNG file info */
54   *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
55   if (!*png_ptr)
56     return 0;
57
58   *info_ptr = png_create_info_struct(*png_ptr);
59   if (!*info_ptr) {
60     png_destroy_read_struct(png_ptr, NULL, NULL);
61     return 0;
62   }
63
64   if (setjmp(png_jmpbuf(*png_ptr))) {
65     DBG_INFO(80, L"error reading png!\n");
66     png_destroy_read_struct(png_ptr, info_ptr, NULL);
67     return 0;
68   }
69
70   png_init_io(*png_ptr, fp);
71   png_set_sig_bytes(*png_ptr, PNG_CHK_BYTES);
72   png_read_info(*png_ptr, *info_ptr);
73
74   return 1;
75 }
76
77 uint8*
78 TxImage::readPNG(FILE* fp, int* width, int* height, uint16* format)
79 {
80   /* NOTE: returned image format is GR_TEXFMT_ARGB_8888 */
81
82   png_structp png_ptr;
83   png_infop info_ptr;
84   uint8 *image = NULL;
85   int bit_depth, color_type, interlace_type, compression_type, filter_type,
86       row_bytes, o_width, o_height, num_pas;
87
88   /* initialize */
89   *width  = 0;
90   *height = 0;
91   *format = 0;
92
93   /* check if we have a valid png file */
94   if (!fp)
95     return NULL;
96
97   if (!getPNGInfo(fp, &png_ptr, &info_ptr)) {
98     INFO(80, L"error reading png file! png image is corrupt.\n");
99     return NULL;
100   }
101
102   png_get_IHDR(png_ptr, info_ptr,
103                (png_uint_32*)&o_width, (png_uint_32*)&o_height, &bit_depth, &color_type,
104                &interlace_type, &compression_type, &filter_type);
105
106   DBG_INFO(80, L"png format %d x %d bitdepth:%d color:%x interlace:%x compression:%x filter:%x\n",
107            o_width, o_height, bit_depth, color_type,
108            interlace_type, compression_type, filter_type);
109
110   /* transformations */
111
112   /* Rice hi-res textures
113    * _all.png
114    * _rgb.png, _a.png
115    * _ciByRGBA.png
116    * _allciByRGBA.png
117    */
118
119   /* strip if color channel is larger than 8 bits */
120   if (bit_depth > 8) {
121     png_set_strip_16(png_ptr);
122     bit_depth = 8;
123   }
124
125 #if 1
126   /* These are not really required per Rice format spec,
127    * but is done just in case someone uses them.
128    */
129   /* convert palette color to rgb color */
130   if (color_type == PNG_COLOR_TYPE_PALETTE) {
131     png_set_palette_to_rgb(png_ptr);
132     color_type = PNG_COLOR_TYPE_RGB;
133   }
134
135   /* expand 1,2,4 bit gray scale to 8 bit gray scale */
136   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
137     png_set_expand_gray_1_2_4_to_8(png_ptr);
138
139   /* convert gray scale or gray scale + alpha to rgb color */
140   if (color_type == PNG_COLOR_TYPE_GRAY ||
141       color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
142     png_set_gray_to_rgb(png_ptr);
143     color_type = PNG_COLOR_TYPE_RGB;
144   }
145 #endif
146
147   /* add alpha channel if any */
148   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
149     png_set_tRNS_to_alpha(png_ptr);
150     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
151   }
152
153   /* convert rgb to rgba */
154   if (color_type == PNG_COLOR_TYPE_RGB) {
155     png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
156     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
157   }
158
159   /* punt invalid formats */
160   if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
161     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
162     DBG_INFO(80, L"Error: not PNG_COLOR_TYPE_RGB_ALPHA format!\n");
163     return NULL;
164   }
165
166   /*png_color_8p sig_bit;
167   if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
168     png_set_shift(png_ptr, sig_bit);*/
169
170   /* convert rgba to bgra */
171   png_set_bgr(png_ptr);
172
173   /* turn on interlace handling to cope with the weirdness
174    * of texture authors using interlaced format */
175   num_pas = png_set_interlace_handling(png_ptr);
176
177   /* update info structure */
178   png_read_update_info(png_ptr, info_ptr);
179
180   /* we only get here if ARGB8888 */
181   row_bytes = png_get_rowbytes(png_ptr, info_ptr);
182
183   /* allocate memory to read in image */
184   image = (uint8*)malloc(row_bytes * o_height);
185
186   /* read in image */
187   if (image) {
188     int pas, i;
189     uint8* tmpimage;
190
191     for (pas = 0; pas < num_pas; pas++) { /* deal with interlacing */
192       tmpimage = image;
193
194       for (i = 0; i < o_height; i++) {
195         /* copy row */
196         png_read_rows(png_ptr, &tmpimage, NULL, 1);
197         tmpimage += row_bytes;
198       }
199     }
200
201     /* read rest of the info structure */
202     png_read_end(png_ptr, info_ptr);
203
204     *width = (row_bytes >> 2);
205     *height = o_height;
206     *format = GR_TEXFMT_ARGB_8888;
207
208 #if POW2_TEXTURES
209     /* next power of 2 size conversions */
210     /* NOTE: I can do this in the above loop for faster operations, but some
211      * texture packs require a workaround. see HACKALERT in nextPow2().
212      */
213
214     TxReSample txReSample = new TxReSample; // XXX: temporary. move to a better place.
215
216 #if (POW2_TEXTURES == 2)
217     if (!txReSample->nextPow2(&image, width, height, 32, 1)) {
218 #else
219     if (!txReSample->nextPow2(&image, width, height, 32, 0)) {
220 #endif
221       if (image) {
222         free(image);
223         image = NULL;
224       }
225       *width = 0;
226       *height = 0;
227       *format = 0;
228     }
229
230     delete txReSample;
231
232 #endif /* POW2_TEXTURES */
233   }
234
235   /* clean up */
236   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
237
238 #ifdef DEBUG
239   if (!image) {
240     DBG_INFO(80, L"Error: failed to load png image!\n");
241   }
242 #endif
243
244   return image;
245 }
246
247 boolean
248 TxImage::writePNG(uint8* src, FILE* fp, int width, int height, int rowStride, uint16 format, uint8 *palette)
249 {
250   png_structp png_ptr;
251   png_infop info_ptr;
252   png_color_8 sig_bit;
253   png_colorp palette_ptr = NULL;
254   png_bytep trans_ptr = NULL;
255   int bit_depth, color_type, row_bytes, num_palette;
256   int i;
257   //uint16 srcfmt, destfmt;
258
259   if (!src || !fp)
260     return 0;
261
262   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
263   if (png_ptr == NULL)
264     return 0;
265
266   info_ptr = png_create_info_struct(png_ptr);
267   if (info_ptr == NULL) {
268     png_destroy_write_struct(&png_ptr, NULL);
269     return 0;
270   }
271
272   if (png_jmpbuf(png_ptr)) {
273     png_destroy_write_struct(&png_ptr, &info_ptr);
274     return 0;
275   }
276
277   png_init_io(png_ptr, fp);
278
279   /* TODO: images must be converted to RGBA8888 or CI8,
280    * palettes need to be separated to A and RGB. */
281
282   /* N64 formats
283    * Format: 0 - RGBA, 1 - YUV, 2 - CI, 3 - IA, 4 - I
284    * Size:   0 - 4bit, 1 - 8bit, 2 - 16bit, 3 - 32 bit
285    * format = (Format << 8 | Size);
286    */
287
288   /* each channel is saved in 8bits for consistency */
289   switch (format) {
290   case 0x0002:/* RGBA5551 */
291     bit_depth = 8;
292     sig_bit.red   = 5;
293     sig_bit.green = 5;
294     sig_bit.blue  = 5;
295     sig_bit.alpha = 1;
296     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
297     break;
298   case 0x0003:/* RGBA8888 */
299   case 0x0302:/* IA88 */
300     bit_depth = 8;
301     sig_bit.red   = 8;
302     sig_bit.green = 8;
303     sig_bit.blue  = 8;
304     sig_bit.alpha = 8;
305     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
306     break;
307   case 0x0300:/* IA31 */
308     bit_depth = 8;
309     sig_bit.red   = 3;
310     sig_bit.green = 3;
311     sig_bit.blue  = 3;
312     sig_bit.alpha = 1;
313     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
314     break;
315   case 0x0301:/* IA44 */
316     bit_depth = 8;
317     sig_bit.red   = 4;
318     sig_bit.green = 4;
319     sig_bit.blue  = 4;
320     sig_bit.alpha = 4;
321     color_type = PNG_COLOR_TYPE_RGB_ALPHA;
322     break;
323   case 0x0400:/* I4 */
324     bit_depth = 8;
325     sig_bit.red   = 4;
326     sig_bit.green = 4;
327     sig_bit.blue  = 4;
328     color_type = PNG_COLOR_TYPE_RGB;
329     break;
330   case 0x0401:/* I8 */
331   case 0x0402:/* I16 */
332     bit_depth = 8;
333     sig_bit.red   = 8;
334     sig_bit.green = 8;
335     sig_bit.blue  = 8;
336     color_type = PNG_COLOR_TYPE_RGB;
337     break;
338   case 0x0200:/* CI4 */
339     bit_depth = 8;
340     num_palette = 16;
341     color_type = PNG_COLOR_TYPE_PALETTE;
342     break;
343   case 0x0201:/* CI8 */
344     bit_depth = 8;
345     num_palette = 256;
346     color_type = PNG_COLOR_TYPE_PALETTE;
347     break;
348   case 0x0102:/* YUV ? */
349   case 0x0103:
350   default:
351     /* unsupported format */
352     png_destroy_write_struct(&png_ptr, &info_ptr);
353     return 0;
354   }
355
356   switch (color_type) {
357   case PNG_COLOR_TYPE_RGB_ALPHA:
358   case PNG_COLOR_TYPE_RGB:
359     //row_bytes = (bit_depth * width) >> 1;
360     row_bytes = rowStride;
361     png_set_bgr(png_ptr);
362     png_set_sBIT(png_ptr, info_ptr, &sig_bit);
363     break;
364   case PNG_COLOR_TYPE_PALETTE:
365     //row_bytes = (bit_depth * width) >> 3;
366     row_bytes = rowStride;
367     png_set_PLTE(png_ptr, info_ptr, palette_ptr, num_palette);
368     png_set_tRNS(png_ptr, info_ptr, trans_ptr, num_palette, 0);
369   }
370
371   //png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);
372
373   //if (bit_depth == 16)
374   //  png_set_swap(png_ptr);
375
376   //if (bit_depth < 8)
377   //  png_set_packswap(png_ptr);
378
379   png_set_IHDR(png_ptr, info_ptr, width, height,
380                bit_depth, color_type, PNG_INTERLACE_NONE,
381                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
382
383   //png_set_gAMA(png_ptr, info_ptr, 1.0);
384
385   png_write_info(png_ptr, info_ptr);
386   for (i = 0; i < height; i++) {
387     png_write_row(png_ptr, (png_bytep)src);
388     src += row_bytes;
389   }
390   png_write_end(png_ptr, info_ptr);
391
392   png_destroy_write_struct(&png_ptr, &info_ptr);
393
394   //if (tex_ptr) delete [] tex_ptr;
395
396   return 1;
397 }
398
399 boolean
400 TxImage::getBMPInfo(FILE* fp, BITMAPFILEHEADER* bmp_fhdr, BITMAPINFOHEADER* bmp_ihdr)
401 {
402   /*
403    * read in BITMAPFILEHEADER
404    */
405
406   /* is this a BMP file? */
407   if (fread(&bmp_fhdr->bfType, 2, 1, fp) != 1)
408     return 0;
409
410   if (memcmp(&bmp_fhdr->bfType, "BM", 2) != 0)
411     return 0;
412
413   /* get file size */
414   if (fread(&bmp_fhdr->bfSize, 4, 1, fp) != 1)
415     return 0;
416
417   /* reserved 1 */
418   if (fread(&bmp_fhdr->bfReserved1, 2, 1, fp) != 1)
419     return 0;
420
421   /* reserved 2 */
422   if (fread(&bmp_fhdr->bfReserved2, 2, 1, fp) != 1)
423     return 0;
424
425   /* offset to the image data */
426   if (fread(&bmp_fhdr->bfOffBits, 4, 1, fp) != 1)
427     return 0;
428
429   /*
430    * read in BITMAPINFOHEADER
431    */
432
433   /* size of BITMAPINFOHEADER */
434   if (fread(&bmp_ihdr->biSize, 4, 1, fp) != 1)
435     return 0;
436
437   /* is this a Windows BMP? */
438   if (bmp_ihdr->biSize != 40)
439     return 0;
440
441   /* width of the bitmap in pixels */
442   if (fread(&bmp_ihdr->biWidth, 4, 1, fp) != 1)
443     return 0;
444
445   /* height of the bitmap in pixels */
446   if (fread(&bmp_ihdr->biHeight, 4, 1, fp) != 1)
447     return 0;
448
449   /* number of planes (always 1) */
450   if (fread(&bmp_ihdr->biPlanes, 2, 1, fp) != 1)
451     return 0;
452
453   /* number of bits-per-pixel. (1, 4, 8, 16, 24, 32) */
454   if (fread(&bmp_ihdr->biBitCount, 2, 1, fp) != 1)
455     return 0;
456
457   /* compression for a compressed bottom-up bitmap
458    *   0 : uncompressed format
459    *   1 : run-length encoded 4 bpp format
460    *   2 : run-length encoded 8 bpp format
461    *   3 : bitfield
462    */
463   if (fread(&bmp_ihdr->biCompression, 4, 1, fp) != 1)
464     return 0;
465
466   /* size of the image in bytes */
467   if (fread(&bmp_ihdr->biSizeImage, 4, 1, fp) != 1)
468     return 0;
469
470   /* horizontal resolution in pixels-per-meter */
471   if (fread(&bmp_ihdr->biXPelsPerMeter, 4, 1, fp) != 1)
472     return 0;
473
474   /* vertical resolution in pixels-per-meter */
475   if (fread(&bmp_ihdr->biYPelsPerMeter, 4, 1, fp) != 1)
476     return 0;
477
478   /* number of color indexes in the color table that are actually used */
479   if (fread(&bmp_ihdr->biClrUsed, 4, 1, fp) != 1)
480     return 0;
481
482   /*  the number of color indexes that are required for displaying */
483   if (fread(&bmp_ihdr->biClrImportant, 4, 1, fp) != 1)
484     return 0;
485
486   return 1;
487 }
488
489 uint8*
490 TxImage::readBMP(FILE* fp, int* width, int* height, uint16* format)
491 {
492   /* NOTE: returned image format;
493    *       4, 8bit palette bmp -> GR_TEXFMT_P_8
494    *       24, 32bit bmp -> GR_TEXFMT_ARGB_8888
495    */
496
497   uint8 *image = NULL;
498   uint8 *image_row = NULL;
499   uint8 *tmpimage = NULL;
500   unsigned int row_bytes, pos;
501   int i, j;
502   /* Windows Bitmap */
503   BITMAPFILEHEADER bmp_fhdr;
504   BITMAPINFOHEADER bmp_ihdr;
505
506   /* initialize */
507   *width  = 0;
508   *height = 0;
509   *format = 0;
510
511   /* check if we have a valid bmp file */
512   if (!fp)
513     return NULL;
514
515   if (!getBMPInfo(fp, &bmp_fhdr, &bmp_ihdr)) {
516     INFO(80, L"error reading bitmap file! bitmap image is corrupt.\n");
517     return NULL;
518   }
519
520   DBG_INFO(80, L"bmp format %d x %d bitdepth:%d compression:%x offset:%d\n",
521            bmp_ihdr.biWidth, bmp_ihdr.biHeight, bmp_ihdr.biBitCount,
522            bmp_ihdr.biCompression, bmp_fhdr.bfOffBits);
523
524   /* rowStride in bytes */
525   row_bytes = (bmp_ihdr.biWidth * bmp_ihdr.biBitCount) >> 3;
526   /* align to 4bytes boundary */
527   row_bytes = (row_bytes + 3) & ~3;
528
529   /* Rice hi-res textures */
530   if (!(bmp_ihdr.biBitCount == 8 || bmp_ihdr.biBitCount == 4 || bmp_ihdr.biBitCount == 32 || bmp_ihdr.biBitCount == 24) ||
531       bmp_ihdr.biCompression != 0) {
532     DBG_INFO(80, L"Error: incompatible bitmap format!\n");
533     return NULL;
534   }
535
536   switch (bmp_ihdr.biBitCount) {
537   case 8:
538   case 32:
539     /* 8 bit, 32 bit bitmap */
540     image = (uint8*)malloc(row_bytes * bmp_ihdr.biHeight);
541     if (image) {
542       tmpimage = image;
543       pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);
544       for (i = 0; i < bmp_ihdr.biHeight; i++) {
545         /* read in image */
546         fseek(fp, pos, SEEK_SET);
547         if (fread(tmpimage, 1, row_bytes, fp) != row_bytes)
548             ERRLOG("fread() failed for row of '%i' bytes in 8/32-bit BMP image", row_bytes);
549         tmpimage += row_bytes;
550         pos -= row_bytes;
551       }
552     }
553     break;
554   case 4:
555     /* 4bit bitmap */
556     image = (uint8*)malloc((row_bytes * bmp_ihdr.biHeight) << 1);
557     image_row = (uint8*)malloc(row_bytes);
558     if (image && image_row) {
559       tmpimage = image;
560       pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);
561       for (i = 0; i < bmp_ihdr.biHeight; i++) {
562         /* read in image */
563         fseek(fp, pos, SEEK_SET);
564         if (fread(image_row, 1, row_bytes, fp) != row_bytes)
565             ERRLOG("fread failed for row of '%i' bytes in 4-bit BMP image", row_bytes);
566         /* expand 4bpp to 8bpp. stuff 4bit values into 8bit comps. */
567         for (j = 0; j < (int) row_bytes; j++) {
568           tmpimage[j << 1] = image_row[j] & 0x0f;
569           tmpimage[(j << 1) + 1] = (image_row[j] & 0xf0) >> 4;
570         }
571         tmpimage += (row_bytes << 1);
572         pos -= row_bytes;
573       }
574       free(image_row);
575     } else {
576       if (image_row) free(image_row);
577       if (image) free(image);
578       image = NULL;
579     }
580     break;
581   case 24:
582     /* 24 bit bitmap */
583     image = (uint8*)malloc((bmp_ihdr.biWidth * bmp_ihdr.biHeight) << 2);
584     image_row = (uint8*)malloc(row_bytes);
585     if (image && image_row) {
586       tmpimage = image;
587       pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);
588       for (i = 0; i < bmp_ihdr.biHeight; i++) {
589         /* read in image */
590         fseek(fp, pos, SEEK_SET);
591         if (fread(image_row, 1, row_bytes, fp) != row_bytes)
592             ERRLOG("fread failed for row of '%i' bytes in 24-bit BMP image", row_bytes);
593         /* convert 24bpp to 32bpp. */
594         for (j = 0; j < bmp_ihdr.biWidth; j++) {
595           tmpimage[(j << 2)]     = image_row[j * 3];
596           tmpimage[(j << 2) + 1] = image_row[j * 3 + 1];
597           tmpimage[(j << 2) + 2] = image_row[j * 3 + 2];
598           tmpimage[(j << 2) + 3] = 0xFF;
599         }
600         tmpimage += (bmp_ihdr.biWidth << 2);
601         pos -= row_bytes;
602       }
603       free(image_row);
604     } else {
605       if (image_row) free(image_row);
606       if (image) free(image);
607       image = NULL;
608     }
609   }
610
611   if (image) {
612     *width = (row_bytes << 3) / bmp_ihdr.biBitCount;
613     *height = bmp_ihdr.biHeight;
614
615     switch (bmp_ihdr.biBitCount) {
616     case 8:
617     case 4:
618       *format = GR_TEXFMT_P_8;
619       break;
620     case 32:
621     case 24:
622       *format = GR_TEXFMT_ARGB_8888;
623     }
624
625 #if POW2_TEXTURES
626     /* next power of 2 size conversions */
627     /* NOTE: I can do this in the above loop for faster operations, but some
628      * texture packs require a workaround. see HACKALERT in nextPow2().
629      */
630
631     TxReSample txReSample = new TxReSample; // XXX: temporary. move to a better place.
632
633 #if (POW2_TEXTURES == 2)
634     if (!txReSample->nextPow2(&image, width, height, 8, 1)) {
635 #else
636     if (!txReSample->nextPow2(&image, width, height, 8, 0)) {
637 #endif
638       if (image) {
639         free(image);
640         image = NULL;
641       }
642       *width = 0;
643       *height = 0;
644       *format = 0;
645     }
646
647     delete txReSample;
648
649 #endif /* POW2_TEXTURES */
650   }
651
652 #ifdef DEBUG
653   if (!image) {
654     DBG_INFO(80, L"Error: failed to load bmp image!\n");
655   }
656 #endif
657
658   return image;
659 }
660
661 boolean
662 TxImage::getDDSInfo(FILE *fp, DDSFILEHEADER *dds_fhdr)
663 {
664   /*
665    * read in DDSFILEHEADER
666    */
667
668   /* is this a DDS file? */
669   if (fread(&dds_fhdr->dwMagic, 4, 1, fp) != 1)
670     return 0;
671
672   if (memcmp(&dds_fhdr->dwMagic, "DDS ", 4) != 0)
673     return 0;
674
675   if (fread(&dds_fhdr->dwSize, 4, 1, fp) != 1)
676     return 0;
677
678   /* get file flags */
679   if (fread(&dds_fhdr->dwFlags, 4, 1, fp) != 1)
680     return 0;
681
682   /* height of dds in pixels */
683   if (fread(&dds_fhdr->dwHeight, 4, 1, fp) != 1)
684     return 0;
685
686   /* width of dds in pixels */
687   if (fread(&dds_fhdr->dwWidth, 4, 1, fp) != 1)
688     return 0;
689
690   if (fread(&dds_fhdr->dwLinearSize, 4, 1, fp) != 1)
691     return 0;
692
693   if (fread(&dds_fhdr->dwDepth, 4, 1, fp) != 1)
694     return 0;
695
696   if (fread(&dds_fhdr->dwMipMapCount, 4, 1, fp) != 1)
697     return 0;
698
699   if (fread(&dds_fhdr->dwReserved1, 4 * 11, 1, fp) != 1)
700     return 0;
701
702   if (fread(&dds_fhdr->ddpf.dwSize, 4, 1, fp) != 1)
703     return 0;
704
705   if (fread(&dds_fhdr->ddpf.dwFlags, 4, 1, fp) != 1)
706     return 0;
707
708   if (fread(&dds_fhdr->ddpf.dwFourCC, 4, 1, fp) != 1)
709     return 0;
710
711   if (fread(&dds_fhdr->ddpf.dwRGBBitCount, 4, 1, fp) != 1)
712     return 0;
713
714   if (fread(&dds_fhdr->ddpf.dwRBitMask, 4, 1, fp) != 1)
715     return 0;
716
717   if (fread(&dds_fhdr->ddpf.dwGBitMask, 4, 1, fp) != 1)
718     return 0;
719
720   if (fread(&dds_fhdr->ddpf.dwBBitMask, 4, 1, fp) != 1)
721     return 0;
722
723   if (fread(&dds_fhdr->ddpf.dwRGBAlphaBitMask, 4, 1, fp) != 1)
724     return 0;
725
726   if (fread(&dds_fhdr->dwCaps1, 4, 1, fp) != 1)
727     return 0;
728
729   if (fread(&dds_fhdr->dwCaps2, 4, 1, fp) != 1)
730     return 0;
731
732   return 1;
733 }
734
735 uint8*
736 TxImage::readDDS(FILE* fp, int* width, int* height, uint16* format)
737 {
738   uint8 *image = NULL;
739   DDSFILEHEADER dds_fhdr;
740   uint16 tmpformat = 0;
741
742   /* initialize */
743   *width  = 0;
744   *height = 0;
745   *format = 0;
746
747   /* check if we have a valid dds file */
748   if (!fp)
749     return NULL;
750
751   if (!getDDSInfo(fp, &dds_fhdr)) {
752     INFO(80, L"error reading dds file! dds image is corrupt.\n");
753     return NULL;
754   }
755
756   DBG_INFO(80, L"dds format %d x %d HeaderSize %d LinearSize %d\n",
757            dds_fhdr.dwWidth, dds_fhdr.dwHeight, dds_fhdr.dwSize, dds_fhdr.dwLinearSize);
758
759   if (!(dds_fhdr.dwFlags & (DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT|DDSD_LINEARSIZE))) {
760     DBG_INFO(80, L"Error: incompatible dds format!\n");
761     return NULL;
762   }
763
764   if ((dds_fhdr.dwFlags & DDSD_MIPMAPCOUNT) && dds_fhdr.dwMipMapCount != 1) {
765     DBG_INFO(80, L"Error: mipmapped dds not supported!\n");
766     return NULL;
767   }
768
769   if (!((dds_fhdr.ddpf.dwFlags & DDPF_FOURCC) && dds_fhdr.dwCaps2 == 0)) {
770     DBG_INFO(80, L"Error: not fourcc standard texture!\n");
771     return NULL;
772   }
773
774   if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT1", 4) == 0) {
775     DBG_INFO(80, L"DXT1 format\n");
776     /* compensate for missing LinearSize */
777     dds_fhdr.dwLinearSize = (dds_fhdr.dwWidth * dds_fhdr.dwHeight) >> 1;
778     tmpformat = GR_TEXFMT_ARGB_CMP_DXT1;
779   } else if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT3", 4) == 0) {
780     DBG_INFO(80, L"DXT3 format\n");
781     dds_fhdr.dwLinearSize = dds_fhdr.dwWidth * dds_fhdr.dwHeight;
782     tmpformat = GR_TEXFMT_ARGB_CMP_DXT3;
783   } else if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT5", 4) == 0) {
784     DBG_INFO(80, L"DXT5 format\n");
785     dds_fhdr.dwLinearSize = dds_fhdr.dwWidth * dds_fhdr.dwHeight;
786     tmpformat = GR_TEXFMT_ARGB_CMP_DXT5;
787   } else {
788     DBG_INFO(80, L"Error: not DXT1 or DXT3 or DXT5 format!\n");
789     return NULL;
790   }
791
792   /* read in image */
793   image = (uint8*)malloc(dds_fhdr.dwLinearSize);
794   if (image) {
795     *width  = dds_fhdr.dwWidth;
796     *height = dds_fhdr.dwHeight;
797     *format = tmpformat;
798
799     fseek(fp, 128, SEEK_SET); /* size of header is 128 bytes */
800     if (fread(image, 1, dds_fhdr.dwLinearSize, fp) != dds_fhdr.dwLinearSize)
801         ERRLOG("fread failed to read DDS image of '%i' bytes", dds_fhdr.dwLinearSize);
802   }
803
804   return image;
805 }