Path: blob/master/libmupen64plus/mupen64plus-video-glide64mk2/src/GlideHQ/TxImage.cpp
2 views
/*1* Texture Filtering2* Version: 1.03*4* Copyright (C) 2007 Hiroshi Morii All Rights Reserved.5* Email koolsmoky(at)users.sourceforge.net6* Web http://www.3dfxzone.it/koolsmoky7*8* this is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2, or (at your option)11* any later version.12*13* this is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with GNU Make; see the file COPYING. If not, write to20* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.21*/2223/* use power of 2 texture size24* (0:disable, 1:enable, 2:3dfx) */25#define POW2_TEXTURES 02627/* check 8 bytes. use a larger value if needed. */28#define PNG_CHK_BYTES 82930#include "TxImage.h"31#include "TxReSample.h"32#include "TxDbg.h"33#include <stdlib.h>34#include "../Glide64/Gfx_1.3.h"3536boolean37TxImage::getPNGInfo(FILE *fp, png_structp *png_ptr, png_infop *info_ptr)38{39unsigned char sig[PNG_CHK_BYTES];4041/* check for valid file pointer */42if (!fp)43return 0;4445/* check if file is PNG */46if (fread(sig, 1, PNG_CHK_BYTES, fp) != PNG_CHK_BYTES)47return 0;4849if (png_sig_cmp(sig, 0, PNG_CHK_BYTES) != 0)50return 0;5152/* get PNG file info */53*png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);54if (!*png_ptr)55return 0;5657*info_ptr = png_create_info_struct(*png_ptr);58if (!*info_ptr) {59png_destroy_read_struct(png_ptr, NULL, NULL);60return 0;61}6263if (setjmp(png_jmpbuf(*png_ptr))) {64DBG_INFO(80, L"error reading png!\n");65png_destroy_read_struct(png_ptr, info_ptr, NULL);66return 0;67}6869png_init_io(*png_ptr, fp);70png_set_sig_bytes(*png_ptr, PNG_CHK_BYTES);71png_read_info(*png_ptr, *info_ptr);7273return 1;74}7576uint8*77TxImage::readPNG(FILE* fp, int* width, int* height, uint16* format)78{79/* NOTE: returned image format is GR_TEXFMT_ARGB_8888 */8081png_structp png_ptr;82png_infop info_ptr;83uint8 *image = NULL;84int bit_depth, color_type, interlace_type, compression_type, filter_type,85row_bytes, o_width, o_height, num_pas;8687/* initialize */88*width = 0;89*height = 0;90*format = 0;9192/* check if we have a valid png file */93if (!fp)94return NULL;9596if (!getPNGInfo(fp, &png_ptr, &info_ptr)) {97INFO(80, L"error reading png file! png image is corrupt.\n");98return NULL;99}100101png_get_IHDR(png_ptr, info_ptr,102(png_uint_32*)&o_width, (png_uint_32*)&o_height, &bit_depth, &color_type,103&interlace_type, &compression_type, &filter_type);104105DBG_INFO(80, L"png format %d x %d bitdepth:%d color:%x interlace:%x compression:%x filter:%x\n",106o_width, o_height, bit_depth, color_type,107interlace_type, compression_type, filter_type);108109/* transformations */110111/* Rice hi-res textures112* _all.png113* _rgb.png, _a.png114* _ciByRGBA.png115* _allciByRGBA.png116*/117118/* strip if color channel is larger than 8 bits */119if (bit_depth > 8) {120png_set_strip_16(png_ptr);121bit_depth = 8;122}123124#if 1125/* These are not really required per Rice format spec,126* but is done just in case someone uses them.127*/128/* convert palette color to rgb color */129if (color_type == PNG_COLOR_TYPE_PALETTE) {130png_set_palette_to_rgb(png_ptr);131color_type = PNG_COLOR_TYPE_RGB;132}133134/* expand 1,2,4 bit gray scale to 8 bit gray scale */135if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)136png_set_expand_gray_1_2_4_to_8(png_ptr);137138/* convert gray scale or gray scale + alpha to rgb color */139if (color_type == PNG_COLOR_TYPE_GRAY ||140color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {141png_set_gray_to_rgb(png_ptr);142color_type = PNG_COLOR_TYPE_RGB;143}144#endif145146/* add alpha channel if any */147if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {148png_set_tRNS_to_alpha(png_ptr);149color_type = PNG_COLOR_TYPE_RGB_ALPHA;150}151152/* convert rgb to rgba */153if (color_type == PNG_COLOR_TYPE_RGB) {154png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);155color_type = PNG_COLOR_TYPE_RGB_ALPHA;156}157158/* punt invalid formats */159if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {160png_destroy_read_struct(&png_ptr, &info_ptr, NULL);161DBG_INFO(80, L"Error: not PNG_COLOR_TYPE_RGB_ALPHA format!\n");162return NULL;163}164165/*png_color_8p sig_bit;166if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))167png_set_shift(png_ptr, sig_bit);*/168169/* convert rgba to bgra */170png_set_bgr(png_ptr);171172/* turn on interlace handling to cope with the weirdness173* of texture authors using interlaced format */174num_pas = png_set_interlace_handling(png_ptr);175176/* update info structure */177png_read_update_info(png_ptr, info_ptr);178179/* we only get here if ARGB8888 */180row_bytes = png_get_rowbytes(png_ptr, info_ptr);181182/* allocate memory to read in image */183image = (uint8*)malloc(row_bytes * o_height);184185/* read in image */186if (image) {187int pas, i;188uint8* tmpimage;189190for (pas = 0; pas < num_pas; pas++) { /* deal with interlacing */191tmpimage = image;192193for (i = 0; i < o_height; i++) {194/* copy row */195png_read_rows(png_ptr, &tmpimage, NULL, 1);196tmpimage += row_bytes;197}198}199200/* read rest of the info structure */201png_read_end(png_ptr, info_ptr);202203*width = (row_bytes >> 2);204*height = o_height;205*format = GR_TEXFMT_ARGB_8888;206207#if POW2_TEXTURES208/* next power of 2 size conversions */209/* NOTE: I can do this in the above loop for faster operations, but some210* texture packs require a workaround. see HACKALERT in nextPow2().211*/212213TxReSample txReSample = new TxReSample; // XXX: temporary. move to a better place.214215#if (POW2_TEXTURES == 2)216if (!txReSample->nextPow2(&image, width, height, 32, 1)) {217#else218if (!txReSample->nextPow2(&image, width, height, 32, 0)) {219#endif220if (image) {221free(image);222image = NULL;223}224*width = 0;225*height = 0;226*format = 0;227}228229delete txReSample;230231#endif /* POW2_TEXTURES */232}233234/* clean up */235png_destroy_read_struct(&png_ptr, &info_ptr, NULL);236237#ifdef DEBUG238if (!image) {239DBG_INFO(80, L"Error: failed to load png image!\n");240}241#endif242243return image;244}245246boolean247TxImage::writePNG(uint8* src, FILE* fp, int width, int height, int rowStride, uint16 format, uint8 *palette)248{249png_structp png_ptr;250png_infop info_ptr;251png_color_8 sig_bit;252png_colorp palette_ptr = NULL;253png_bytep trans_ptr = NULL;254int bit_depth, color_type, row_bytes, num_palette;255int i;256//uint16 srcfmt, destfmt;257258if (!src || !fp)259return 0;260261png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);262if (png_ptr == NULL)263return 0;264265info_ptr = png_create_info_struct(png_ptr);266if (info_ptr == NULL) {267png_destroy_write_struct(&png_ptr, NULL);268return 0;269}270271if (png_jmpbuf(png_ptr)) {272png_destroy_write_struct(&png_ptr, &info_ptr);273return 0;274}275276png_init_io(png_ptr, fp);277278/* TODO: images must be converted to RGBA8888 or CI8,279* palettes need to be separated to A and RGB. */280281/* N64 formats282* Format: 0 - RGBA, 1 - YUV, 2 - CI, 3 - IA, 4 - I283* Size: 0 - 4bit, 1 - 8bit, 2 - 16bit, 3 - 32 bit284* format = (Format << 8 | Size);285*/286287/* each channel is saved in 8bits for consistency */288switch (format) {289case 0x0002:/* RGBA5551 */290bit_depth = 8;291sig_bit.red = 5;292sig_bit.green = 5;293sig_bit.blue = 5;294sig_bit.alpha = 1;295color_type = PNG_COLOR_TYPE_RGB_ALPHA;296break;297case 0x0003:/* RGBA8888 */298case 0x0302:/* IA88 */299bit_depth = 8;300sig_bit.red = 8;301sig_bit.green = 8;302sig_bit.blue = 8;303sig_bit.alpha = 8;304color_type = PNG_COLOR_TYPE_RGB_ALPHA;305break;306case 0x0300:/* IA31 */307bit_depth = 8;308sig_bit.red = 3;309sig_bit.green = 3;310sig_bit.blue = 3;311sig_bit.alpha = 1;312color_type = PNG_COLOR_TYPE_RGB_ALPHA;313break;314case 0x0301:/* IA44 */315bit_depth = 8;316sig_bit.red = 4;317sig_bit.green = 4;318sig_bit.blue = 4;319sig_bit.alpha = 4;320color_type = PNG_COLOR_TYPE_RGB_ALPHA;321break;322case 0x0400:/* I4 */323bit_depth = 8;324sig_bit.red = 4;325sig_bit.green = 4;326sig_bit.blue = 4;327color_type = PNG_COLOR_TYPE_RGB;328break;329case 0x0401:/* I8 */330case 0x0402:/* I16 */331bit_depth = 8;332sig_bit.red = 8;333sig_bit.green = 8;334sig_bit.blue = 8;335color_type = PNG_COLOR_TYPE_RGB;336break;337case 0x0200:/* CI4 */338bit_depth = 8;339num_palette = 16;340color_type = PNG_COLOR_TYPE_PALETTE;341break;342case 0x0201:/* CI8 */343bit_depth = 8;344num_palette = 256;345color_type = PNG_COLOR_TYPE_PALETTE;346break;347case 0x0102:/* YUV ? */348case 0x0103:349default:350/* unsupported format */351png_destroy_write_struct(&png_ptr, &info_ptr);352return 0;353}354355switch (color_type) {356case PNG_COLOR_TYPE_RGB_ALPHA:357case PNG_COLOR_TYPE_RGB:358//row_bytes = (bit_depth * width) >> 1;359row_bytes = rowStride;360png_set_bgr(png_ptr);361png_set_sBIT(png_ptr, info_ptr, &sig_bit);362break;363case PNG_COLOR_TYPE_PALETTE:364//row_bytes = (bit_depth * width) >> 3;365row_bytes = rowStride;366png_set_PLTE(png_ptr, info_ptr, palette_ptr, num_palette);367png_set_tRNS(png_ptr, info_ptr, trans_ptr, num_palette, 0);368}369370//png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);371372//if (bit_depth == 16)373// png_set_swap(png_ptr);374375//if (bit_depth < 8)376// png_set_packswap(png_ptr);377378png_set_IHDR(png_ptr, info_ptr, width, height,379bit_depth, color_type, PNG_INTERLACE_NONE,380PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);381382//png_set_gAMA(png_ptr, info_ptr, 1.0);383384png_write_info(png_ptr, info_ptr);385for (i = 0; i < height; i++) {386png_write_row(png_ptr, (png_bytep)src);387src += row_bytes;388}389png_write_end(png_ptr, info_ptr);390391png_destroy_write_struct(&png_ptr, &info_ptr);392393//if (tex_ptr) delete [] tex_ptr;394395return 1;396}397398boolean399TxImage::getBMPInfo(FILE* fp, BITMAPFILEHEADER* bmp_fhdr, BITMAPINFOHEADER* bmp_ihdr)400{401/*402* read in BITMAPFILEHEADER403*/404405/* is this a BMP file? */406if (fread(&bmp_fhdr->bfType, 2, 1, fp) != 1)407return 0;408409if (memcmp(&bmp_fhdr->bfType, "BM", 2) != 0)410return 0;411412/* get file size */413if (fread(&bmp_fhdr->bfSize, 4, 1, fp) != 1)414return 0;415416/* reserved 1 */417if (fread(&bmp_fhdr->bfReserved1, 2, 1, fp) != 1)418return 0;419420/* reserved 2 */421if (fread(&bmp_fhdr->bfReserved2, 2, 1, fp) != 1)422return 0;423424/* offset to the image data */425if (fread(&bmp_fhdr->bfOffBits, 4, 1, fp) != 1)426return 0;427428/*429* read in BITMAPINFOHEADER430*/431432/* size of BITMAPINFOHEADER */433if (fread(&bmp_ihdr->biSize, 4, 1, fp) != 1)434return 0;435436/* is this a Windows BMP? */437if (bmp_ihdr->biSize != 40)438return 0;439440/* width of the bitmap in pixels */441if (fread(&bmp_ihdr->biWidth, 4, 1, fp) != 1)442return 0;443444/* height of the bitmap in pixels */445if (fread(&bmp_ihdr->biHeight, 4, 1, fp) != 1)446return 0;447448/* number of planes (always 1) */449if (fread(&bmp_ihdr->biPlanes, 2, 1, fp) != 1)450return 0;451452/* number of bits-per-pixel. (1, 4, 8, 16, 24, 32) */453if (fread(&bmp_ihdr->biBitCount, 2, 1, fp) != 1)454return 0;455456/* compression for a compressed bottom-up bitmap457* 0 : uncompressed format458* 1 : run-length encoded 4 bpp format459* 2 : run-length encoded 8 bpp format460* 3 : bitfield461*/462if (fread(&bmp_ihdr->biCompression, 4, 1, fp) != 1)463return 0;464465/* size of the image in bytes */466if (fread(&bmp_ihdr->biSizeImage, 4, 1, fp) != 1)467return 0;468469/* horizontal resolution in pixels-per-meter */470if (fread(&bmp_ihdr->biXPelsPerMeter, 4, 1, fp) != 1)471return 0;472473/* vertical resolution in pixels-per-meter */474if (fread(&bmp_ihdr->biYPelsPerMeter, 4, 1, fp) != 1)475return 0;476477/* number of color indexes in the color table that are actually used */478if (fread(&bmp_ihdr->biClrUsed, 4, 1, fp) != 1)479return 0;480481/* the number of color indexes that are required for displaying */482if (fread(&bmp_ihdr->biClrImportant, 4, 1, fp) != 1)483return 0;484485return 1;486}487488uint8*489TxImage::readBMP(FILE* fp, int* width, int* height, uint16* format)490{491/* NOTE: returned image format;492* 4, 8bit palette bmp -> GR_TEXFMT_P_8493* 24, 32bit bmp -> GR_TEXFMT_ARGB_8888494*/495496uint8 *image = NULL;497uint8 *image_row = NULL;498uint8 *tmpimage = NULL;499unsigned int row_bytes, pos;500int i, j;501/* Windows Bitmap */502BITMAPFILEHEADER bmp_fhdr;503BITMAPINFOHEADER bmp_ihdr;504505/* initialize */506*width = 0;507*height = 0;508*format = 0;509510/* check if we have a valid bmp file */511if (!fp)512return NULL;513514if (!getBMPInfo(fp, &bmp_fhdr, &bmp_ihdr)) {515INFO(80, L"error reading bitmap file! bitmap image is corrupt.\n");516return NULL;517}518519DBG_INFO(80, L"bmp format %d x %d bitdepth:%d compression:%x offset:%d\n",520bmp_ihdr.biWidth, bmp_ihdr.biHeight, bmp_ihdr.biBitCount,521bmp_ihdr.biCompression, bmp_fhdr.bfOffBits);522523/* rowStride in bytes */524row_bytes = (bmp_ihdr.biWidth * bmp_ihdr.biBitCount) >> 3;525/* align to 4bytes boundary */526row_bytes = (row_bytes + 3) & ~3;527528/* Rice hi-res textures */529if (!(bmp_ihdr.biBitCount == 8 || bmp_ihdr.biBitCount == 4 || bmp_ihdr.biBitCount == 32 || bmp_ihdr.biBitCount == 24) ||530bmp_ihdr.biCompression != 0) {531DBG_INFO(80, L"Error: incompatible bitmap format!\n");532return NULL;533}534535switch (bmp_ihdr.biBitCount) {536case 8:537case 32:538/* 8 bit, 32 bit bitmap */539image = (uint8*)malloc(row_bytes * bmp_ihdr.biHeight);540if (image) {541tmpimage = image;542pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);543for (i = 0; i < bmp_ihdr.biHeight; i++) {544/* read in image */545fseek(fp, pos, SEEK_SET);546if (fread(tmpimage, 1, row_bytes, fp) != row_bytes)547ERRLOG("fread() failed for row of '%i' bytes in 8/32-bit BMP image", row_bytes);548tmpimage += row_bytes;549pos -= row_bytes;550}551}552break;553case 4:554/* 4bit bitmap */555image = (uint8*)malloc((row_bytes * bmp_ihdr.biHeight) << 1);556image_row = (uint8*)malloc(row_bytes);557if (image && image_row) {558tmpimage = image;559pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);560for (i = 0; i < bmp_ihdr.biHeight; i++) {561/* read in image */562fseek(fp, pos, SEEK_SET);563if (fread(image_row, 1, row_bytes, fp) != row_bytes)564ERRLOG("fread failed for row of '%i' bytes in 4-bit BMP image", row_bytes);565/* expand 4bpp to 8bpp. stuff 4bit values into 8bit comps. */566for (j = 0; j < (int) row_bytes; j++) {567tmpimage[j << 1] = image_row[j] & 0x0f;568tmpimage[(j << 1) + 1] = (image_row[j] & 0xf0) >> 4;569}570tmpimage += (row_bytes << 1);571pos -= row_bytes;572}573free(image_row);574} else {575if (image_row) free(image_row);576if (image) free(image);577image = NULL;578}579break;580case 24:581/* 24 bit bitmap */582image = (uint8*)malloc((bmp_ihdr.biWidth * bmp_ihdr.biHeight) << 2);583image_row = (uint8*)malloc(row_bytes);584if (image && image_row) {585tmpimage = image;586pos = bmp_fhdr.bfOffBits + row_bytes * (bmp_ihdr.biHeight - 1);587for (i = 0; i < bmp_ihdr.biHeight; i++) {588/* read in image */589fseek(fp, pos, SEEK_SET);590if (fread(image_row, 1, row_bytes, fp) != row_bytes)591ERRLOG("fread failed for row of '%i' bytes in 24-bit BMP image", row_bytes);592/* convert 24bpp to 32bpp. */593for (j = 0; j < bmp_ihdr.biWidth; j++) {594tmpimage[(j << 2)] = image_row[j * 3];595tmpimage[(j << 2) + 1] = image_row[j * 3 + 1];596tmpimage[(j << 2) + 2] = image_row[j * 3 + 2];597tmpimage[(j << 2) + 3] = 0xFF;598}599tmpimage += (bmp_ihdr.biWidth << 2);600pos -= row_bytes;601}602free(image_row);603} else {604if (image_row) free(image_row);605if (image) free(image);606image = NULL;607}608}609610if (image) {611*width = (row_bytes << 3) / bmp_ihdr.biBitCount;612*height = bmp_ihdr.biHeight;613614switch (bmp_ihdr.biBitCount) {615case 8:616case 4:617*format = GR_TEXFMT_P_8;618break;619case 32:620case 24:621*format = GR_TEXFMT_ARGB_8888;622}623624#if POW2_TEXTURES625/* next power of 2 size conversions */626/* NOTE: I can do this in the above loop for faster operations, but some627* texture packs require a workaround. see HACKALERT in nextPow2().628*/629630TxReSample txReSample = new TxReSample; // XXX: temporary. move to a better place.631632#if (POW2_TEXTURES == 2)633if (!txReSample->nextPow2(&image, width, height, 8, 1)) {634#else635if (!txReSample->nextPow2(&image, width, height, 8, 0)) {636#endif637if (image) {638free(image);639image = NULL;640}641*width = 0;642*height = 0;643*format = 0;644}645646delete txReSample;647648#endif /* POW2_TEXTURES */649}650651#ifdef DEBUG652if (!image) {653DBG_INFO(80, L"Error: failed to load bmp image!\n");654}655#endif656657return image;658}659660boolean661TxImage::getDDSInfo(FILE *fp, DDSFILEHEADER *dds_fhdr)662{663/*664* read in DDSFILEHEADER665*/666667/* is this a DDS file? */668if (fread(&dds_fhdr->dwMagic, 4, 1, fp) != 1)669return 0;670671if (memcmp(&dds_fhdr->dwMagic, "DDS ", 4) != 0)672return 0;673674if (fread(&dds_fhdr->dwSize, 4, 1, fp) != 1)675return 0;676677/* get file flags */678if (fread(&dds_fhdr->dwFlags, 4, 1, fp) != 1)679return 0;680681/* height of dds in pixels */682if (fread(&dds_fhdr->dwHeight, 4, 1, fp) != 1)683return 0;684685/* width of dds in pixels */686if (fread(&dds_fhdr->dwWidth, 4, 1, fp) != 1)687return 0;688689if (fread(&dds_fhdr->dwLinearSize, 4, 1, fp) != 1)690return 0;691692if (fread(&dds_fhdr->dwDepth, 4, 1, fp) != 1)693return 0;694695if (fread(&dds_fhdr->dwMipMapCount, 4, 1, fp) != 1)696return 0;697698if (fread(&dds_fhdr->dwReserved1, 4 * 11, 1, fp) != 1)699return 0;700701if (fread(&dds_fhdr->ddpf.dwSize, 4, 1, fp) != 1)702return 0;703704if (fread(&dds_fhdr->ddpf.dwFlags, 4, 1, fp) != 1)705return 0;706707if (fread(&dds_fhdr->ddpf.dwFourCC, 4, 1, fp) != 1)708return 0;709710if (fread(&dds_fhdr->ddpf.dwRGBBitCount, 4, 1, fp) != 1)711return 0;712713if (fread(&dds_fhdr->ddpf.dwRBitMask, 4, 1, fp) != 1)714return 0;715716if (fread(&dds_fhdr->ddpf.dwGBitMask, 4, 1, fp) != 1)717return 0;718719if (fread(&dds_fhdr->ddpf.dwBBitMask, 4, 1, fp) != 1)720return 0;721722if (fread(&dds_fhdr->ddpf.dwRGBAlphaBitMask, 4, 1, fp) != 1)723return 0;724725if (fread(&dds_fhdr->dwCaps1, 4, 1, fp) != 1)726return 0;727728if (fread(&dds_fhdr->dwCaps2, 4, 1, fp) != 1)729return 0;730731return 1;732}733734uint8*735TxImage::readDDS(FILE* fp, int* width, int* height, uint16* format)736{737uint8 *image = NULL;738DDSFILEHEADER dds_fhdr;739uint16 tmpformat = 0;740741/* initialize */742*width = 0;743*height = 0;744*format = 0;745746/* check if we have a valid dds file */747if (!fp)748return NULL;749750if (!getDDSInfo(fp, &dds_fhdr)) {751INFO(80, L"error reading dds file! dds image is corrupt.\n");752return NULL;753}754755DBG_INFO(80, L"dds format %d x %d HeaderSize %d LinearSize %d\n",756dds_fhdr.dwWidth, dds_fhdr.dwHeight, dds_fhdr.dwSize, dds_fhdr.dwLinearSize);757758if (!(dds_fhdr.dwFlags & (DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT|DDSD_LINEARSIZE))) {759DBG_INFO(80, L"Error: incompatible dds format!\n");760return NULL;761}762763if ((dds_fhdr.dwFlags & DDSD_MIPMAPCOUNT) && dds_fhdr.dwMipMapCount != 1) {764DBG_INFO(80, L"Error: mipmapped dds not supported!\n");765return NULL;766}767768if (!((dds_fhdr.ddpf.dwFlags & DDPF_FOURCC) && dds_fhdr.dwCaps2 == 0)) {769DBG_INFO(80, L"Error: not fourcc standard texture!\n");770return NULL;771}772773if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT1", 4) == 0) {774DBG_INFO(80, L"DXT1 format\n");775/* compensate for missing LinearSize */776dds_fhdr.dwLinearSize = (dds_fhdr.dwWidth * dds_fhdr.dwHeight) >> 1;777tmpformat = GR_TEXFMT_ARGB_CMP_DXT1;778} else if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT3", 4) == 0) {779DBG_INFO(80, L"DXT3 format\n");780dds_fhdr.dwLinearSize = dds_fhdr.dwWidth * dds_fhdr.dwHeight;781tmpformat = GR_TEXFMT_ARGB_CMP_DXT3;782} else if (memcmp(&dds_fhdr.ddpf.dwFourCC, "DXT5", 4) == 0) {783DBG_INFO(80, L"DXT5 format\n");784dds_fhdr.dwLinearSize = dds_fhdr.dwWidth * dds_fhdr.dwHeight;785tmpformat = GR_TEXFMT_ARGB_CMP_DXT5;786} else {787DBG_INFO(80, L"Error: not DXT1 or DXT3 or DXT5 format!\n");788return NULL;789}790791/* read in image */792image = (uint8*)malloc(dds_fhdr.dwLinearSize);793if (image) {794*width = dds_fhdr.dwWidth;795*height = dds_fhdr.dwHeight;796*format = tmpformat;797798fseek(fp, 128, SEEK_SET); /* size of header is 128 bytes */799if (fread(image, 1, dds_fhdr.dwLinearSize, fp) != dds_fhdr.dwLinearSize)800ERRLOG("fread failed to read DDS image of '%i' bytes", dds_fhdr.dwLinearSize);801}802803return image;804}805806807