1
// Copyright (C) 2002-2011 Thomas Alten
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
6
Based on Code from Copyright (c) 2003 Randy Reddig
7
Based on code from Nvidia's DDS example:
8
http://www.nvidia.com/object/dxtc_decompression_code.html
14
#include "CImageLoaderDDS.h"
16
#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
18
#include "IReadFile.h"
20
#include "CColorConverter.h"
22
#include "irrString.h"
35
DDSDecodePixelFormat()
36
determines which pixel format the dds texture is in
38
void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf )
41
if( dds == NULL || pf == NULL )
45
const u32 fourCC = dds->pixelFormat.fourCC;
49
*pf = DDS_PF_ARGB8888;
50
else if( fourCC == *((u32*) "DXT1") )
52
else if( fourCC == *((u32*) "DXT2") )
54
else if( fourCC == *((u32*) "DXT3") )
56
else if( fourCC == *((u32*) "DXT4") )
58
else if( fourCC == *((u32*) "DXT5") )
67
extracts relevant info from a dds texture, returns 0 on success
69
s32 DDSGetInfo( ddsBuffer *dds, s32 *width, s32 *height, eDDSPixelFormat *pf )
76
if( *((s32*) dds->magic) != *((s32*) "DDS ") )
78
if( DDSLittleLong( dds->size ) != 124 )
81
/* extract width and height */
83
*width = DDSLittleLong( dds->width );
85
*height = DDSLittleLong( dds->height );
87
/* get pixel format */
88
DDSDecodePixelFormat( dds, pf );
96
DDSGetColorBlockColors()
97
extracts colors from a dds color block
99
void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] )
105
word = DDSLittleShort( block->colors[ 0 ] );
106
colors[ 0 ].a = 0xff;
108
/* extract rgb bits */
109
colors[ 0 ].b = (u8) word;
111
colors[ 0 ].b |= (colors[ 0 ].b >> 5);
113
colors[ 0 ].g = (u8) word;
115
colors[ 0 ].g |= (colors[ 0 ].g >> 5);
117
colors[ 0 ].r = (u8) word;
119
colors[ 0 ].r |= (colors[ 0 ].r >> 5);
121
/* same for color 1 */
122
word = DDSLittleShort( block->colors[ 1 ] );
123
colors[ 1 ].a = 0xff;
125
/* extract rgb bits */
126
colors[ 1 ].b = (u8) word;
128
colors[ 1 ].b |= (colors[ 1 ].b >> 5);
130
colors[ 1 ].g = (u8) word;
132
colors[ 1 ].g |= (colors[ 1 ].g >> 5);
134
colors[ 1 ].r = (u8) word;
136
colors[ 1 ].r |= (colors[ 1 ].r >> 5);
138
/* use this for all but the super-freak math method */
139
if( block->colors[ 0 ] > block->colors[ 1 ] )
141
/* four-color block: derive the other two colors.
142
00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3
143
these two bit codes correspond to the 2-bit fields
144
stored in the 64-bit block. */
146
word = ((u16) colors[ 0 ].r * 2 + (u16) colors[ 1 ].r ) / 3;
147
/* no +1 for rounding */
148
/* as bits have been shifted to 888 */
149
colors[ 2 ].r = (u8) word;
150
word = ((u16) colors[ 0 ].g * 2 + (u16) colors[ 1 ].g) / 3;
151
colors[ 2 ].g = (u8) word;
152
word = ((u16) colors[ 0 ].b * 2 + (u16) colors[ 1 ].b) / 3;
153
colors[ 2 ].b = (u8) word;
154
colors[ 2 ].a = 0xff;
156
word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r * 2) / 3;
157
colors[ 3 ].r = (u8) word;
158
word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g * 2) / 3;
159
colors[ 3 ].g = (u8) word;
160
word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b * 2) / 3;
161
colors[ 3 ].b = (u8) word;
162
colors[ 3 ].a = 0xff;
166
/* three-color block: derive the other color.
167
00 = color 0, 01 = color 1, 10 = color 2,
169
These two bit codes correspond to the 2-bit fields
170
stored in the 64-bit block */
172
word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r) / 2;
173
colors[ 2 ].r = (u8) word;
174
word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g) / 2;
175
colors[ 2 ].g = (u8) word;
176
word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b) / 2;
177
colors[ 2 ].b = (u8) word;
178
colors[ 2 ].a = 0xff;
180
/* random color to indicate alpha */
181
colors[ 3 ].r = 0x00;
182
colors[ 3 ].g = 0xff;
183
colors[ 3 ].b = 0xff;
184
colors[ 3 ].a = 0x00;
190
DDSDecodeColorBlock()
191
decodes a dds color block
192
fixme: make endian-safe
195
void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 colors[ 4 ] )
199
u32 masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */
200
s32 shift[] = { 0, 2, 4, 6 };
203
/* r steps through lines in y */
204
for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as u32 ptr inc will * 4 */
206
/* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */
208
/* n steps through pixels */
209
for( n = 0; n < 4; n++ )
211
bits = block->row[ r ] & masks[ n ];
217
*pixel = colors[ 0 ];
222
*pixel = colors[ 1 ];
227
*pixel = colors[ 2 ];
232
*pixel = colors[ 3 ];
247
DDSDecodeAlphaExplicit()
248
decodes a dds explicit alpha block
250
void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 width, u32 alphaZero )
263
for( row = 0; row < 4; row++, pixel += (width - 4) )
265
word = DDSLittleShort( alphaBlock->row[ row ] );
268
for( pix = 0; pix < 4; pix++ )
270
/* zero the alpha bits of image pixel */
272
color.a = word & 0x000F;
273
color.a = color.a | (color.a << 4);
274
*pixel |= *((u32*) &color);
275
word >>= 4; /* move next bits to lowest 4 */
276
pixel++; /* move to next pixel in the row */
284
DDSDecodeAlpha3BitLinear()
285
decodes interpolated alpha block
287
void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, s32 width, u32 alphaZero )
294
ddsColor aColors[ 4 ][ 4 ];
296
/* get initial alphas */
297
alphas[ 0 ] = alphaBlock->alpha0;
298
alphas[ 1 ] = alphaBlock->alpha1;
301
if( alphas[ 0 ] > alphas[ 1 ] )
303
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
304
alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */
305
alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */
306
alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */
307
alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */
308
alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */
309
alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */
315
/* 000 = alpha_0, 001 = alpha_1, others are interpolated */
316
alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */
317
alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */
318
alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */
319
alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */
320
alphas[ 6 ] = 0; /* bit code 110 */
321
alphas[ 7 ] = 255; /* bit code 111 */
324
/* decode 3-bit fields into array of 16 bytes with same value */
326
/* first two rows of 4 pixels each */
327
stuff = *((u32*) &(alphaBlock->stuff[ 0 ]));
329
bits[ 0 ][ 0 ] = (u8) (stuff & 0x00000007);
331
bits[ 0 ][ 1 ] = (u8) (stuff & 0x00000007);
333
bits[ 0 ][ 2 ] = (u8) (stuff & 0x00000007);
335
bits[ 0 ][ 3 ] = (u8) (stuff & 0x00000007);
337
bits[ 1 ][ 0 ] = (u8) (stuff & 0x00000007);
339
bits[ 1 ][ 1 ] = (u8) (stuff & 0x00000007);
341
bits[ 1 ][ 2 ] = (u8) (stuff & 0x00000007);
343
bits[ 1 ][ 3 ] = (u8) (stuff & 0x00000007);
346
stuff = *((u32*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */
348
bits[ 2 ][ 0 ] = (u8) (stuff & 0x00000007);
350
bits[ 2 ][ 1 ] = (u8) (stuff & 0x00000007);
352
bits[ 2 ][ 2 ] = (u8) (stuff & 0x00000007);
354
bits[ 2 ][ 3 ] = (u8) (stuff & 0x00000007);
356
bits[ 3 ][ 0 ] = (u8) (stuff & 0x00000007);
358
bits[ 3 ][ 1 ] = (u8) (stuff & 0x00000007);
360
bits[ 3 ][ 2 ] = (u8) (stuff & 0x00000007);
362
bits[ 3 ][ 3 ] = (u8) (stuff & 0x00000007);
364
/* decode the codes into alpha values */
365
for( row = 0; row < 4; row++ )
367
for( pix=0; pix < 4; pix++ )
369
aColors[ row ][ pix ].r = 0;
370
aColors[ row ][ pix ].g = 0;
371
aColors[ row ][ pix ].b = 0;
372
aColors[ row ][ pix ].a = (u8) alphas[ bits[ row ][ pix ] ];
376
/* write out alpha values to the image bits */
377
for( row = 0; row < 4; row++, pixel += width-4 )
379
for( pix = 0; pix < 4; pix++ )
381
/* zero the alpha bits of image pixel */
384
/* or the bits into the prev. nulled alpha */
385
*pixel |= *((u32*) &(aColors[ row ][ pix ]));
394
decompresses a dxt1 format texture
396
s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
398
s32 x, y, xBlocks, yBlocks;
400
ddsColorBlock *block;
401
ddsColor colors[ 4 ];
405
yBlocks = height / 4;
408
for( y = 0; y < yBlocks; y++ )
410
/* 8 bytes per block */
411
block = (ddsColorBlock*) (dds->data + y * xBlocks * 8);
414
for( x = 0; x < xBlocks; x++, block++ )
416
DDSGetColorBlockColors( block, colors );
417
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
418
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
429
decompresses a dxt3 format texture
432
s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
434
s32 x, y, xBlocks, yBlocks;
435
u32 *pixel, alphaZero;
436
ddsColorBlock *block;
437
ddsAlphaBlockExplicit *alphaBlock;
438
ddsColor colors[ 4 ];
442
yBlocks = height / 4;
444
/* create zero alpha */
446
colors[ 0 ].r = 0xFF;
447
colors[ 0 ].g = 0xFF;
448
colors[ 0 ].b = 0xFF;
449
alphaZero = *((u32*) &colors[ 0 ]);
452
for( y = 0; y < yBlocks; y++ )
454
/* 8 bytes per block, 1 block for alpha, 1 block for color */
455
block = (ddsColorBlock*) (dds->data + y * xBlocks * 16);
458
for( x = 0; x < xBlocks; x++, block++ )
460
/* get alpha block */
461
alphaBlock = (ddsAlphaBlockExplicit*) block;
463
/* get color block */
465
DDSGetColorBlockColors( block, colors );
467
/* decode color block */
468
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
469
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
471
/* overwrite alpha bits with alpha block */
472
DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero );
483
decompresses a dxt5 format texture
485
s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
487
s32 x, y, xBlocks, yBlocks;
488
u32 *pixel, alphaZero;
489
ddsColorBlock *block;
490
ddsAlphaBlock3BitLinear *alphaBlock;
491
ddsColor colors[ 4 ];
495
yBlocks = height / 4;
497
/* create zero alpha */
499
colors[ 0 ].r = 0xFF;
500
colors[ 0 ].g = 0xFF;
501
colors[ 0 ].b = 0xFF;
502
alphaZero = *((u32*) &colors[ 0 ]);
505
for( y = 0; y < yBlocks; y++ )
507
/* 8 bytes per block, 1 block for alpha, 1 block for color */
508
block = (ddsColorBlock*) (dds->data + y * xBlocks * 16);
511
for( x = 0; x < xBlocks; x++, block++ )
513
/* get alpha block */
514
alphaBlock = (ddsAlphaBlock3BitLinear*) block;
516
/* get color block */
518
DDSGetColorBlockColors( block, colors );
520
/* decode color block */
521
pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4);
522
DDSDecodeColorBlock( pixel, block, width, (u32*) colors );
524
/* overwrite alpha bits with alpha block */
525
DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero );
536
decompresses a dxt2 format texture (fixme: un-premultiply alpha)
538
s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
540
/* decompress dxt3 first */
541
const s32 r = DDSDecompressDXT3( dds, width, height, pixels );
543
/* return to sender */
550
decompresses a dxt4 format texture (fixme: un-premultiply alpha)
552
s32 DDSDecompressDXT4( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
554
/* decompress dxt5 first */
555
const s32 r = DDSDecompressDXT5( dds, width, height, pixels );
557
/* return to sender */
563
DDSDecompressARGB8888()
564
decompresses an argb 8888 format texture
566
s32 DDSDecompressARGB8888( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
573
for(s32 y = 0; y < height; y++)
576
for(s32 x = 0; x < width; x++)
592
decompresses a dds texture into an rgba image buffer, returns 0 on success
594
s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
600
s32 r = DDSGetInfo( dds, &width, &height, &pf );
607
case DDS_PF_ARGB8888:
608
/* fixme: support other [a]rgb formats */
609
r = DDSDecompressARGB8888( dds, width, height, pixels );
613
r = DDSDecompressDXT1( dds, width, height, pixels );
617
r = DDSDecompressDXT2( dds, width, height, pixels );
621
r = DDSDecompressDXT3( dds, width, height, pixels );
625
r = DDSDecompressDXT4( dds, width, height, pixels );
629
r = DDSDecompressDXT5( dds, width, height, pixels );
634
memset( pixels, 0xFF, width * height * 4 );
639
/* return to sender */
643
} // end anonymous namespace
646
//! returns true if the file maybe is able to be loaded by this class
647
//! based on the file extension (e.g. ".tga")
648
bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const
650
return core::hasFileExtension ( filename, "dds" );
654
//! returns true if the file maybe is able to be loaded by this class
655
bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const
661
file->read(&header, sizeof(header));
664
eDDSPixelFormat pixelFormat;
666
return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat));
670
//! creates a surface from the file
671
IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const
673
u8 *memFile = new u8 [ file->getSize() ];
674
file->read ( memFile, file->getSize() );
676
ddsBuffer *header = (ddsBuffer*) memFile;
679
eDDSPixelFormat pixelFormat;
681
if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) )
683
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
685
if ( DDSDecompress( header, (u8*) image->lock() ) == -1)
701
//! creates a loader which is able to load dds images
702
IImageLoader* createImageLoaderDDS()
704
return new CImageLoaderDDS();
708
} // end namespace video
709
} // end namespace irr