summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpixel <pixel>2007-07-17 03:26:32 +0000
committerpixel <pixel>2007-07-17 03:26:32 +0000
commit0ce03af6e877adebeda12787e249871c1fca43f2 (patch)
tree8d06f83f734972e228768344e1ebc22c1016114b
parente50632000d629de08fa3dae2e0d41fb67f8b2892 (diff)
Adding DDS support.
-rw-r--r--include/dds.h7
-rw-r--r--lib/dds.c298
2 files changed, 305 insertions, 0 deletions
diff --git a/include/dds.h b/include/dds.h
new file mode 100644
index 0000000..05911d2
--- /dev/null
+++ b/include/dds.h
@@ -0,0 +1,7 @@
+#ifndef __DDS_H__
+#define __DDS_H__
+
+// returns the OpenGL-generated texture index.
+int loadCompressedTexture( const char *fname );
+
+#endif
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 <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <inttypes.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h> // 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;
+}