- Added partially (IImageCompressed part) support for compressed textures. Currently only DDS format is supported.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4448 dfc29bdd-3216-0410-991c-e03cc46cb475
master
nadro 2013-01-23 04:37:16 +00:00
parent 4250b6f7d3
commit 6f278dd40f
11 changed files with 596 additions and 231 deletions

View File

@ -148,6 +148,56 @@ public:
};
//! Interface for software compressed image data.
/** Image loaders create these images from files. IVideoDrivers convert
these images into their (hardware) textures.
*/
class IImageCompressed : public virtual IReferenceCounted
{
public:
//! Use this to get a pointer to the image data.
virtual const void* getData() const = 0;
//! Returns width and height of image data.
virtual const core::dimension2d<u32>& getDimension() const = 0;
//! Returns bits per pixel.
virtual u32 getBitsPerPixel() const = 0;
//! Returns bytes per pixel
virtual u32 getBytesPerPixel() const = 0;
//! Returns image data size in bytes
virtual u32 getImageDataSizeInBytes() const = 0;
//! Returns image data size in pixels
virtual u32 getImageDataSizeInPixels() const = 0;
//! Returns the color format
virtual ECOLOR_FORMAT getColorFormat() const = 0;
//! Returns pitch of image
virtual u32 getPitch() const = 0;
//! get the amount of Bits per Pixel of the given color format
static u32 getBitsPerPixelFromFormat(const ECOLOR_FORMAT format)
{
switch(format)
{
case ECF_DXT1:
return 16;
case ECF_DXT2:
case ECF_DXT3:
case ECF_DXT4:
case ECF_DXT5:
return 32;
default:
return 0;
}
}
};
} // end namespace video
} // end namespace irr

View File

@ -43,6 +43,15 @@ public:
/** \param file File handle to check.
\return Pointer to newly created image, or 0 upon error. */
virtual IImage* loadImage(io::IReadFile* file) const = 0;
//! Creates a compressed surface from the file
/** \param file File handle to check.
\return Pointer to newly created image, or 0 upon error. */
virtual IImageCompressed* loadImageCompressed(io::IReadFile* file) const
{
// The most of supported file formats are uncompressed, so we define it here.
return 0;
}
};

View File

@ -1218,6 +1218,18 @@ namespace video
bool ownForeignMemory=false,
bool deleteMemory = true) =0;
//! Creates a compressed software image from a file.
virtual IImageCompressed* createImageCompressedFromFile(const io::path& filename) = 0;
//! Creates a compressed software image from a file.
virtual IImageCompressed* createImageCompressedFromFile(io::IReadFile* file) = 0;
//! Creates a software compressed image from a byte array.
virtual IImageCompressed* createImageCompressedFromData(ECOLOR_FORMAT format,
const core::dimension2d<u32>& size, void *data,
bool ownForeignMemory=false,
bool deleteMemory = true) = 0;
//! Creates an empty software image.
/**
\param format Desired color format of the image.

View File

@ -532,14 +532,24 @@ B3D, MS3D or X meshes */
#ifdef NO_IRR_COMPILE_WITH_PSD_LOADER_
#undef _IRR_COMPILE_WITH_PSD_LOADER_
#endif
//! Define _IRR_COMPILE_WITH_DDS_LOADER_ if you want to load .dds files
//! Define _IRR_COMPILE_WITH_DDS_LOADER_ if you want to load compressed .dds files
// Patent problem isn't related to this loader.
#define _IRR_COMPILE_WITH_DDS_LOADER_
#ifdef NO_IRR_COMPILE_WITH_DDS_LOADER_
#undef _IRR_COMPILE_WITH_DDS_LOADER_
#endif
//! Define _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ if you want to load .dds files
//! loader will decompress these files and will send to the memory as uncompressed files.
// Outcommented because
// a) it doesn't compile on 64-bit currently
// b) anyone enabling it should be aware that S3TC compression algorithm which might be used in that loader
// is patented in the US by S3 and they do collect license fees when it's used in applications.
// So if you are unfortunate enough to develop applications for US market and their broken patent system be careful.
// #define _IRR_COMPILE_WITH_DDS_LOADER_
#ifdef NO_IRR_COMPILE_WITH_DDS_LOADER_
// #define _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
#ifdef NO_IRR_COMPILE_WITH_DDS_DECODER_LOADER_
#undef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
#endif
#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
#undef _IRR_COMPILE_WITH_DDS_LOADER_
#endif
//! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files

