Commit 6f278dd4 authored by nadro's avatar nadro

- Added partially (IImageCompressed part) support for compressed textures....

- 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
parent 4250b6f7
...@@ -148,6 +148,56 @@ public: ...@@ -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 video
} // end namespace irr } // end namespace irr
......
...@@ -43,6 +43,15 @@ public: ...@@ -43,6 +43,15 @@ public:
/** \param file File handle to check. /** \param file File handle to check.
\return Pointer to newly created image, or 0 upon error. */ \return Pointer to newly created image, or 0 upon error. */
virtual IImage* loadImage(io::IReadFile* file) const = 0; 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;
}
}; };
......
...@@ -1218,6 +1218,18 @@ namespace video ...@@ -1218,6 +1218,18 @@ namespace video
bool ownForeignMemory=false, bool ownForeignMemory=false,
bool deleteMemory = true) =0; 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. //! Creates an empty software image.
/** /**
\param format Desired color format of the image. \param format Desired color format of the image.
......
...@@ -532,14 +532,24 @@ B3D, MS3D or X meshes */ ...@@ -532,14 +532,24 @@ B3D, MS3D or X meshes */
#ifdef NO_IRR_COMPILE_WITH_PSD_LOADER_ #ifdef NO_IRR_COMPILE_WITH_PSD_LOADER_
#undef _IRR_COMPILE_WITH_PSD_LOADER_ #undef _IRR_COMPILE_WITH_PSD_LOADER_
#endif #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 // Outcommented because
// a) it doesn't compile on 64-bit currently // 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 // 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. // 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. // 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_ // #define _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
#ifdef NO_IRR_COMPILE_WITH_DDS_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_ #undef _IRR_COMPILE_WITH_DDS_LOADER_
#endif #endif
//! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files //! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files
......
...@@ -31,6 +31,23 @@ namespace video ...@@ -31,6 +31,23 @@ namespace video
//! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha. //! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha.
ECF_A8R8G8B8, 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. */ /** 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. //! 16 bit floating point format using 16 bits for the red channel.
......
...@@ -458,5 +458,111 @@ inline SColor CImage::getPixelBox( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) cons ...@@ -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 video
} // end namespace irr } // end namespace irr
...@@ -119,6 +119,59 @@ private: ...@@ -119,6 +119,59 @@ private:
bool DeleteMemory; 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 video
} // end namespace irr } // end namespace irr
......
// 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". // This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h // For conditions of distribution and use, see copyright notice in irrlicht.h
...@@ -10,10 +12,9 @@ ...@@ -10,10 +12,9 @@
mainly c to cpp mainly c to cpp
*/ */
#include "CImageLoaderDDS.h" #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 "IReadFile.h"
#include "os.h" #include "os.h"
...@@ -21,6 +22,38 @@ ...@@ -21,6 +22,38 @@
#include "CImage.h" #include "CImage.h"
#include "irrString.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 namespace irr
{ {
...@@ -28,21 +61,36 @@ namespace irr ...@@ -28,21 +61,36 @@ namespace irr
namespace video namespace video
{ {
namespace /*
{ DDSGetInfo()
extracts relevant info from a dds texture, returns 0 on success
/*!
DDSDecodePixelFormat()
determines which pixel format the dds texture is in
*/ */
void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf ) s32 DDSGetInfo(ddsHeader* dds, s32* width, s32* height, eDDSPixelFormat* pf)
{ {
/* dummy check */ /* dummy test */
if( dds == NULL || pf == NULL ) if( dds == NULL )
return; 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 */ /* extract fourCC */
const u32 fourCC = dds->pixelFormat.fourCC; const u32 fourCC = dds->PixelFormat.FourCC;
/* test it */ /* test it */
if( fourCC == 0 ) if( fourCC == 0 )
...@@ -59,44 +107,47 @@ void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf ) ...@@ -59,44 +107,47 @@ void DDSDecodePixelFormat( ddsBuffer *dds, eDDSPixelFormat *pf )
*pf = DDS_PF_DXT5; *pf = DDS_PF_DXT5;
else else
*pf = DDS_PF_UNKNOWN; *pf = DDS_PF_UNKNOWN;
/* return ok */
return 0;
} }
/*! /*
DDSGetInfo() DDSDecompressARGB8888()
extracts relevant info from a dds texture, returns 0 on success decompresses an argb 8888 format texture
*/ */
s32 DDSGetInfo( ddsBuffer *dds, s32 *width, s32 *height, eDDSPixelFormat *pf ) s32 DDSDecompressARGB8888(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels)
{ {
/* dummy test */ /* setup */
if( dds == NULL ) u8* in = data;
return -1; u8* out = pixels;
/* 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 */ /* walk y */
DDSDecodePixelFormat( dds, pf ); 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 ok */
return 0; return 0;
} }
#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
/*! /*!
DDSGetColorBlockColors() DDSGetColorBlockColors()
extracts colors from a dds color block extracts colors from a dds color block
*/ */
void DDSGetColorBlockColors( ddsColorBlock *block, ddsColor colors[ 4 ] ) void DDSGetColorBlockColors(ddsColorBlock* block, ddsColor colors[4])
{ {
u16 word; u16 word;
...@@ -192,7 +243,7 @@ decodes a dds color block ...@@ -192,7 +243,7 @@ decodes a dds color block
fixme: make endian-safe 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; s32 r, n;
u32 bits; u32 bits;
...@@ -247,7 +298,7 @@ void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 color ...@@ -247,7 +298,7 @@ void DDSDecodeColorBlock( u32 *pixel, ddsColorBlock *block, s32 width, u32 color
DDSDecodeAlphaExplicit() DDSDecodeAlphaExplicit()
decodes a dds explicit alpha block 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; s32 row, pix;
u16 word; u16 word;
...@@ -284,7 +335,7 @@ void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32 ...@@ -284,7 +335,7 @@ void DDSDecodeAlphaExplicit( u32 *pixel, ddsAlphaBlockExplicit *alphaBlock, s32
DDSDecodeAlpha3BitLinear() DDSDecodeAlpha3BitLinear()
decodes interpolated alpha block 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; s32 row, pix;
...@@ -393,7 +444,7 @@ void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock, ...@@ -393,7 +444,7 @@ void DDSDecodeAlpha3BitLinear( u32 *pixel, ddsAlphaBlock3BitLinear *alphaBlock,
DDSDecompressDXT1() DDSDecompressDXT1()
decompresses a dxt1 format texture 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; s32 x, y, xBlocks, yBlocks;
u32 *pixel; u32 *pixel;
...@@ -408,7 +459,7 @@ s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -408,7 +459,7 @@ s32 DDSDecompressDXT1( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
for( y = 0; y < yBlocks; y++ ) for( y = 0; y < yBlocks; y++ )
{ {
/* 8 bytes per block */ /* 8 bytes per block */
block = (ddsColorBlock*) (dds->data + y * xBlocks * 8); block = (ddsColorBlock*) (data + y * xBlocks * 8);
/* walk x */ /* walk x */
for( x = 0; x < xBlocks; x++, block++ ) for( x = 0; x < xBlocks; x++, block++ )
...@@ -429,7 +480,7 @@ DDSDecompressDXT3() ...@@ -429,7 +480,7 @@ DDSDecompressDXT3()
decompresses a dxt3 format texture 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; s32 x, y, xBlocks, yBlocks;
u32 *pixel, alphaZero; u32 *pixel, alphaZero;
...@@ -452,7 +503,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -452,7 +503,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
for( y = 0; y < yBlocks; y++ ) for( y = 0; y < yBlocks; y++ )
{ {
/* 8 bytes per block, 1 block for alpha, 1 block for color */ /* 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 */ /* walk x */
for( x = 0; x < xBlocks; x++, block++ ) for( x = 0; x < xBlocks; x++, block++ )
...@@ -482,7 +533,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -482,7 +533,7 @@ s32 DDSDecompressDXT3( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT5() DDSDecompressDXT5()
decompresses a dxt5 format texture 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; s32 x, y, xBlocks, yBlocks;
u32 *pixel, alphaZero; u32 *pixel, alphaZero;
...@@ -505,7 +556,7 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -505,7 +556,7 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
for( y = 0; y < yBlocks; y++ ) for( y = 0; y < yBlocks; y++ )
{ {
/* 8 bytes per block, 1 block for alpha, 1 block for color */ /* 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 */ /* walk x */
for( x = 0; x < xBlocks; x++, block++ ) for( x = 0; x < xBlocks; x++, block++ )
...@@ -535,10 +586,10 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -535,10 +586,10 @@ s32 DDSDecompressDXT5( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT2() DDSDecompressDXT2()
decompresses a dxt2 format texture (fixme: un-premultiply alpha) 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 */ /* decompress dxt3 first */
const s32 r = DDSDecompressDXT3( dds, width, height, pixels ); const s32 r = DDSDecompressDXT3( dds, data, width, height, pixels );
/* return to sender */ /* return to sender */
return r; return r;
...@@ -549,49 +600,21 @@ s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels ) ...@@ -549,49 +600,21 @@ s32 DDSDecompressDXT2( ddsBuffer *dds, s32 width, s32 height, u8 *pixels )
DDSDecompressDXT4() DDSDecompressDXT4()
decompresses a dxt4 format texture (fixme: un-premultiply alpha) 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 */ /* decompress dxt5 first */
const s32 r = DDSDecompressDXT5( dds, width, height, pixels ); const s32 r = DDSDecompressDXT5( dds, data, width, height, pixels );
/* return to sender */ /* return to sender */
return r; 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() DDSDecompress()
decompresses a dds texture into an rgba image buffer, returns 0 on success 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; s32 width, height;
eDDSPixelFormat pf; eDDSPixelFormat pf;
...@@ -606,32 +629,30 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels ) ...@@ -606,32 +629,30 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
{ {
case DDS_PF_ARGB8888: case DDS_PF_ARGB8888:
/* fixme: support other [a]rgb formats */ /* fixme: support other [a]rgb formats */
r = DDSDecompressARGB8888( dds, width, height, pixels ); r = DDSDecompressARGB8888( dds, data, width, height, pixels );
break; break;
case DDS_PF_DXT1: case DDS_PF_DXT1:
r = DDSDecompressDXT1( dds, width, height, pixels ); r = DDSDecompressDXT1( dds, data, width, height, pixels );
break; break;
case DDS_PF_DXT2: case DDS_PF_DXT2:
r = DDSDecompressDXT2( dds, width, height, pixels ); r = DDSDecompressDXT2( dds, data, width, height, pixels );
break; break;
case DDS_PF_DXT3: case DDS_PF_DXT3:
r = DDSDecompressDXT3( dds, width, height, pixels ); r = DDSDecompressDXT3( dds, data, width, height, pixels );
break; break;
case DDS_PF_DXT4: case DDS_PF_DXT4:
r = DDSDecompressDXT4( dds, width, height, pixels ); r = DDSDecompressDXT4( dds, data, width, height, pixels );
break; break;
case DDS_PF_DXT5: case DDS_PF_DXT5:
r = DDSDecompressDXT5( dds, width, height, pixels ); r = DDSDecompressDXT5( dds, data, width, height, pixels );
break; break;
default: default: // DDS_PF_UNKNOWN
case DDS_PF_UNKNOWN:
memset( pixels, 0xFF, width * height * 4 );
r = -1; r = -1;
break; break;
} }
...@@ -640,14 +661,14 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels ) ...@@ -640,14 +661,14 @@ s32 DDSDecompress( ddsBuffer *dds, u8 *pixels )
return r; return r;
} }
} // end anonymous namespace #endif
//! returns true if the file maybe is able to be loaded by this class //! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".tga") //! based on the file extension (e.g. ".tga")
bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const 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 ...@@ -657,44 +678,127 @@ bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const
if (!file) if (!file)
return false; return false;
ddsBuffer header; c8 MagicWord[4];
file->read(&header, sizeof(header)); file->read(&MagicWord, 4);
s32 width, height; return (MagicWord[0] == 'D' && MagicWord[1] == 'D' && MagicWord[2] == 'S');
eDDSPixelFormat pixelFormat;
return (0 == DDSGetInfo( &header, &width, &height, &pixelFormat));
} }
//! creates a surface from the file //! creates a surface from the file
IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const
{ {
u8 *memFile = new u8 [ file->getSize() ]; ddsHeader header;
file->read ( memFile, file->getSize() );
ddsBuffer *header = (ddsBuffer*) memFile;
IImage* image = 0; IImage* image = 0;
s32 width, height; s32 width, height;
eDDSPixelFormat pixelFormat; eDDSPixelFormat pixelFormat;
if ( 0 == DDSGetInfo( header, &width, &height, &pixelFormat) ) file->seek(0);
{ file->read(&header, sizeof(ddsHeader));
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
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(); u32 newSize = file->getSize() - sizeof(ddsHeader);
image->drop(); u8* memFile = new u8[newSize];
image = 0; 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; return image;
if ( image ) }
image->unlock();
//! 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; return image;
#else
return 0;
#endif
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "IrrCompileConfig.h" #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" #include "IImageLoader.h"
...@@ -16,8 +16,7 @@ namespace irr ...@@ -16,8 +16,7 @@ namespace irr
namespace video namespace video
{ {
/* dependencies */ /* dds pixel format types */
/* dds definition */
enum eDDSPixelFormat enum eDDSPixelFormat
{ {
DDS_PF_ARGB8888, DDS_PF_ARGB8888,
...@@ -29,24 +28,24 @@ enum eDDSPixelFormat ...@@ -29,24 +28,24 @@ enum eDDSPixelFormat
DDS_PF_UNKNOWN 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 // byte-align structures
#include "irrpack.h" #include "irrpack.h"
/* structures */ /* structures */
struct ddsColorKey
struct ddsPixelFormat
{ {
u32 colorSpaceLowValue; u32 Size;
u32 colorSpaceHighValue; u32 Flags;
u32 FourCC;
u32 RGBBitCount;
u32 RBitMask;
u32 GBitMask;
u32 BBitMask;
u32 ABitMask;
} PACK_STRUCT; } PACK_STRUCT;
struct ddsCaps struct ddsCaps
{ {
u32 caps1; u32 caps1;
...@@ -55,108 +54,25 @@ struct ddsCaps ...@@ -55,108 +54,25 @@ struct ddsCaps
u32 caps4; u32 caps4;
} PACK_STRUCT; } PACK_STRUCT;
struct ddsMultiSampleCaps
{
u16 flipMSTypes;
u16 bltMSTypes;
} PACK_STRUCT;
struct ddsHeader
struct ddsPixelFormat
{ {
u32 size; c8 Magic[4];
u32 flags; u32 Size;
u32 fourCC; u32 Flags;
union u32 Height;
{ u32 Width;
u32 rgbBitCount; u32 PitchOrLinearSize;
u32 yuvBitCount; u32 Depth;
u32 zBufferBitDepth; u32 MipMapCount;
u32 alphaBitDepth; u32 Reserved1[11];
u32 luminanceBitCount; ddsPixelFormat PixelFormat;
u32 bumpBitCount; ddsCaps Caps;
u32 privateFormatBitCount; u32 Reserved2;
};
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; } PACK_STRUCT;
struct ddsBuffer #ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_
{
/* 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;
struct ddsColorBlock struct ddsColorBlock
{ {
...@@ -184,6 +100,9 @@ struct ddsColor ...@@ -184,6 +100,9 @@ struct ddsColor
u8 r, g, b, a; u8 r, g, b, a;
} PACK_STRUCT; } PACK_STRUCT;
#endif
// Default alignment // Default alignment
#include "irrunpack.h" #include "irrunpack.h"
...@@ -285,6 +204,9 @@ public: ...@@ -285,6 +204,9 @@ public:
//! creates a surface from the file //! creates a surface from the file
virtual IImage* loadImage(io::IReadFile* file) const; virtual IImage* loadImage(io::IReadFile* file) const;
//! creates a compressed surface from the file
virtual IImageCompressed* loadImageCompressed(io::IReadFile* file) const;
}; };
......
...@@ -139,7 +139,7 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre ...@@ -139,7 +139,7 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_ #ifdef _IRR_COMPILE_WITH_PSD_LOADER_
SurfaceLoader.push_back(video::createImageLoaderPSD()); SurfaceLoader.push_back(video::createImageLoaderPSD());
#endif #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()); SurfaceLoader.push_back(video::createImageLoaderDDS());
#endif #endif
#ifdef _IRR_COMPILE_WITH_PCX_LOADER_ #ifdef _IRR_COMPILE_WITH_PCX_LOADER_
...@@ -1402,6 +1402,77 @@ IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format, ...@@ -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. //! Creates an empty software image.
IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size) IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
{ {
......
...@@ -352,6 +352,17 @@ namespace video ...@@ -352,6 +352,17 @@ namespace video
const core::dimension2d<u32>& size, void *data, const core::dimension2d<u32>& size, void *data,
bool ownForeignMemory=true, bool deleteForeignMemory = true); 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. //! Creates an empty software image.
virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size); virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment