From 0ce03af6e877adebeda12787e249871c1fca43f2 Mon Sep 17 00:00:00 2001 From: pixel Date: Tue, 17 Jul 2007 03:26:32 +0000 Subject: Adding DDS support. --- lib/dds.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 lib/dds.c (limited to 'lib/dds.c') diff --git a/lib/dds.c b/lib/dds.c new file mode 100644 index 0000000..82684d5 --- /dev/null +++ b/lib/dds.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include // Your local header file + +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \ + ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 )) + +typedef enum _D3DFORMAT { + D3DFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'), + D3DFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'), + D3DFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'), + D3DFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'), + D3DFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'), +} D3DFORMAT; + +typedef struct _DDCOLORKEY +{ + uint32_t dwColorSpaceLowValue;/* low boundary of color space that is to + * be treated as Color Key, inclusive + */ + uint32_t dwColorSpaceHighValue;/* high boundary of color space that is + * to be treated as Color Key, inclusive + */ +} DDCOLORKEY,*LPDDCOLORKEY; + +typedef struct _DDPIXELFORMAT { + uint32_t dwSize; /* 0: size of structure */ + uint32_t dwFlags; /* 4: pixel format flags */ + uint32_t dwFourCC; /* 8: (FOURCC code) */ + union { + uint32_t dwRGBBitCount; /* C: how many bits per pixel */ + uint32_t dwYUVBitCount; /* C: how many bits per pixel */ + uint32_t dwZBufferBitDepth; /* C: how many bits for z buffers */ + uint32_t dwAlphaBitDepth; /* C: how many bits for alpha channels*/ + uint32_t dwLuminanceBitCount; + uint32_t dwBumpBitCount; + } DUMMYUNIONNAME1; + union { + uint32_t dwRBitMask; /* 10: mask for red bit*/ + uint32_t dwYBitMask; /* 10: mask for Y bits*/ + uint32_t dwStencilBitDepth; + uint32_t dwLuminanceBitMask; + uint32_t dwBumpDuBitMask; + } DUMMYUNIONNAME2; + union { + uint32_t dwGBitMask; /* 14: mask for green bits*/ + uint32_t dwUBitMask; /* 14: mask for U bits*/ + uint32_t dwZBitMask; + uint32_t dwBumpDvBitMask; + } DUMMYUNIONNAME3; + union { + uint32_t dwBBitMask; /* 18: mask for blue bits*/ + uint32_t dwVBitMask; /* 18: mask for V bits*/ + uint32_t dwStencilBitMask; + uint32_t dwBumpLuminanceBitMask; + } DUMMYUNIONNAME4; + union { + uint32_t dwRGBAlphaBitMask; /* 1C: mask for alpha channel */ + uint32_t dwYUVAlphaBitMask; /* 1C: mask for alpha channel */ + uint32_t dwLuminanceAlphaBitMask; + uint32_t dwRGBZBitMask; /* 1C: mask for Z channel */ + uint32_t dwYUVZBitMask; /* 1C: mask for Z channel */ + } DUMMYUNIONNAME5; + /* 20: next structure */ +} DDPIXELFORMAT,*LPDDPIXELFORMAT; + +typedef struct _DDSCAPS2 { + uint32_t dwCaps; /* capabilities of surface wanted */ + uint32_t dwCaps2; /* additional capabilities */ + uint32_t dwCaps3; /* reserved capabilities */ + uint32_t dwCaps4; /* more reserved capabilities */ +} DDSCAPS2,*LPDDSCAPS2; + +typedef struct _DDSURFACEDESC2 +{ + uint32_t dwSize; /* 0: size of the DDSURFACEDESC2 structure*/ + uint32_t dwFlags; /* 4: determines what fields are valid*/ + uint32_t dwHeight; /* 8: height of surface to be created*/ + uint32_t dwWidth; /* C: width of input surface*/ + union { + uint32_t lPitch; /*10: distance to start of next line (return value only)*/ + uint32_t dwLinearSize; /*10: formless late-allocated optimized surface size */ + } x; + uint32_t dwBackBufferCount;/* 14: number of back buffers requested*/ + union { + uint32_t dwMipMapCount;/* 18:number of mip-map levels requested*/ + uint32_t dwRefreshRate;/* 18:refresh rate (used when display mode is described)*/ + uint32_t dwSrcVBHandle;/* 18:source used in VB::Optimize */ + } y; + uint32_t dwAlphaBitDepth;/* 1C:depth of alpha buffer requested*/ + uint32_t dwReserved; /* 20:reserved*/ + void * lpSurface; /* 24:pointer to the associated surface memory*/ + union { + DDCOLORKEY ddckCKDestOverlay; /* 28: CK for dest overlay use*/ + uint32_t dwEmptyFaceColor; /* 28: color for empty cubemap faces */ + } z; + DDCOLORKEY ddckCKDestBlt; /* 30: CK for destination blt use*/ + DDCOLORKEY ddckCKSrcOverlay;/* 38: CK for source overlay use*/ + DDCOLORKEY ddckCKSrcBlt; /* 40: CK for source blt use*/ + + union { + DDPIXELFORMAT ddpfPixelFormat;/* 48: pixel format description of the surface*/ + uint32_t dwFVF; /* 48: vertex format description of vertex buffers */ + } t; + DDSCAPS2 ddsCaps; /* 68: DDraw surface caps */ + uint32_t dwTextureStage; /* 78: stage in multitexture cascade */ +} DDSURFACEDESC2,*LPDDSURFACEDESC2; + +typedef struct +{ + GLsizei width; + GLsizei height; + GLint components; + GLenum format; + int numMipMaps; + GLubyte *pixels; +} DDS_IMAGE_DATA; + +static DDS_IMAGE_DATA* loadDDSTextureFile( const char *filename ) +{ + DDS_IMAGE_DATA *pDDSImageData; + DDSURFACEDESC2 ddsd; + char filecode[4]; + FILE *pFile; + int factor; + int bufferSize; + + // Open the file + pFile = fopen( filename, "rb" ); + + if( pFile == NULL ) + { + char str[255]; + sprintf( str, "loadDDSTextureFile couldn't find, or failed to load \"%s\"", filename ); +// MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION ); + return NULL; + } + + // Verify the file is a true .dds file + fread( filecode, 1, 4, pFile ); + + if( strncmp( filecode, "DDS ", 4 ) != 0 ) + { + char str[255]; + sprintf( str, "The file \"%s\" doesn't appear to be a valid .dds file!", filename ); +// MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION ); + fclose( pFile ); + return NULL; + } + + // Get the surface descriptor + fread( &ddsd, sizeof(ddsd), 1, pFile ); + + pDDSImageData = (DDS_IMAGE_DATA*) malloc(sizeof(DDS_IMAGE_DATA)); + + memset( pDDSImageData, 0, sizeof(DDS_IMAGE_DATA) ); + + // + // This .dds loader supports the loading of compressed formats DXT1, DXT3 + // and DXT5. + // + + switch( ddsd.t.ddpfPixelFormat.dwFourCC ) + { + case D3DFMT_DXT1: + // DXT1's compression ratio is 8:1 + pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + factor = 2; + break; + + case D3DFMT_DXT3: + // DXT3's compression ratio is 4:1 + pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + factor = 4; + break; + + case D3DFMT_DXT5: + // DXT5's compression ratio is 4:1 + pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + factor = 4; + break; + + default: { + char str[255]; + sprintf( str, "The file \"%s\" doesn't appear to be compressed " + "using DXT1, DXT3, or DXT5!", filename ); +// MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION ); + return NULL; + } + } + + // + // How big will the buffer need to be to load all of the pixel data + // including mip-maps? + // + + if( ddsd.x.dwLinearSize == 0 ) + { +// MessageBox( NULL, "dwLinearSize is 0!","ERROR", +// MB_OK|MB_ICONEXCLAMATION); + return NULL; + } + + if( ddsd.y.dwMipMapCount > 1 ) + bufferSize = ddsd.x.dwLinearSize * factor; + else + bufferSize = ddsd.x.dwLinearSize; + + pDDSImageData->pixels = (unsigned char*)malloc(bufferSize * sizeof(unsigned char)); + + fread( pDDSImageData->pixels, 1, bufferSize, pFile ); + + // Close the file + fclose( pFile ); + + pDDSImageData->width = ddsd.dwWidth; + pDDSImageData->height = ddsd.dwHeight; + pDDSImageData->numMipMaps = ddsd.y.dwMipMapCount; + + if( ddsd.t.ddpfPixelFormat.dwFourCC == D3DFMT_DXT1 ) + pDDSImageData->components = 3; + else + pDDSImageData->components = 4; + + return pDDSImageData; +} + +int loadCompressedTexture( const char *fname ) +{ + int g_compressedTextureID; + DDS_IMAGE_DATA *pDDSImageData = loadDDSTextureFile( fname ); + + if( pDDSImageData != NULL ) + { + int nHeight = pDDSImageData->height; + int nWidth = pDDSImageData->width; + int nNumMipMaps = pDDSImageData->numMipMaps; + + int nBlockSize; + + if( pDDSImageData->format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ) + nBlockSize = 8; + else + nBlockSize = 16; + + glGenTextures( 1, &g_compressedTextureID ); + glBindTexture( GL_TEXTURE_2D, g_compressedTextureID ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + int nSize; + int nOffset = 0; + int i; + + // Load the mip-map levels + + for( i = 0; i < nNumMipMaps; ++i ) + { + if( nWidth == 0 ) nWidth = 1; + if( nHeight == 0 ) nHeight = 1; + + nSize = ((nWidth+3)/4) * ((nHeight+3)/4) * nBlockSize; + + glCompressedTexImage2DARB( GL_TEXTURE_2D, + i, + pDDSImageData->format, + nWidth, + nHeight, + 0, + nSize, + pDDSImageData->pixels + nOffset ); + + nOffset += nSize; + + // Half the image size for the next mip-map level... + nWidth = (nWidth / 2); + nHeight = (nHeight / 2); + } + } + + if( pDDSImageData != NULL ) + { + if( pDDSImageData->pixels != NULL ) + free( pDDSImageData->pixels ); + + free( pDDSImageData ); + } + + return g_compressedTextureID; +} -- cgit v1.2.3