]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/ddslib/ddslib.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / libs / ddslib / ddslib.c
1 /* -----------------------------------------------------------------------------\r
2 \r
3 DDS Library \r
4 \r
5 Based on code from Nvidia's DDS example:\r
6 http://www.nvidia.com/object/dxtc_decompression_code.html\r
7 \r
8 Copyright (c) 2003 Randy Reddig\r
9 All rights reserved.\r
10 \r
11 Redistribution and use in source and binary forms, with or without modification,\r
12 are permitted provided that the following conditions are met:\r
13 \r
14 Redistributions of source code must retain the above copyright notice, this list\r
15 of conditions and the following disclaimer.\r
16 \r
17 Redistributions in binary form must reproduce the above copyright notice, this\r
18 list of conditions and the following disclaimer in the documentation and/or\r
19 other materials provided with the distribution.\r
20 \r
21 Neither the names of the copyright holders nor the names of its contributors may\r
22 be used to endorse or promote products derived from this software without\r
23 specific prior written permission. \r
24 \r
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
26 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
28 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
29 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
30 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
32 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
34 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
35 \r
36 ----------------------------------------------------------------------------- */\r
37 \r
38 \r
39 \r
40 /* marker */\r
41 #define DDSLIB_C\r
42 \r
43 \r
44 \r
45 /* dependencies */\r
46 #include "ddslib.h"\r
47 \r
48 \r
49 \r
50 /* endian tomfoolery */\r
51 typedef union\r
52 {\r
53         float   f;\r
54         char    c[ 4 ];\r
55 }\r
56 floatSwapUnion;\r
57 \r
58 \r
59 #ifndef __BIG_ENDIAN__\r
60         #ifdef _SGI_SOURCE\r
61                 #define __BIG_ENDIAN__\r
62         #endif\r
63 #endif\r
64 \r
65 \r
66 #ifdef __BIG_ENDIAN__\r
67 \r
68         int   DDSBigLong( int src ) { return src; }\r
69         short DDSBigShort( short src ) { return src; }\r
70         float DDSBigFloat( float src ) { return src; }\r
71 \r
72         int DDSLittleLong( int src )\r
73         {\r
74                 return ((src & 0xFF000000) >> 24) |\r
75                            ((src & 0x00FF0000) >> 8) |\r
76                            ((src & 0x0000FF00) << 8) |\r
77                            ((src & 0x000000FF) << 24);\r
78         }\r
79 \r
80         short DDSLittleShort( short src )\r
81         {\r
82                 return ((src & 0xFF00) >> 8) |\r
83                            ((src & 0x00FF) << 8);\r
84         }\r
85 \r
86         float DDSLittleFloat( float src )\r
87         {\r
88                 floatSwapUnion in,out;\r
89                 in.f = src;\r
90                 out.c[ 0 ] = in.c[ 3 ];\r
91                 out.c[ 1 ] = in.c[ 2 ];\r
92                 out.c[ 2 ] = in.c[ 1 ];\r
93                 out.c[ 3 ] = in.c[ 0 ];\r
94                 return out.f;\r
95         }\r
96 \r
97 #else /*__BIG_ENDIAN__*/\r
98 \r
99         int   DDSLittleLong( int src ) { return src; }\r
100         short DDSLittleShort( short src ) { return src; }\r
101         float DDSLittleFloat( float src ) { return src; }\r
102                 \r
103         int DDSBigLong( int src )\r
104         {\r
105                 return ((src & 0xFF000000) >> 24) |\r
106                            ((src & 0x00FF0000) >> 8) |\r
107                            ((src & 0x0000FF00) << 8) |\r
108                            ((src & 0x000000FF) << 24);\r
109         }\r
110                 \r
111         short DDSBigShort( short src )\r
112         {\r
113                 return ((src & 0xFF00) >> 8) |\r
114                            ((src & 0x00FF) << 8);\r
115         }\r
116                 \r
117         float DDSBigFloat( float src )\r
118         {\r
119                 floatSwapUnion in,out;\r
120                 in.f = src;\r
121                 out.c[ 0 ] = in.c[ 3 ];\r
122                 out.c[ 1 ] = in.c[ 2 ];\r
123                 out.c[ 2 ] = in.c[ 1 ];\r
124                 out.c[ 3 ] = in.c[ 0 ];\r
125                 return out.f;\r
126         }\r
127 \r
128 #endif /*__BIG_ENDIAN__*/\r
129 \r
130 \r
131 \r
132 /*\r
133 DDSDecodePixelFormat()\r
134 determines which pixel format the dds texture is in\r
135 */\r
136 \r
137 static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf )\r
138 {\r
139         unsigned int    fourCC;\r
140         \r
141         \r
142         /* dummy check */\r
143         if(     dds == NULL || pf == NULL )\r
144                 return;\r
145         \r
146         /* extract fourCC */\r
147         fourCC = dds->pixelFormat.fourCC;\r
148         \r
149         /* test it */\r
150         if( fourCC == 0 )\r
151                 *pf = DDS_PF_ARGB8888;\r
152         else if( fourCC == *((unsigned int*) "DXT1") )\r
153                 *pf = DDS_PF_DXT1;\r
154         else if( fourCC == *((unsigned int*) "DXT2") )\r
155                 *pf = DDS_PF_DXT2;\r
156         else if( fourCC == *((unsigned int*) "DXT3") )\r
157                 *pf = DDS_PF_DXT3;\r
158         else if( fourCC == *((unsigned int*) "DXT4") )\r
159                 *pf = DDS_PF_DXT4;\r
160         else if( fourCC == *((unsigned int*) "DXT5") )\r
161                 *pf = DDS_PF_DXT5;\r
162         else\r
163                 *pf = DDS_PF_UNKNOWN;\r
164 }\r
165 \r
166 \r
167 \r
168 /*\r
169 DDSGetInfo()\r
170 extracts relevant info from a dds texture, returns 0 on success\r
171 */\r
172 \r
173 int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf )\r
174 {\r
175         /* dummy test */\r
176         if( dds == NULL )\r
177                 return -1;\r
178         \r
179         /* test dds header */\r
180         if( *((int*) dds->magic) != *((int*) "DDS ") )\r
181                 return -1;\r
182         if( DDSLittleLong( dds->size ) != 124 )\r
183                 return -1;\r
184         \r
185         /* extract width and height */\r
186         if( width != NULL )\r
187                 *width = DDSLittleLong( dds->width );\r
188         if( height != NULL )\r
189                 *height = DDSLittleLong( dds->height );\r
190         \r
191         /* get pixel format */\r
192         DDSDecodePixelFormat( dds, pf );\r
193         \r
194         /* return ok */\r
195         return 0;\r
196 }\r
197 \r
198 \r
199 \r
200 /*\r
201 DDSGetColorBlockColors()\r
202 extracts colors from a dds color block\r
203 */\r
204 \r
205 static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] )\r
206 {\r
207         unsigned short          word;\r
208 \r
209         \r
210         /* color 0 */\r
211         word = DDSLittleShort( block->colors[ 0 ] );\r
212         colors[ 0 ].a = 0xff;\r
213         \r
214         /* extract rgb bits */\r
215         colors[ 0 ].b = (unsigned char) word;\r
216         colors[ 0 ].b <<= 3;\r
217         colors[ 0 ].b |= (colors[ 0 ].b >> 5);\r
218         word >>= 5;\r
219         colors[ 0 ].g = (unsigned char) word;\r
220         colors[ 0 ].g <<= 2;\r
221         colors[ 0 ].g |= (colors[ 0 ].g >> 5);\r
222         word >>= 6;\r
223         colors[ 0 ].r = (unsigned char) word;\r
224         colors[ 0 ].r <<= 3;\r
225         colors[ 0 ].r |= (colors[ 0 ].r >> 5);\r
226 \r
227         /* same for color 1 */\r
228         word = DDSLittleShort( block->colors[ 1 ] );\r
229         colors[ 1 ].a = 0xff;\r
230         \r
231         /* extract rgb bits */\r
232         colors[ 1 ].b = (unsigned char) word;\r
233         colors[ 1 ].b <<= 3;\r
234         colors[ 1 ].b |= (colors[ 1 ].b >> 5);\r
235         word >>= 5;\r
236         colors[ 1 ].g = (unsigned char) word;\r
237         colors[ 1 ].g <<= 2;\r
238         colors[ 1 ].g |= (colors[ 1 ].g >> 5);\r
239         word >>= 6;\r
240         colors[ 1 ].r = (unsigned char) word;\r
241         colors[ 1 ].r <<= 3;\r
242         colors[ 1 ].r |= (colors[ 1 ].r >> 5);\r
243         \r
244         /* use this for all but the super-freak math method */\r
245         if( block->colors[ 0 ] > block->colors[ 1 ] )\r
246         {\r
247                 /* four-color block: derive the other two colors.    \r
248                    00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3\r
249                    these two bit codes correspond to the 2-bit fields \r
250                    stored in the 64-bit block. */\r
251 \r
252                 word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3;\r
253                                                                                         /* no +1 for rounding */\r
254                                                                                         /* as bits have been shifted to 888 */\r
255                 colors[ 2 ].r = (unsigned char) word;\r
256                 word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3;\r
257                 colors[ 2 ].g = (unsigned char) word;\r
258                 word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3;\r
259                 colors[ 2 ].b = (unsigned char) word;\r
260                 colors[ 2 ].a = 0xff;\r
261 \r
262                 word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3;\r
263                 colors[ 3 ].r = (unsigned char) word;\r
264                 word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3;\r
265                 colors[ 3 ].g = (unsigned char) word;\r
266                 word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3;\r
267                 colors[ 3 ].b = (unsigned char) word;\r
268                 colors[ 3 ].a = 0xff;\r
269         }\r
270         else\r
271         {\r
272                 /* three-color block: derive the other color.\r
273                    00 = color 0, 01 = color 1, 10 = color 2,  \r
274                    11 = transparent.\r
275                    These two bit codes correspond to the 2-bit fields \r
276                    stored in the 64-bit block */\r
277 \r
278                 word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2;\r
279                 colors[ 2 ].r = (unsigned char) word;\r
280                 word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2;\r
281                 colors[ 2 ].g = (unsigned char) word;\r
282                 word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2;\r
283                 colors[ 2 ].b = (unsigned char) word;\r
284                 colors[ 2 ].a = 0xff;\r
285                 \r
286                 /* random color to indicate alpha */\r
287                 colors[ 3 ].r = 0x00;\r
288                 colors[ 3 ].g = 0xff;\r
289                 colors[ 3 ].b = 0xff;\r
290                 colors[ 3 ].a = 0x00;\r
291         }\r
292 }\r
293 \r
294 \r
295 \r
296 /*\r
297 DDSDecodeColorBlock()\r
298 decodes a dds color block\r
299 fixme: make endian-safe\r
300 */\r
301 \r
302 static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] )\r
303 {\r
304         int                             r, n;\r
305         unsigned int    bits;\r
306         unsigned int    masks[] = { 3, 12, 3 << 4, 3 << 6 };    /* bit masks = 00000011, 00001100, 00110000, 11000000 */\r
307         int                             shift[] = { 0, 2, 4, 6 };\r
308         \r
309         \r
310         /* r steps through lines in y */\r
311         for( r = 0; r < 4; r++, pixel += (width - 4) )  /* no width * 4 as unsigned int ptr inc will * 4 */\r
312         {\r
313                 /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */\r
314 \r
315                 /* n steps through pixels */\r
316                 for( n = 0; n < 4; n++ )\r
317                 {\r
318                         bits = block->row[ r ] & masks[ n ];\r
319                         bits >>= shift[ n ];\r
320 \r
321                         switch( bits )\r
322                         {\r
323                                 case 0:\r
324                                         *pixel = colors[ 0 ];\r
325                                         pixel++;\r
326                                         break;\r
327 \r
328                                 case 1:\r
329                                         *pixel = colors[ 1 ];\r
330                                         pixel++;\r
331                                         break;\r
332 \r
333                                 case 2:\r
334                                         *pixel = colors[ 2 ];\r
335                                         pixel++;\r
336                                         break;\r
337 \r
338                                 case 3:\r
339                                         *pixel = colors[ 3 ];\r
340                                         pixel++;\r
341                                         break;\r
342 \r
343                                 default:\r
344                                         /* invalid */\r
345                                         pixel++;\r
346                                         break;\r
347                         }\r
348                 }\r
349         }\r
350 }\r
351 \r
352 \r
353 \r
354 /*\r
355 DDSDecodeAlphaExplicit()\r
356 decodes a dds explicit alpha block\r
357 */\r
358 \r
359 static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero )\r
360 {       \r
361         int                             row, pix;\r
362         unsigned short  word;\r
363         ddsColor_t              color;\r
364         \r
365         \r
366         /* clear color */\r
367         color.r = 0;\r
368         color.g = 0;\r
369         color.b = 0;\r
370         \r
371         /* walk rows */\r
372         for( row = 0; row < 4; row++, pixel += (width - 4) )\r
373         {\r
374                 word = DDSLittleShort( alphaBlock->row[ row ] );\r
375                 \r
376                 /* walk pixels */\r
377                 for( pix = 0; pix < 4; pix++ )\r
378                 {\r
379                         /* zero the alpha bits of image pixel */\r
380                         *pixel &= alphaZero;\r
381                         color.a = word & 0x000F;\r
382                         color.a = color.a | (color.a << 4);\r
383                         *pixel |= *((unsigned int*) &color);\r
384                         word >>= 4;             /* move next bits to lowest 4 */\r
385                         pixel++;                /* move to next pixel in the row */\r
386 \r
387                 }\r
388         }\r
389 }\r
390 \r
391 \r
392 \r
393 /*\r
394 DDSDecodeAlpha3BitLinear()\r
395 decodes interpolated alpha block\r
396 */\r
397 \r
398 static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero )\r
399 {\r
400         \r
401         int                                     row, pix;\r
402         unsigned int            stuff;\r
403         unsigned char           bits[ 4 ][ 4 ];\r
404         unsigned short          alphas[ 8 ];\r
405         ddsColor_t                      aColors[ 4 ][ 4 ];\r
406         \r
407         \r
408         /* get initial alphas */\r
409         alphas[ 0 ] = alphaBlock->alpha0;\r
410         alphas[ 1 ] = alphaBlock->alpha1;\r
411         \r
412         /* 8-alpha block */\r
413         if( alphas[ 0 ] > alphas[ 1 ] )\r
414         {\r
415                 /* 000 = alpha_0, 001 = alpha_1, others are interpolated */\r
416                 alphas[ 2 ] = ( 6 * alphas[ 0 ] +     alphas[ 1 ]) / 7; /* bit code 010 */\r
417                 alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */\r
418                 alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */\r
419                 alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */\r
420                 alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */\r
421                 alphas[ 7 ] = (     alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */\r
422         }\r
423         \r
424         /* 6-alpha block */\r
425         else\r
426         { \r
427                 /* 000 = alpha_0, 001 = alpha_1, others are interpolated */\r
428                 alphas[ 2 ] = (4 * alphas[ 0 ] +     alphas[ 1 ]) / 5;  /* bit code 010 */\r
429                 alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5;  /* bit code 011 */\r
430                 alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5;  /* bit code 100 */\r
431                 alphas[ 5 ] = (    alphas[ 0 ] + 4 * alphas[ 1 ]) / 5;  /* bit code 101 */\r
432                 alphas[ 6 ] = 0;                                                                                /* bit code 110 */\r
433                 alphas[ 7 ] = 255;                                                                              /* bit code 111 */\r
434         }\r
435         \r
436         /* decode 3-bit fields into array of 16 bytes with same value */\r
437         \r
438         /* first two rows of 4 pixels each */\r
439         stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ]));\r
440         \r
441         bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007);\r
442         stuff >>= 3;\r
443         bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007);\r
444         stuff >>= 3;\r
445         bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007);\r
446         stuff >>= 3;\r
447         bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007);\r
448         stuff >>= 3;\r
449         bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007);\r
450         stuff >>= 3;\r
451         bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007);\r
452         stuff >>= 3;\r
453         bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007);\r
454         stuff >>= 3;\r
455         bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007);\r
456         \r
457         /* last two rows */\r
458         stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */\r
459         \r
460         bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007);\r
461         stuff >>= 3;\r
462         bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007);\r
463         stuff >>= 3;\r
464         bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007);\r
465         stuff >>= 3;\r
466         bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007);\r
467         stuff >>= 3;\r
468         bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007);\r
469         stuff >>= 3;\r
470         bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007);\r
471         stuff >>= 3;\r
472         bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007);\r
473         stuff >>= 3;\r
474         bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007);\r
475         \r
476         /* decode the codes into alpha values */\r
477         for( row = 0; row < 4; row++ )\r
478         {\r
479                 for( pix=0; pix < 4; pix++ )\r
480                 {\r
481                         aColors[ row ][ pix ].r = 0;\r
482                         aColors[ row ][ pix ].g = 0;\r
483                         aColors[ row ][ pix ].b = 0;\r
484                         aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ];\r
485                 }\r
486         }\r
487         \r
488         /* write out alpha values to the image bits */\r
489         for( row = 0; row < 4; row++, pixel += width-4 )\r
490         {\r
491                 for( pix = 0; pix < 4; pix++ )\r
492                 {\r
493                         /* zero the alpha bits of image pixel */\r
494                         *pixel &= alphaZero;\r
495                         \r
496                         /* or the bits into the prev. nulled alpha */\r
497                         *pixel |= *((unsigned int*) &(aColors[ row ][ pix ]));  \r
498                         pixel++;\r
499                 }\r
500         }\r
501 }\r
502 \r
503 \r
504 \r
505 /*\r
506 DDSDecompressDXT1()\r
507 decompresses a dxt1 format texture\r
508 */\r
509 \r
510 static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
511 {\r
512         int                             x, y, xBlocks, yBlocks;\r
513         unsigned int    *pixel;\r
514         ddsColorBlock_t *block;\r
515         ddsColor_t              colors[ 4 ];\r
516         \r
517         \r
518         /* setup */\r
519         xBlocks = width / 4;\r
520         yBlocks = height / 4;\r
521         \r
522         /* walk y */\r
523         for( y = 0; y < yBlocks; y++ )\r
524         {\r
525                 /* 8 bytes per block */\r
526                 block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8);\r
527 \r
528                 /* walk x */\r
529                 for( x = 0; x < xBlocks; x++, block++ )\r
530                 {\r
531                         DDSGetColorBlockColors( block, colors );\r
532                         pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);\r
533                         DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );\r
534                 }\r
535         }\r
536         \r
537         /* return ok */\r
538         return 0;\r
539 }\r
540 \r
541 \r
542 \r
543 /*\r
544 DDSDecompressDXT3()\r
545 decompresses a dxt3 format texture\r
546 */\r
547 \r
548 static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
549 {\r
550         int                                             x, y, xBlocks, yBlocks;\r
551         unsigned int                    *pixel, alphaZero;\r
552         ddsColorBlock_t                 *block;\r
553         ddsAlphaBlockExplicit_t *alphaBlock;\r
554         ddsColor_t                              colors[ 4 ];\r
555 \r
556 \r
557         /* setup */\r
558         xBlocks = width / 4;\r
559         yBlocks = height / 4;\r
560         \r
561         /* create zero alpha */\r
562         colors[ 0 ].a = 0;\r
563         colors[ 0 ].r = 0xFF;\r
564         colors[ 0 ].g = 0xFF;\r
565         colors[ 0 ].b = 0xFF;\r
566         alphaZero = *((unsigned int*) &colors[ 0 ]);\r
567         \r
568         /* walk y */\r
569         for( y = 0; y < yBlocks; y++ )\r
570         {\r
571                 /* 8 bytes per block, 1 block for alpha, 1 block for color */\r
572                 block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16);\r
573 \r
574                 /* walk x */\r
575                 for( x = 0; x < xBlocks; x++, block++ )\r
576                 {\r
577                         /* get alpha block */\r
578                         alphaBlock = (ddsAlphaBlockExplicit_t*) block;\r
579                         \r
580                         /* get color block */\r
581                         block++;\r
582                         DDSGetColorBlockColors( block, colors );\r
583                         \r
584                         /* decode color block */\r
585                         pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);\r
586                         DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );\r
587                         \r
588                         /* overwrite alpha bits with alpha block */\r
589                         DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero );\r
590                 }\r
591         }\r
592         \r
593         /* return ok */\r
594         return 0;\r
595 }\r
596 \r
597 \r
598 \r
599 /*\r
600 DDSDecompressDXT5()\r
601 decompresses a dxt5 format texture\r
602 */\r
603 \r
604 static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
605 {\r
606         int                                                     x, y, xBlocks, yBlocks;\r
607         unsigned int                            *pixel, alphaZero;\r
608         ddsColorBlock_t                         *block;\r
609         ddsAlphaBlock3BitLinear_t       *alphaBlock;\r
610         ddsColor_t                                      colors[ 4 ];\r
611 \r
612 \r
613         /* setup */\r
614         xBlocks = width / 4;\r
615         yBlocks = height / 4;\r
616         \r
617         /* create zero alpha */\r
618         colors[ 0 ].a = 0;\r
619         colors[ 0 ].r = 0xFF;\r
620         colors[ 0 ].g = 0xFF;\r
621         colors[ 0 ].b = 0xFF;\r
622         alphaZero = *((unsigned int*) &colors[ 0 ]);\r
623         \r
624         /* walk y */\r
625         for( y = 0; y < yBlocks; y++ )\r
626         {\r
627                 /* 8 bytes per block, 1 block for alpha, 1 block for color */\r
628                 block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16);\r
629 \r
630                 /* walk x */\r
631                 for( x = 0; x < xBlocks; x++, block++ )\r
632                 {\r
633                         /* get alpha block */\r
634                         alphaBlock = (ddsAlphaBlock3BitLinear_t*) block;\r
635                         \r
636                         /* get color block */\r
637                         block++;\r
638                         DDSGetColorBlockColors( block, colors );\r
639                         \r
640                         /* decode color block */\r
641                         pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4);\r
642                         DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors );\r
643                         \r
644                         /* overwrite alpha bits with alpha block */\r
645                         DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero );\r
646                 }\r
647         }\r
648         \r
649         /* return ok */\r
650         return 0;\r
651 }\r
652 \r
653 \r
654 \r
655 /*\r
656 DDSDecompressDXT2()\r
657 decompresses a dxt2 format texture (fixme: un-premultiply alpha)\r
658 */\r
659 \r
660 static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
661 {\r
662         int             r;\r
663         \r
664         \r
665         /* decompress dxt3 first */\r
666         r = DDSDecompressDXT3( dds, width, height, pixels );\r
667         \r
668         /* return to sender */\r
669         return r;\r
670 }\r
671 \r
672 \r
673 \r
674 /*\r
675 DDSDecompressDXT4()\r
676 decompresses a dxt4 format texture (fixme: un-premultiply alpha)\r
677 */\r
678 \r
679 static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
680 {\r
681         int             r;\r
682         \r
683         \r
684         /* decompress dxt5 first */\r
685         r = DDSDecompressDXT5( dds, width, height, pixels );\r
686         \r
687         /* return to sender */\r
688         return r;\r
689 }\r
690 \r
691 \r
692 \r
693 /*\r
694 DDSDecompressARGB8888()\r
695 decompresses an argb 8888 format texture\r
696 */\r
697 \r
698 static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )\r
699 {\r
700         int                                                     x, y;\r
701         unsigned char                           *in, *out;\r
702         \r
703         \r
704         /* setup */\r
705         in = dds->data;\r
706         out = pixels;\r
707         \r
708         /* walk y */\r
709         for( y = 0; y < height; y++ )\r
710         {\r
711                 /* walk x */\r
712                 for( x = 0; x < width; x++ )\r
713                 {\r
714                         *out++ = *in++;\r
715                         *out++ = *in++;\r
716                         *out++ = *in++;\r
717                         *out++ = *in++;\r
718                 }\r
719         }\r
720         \r
721         /* return ok */\r
722         return 0;\r
723 }\r
724 \r
725 \r
726 \r
727 /*\r
728 DDSDecompress()\r
729 decompresses a dds texture into an rgba image buffer, returns 0 on success\r
730 */\r
731 \r
732 int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels )\r
733 {\r
734         int                     width, height, r;\r
735         ddsPF_t         pf;\r
736         \r
737         \r
738         /* get dds info */\r
739         r = DDSGetInfo( dds, &width, &height, &pf );\r
740         if( r )\r
741                 return r;\r
742         \r
743         /* decompress */\r
744         switch( pf )\r
745         {\r
746                 case DDS_PF_ARGB8888:\r
747                         /* fixme: support other [a]rgb formats */\r
748                         r = DDSDecompressARGB8888( dds, width, height, pixels );\r
749                         break;\r
750                 \r
751                 case DDS_PF_DXT1:\r
752                         r = DDSDecompressDXT1( dds, width, height, pixels );\r
753                         break;\r
754                 \r
755                 case DDS_PF_DXT2:\r
756                         r = DDSDecompressDXT2( dds, width, height, pixels );\r
757                         break;\r
758                 \r
759                 case DDS_PF_DXT3:\r
760                         r = DDSDecompressDXT3( dds, width, height, pixels );    \r
761                         break;\r
762                 \r
763                 case DDS_PF_DXT4:\r
764                         r = DDSDecompressDXT4( dds, width, height, pixels );\r
765                         break;\r
766                 \r
767                 case DDS_PF_DXT5:\r
768                         r = DDSDecompressDXT5( dds, width, height, pixels );            \r
769                         break;\r
770                 \r
771                 default:\r
772                 case DDS_PF_UNKNOWN:\r
773                         memset( pixels, 0xFF, width * height * 4 );\r
774                         r = -1;\r
775                         break;\r
776         }\r
777         \r
778         /* return to sender */\r
779         return r;\r
780 }\r
781 \r