View File

@ -31,6 +31,23 @@ namespace video
//! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha.
ECF_A8R8G8B8,
/** Compressed image formats. **/
//! DXT1 color format.
ECF_DXT1,
//! DXT2 color format.
ECF_DXT2,
//! DXT3 color format.
ECF_DXT3,
//! DXT4 color format.
ECF_DXT4,
//! DXT5 color format.
ECF_DXT5,
/** Floating Point formats. The following formats may only be used for render target textures. */
//! 16 bit floating point format using 16 bits for the red channel.

View File

@ -458,5 +458,111 @@ inline SColor CImage::getPixelBox( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) cons
}
/** Compressed image **/
//! Constructor
CImageCompressed::CImageCompressed(ECOLOR_FORMAT format, const core::dimension2d<u32>& size, void* data,
bool ownForeignMemory, bool deleteForeignMemory)
: Data(0), Size(size), Format(format), DeleteMemory(deleteForeignMemory)
{
if (ownForeignMemory)
{
Data = (u8*)0xbadf00d;
initData();
Data = (u8*)data;
}
else
{
Data = 0;
initData();
memcpy(Data, data, Size.Height * Pitch);
}
}
//! Destructor
CImageCompressed::~CImageCompressed()
{
if (DeleteMemory)
delete [] Data;
}
//! assumes format and size has been set and creates the rest
void CImageCompressed::initData()
{
#ifdef _DEBUG
setDebugName("CImageCompressed");
#endif
BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8;
// Pitch should be aligned...
Pitch = BytesPerPixel * Size.Width;
if (!Data)
{
DeleteMemory=true;
Data = new u8[Size.Height * Pitch];
}
}
//! Use this to get a pointer to the image data.
const void* CImageCompressed::getData() const
{
return Data;
}
//! Returns width and height of image data.
const core::dimension2d<u32>& CImageCompressed::getDimension() const
{
return Size;
}
//! Returns bits per pixel.
u32 CImageCompressed::getBitsPerPixel() const
{
return getBitsPerPixelFromFormat(Format);
}
//! Returns bytes per pixel
u32 CImageCompressed::getBytesPerPixel() const
{
return BytesPerPixel;
}
//! Returns image data size in bytes
u32 CImageCompressed::getImageDataSizeInBytes() const
{
return Pitch * Size.Height;
}
//! Returns image data size in pixels
u32 CImageCompressed::getImageDataSizeInPixels() const
{
return Size.Width * Size.Height;
}
//! returns the color format
ECOLOR_FORMAT CImageCompressed::getColorFormat() const
{
return Format;
}
//! returns pitch of image
u32 CImageCompressed::getPitch() const
{
return Pitch;
}
} // end namespace video
} // end namespace irr

View File

