summaryrefslogtreecommitdiff
path: root/lib/dds.c
blob: 8138cd9d453adc778c55c9674cd938cdcea5796f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#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;

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;
}

void destroyDDS( DDS_IMAGE_DATA *pDDSImageData )
{
    if( pDDSImageData != NULL )
    {
        if( pDDSImageData->pixels != NULL )
            free( pDDSImageData->pixels );

        free( pDDSImageData );
    }
}

int loadCompressedTexture( DDS_IMAGE_DATA *pDDSImageData )
{
    int g_compressedTextureID;

    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);
        }
    }

    return g_compressedTextureID;
}

int ddsInit() {
    char *ext = (char*)glGetString( GL_EXTENSIONS );

    if( strstr( ext, "ARB_texture_compression" ) == NULL )
    {
//        MessageBox(NULL,"ARB_texture_compression extension was not found",
//            "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return -1;
    }
    else
    {
//        glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)glxGetProcAddress("glCompressedTexImage2DARB");

//        if( !glCompressedTexImage2DARB )
//        {
//            MessageBox(NULL,"One or more ARB_texture_compression functions were not found",
//                "ERROR",MB_OK|MB_ICONEXCLAMATION);
//            return -2;
//        }
    }

    return 0;
}