Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / GlideHQ / TxImage.cpp
CommitLineData
98e75f2d 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
37boolean
38TxImage::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
77uint8*
78TxImage::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
247boolean
248TxImage::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
399boolean
400TxImage::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
489uint8*
490TxImage::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
661boolean
662TxImage::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
735uint8*
736TxImage::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}