@ -119,6 +119,59 @@ private:
bool DeleteMemory;
};
//! Internal interface for software compressed image data.
class CImageCompressed : public IImageCompressed
{
public:
//! Constructor
/** \param useForeignMemory: If true, the image will use the data pointer
directly and own it from now on, which means it will also try to delete [] the
data when the image will be destructed. If false, the memory will by copied. */
CImageCompressed(ECOLOR_FORMAT format, const core::dimension2d<u32>& size,
void* data, bool ownForeignMemory=true, bool deleteMemory = true);
//! Destructor
virtual ~CImageCompressed();
//! Use this to get a pointer to the image data.
virtual const void* getData() const;
//! Returns width and height of image data.
virtual const core::dimension2d<u32>& getDimension() const;
//! Returns bits per pixel.
virtual u32 getBitsPerPixel() const;
//! Returns bytes per pixel
virtual u32 getBytesPerPixel() const;
//! Returns image data size in bytes
virtual u32 getImageDataSizeInBytes() const;
//! Returns image data size in pixels
virtual u32 getImageDataSizeInPixels() const;
//! returns the color format
virtual ECOLOR_FORMAT getColorFormat() const;
//! returns pitch of image
virtual u32 getPitch() const;
private:
//! assumes format and size has been set and creates the rest
void initData();
u8* Data;
core::dimension2d<u32> Size;
u32 BytesPerPixel;
u32 Pitch;
ECOLOR_FORMAT Format;
bool DeleteMemory;
};
} // end namespace video
} // end namespace irr

View File

