1 /* -----------------------------------------------------------------------------
\r
5 Based on code from Nvidia's DDS example:
\r
6 http://www.nvidia.com/object/dxtc_decompression_code.html
\r
8 Copyright (c) 2003 Randy Reddig
\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
14 Redistributions of source code must retain the above copyright notice, this list
\r
15 of conditions and the following disclaimer.
\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
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
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
36 ----------------------------------------------------------------------------- */
\r
50 /* endian tomfoolery */
\r
59 #ifndef __BIG_ENDIAN__
\r
61 #define __BIG_ENDIAN__
\r
66 #ifdef __BIG_ENDIAN__
\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
72 int DDSLittleLong( int src )
\r
74 return ((src & 0xFF000000) >> 24) |
\r
75 ((src & 0x00FF0000) >> 8) |
\r
76 ((src & 0x0000FF00) << 8) |
\r
77 ((src & 0x000000FF) << 24);
\r
80 short DDSLittleShort( short src )
\r
82 return ((src & 0xFF00) >> 8) |
\r
83 ((src & 0x00FF) << 8);
\r
86 float DDSLittleFloat( float src )
\r
88 floatSwapUnion in,out;
\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
97 #else /*__BIG_ENDIAN__*/
\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
103 int DDSBigLong( int src )
\r
105 return ((src & 0xFF000000) >> 24) |
\r
106 ((src & 0x00FF0000) >> 8) |
\r
107 ((src & 0x0000FF00) << 8) |
\r
108 ((src & 0x000000FF) << 24);
\r
111 short DDSBigShort( short src )
\r
113 return ((src & 0xFF00) >> 8) |
\r
114 ((src & 0x00FF) << 8);
\r
117 float DDSBigFloat( float src )
\r
119 floatSwapUnion in,out;
\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
128 #endif /*__BIG_ENDIAN__*/
\r
133 DDSDecodePixelFormat()
\r
134 determines which pixel format the dds texture is in
\r
137 static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf )
\r
139 unsigned int fourCC;
\r
143 if( dds == NULL || pf == NULL )
\r
146 /* extract fourCC */
\r
147 fourCC = dds->pixelFormat.fourCC;
\r
151 *pf = DDS_PF_ARGB8888;
\r
152 else if( fourCC == *((unsigned int*) "DXT1") )
\r
154 else if( fourCC == *((unsigned int*) "DXT2") )
\r
156 else if( fourCC == *((unsigned int*) "DXT3") )
\r
158 else if( fourCC == *((unsigned int*) "DXT4") )
\r
160 else if( fourCC == *((unsigned int*) "DXT5") )
\r
163 *pf = DDS_PF_UNKNOWN;
\r
170 extracts relevant info from a dds texture, returns 0 on success
\r
173 int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf )
\r
179 /* test dds header */
\r
180 if( *((int*) dds->magic) != *((int*) "DDS ") )
\r
182 if( DDSLittleLong( dds->size ) != 124 )
\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
191 /* get pixel format */
\r
192 DDSDecodePixelFormat( dds, pf );
\r
201 DDSGetColorBlockColors()
\r
202 extracts colors from a dds color block
\r
205 static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] )
\r
207 unsigned short word;
\r
211 word = DDSLittleShort( block->colors[ 0 ] );
\r
212 colors[ 0 ].a = 0xff;
\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
219 colors[ 0 ].g = (unsigned char) word;
\r
220 colors[ 0 ].g <<= 2;
\r
221 colors[ 0 ].g |= (colors[ 0 ].g >> 5);
\r
223 colors[ 0 ].r = (unsigned char) word;
\r
224 colors[ 0 ].r <<= 3;
\r
225 colors[ 0 ].r |= (colors[ 0 ].r >> 5);
\r
227 /* same for color 1 */
\r
228 word = DDSLittleShort( block->colors[ 1 ] );
\r
229 colors[ 1 ].a = 0xff;
\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
236 colors[ 1 ].g = (unsigned char) word;
\r
237 colors[ 1 ].g <<= 2;
\r
238 colors[ 1 ].g |= (colors[ 1 ].g >> 5);
\r
240 colors[ 1 ].r = (unsigned char) word;
\r
241 colors[ 1 ].r <<= 3;
\r
242 colors[ 1 ].r |= (colors[ 1 ].r >> 5);
\r
244 /* use this for all but the super-freak math method */
\r
245 if( block->colors[ 0 ] > block->colors[ 1 ] )
\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
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
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
272 /* three-color block: derive the other color.
\r
273 00 = color 0, 01 = color 1, 10 = color 2,
\r
275 These two bit codes correspond to the 2-bit fields
\r
276 stored in the 64-bit block */
\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
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
297 DDSDecodeColorBlock()
\r
298 decodes a dds color block
\r
299 fixme: make endian-safe
\r
302 static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] )
\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
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
313 /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */
\r
315 /* n steps through pixels */
\r
316 for( n = 0; n < 4; n++ )
\r
318 bits = block->row[ r ] & masks[ n ];
\r
319 bits >>= shift[ n ];
\r
324 *pixel = colors[ 0 ];
\r
329 *pixel = colors[ 1 ];
\r
334 *pixel = colors[ 2 ];
\r
339 *pixel = colors[ 3 ];
\r
355 DDSDecodeAlphaExplicit()
\r
356 decodes a dds explicit alpha block
\r
359 static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero )
\r
362 unsigned short word;
\r
372 for( row = 0; row < 4; row++, pixel += (width - 4) )
\r
374 word = DDSLittleShort( alphaBlock->row[ row ] );
\r
377 for( pix = 0; pix < 4; pix++ )
\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
394 DDSDecodeAlpha3BitLinear()
\r
395 decodes interpolated alpha block
\r
398 static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero )
\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
408 /* get initial alphas */
\r
409 alphas[ 0 ] = alphaBlock->alpha0;
\r
410 alphas[ 1 ] = alphaBlock->alpha1;
\r
412 /* 8-alpha block */
\r
413 if( alphas[ 0 ] > alphas[ 1 ] )
\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
424 /* 6-alpha block */
\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
436 /* decode 3-bit fields into array of 16 bytes with same value */
\r
438 /* first two rows of 4 pixels each */
\r
439 stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ]));
\r
441 bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
\r
443 bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
\r
445 bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
\r
447 bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
\r
449 bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
\r
451 bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
\r
453 bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
\r
455 bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
\r
457 /* last two rows */
\r
458 stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */
\r
460 bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
\r
462 bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
\r
464 bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
\r
466 bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
\r
468 bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007);
\r
470 bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007);
\r
472 bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007);
\r
474 bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007);
\r
476 /* decode the codes into alpha values */
\r
477 for( row = 0; row < 4; row++ )
\r
479 for( pix=0; pix < 4; pix++ )
\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
488 /* write out alpha values to the image bits */
\r
489 for( row = 0; row < 4; row++, pixel += width-4 )
\r
491 for( pix = 0; pix < 4; pix++ )
\r
493 /* zero the alpha bits of image pixel */
\r
494 *pixel &= alphaZero;
\r
496 /* or the bits into the prev. nulled alpha */
\r
497 *pixel |= *((unsigned int*) &(aColors[ row ][ pix ]));
\r
506 DDSDecompressDXT1()
\r
507 decompresses a dxt1 format texture
\r
510 static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\r
512 int x, y, xBlocks, yBlocks;
\r
513 unsigned int *pixel;
\r
514 ddsColorBlock_t *block;
\r
515 ddsColor_t colors[ 4 ];
\r
519 xBlocks = width / 4;
\r
520 yBlocks = height / 4;
\r
523 for( y = 0; y < yBlocks; y++ )
\r
525 /* 8 bytes per block */
\r
526 block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8);
\r
529 for( x = 0; x < xBlocks; x++, block++ )
\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
544 DDSDecompressDXT3()
\r
545 decompresses a dxt3 format texture
\r
548 static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\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
558 xBlocks = width / 4;
\r
559 yBlocks = height / 4;
\r
561 /* create zero alpha */
\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
569 for( y = 0; y < yBlocks; y++ )
\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
575 for( x = 0; x < xBlocks; x++, block++ )
\r
577 /* get alpha block */
\r
578 alphaBlock = (ddsAlphaBlockExplicit_t*) block;
\r
580 /* get color block */
\r
582 DDSGetColorBlockColors( block, colors );
\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
588 /* overwrite alpha bits with alpha block */
\r
589 DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero );
\r
600 DDSDecompressDXT5()
\r
601 decompresses a dxt5 format texture
\r
604 static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\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
614 xBlocks = width / 4;
\r
615 yBlocks = height / 4;
\r
617 /* create zero alpha */
\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
625 for( y = 0; y < yBlocks; y++ )
\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
631 for( x = 0; x < xBlocks; x++, block++ )
\r
633 /* get alpha block */
\r
634 alphaBlock = (ddsAlphaBlock3BitLinear_t*) block;
\r
636 /* get color block */
\r
638 DDSGetColorBlockColors( block, colors );
\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
644 /* overwrite alpha bits with alpha block */
\r
645 DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero );
\r
656 DDSDecompressDXT2()
\r
657 decompresses a dxt2 format texture (fixme: un-premultiply alpha)
\r
660 static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\r
665 /* decompress dxt3 first */
\r
666 r = DDSDecompressDXT3( dds, width, height, pixels );
\r
668 /* return to sender */
\r
675 DDSDecompressDXT4()
\r
676 decompresses a dxt4 format texture (fixme: un-premultiply alpha)
\r
679 static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\r
684 /* decompress dxt5 first */
\r
685 r = DDSDecompressDXT5( dds, width, height, pixels );
\r
687 /* return to sender */
\r
694 DDSDecompressARGB8888()
\r
695 decompresses an argb 8888 format texture
\r
698 static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels )
\r
701 unsigned char *in, *out;
\r
709 for( y = 0; y < height; y++ )
\r
712 for( x = 0; x < width; x++ )
\r
729 decompresses a dds texture into an rgba image buffer, returns 0 on success
\r
732 int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels )
\r
734 int width, height, r;
\r
739 r = DDSGetInfo( dds, &width, &height, &pf );
\r
746 case DDS_PF_ARGB8888:
\r
747 /* fixme: support other [a]rgb formats */
\r
748 r = DDSDecompressARGB8888( dds, width, height, pixels );
\r
752 r = DDSDecompressDXT1( dds, width, height, pixels );
\r
756 r = DDSDecompressDXT2( dds, width, height, pixels );
\r
760 r = DDSDecompressDXT3( dds, width, height, pixels );
\r
764 r = DDSDecompressDXT4( dds, width, height, pixels );
\r
768 r = DDSDecompressDXT5( dds, width, height, pixels );
\r
772 case DDS_PF_UNKNOWN:
\r
773 memset( pixels, 0xFF, width * height * 4 );
\r
778 /* return to sender */
\r