From 393b5cd1dc438872af89d334ef6e5fcc59f27d47 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 17:24:39 +1000 Subject: Added Irrlicht 1.8, but without all the Windows binaries. --- .../source/Irrlicht/CImageLoaderDDS.cpp | 712 +++++++++++++++++++++ 1 file changed, 712 insertions(+) create mode 100644 libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderDDS.cpp (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderDDS.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderDDS.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderDDS.cpp new file mode 100644 index 0000000..646abd2 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderDDS.cpp @@ -0,0 +1,712 @@ +// Copyright (C) 2002-2012 Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +/* + Based on Code from Copyright (c) 2003 Randy Reddig + Based on code from Nvidia's DDS example: + http://www.nvidia.com/object/dxtc_decompression_code.html + + mainly c to cpp +*/ + + +#include "CImageLoaderDDS.h" + +#ifdef _IRR_COMPILE_WITH_DDS_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "irrString.h" + + +namespace irr +{ + +namespace video +{ + +namespace +{ + +/*! + DDSDecodePixelFormat() + determines which pixel format the dds texture is in +*/ +void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf ) +{ + /* dummy check */ + if( dds == NULL || pf == NULL ) + return; + + /* extract fourCC */ + const u32 fourCC = dds->pixelFormat.fourCC; + + /* test it */ + if( fourCC == 0 ) + *pf = DDS_PF_ARGB8888; + else if( fourCC == *((u32*) "DXT1") ) + *pf = DDS_PF_DXT1; + else if( fourCC == *((u32*) "DXT2") ) + *pf = DDS_PF_DXT2; + else if( fourCC == *((u32*) "DXT3") ) + *pf = DDS_PF_DXT3; + else if( fourCC == *((u32*) "DXT4") ) + *pf = DDS_PF_DXT4; + else if( fourCC == *((u32*) "DXT5") ) + *pf = DDS_PF_DXT5; + else + *pf = DDS_PF_UNKNOWN; +} + + +/*! +DDSGetInfo() +extracts relevant info from a dds texture, returns 0 on success +*/ +s32 DDSGetInfo( ddsBuffer *dds, s32 *width, s32 *height, eDDSPixelFormat *pf ) +{ + /* dummy test */ + if( dds == NULL ) + return -1; + + /* test dds header */ + if( *((s32*) dds->magic) != *((s32*) "DDS ") ) + return -1; + if( DDSLittleLong( dds->size ) != 124 ) + return -1; + + /* extract width and height */ + if( width != NULL ) + *width = DDSLittleLong( dds->width ); + if( height != NULL ) + *height = DDSLittleLong( dds->height ); + + /* get pixel format */ + DDSDecodePixelFormat( dds, pf ); + + /* return ok */ + return 0; +} + + +/*! + DDSGetColorBlockColors() + extracts colors from a dds color block +*/ +void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] ) +{ + u16 word; + + + /* color 0 */ + word = DDSLittleShort( block->colors[ 0 ] ); + colors[ 0 ].a = 0xff; + + /* extract rgb bits */ + colors[ 0 ].b = (u8) word; + colors[ 0 ].b <<= 3; + colors[ 0 ].b |= (colors[ 0 ].b >> 5); + word >>= 5; + colors[ 0 ].g = (u8) word; + colors[ 0 ].g <<= 2; + colors[ 0 ].g |= (colors[ 0 ].g >> 5); + word >>= 6; + colors[ 0 ].r = (u8) word; + colors[ 0 ].r <<= 3; + colors[ 0 ].r |= (colors[ 0 ].r >> 5); + + /* same for color 1 */ + word = DDSLittleShort( block->colors[ 1 ] ); + colors[ 1 ].a = 0xff; + + /* extract rgb bits */ + colors[ 1 ].b = (u8) word; + colors[ 1 ].b <<= 3; + colors[ 1 ].b |= (colors[ 1 ].b >> 5); + word >>= 5; + colors[ 1 ].g = (u8) word; + colors[ 1 ].g <<= 2; + colors[ 1 ].g |= (colors[ 1 ].g >> 5); + word >>= 6; + colors[ 1 ].r = (u8) word; + colors[ 1 ].r <<= 3; + colors[ 1 ].r |= (colors[ 1 ].r >> 5); + + /* use this for all but the super-freak math method */ + if( block->colors[ 0 ] > block->colors[ 1 ] ) + { + /* four-color block: derive the other two colors. + 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 + these two bit codes correspond to the 2-bit fields + stored in the 64-bit block. */ + + word = ((u16) colors[ 0 ].r * 2 + (u16) colors[ 1 ].r ) / 3; + /* no +1 for rounding */ + /* as bits have been shifted to 888 */ + colors[ 2 ].r = (u8) word; + word = ((u16) colors[ 0 ].g * 2 + (u16) colors[ 1 ].g) / 3; + colors[ 2 ].g = (u8) word; + word = ((u16) colors[ 0 ].b * 2 + (u16) colors[ 1 ].b) / 3; + colors[ 2 ].b = (u8) word; + colors[ 2 ].a = 0xff; + + word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r * 2) / 3; + colors[ 3 ].r = (u8) word; + word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g * 2) / 3; + colors[ 3 ].g = (u8) word; + word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b * 2) / 3; + colors[ 3 ].b = (u8) word; + colors[ 3 ].a = 0xff; + } + else + { + /* three-color block: derive the other color. + 00 = color 0, 01 = color 1, 10 = color 2, + 11 = transparent. + These two bit codes correspond to the 2-bit fields + stored in the 64-bit block */ + + word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r) / 2; + colors[ 2 ].r = (u8) word; + word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g) / 2; + colors[ 2 ].g = (u8) word; + word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b) / 2; + colors[ 2 ].b = (u8) word; + colors[ 2 ].a = 0xff; + + /* random color to indicate alpha */ + colors[ 3 ].r = 0x00; + colors[ 3 ].g = 0xff; + colors[ 3 ].b = 0xff; + colors[ 3 ].a = 0x00; + } +} + + +/* +DDSDecodeColorBlock() +decodes a dds color block +fixme: make endian-safe +*/ + +void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 colors[ 4 ] ) +{ + s32 r, n; + u32 bits; + u32 masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ + s32 shift[] = { 0, 2, 4, 6 }; + + + /* r steps through lines in y */ + for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as u32 ptr inc will * 4 */ + { + /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ + + /* n steps through pixels */ + for( n = 0; n < 4; n++ ) + { + bits = block->row[ r ] & masks[ n ]; + bits >>= shift[ n ]; + + switch( bits ) + { + case 0: + *pixel = colors[ 0 ]; + pixel++; + break; + + case 1: + *pixel = colors[ 1 ]; + pixel++; + break; + + case 2: + *pixel = colors[ 2 ]; + pixel++; + break; + + case 3: + *pixel = colors[ 3 ]; + pixel++; + break; + + default: + /* invalid */ + pixel++; + break; + } + } + } +} + + +/* +DDSDecodeAlphaExplicit() +decodes a dds explicit alpha block +*/ +void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 width, u32 alphaZero ) +{ + s32 row, pix; + u16 word; + ddsColor color; + + + /* clear color */ + color.r = 0; + color.g = 0; + color.b = 0; + + /* walk rows */ + for( row = 0; row < 4; row++, pixel += (width - 4) ) + { + word = DDSLittleShort( alphaBlock->row[ row ] ); + + /* walk pixels */ + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + color.a = word & 0x000F; + color.a = color.a | (color.a << 4); + *pixel |= *((u32*) &color); + word >>= 4; /* move next bits to lowest 4 */ + pixel++; /* move to next pixel in the row */ + } + } +} + + + +/* +DDSDecodeAlpha3BitLinear() +decodes interpolated alpha block +*/ +void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, s32 width, u32 alphaZero ) +{ + + s32 row, pix; + u32 stuff; + u8 bits[ 4 ][ 4 ]; + u16 alphas[ 8 ]; + ddsColor aColors[ 4 ][ 4 ]; + + /* get initial alphas */ + alphas[ 0 ] = alphaBlock->alpha0; + alphas[ 1 ] = alphaBlock->alpha1; + + /* 8-alpha block */ + if( alphas[ 0 ] > alphas[ 1 ] ) + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ + alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ + alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ + alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ + alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ + alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ + } + + /* 6-alpha block */ + else + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ + alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ + alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ + alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ + alphas[ 6 ] = 0; /* bit code 110 */ + alphas[ 7 ] = 255; /* bit code 111 */ + } + + /* decode 3-bit fields into array of 16 bytes with same value */ + + /* first two rows of 4 pixels each */ + stuff = *((u32*) &(alphaBlock->stuff[ 0 ])); + + bits[ 0 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 3 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 3 ] = (u8) (stuff & 0x00000007); + + /* last two rows */ + stuff = *((u32*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ + + bits[ 2 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 3 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 3 ] = (u8) (stuff & 0x00000007); + + /* decode the codes into alpha values */ + for( row = 0; row < 4; row++ ) + { + for( pix=0; pix < 4; pix++ ) + { + aColors[ row ][ pix ].r = 0; + aColors[ row ][ pix ].g = 0; + aColors[ row ][ pix ].b = 0; + aColors[ row ][ pix ].a = (u8) alphas[ bits[ row ][ pix ] ]; + } + } + + /* write out alpha values to the image bits */ + for( row = 0; row < 4; row++, pixel += width-4 ) + { + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + + /* or the bits into the prev. nulled alpha */ + *pixel |= *((u32*) &(aColors[ row ][ pix ])); + pixel++; + } + } +} + + +/* +DDSDecompressDXT1() +decompresses a dxt1 format texture +*/ +s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel; + ddsColorBlock *block; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block */ + block = (ddsColorBlock*) (dds->data + y * xBlocks * 8); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + DDSGetColorBlockColors( block, colors ); + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT3() +decompresses a dxt3 format texture +*/ + +s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel, alphaZero; + ddsColorBlock *block; + ddsAlphaBlockExplicit *alphaBlock; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((u32*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock*) (dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlockExplicit*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT5() +decompresses a dxt5 format texture +*/ +s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel, alphaZero; + ddsColorBlock *block; + ddsAlphaBlock3BitLinear *alphaBlock; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((u32*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock*) (dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlock3BitLinear*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT2() +decompresses a dxt2 format texture (fixme: un-premultiply alpha) +*/ +s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + /* decompress dxt3 first */ + const s32 r = DDSDecompressDXT3( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + +/* +DDSDecompressDXT4() +decompresses a dxt4 format texture (fixme: un-premultiply alpha) +*/ +s32 DDSDecompressDXT4( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + /* decompress dxt5 first */ + const s32 r = DDSDecompressDXT5( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + +/* +DDSDecompressARGB8888() +decompresses an argb 8888 format texture +*/ +s32 DDSDecompressARGB8888( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) +{ + /* setup */ + u8* in = dds->data; + u8* out = pixels; + + /* walk y */ + for(s32 y = 0; y < height; y++) + { + /* walk x */ + for(s32 x = 0; x < width; x++) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompress() +decompresses a dds texture into an rgba image buffer, returns 0 on success +*/ +s32 DDSDecompress( ddsBuffer *dds, u8 *pixels ) +{ + s32 width, height; + eDDSPixelFormat pf; + + /* get dds info */ + s32 r = DDSGetInfo( dds, &width, &height, &pf ); + if ( r ) + return r; + + /* decompress */ + switch( pf ) + { + case DDS_PF_ARGB8888: + /* fixme: support other [a]rgb formats */ + r = DDSDecompressARGB8888( dds, width, height, pixels ); + break; + + case DDS_PF_DXT1: + r = DDSDecompressDXT1( dds, width, height, pixels ); + break; + + case DDS_PF_DXT2: + r = DDSDecompressDXT2( dds, width, height, pixels ); + break; + + case DDS_PF_DXT3: + r = DDSDecompressDXT3( dds, width, height, pixels ); + break; + + case DDS_PF_DXT4: + r = DDSDecompressDXT4( dds, width, height, pixels ); + break; + + case DDS_PF_DXT5: + r = DDSDecompressDXT5( dds, width, height, pixels ); + break; + + default: + case DDS_PF_UNKNOWN: + memset( pixels, 0xFF, width * height * 4 ); + r = -1; + break; + } + + /* return to sender */ + return r; +} + +} // end anonymous namespace + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "dds" ); +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const +{ + if (!file) + return false; + + ddsBuffer header; + file->read(&header, sizeof(header)); + + s32 width, height; + eDDSPixelFormat pixelFormat; + + return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat)); +} + + +//! creates a surface from the file +IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const +{ + u8 *memFile = new u8 [ file->getSize() ]; + file->read ( memFile, file->getSize() ); + + ddsBuffer *header = (ddsBuffer*) memFile; + IImage* image = 0; + s32 width, height; + eDDSPixelFormat pixelFormat; + + if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) ) + { + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + + if ( DDSDecompress( header, (u8*) image->lock() ) == -1) + { + image->unlock(); + image->drop(); + image = 0; + } + } + + delete [] memFile; + if ( image ) + image->unlock(); + + return image; +} + + +//! creates a loader which is able to load dds images +IImageLoader* createImageLoaderDDS() +{ + return new CImageLoaderDDS(); +} + + +} // end namespace video +} // end namespace irr + +#endif + -- cgit v1.1