Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-video-glide64mk2/src/GlideHQ/TxImage.cpp
2 views
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
}
806
807