@ -1,4 +1,6 @@
// Copyright (C) 2002-2012 Thomas Alten
// Copyright (C) 2013 Patryk Nadrowski
// Heavily based on the DDS loader implemented by Thomas Alten
// and DDS loader from IrrSpintz implemented by Thomas Ince
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
@ -10,10 +12,9 @@
mainly c to cpp
*/
#include "CImageLoaderDDS.h"
#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_)
#include "IReadFile.h"
#include "os.h"
@ -21,6 +22,38 @@
#include "CImage.h"
#include "irrString.h"
// Header flag values
#define DDSD_CAPS 0x00000001
#define DDSD_HEIGHT 0x00000002
#define DDSD_WIDTH 0x00000004
#define DDSD_PITCH 0x00000008
#define DDSD_PIXELFORMAT 0x00001000
#define DDSD_MIPMAPCOUNT 0x00020000
#define DDSD_LINEARSIZE 0x00080000
#define DDSD_DEPTH 0x00800000
// Pixel format flag values
#define DDPF_ALPHAPIXELS 0x00000001
#define DDPF_ALPHA 0x00000002
#define DDPF_FOURCC 0x00000004
#define DDPF_RGB 0x00000040
#define DDPF_COMPRESSED 0x00000080
#define DDPF_LUMINANCE 0x00020000
// Caps1 values
#define DDSCAPS1_COMPLEX 0x00000008
#define DDSCAPS1_TEXTURE 0x00001000
#define DDSCAPS1_MIPMAP 0x00400000
// Caps2 values
#define DDSCAPS2_CUBEMAP 0x00000200
#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
#define DDSCAPS2_VOLUME 0x00200000
namespace irr
{
@ -28,21 +61,36 @@ namespace irr
namespace video
{
namespace
{
/*!
DDSDecodePixelFormat()
determines which pixel format the dds texture is in
/*
DDSGetInfo()
extracts relevant info from a dds texture, returns 0 on success
*/
void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf )
s32 DDSGetInfo(ddsHeader* dds, s32* width, s32* height, eDDSPixelFormat* pf)
{
/* dummy check */
if( dds == NULL || pf == NULL )
return;
/* 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;
if( !(DDSLittleLong( dds->Flags ) & DDSD_PIXELFORMAT) )
return -1;
if( !(DDSLittleLong( dds->Flags ) & DDSD_CAPS) )
return -1;
/* extract width and height */
if( width != NULL )
*width = DDSLittleLong( dds->Width );
if( height != NULL )
*height = DDSLittleLong( dds->Height );
/* get pixel format */
/* extract fourCC */
const u32 fourCC = dds->pixelFormat.fourCC;
const u32 fourCC = dds->PixelFormat.FourCC;
/* test it */
if( fourCC == 0 )
@ -59,44 +107,47 @@ void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf )
*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;
}
/*
DDSDecompressARGB8888()
decompresses an argb 8888 format texture
*/
s32 DDSDecompressARGB8888(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
/* setup */
u8* in = 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;
}
#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
/*!
DDSGetColorBlockColors()
extracts colors from a dds color block
*/
void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] )
void DDSGetColorBlockColors(ddsColorBlock* block, ddsColor colors[4])
{
u16 word;
@ -192,7 +243,7 @@ decodes a dds color block
fixme: make endian-safe
*/
void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 colors[ 4 ] )
void DDSDecodeColorBlock(u32* pixel, ddsColorBlock* block, s32 width, u32 colors[4])
{
s32 r, n;
u32 bits;
@ -247,7 +298,7 @@ void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 color
DDSDecodeAlphaExplicit()
decodes a dds explicit alpha block
*/
void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 width, u32 alphaZero )
void DDSDecodeAlphaExplicit(u32* pixel, ddsAlphaBlockExplicit* alphaBlock, s32 width, u32 alphaZero)
{
s32 row, pix;
u16 word;
@ -284,7 +335,7 @@ void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32
DDSDecodeAlpha3BitLinear()
decodes interpolated alpha block
*/
void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, s32 width, u32 alphaZero )
void DDSDecodeAlpha3BitLinear(u32* pixel, ddsAlphaBlock3BitLinear* alphaBlock, s32 width, u32 alphaZero)
{
s32 row, pix;
@ -393,7 +444,7 @@ void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock,
DDSDecompressDXT1()
decompresses a dxt1 format texture
*/
s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
s32 DDSDecompressDXT1(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
s32 x, y, xBlocks, yBlocks;
u32 *pixel;
@ -408,7 +459,7 @@ s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
for( y = 0; y < yBlocks; y++ )
{
/* 8 bytes per block */
block = (ddsColorBlock*) (dds->data + y * xBlocks * 8);
block = (ddsColorBlock*) (data + y * xBlocks * 8);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
@ -429,7 +480,7 @@ DDSDecompressDXT3()
decompresses a dxt3 format texture
*/
s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
s32 DDSDecompressDXT3(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
s32 x, y, xBlocks, yBlocks;
u32 *pixel, alphaZero;
@ -452,7 +503,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
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);
block = (ddsColorBlock*) (data + y * xBlocks * 16);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
@ -482,7 +533,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT5()
decompresses a dxt5 format texture
*/
s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
s32 DDSDecompressDXT5(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
s32 x, y, xBlocks, yBlocks;
u32 *pixel, alphaZero;
@ -505,7 +556,7 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
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);
block = (ddsColorBlock*) (data + y * xBlocks * 16);
/* walk x */
for( x = 0; x < xBlocks; x++, block++ )
@ -535,10 +586,10 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT2()
decompresses a dxt2 format texture (fixme: un-premultiply alpha)
*/
s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
s32 DDSDecompressDXT2(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
/* decompress dxt3 first */
const s32 r = DDSDecompressDXT3( dds, width, height, pixels );
const s32 r = DDSDecompressDXT3( dds, data, width, height, pixels );
/* return to sender */
return r;
@ -549,49 +600,21 @@ s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT4()
decompresses a dxt4 format texture (fixme: un-premultiply alpha)
*/
s32 DDSDecompressDXT4( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
s32 DDSDecompressDXT4(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{
/* decompress dxt5 first */
const s32 r = DDSDecompressDXT5( dds, width, height, pixels );
const s32 r = DDSDecompressDXT5( dds, data, 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 DDSDecompress(ddsHeader* dds, u8* data, u8* pixels)
{
s32 width, height;
eDDSPixelFormat pf;
@ -606,32 +629,30 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
{
case DDS_PF_ARGB8888:
/* fixme: support other [a]rgb formats */
r = DDSDecompressARGB8888( dds, width, height, pixels );
r = DDSDecompressARGB8888( dds, data, width, height, pixels );
break;
case DDS_PF_DXT1:
r = DDSDecompressDXT1( dds, width, height, pixels );
r = DDSDecompressDXT1( dds, data, width, height, pixels );
break;
case DDS_PF_DXT2:
r = DDSDecompressDXT2( dds, width, height, pixels );
r = DDSDecompressDXT2( dds, data, width, height, pixels );
break;
case DDS_PF_DXT3:
r = DDSDecompressDXT3( dds, width, height, pixels );
r = DDSDecompressDXT3( dds, data, width, height, pixels );
break;
case DDS_PF_DXT4:
r = DDSDecompressDXT4( dds, width, height, pixels );
r = DDSDecompressDXT4( dds, data, width, height, pixels );
break;
case DDS_PF_DXT5:
r = DDSDecompressDXT5( dds, width, height, pixels );
r = DDSDecompressDXT5( dds, data, width, height, pixels );
break;
default:
case DDS_PF_UNKNOWN:
memset( pixels, 0xFF, width * height * 4 );
default: // DDS_PF_UNKNOWN
r = -1;
break;
}
@ -640,14 +661,14 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
return r;
}
} // end anonymous namespace
#endif
//! 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" );
return core::hasFileExtension(filename, "dds");
}
@ -657,44 +678,127 @@ bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const
if (!file)
return false;
ddsBuffer header;
file->read(&header, sizeof(header));
c8 MagicWord[4];
file->read(&MagicWord, 4);
s32 width, height;
eDDSPixelFormat pixelFormat;
return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat));
return (MagicWord[0] == 'D' && MagicWord[1] == 'D' && MagicWord[2] == 'S');
}
//! 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;
ddsHeader header;
IImage* image = 0;
s32 width, height;
eDDSPixelFormat pixelFormat;
if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) )
{
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
file->seek(0);
file->read(&header, sizeof(ddsHeader));
if ( DDSDecompress( header, (u8*) image->lock() ) == -1)
if (0 == DDSGetInfo(&header, &width, &height, &pixelFormat))
{
#ifndef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
if(pixelFormat == DDS_PF_ARGB8888)
#endif
{
image->unlock();
image->drop();
image = 0;
u32 newSize = file->getSize() - sizeof(ddsHeader);
u8* memFile = new u8[newSize];
file->read(memFile, newSize);
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
#ifndef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
DDSDecompressARGB8888(&header, memFile, width, height, (u8*)image->lock());
#else
if (DDSDecompress(&header, memFile, (u8*)image->lock()) == -1)
{
image->unlock();
image->drop();
image = 0;
}
#endif
delete[] memFile;
if (image)
image->unlock();
}
}
delete [] memFile;
if ( image )
image->unlock();
return image;
}
//! creates a compressed surface from the file
IImageCompressed* CImageLoaderDDS::loadImageCompressed(io::IReadFile* file) const
{
#ifndef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
ddsHeader header;
IImageCompressed* image = 0;
s32 width, height;
eDDSPixelFormat pixelFormat;
file->seek(0);
file->read(&header, sizeof(ddsHeader));
ECOLOR_FORMAT format = ECF_UNKNOWN;
u32 dataSize = 0;
bool is3D = false;
if (0 == DDSGetInfo(&header, &width, &height, &pixelFormat))
{
is3D = header.Depth > 0 && (header.Flags & DDSD_DEPTH);
if (!is3D)
header.Depth = 1;
if (header.PixelFormat.Flags & DDPF_FOURCC) // Compressed formats
{
switch(pixelFormat)
{
case DDS_PF_DXT1:
{
dataSize = (header.Width / 4 ) * (header.Height / 4) * 8;
format = ECF_DXT1;
os::Printer::log("Detected ECF_DXT1 format", ELL_DEBUG);
break;
}
case DDS_PF_DXT2:
case DDS_PF_DXT3:
{
dataSize = (header.Width / 4 ) * (header.Height / 4) * 16;
format = ECF_DXT3;
os::Printer::log("Detected ECF_DXT3 format", ELL_DEBUG);
break;
}
case DDS_PF_DXT4:
case DDS_PF_DXT5:
{
dataSize = (header.Width / 4 ) * (header.Height / 4) * 16;
format = ECF_DXT5;
os::Printer::log("Detected ECF_DXT5 format", ELL_DEBUG);
break;
}
}
if( format != ECF_UNKNOWN )
{
if (!is3D) // Currently 3D textures are unsupported.
{
u8* data = new u8[dataSize];
file->read(data, dataSize);
image = new CImageCompressed(format, core::dimension2d<u32>(header.Width, header.Height ), data);
}
}
}
}
return image;
#else
return 0;
#endif
}

View File

@ -7,7 +7,7 @@
#include "IrrCompileConfig.h"
#if defined(_IRR_COMPILE_WITH_DDS_LOADER_)
#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_)
#include "IImageLoader.h"
@ -16,8 +16,7 @@ namespace irr
namespace video
{
/* dependencies */
/* dds definition */
/* dds pixel format types */
enum eDDSPixelFormat
{
DDS_PF_ARGB8888,
@ -29,24 +28,24 @@ enum eDDSPixelFormat
DDS_PF_UNKNOWN
};
/* 16bpp stuff */
#define DDS_LOW_5 0x001F;
#define DDS_MID_6 0x07E0;
#define DDS_HIGH_5 0xF800;
#define DDS_MID_555 0x03E0;
#define DDS_HI_555 0x7C00;
// byte-align structures
#include "irrpack.h"
/* structures */
struct ddsColorKey
struct ddsPixelFormat
{
u32 colorSpaceLowValue;
u32 colorSpaceHighValue;
u32 Size;
u32 Flags;
u32 FourCC;
u32 RGBBitCount;
u32 RBitMask;
u32 GBitMask;
u32 BBitMask;
u32 ABitMask;
} PACK_STRUCT;
struct ddsCaps
{
u32 caps1;
@ -55,108 +54,25 @@ struct ddsCaps
u32 caps4;
} PACK_STRUCT;
struct ddsMultiSampleCaps
struct ddsHeader
{
u16 flipMSTypes;
u16 bltMSTypes;
c8 Magic[4];
u32 Size;
u32 Flags;
u32 Height;
u32 Width;
u32 PitchOrLinearSize;
u32 Depth;
u32 MipMapCount;
u32 Reserved1[11];
ddsPixelFormat PixelFormat;
ddsCaps Caps;
u32 Reserved2;
} PACK_STRUCT;
struct ddsPixelFormat
{
u32 size;
u32 flags;
u32 fourCC;
union
{
u32 rgbBitCount;
u32 yuvBitCount;
u32 zBufferBitDepth;
u32 alphaBitDepth;
u32 luminanceBitCount;
u32 bumpBitCount;
u32 privateFormatBitCount;
};
union
{
u32 rBitMask;
u32 yBitMask;
u32 stencilBitDepth;
u32 luminanceBitMask;
u32 bumpDuBitMask;
u32 operations;
};
union
{
u32 gBitMask;
u32 uBitMask;
u32 zBitMask;
u32 bumpDvBitMask;
ddsMultiSampleCaps multiSampleCaps;
};
union
{
u32 bBitMask;
u32 vBitMask;
u32 stencilBitMask;
u32 bumpLuminanceBitMask;
};
union
{
u32 rgbAlphaBitMask;
u32 yuvAlphaBitMask;
u32 luminanceAlphaBitMask;
u32 rgbZBitMask;
u32 yuvZBitMask;
};
} PACK_STRUCT;
struct ddsBuffer
{
/* magic: 'dds ' */
c8 magic[ 4 ];
/* directdraw surface */
u32 size;
u32 flags;
u32 height;
u32 width;
union
{
s32 pitch;
u32 linearSize;
};
u32 backBufferCount;
union
{
u32 mipMapCount;
u32 refreshRate;
u32 srcVBHandle;
};
u32 alphaBitDepth;
u32 reserved;
void *surface;
union
{
ddsColorKey ckDestOverlay;
u32 emptyFaceColor;
};
ddsColorKey ckDestBlt;
ddsColorKey ckSrcOverlay;
ddsColorKey ckSrcBlt;
union
{
ddsPixelFormat pixelFormat;
u32 fvf;
};
ddsCaps caps;
u32 textureStage;
/* data (Varying size) */
u8 data[ 4 ];
} PACK_STRUCT;
#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
struct ddsColorBlock
{
@ -184,6 +100,9 @@ struct ddsColor
u8 r, g, b, a;
} PACK_STRUCT;
#endif
// Default alignment
#include "irrunpack.h"
@ -285,6 +204,9 @@ public:
//! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file) const;
//! creates a compressed surface from the file
virtual IImageCompressed* loadImageCompressed(io::IReadFile* file) const;
};

View File

@ -139,7 +139,7 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
SurfaceLoader.push_back(video::createImageLoaderPSD());
#endif
#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_)
SurfaceLoader.push_back(video::createImageLoaderDDS());
#endif
#ifdef _IRR_COMPILE_WITH_PCX_LOADER_
@ -1402,6 +1402,77 @@ IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
}
//! Creates a compressed software image from a file.
IImageCompressed* CNullDriver::createImageCompressedFromFile(const io::path& filename)
{
if (!filename.size())
return 0;
IImageCompressed* image = 0;
io::IReadFile* file = FileSystem->createAndOpenFile(filename);
if (file)
{
image = createImageCompressedFromFile(file);
file->drop();
}
else
os::Printer::log("Could not open file of image", filename, ELL_WARNING);
return image;
}
//! Creates a compressed software image from a file.
IImageCompressed* CNullDriver::createImageCompressedFromFile(io::IReadFile* file)
{
if (!file)
return 0;
IImageCompressed* image = 0;
s32 i;
// try to load file based on file extension
for (i=SurfaceLoader.size()-1; i>=0; --i)
{
if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
{
// reset file position which might have changed due to previous loadImage calls
file->seek(0);
image = SurfaceLoader[i]->loadImageCompressed(file);
if (image)
return image;
}
}
// try to load file based on what is in it
for (i=SurfaceLoader.size()-1; i>=0; --i)
{
// dito
file->seek(0);
if (SurfaceLoader[i]->isALoadableFileFormat(file))
{
file->seek(0);
image = SurfaceLoader[i]->loadImageCompressed(file);
if (image)
return image;
}
}
return 0; // failed to load
}
//! Creates a software compressed image from a byte array.
IImageCompressed* CNullDriver::createImageCompressedFromData(ECOLOR_FORMAT format,
const core::dimension2d<u32>& size, void *data,
bool ownForeignMemory, bool deleteMemory)
{
return new CImageCompressed(format, size, data, ownForeignMemory, deleteMemory);
}
//! Creates an empty software image.
IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
{

View File

@ -352,6 +352,17 @@ namespace video
const core::dimension2d<u32>& size, void *data,
bool ownForeignMemory=true, bool deleteForeignMemory = true);
//! Creates a compressed software image from a file.
virtual IImageCompressed* createImageCompressedFromFile(const io::path& filename);
//! Creates a compressed software image from a file.
virtual IImageCompressed* createImageCompressedFromFile(io::IReadFile* file);
//! Creates a software compressed image from a byte array.
virtual IImageCompressed* createImageCompressedFromData(ECOLOR_FORMAT format,
const core::dimension2d<u32>& size, void *data,
bool ownForeignMemory=false, bool deleteMemory = true);
//! Creates an empty software image.
virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size);