diff -r 4ea92975a277 code/nel/include/nel/misc/bitmap.h --- a/code/nel/include/nel/misc/bitmap.h Tue Feb 01 18:56:55 2011 +0100 +++ b/code/nel/include/nel/misc/bitmap.h Tue Feb 08 16:37:37 2011 +0100 @@ -1,652 +1,643 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - - -#ifndef NL_BITMAP_H -#define NL_BITMAP_H - - -#include "types_nl.h" -#include "rgba.h" -#include "debug.h" -#include -#include "object_vector.h" - - -namespace NLMISC -{ - - -class IStream; - -//------------------ DDS STUFFS -------------------- - -#ifndef NL_MAKEFOURCC - #ifdef NL_LITTLE_ENDIAN - #define NL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ - ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ - ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 )) - #else - #define NL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ - ((uint32)(uint8)(ch3) | ((uint32)(uint8)(ch2) << 8) | \ - ((uint32)(uint8)(ch1) << 16) | ((uint32)(uint8)(ch0) << 24 )) - #endif -#endif - -const uint32 DDS_HEADER = NL_MAKEFOURCC('D', 'D', 'S', ' '); -const uint32 DXT_HEADER = NL_MAKEFOURCC('D', 'X', 'T', '\0'); -const uint32 PNG_HEADER = NL_MAKEFOURCC(0x89, 'P', 'N', 'G'); -const uint32 JPG_HEADER = NL_MAKEFOURCC(0xff, 0xd8, 0xff, 0xe0); - - -// dwLinearSize is valid -#define DDSD_LINEARSIZE 0x00080000l - - -//---------------- END OF DDS STUFFS ------------------ - - -const uint8 MAX_MIPMAP = 16; - - - - -/** - * Class Bitmap - * - * \author Stephane Coutelas - * \author Nevrax France - * \date 2000 - */ -/* *** IMPORTANT ******************** - * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL - * ********************************** - */ -class CBitmap -{ -protected : - CObjectVector _Data[MAX_MIPMAP]; - - // The number of mipmaps. base image IS a mipmap. 1 means a base image with no mipmaping. - uint8 _MipMapCount; - bool _LoadGrayscaleAsAlpha; - uint32 _Width; - uint32 _Height; - - // don't forget to update operator=() and swap() if adding a data member - -private : - - - /** - * blend 2 integers between 0 and 255 . - * \param n0 first integer - * \param n1 second integer - * \param coef coefficient for the first integer (must be in [0,256]) - */ - uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0); - - - /** - * Read a DDS from an IStream. - * The bitmap is readen as a set of bytes and stocked compressed. - * Width and Height are multiple of 4. - * \param IStream The stream must be in reading mode. - * \return image depth - * \throw EDDSBadHeader : surface is header is not valid. - */ - uint8 readDDS(NLMISC::IStream &f, uint mipMapSkip); - - - /** - * Read a TGA from an IStream. - * TGA pictures can be in 24 or 32 bits, RLE or uncompressed - * \param f IStream (must be a reading stream) - * \return image depth if succeed, 0 else - */ - uint8 readTGA( NLMISC::IStream &f); - - - /** - * Read a PNG from an IStream. - * PNG pictures can be in 24 or 32 bits - * \param f IStream (must be a reading stream) - * \return image depth if succeed, 0 else - */ - uint8 readPNG( NLMISC::IStream &f ); - - - /** - * Read a JPG from an IStream. - * JPG pictures can be in 24 - * \param f IStream (must be a reading stream) - * \return image depth if succeed, 0 else - */ - uint8 readJPG( NLMISC::IStream &f ); - - - /** - * Change bitmap format - * - * about DXTC1 to DXTC5 : - * Does nothing if the format is not DXTC1 - * about alpha encoding : - * alpha0 == alpha1 - * code(x,y) == 7 for every (x,y) - * - * about luminance to alpha and alpha to luminance : - * the buffer keeps unchanged - * - */ - ///@{ - bool convertToDXTC5(); - - bool convertToRGBA(); - bool luminanceToRGBA(); - bool alphaToRGBA(); - bool alphaLuminanceToRGBA(); - - bool convertToLuminance(); - bool rgbaToLuminance(); - bool alphaToLuminance(); - bool alphaLuminanceToLuminance(); - - bool convertToAlpha(); - bool rgbaToAlpha(); - bool luminanceToAlpha(); - bool alphaLuminanceToAlpha(); - - bool convertToAlphaLuminance(); - bool rgbaToAlphaLuminance(); - bool luminanceToAlphaLuminance(); - bool alphaToAlphaLuminance(); - - ///@} - - /** - * Decompress bitmap compressed with S3TC DXT1 algorithm. - * \param alpha if alpha is true there's alpha. - */ - bool decompressDXT1(bool alpha); - - /** - * Decompress bitmap compressed with S3TC DXT3 algorithm. - * \throw EAllocationFailure : can't allocate memory. - */ - bool decompressDXT3(); - - - /** - * Decompress bitmap compressed with S3TC DXT3 algorithm. - * \throw EAllocationFailure : can't allocate memory. - */ - bool decompressDXT5(); - - - /** - * Extracting RGBA infos from a 16bits word. (used by S3TC decompression) - * \param color a 16bits integer - * \param r a CRGBA - */ - static void uncompress(uint16 color, NLMISC::CRGBA &); - - - /** - * The resample function - * \param pSrc CRGBA array - * \param pDest CRGBA array for storing resampled texture - * \param nSrcWidth original width - * \param nSrcHeight original height - * \param nDestWidth width after resample - * \param nDestHeight height after resample - */ - void resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, - sint32 nSrcWidth, sint32 nSrcHeight, - sint32 nDestWidth, sint32 nDestHeight); - - /** - * The FAST resample function : works only when reducing the size by two - * and when the image is square - * \param pSrc CRGBA array - * \param pDest CRGBA array for storing resampled texture - * \param nSrcWidth original width - * \param nSrcHeight original height - * \param nDestWidth width after resample - * \param nDestHeight height after resample - */ - void resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, - sint32 nSrcWidth, sint32 nSrcHeight, - sint32 nDestWidth, sint32 nDestHeight); - - - /** - * Quadratic interpolator - * \return the interpolation in (x,y) of the values (xy**) - */ - float getColorInterp (float x, float y, float xy00, float xy01, float xy10, float xy11) const; - - - /// name DXTC single texel read - //@{ - static CRGBA getDXTCColorFromBlock(const uint8 *block, sint x, sint y); - CRGBA getDXTC1Texel(sint x, sint y, uint32 numMipMap) const; - CRGBA getDXTC3Texel(sint x, sint y, uint32 numMipMap) const; - CRGBA getDXTC5Texel(sint x, sint y, uint32 numMipMap) const; - //@} - - - CRGBA getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const; - - - // Make a dummy from a bitfield - void makeDummyFromBitField(const uint8 bitmap[1024]); - - // Flip DXTC - void flipHDXTCBlockColor(uint8 *bitColor, uint32 w); - void flipVDXTCBlockColor(uint8 *bitColor, uint32 h); - void flipHDXTCBlockAlpha3(uint8 *bitColor, uint32 w); - void flipVDXTCBlockAlpha3(uint8 *bitColor, uint32 h); - void flipHDXTCBlockAlpha5(uint8 *bitColor, uint32 w); - void flipVDXTCBlockAlpha5(uint8 *bitColor, uint32 h); - void flipDXTC(bool vertical); - void flipDXTCMipMap(bool vertical, uint mm, uint type); - -public: - - enum TType - { - RGBA=0, - Luminance, - Alpha, - AlphaLuminance, - DXTC1, - DXTC1Alpha, - DXTC3, - DXTC5, - DsDt, - ModeCount, - DonTKnow=0xffffffff - } PixelFormat; - - static const uint32 bitPerPixels[ModeCount]; - static const uint32 DXTC1HEADER; - static const uint32 DXTC3HEADER; - static const uint32 DXTC5HEADER; - - // don't forget to update operator=() and swap() if adding a data member - - CBitmap() - { - _MipMapCount = 1; - _Width = 0; - _Height = 0; - PixelFormat = RGBA; - _LoadGrayscaleAsAlpha = true; - } - - virtual ~CBitmap() { } - - // swap 2 bitmaps contents - void swap(CBitmap &other); - - /** - * Read a bitmap(TGA or DDS) from an IStream. - * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5, and - * uncompressed TGA (24 and 32 bits). - * \param IStream The stream must be in reading mode. - * \param mipMapSkip if the file is a DDS with mipMap. N=mipMapSkip mipmaps are skipped. - * \return image depth (24 or 32), or 0 if load failed - * \throw ESeekFailed : seek has failed - */ - uint8 load(NLMISC::IStream &f, uint mipMapSkip=0); - - - /** - * Determinate the bitmap size from a bitmap(TGA or DDS) from an IStream. load just header of the file. - * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5, and - * uncompressed TGA (24 and 32 bits). - * NB: at the end, f is seeked to begin. - * \param IStream The stream must be in reading mode. - * \param width the width of the image. 0 if fails. - * \param height the height of the image. 0 if fails. - * \throw ESeekFailed : seek has failed - */ - static void loadSize(NLMISC::IStream &f, uint32 &width, uint32 &height); - - - /** same than other loadSize(), but with a pathName. - * \see loadSize() - */ - static void loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight); - - - /** - * Make a dummy "?" texture. Useful for file not found. Mode is rgba. - */ - void makeDummy(); - - - /** - * Make a dummy "2" texture. Useful for file not power of 2. Mode is rgba. - */ - void makeNonPowerOf2Dummy(); - - /** - * Return the pixels buffer of the image, or of one of its mipmap. - * Return a reference of an array in pixel format get with getPixelFormat(). - * \return CObjectVector& RGBA pixels - */ - ///@{ - CObjectVector& getPixels(uint32 numMipMap = 0) - { - //nlassert (numMipMap<=_MipMapCount); - return _Data[numMipMap]; - } - const CObjectVector& getPixels(uint32 numMipMap = 0) const - { - //nlassert (numMipMap<=_MipMapCount); - return _Data[numMipMap]; - } - /** Gain ownership of this texture datas. As a result, the bitmap is reseted (put in the same state than when ctor is called, e.g a single mipmap with null size) - * The CObjectVector objects that contains the bitmap (one per mipmap) datas are 'swapped' with those in the array provided by the caller. - * NB : The user must provide at least min(getMipMapCount(), maxMipMapCount) entries in the array - * \param mipmapArray Array of mipmap that receive the bitmap datas - * \param maxMipMapCount Max number of mipmap to be copied in the destination array. - */ - void unattachPixels(CObjectVector *mipmapDestArray, uint maxMipMapCount = MAX_MIPMAP); - - ///@} - - - /** - * Convert bitmap to another type - * conversion to rgba always work. No-op if already rgba. - * \param type new type for the bitmap - * \return true if conversion succeeded, false else - */ - bool convertToType (TType type); - - - - /** - * Return the format of pixels stored at the present time in the object buffer. - * \return Pixel format (rgba luminance alpha alphaLuminance dxtc1 dxtc1Alpha dxtc3 dxtc5) - */ - TType getPixelFormat() const - { - return PixelFormat; - } - - - /** - * Return the image width, or a mipmap width. - * \param mipMap mipmap level - * \return image width (0 if mipmap not found) - */ - virtual uint32 getWidth(uint32 numMipMap = 0) const; - - - /** - * Return the image height, or a mipmap height. - * \param mipMap mipmap level - * \return image height (0 if mipmap not found) - */ - virtual uint32 getHeight(uint32 numMipMap = 0) const; - - - /** - * Return the size (in pixels) of the image: <=> getHeight()*getWidth(). - * \param mipMap mipmap level - * \return image size (0 if mipmap not found) - */ - uint32 getSize(uint32 numMipMap = 0) const; - - - /** - * Return the number of mipmaps. Level0 is a mipmap... - * \return number of mipmaps. 0 if no image at all. 1 if no mipmaping (for the base level). - */ - uint32 getMipMapCount() const - { - return _MipMapCount; - } - - // Compute the number of mipmap needed for that bitmap (independently from the current number of mipmaps that have been set) - uint32 computeNeededMipMapCount() const; - - /** - * Rotate a bitmap in CCW mode. - * - * \see releaseMipMaps(). - */ - void rotateCCW(); - - /** - * Build the mipmaps of the bitmap if they don't exist. - * Work only in RGBA mode... - * \see releaseMipMaps(). - */ - void buildMipMaps(); - - /** - * Release the mipmaps of the bitmap if they exist. - * Work for any mode. - * \see buildMipMaps(). - */ - void releaseMipMaps(); - - /** - * Reset the buffer. Mipmaps are deleted and bitmap is not valid anymore. - * - * \param type is the new type used for this texture - */ - void reset(TType type=RGBA); - - - /** - * Resample the bitmap. If mipmaps exist they are deleted, then rebuilt - * after resampling. - * \param nNewWidth width after resample - * \param nNewHeight height after resample - */ - void resample (sint32 nNewWidth, sint32 nNewHeight); - - - /** - * Resize the bitmap. If mipmaps exist they are deleted and not rebuilt. - * This is not a crop. Pixels are lost after resize. - * - * \param nNewWidth width after resize - * \param nNewHeight height after resize - * \param newType is the new type of the bitmap. If don_t_know, keep the same pixel format that before. - * \param resetTo0 by default the vector are filled by 0. set false to gain performances. - */ - void resize (sint32 nNewWidth, sint32 nNewHeight, TType newType=DonTKnow, bool resetTo0= true); - - - /** ADVANCED USE - * Resize a single mipmap level. resize() should have been called before. - * This is not a crop. Pixels are lost after resize. - * No validity check is made. It is the user responsabitility fo setup correct mipmap size. - * - * \param numMipMap id of the mipmap - * \param nNewWidth width after resize - * \param nNewHeight height after resize - * \param resetTo0 by default the vector are filled by 0. set false to gain performances. - */ - void resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0= true); - - - /** ADVANCED USE - * To use in conjunction with resizeMipMap. Setup the correct total number of mipmap - * No validity check is made. It is the user responsabitility fo setup correct mipmap count. - */ - void setMipMapCount(uint32 mmc); - - - /** - * Write a TGA (24 or 32 bits) from the object pixels buffer. - * If the current pixel format is not rgba then the method does nothing - * If the pixel format is Alpha then we save in 8 bpp - * \param f IStream (must be a reading stream) - * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) - * \param upsideDown if true, the bitmap will be saved with the upside down - * \return true if succeed, false else - */ - bool writeTGA(NLMISC::IStream &f, uint32 d=0, bool upsideDown = false); - - /** - * Write a PNG (24 or 32 bits) from the object pixels buffer. - * If the current pixel format is not rgba then the method does nothing - * If the pixel format is Alpha then we save in 8 bpp - * \param f IStream (must be a reading stream) - * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) - * \return true if succeed, false else - */ - bool writePNG(NLMISC::IStream &f, uint32 d=0); - - /** - * Write a JPG from the object pixels buffer. - * If the current pixel format is not rgba then the method does nothing - * If the pixel format is Alpha then we save in 8 bpp - * \param f IStream (must be a reading stream) - * \param quality 0=very bad quality 100=best quality - * \return true if succeed, false else - */ - bool writeJPG(NLMISC::IStream &f, uint8 quality = 80); - - /** - * Tell the bitmap to load grayscale bitmap as alpha or luminance format. - * - * \param loadAsAlpha is true to load grayscale bitmaps as alpha. false to load grayscale bitmaps as luminance. - * default value is true. - */ - void loadGrayscaleAsAlpha (bool loadAsAlpha) - { - _LoadGrayscaleAsAlpha=loadAsAlpha; - } - - - /** - * Tell if the bitmap loads grayscale bitmap as alpha or luminance format. - * - * \return true if the bitmap loads grayscale bitmaps as alpha, false if it loads grayscale bitmaps as luminance. - */ - bool isGrayscaleAsAlpha () const - { - return _LoadGrayscaleAsAlpha; - } - - - /** - * Perform a simple blit from the source to this bitmap at the (x, y) pos - * The dimension of the original bitmap are preserved - * For now, this texture and the source must have the same format - * With DXTC format, the dest coordinates must be a multiple of 4 - * mipmap are not rebuild when present - * IMPORTANT : copy to self is not handled correctly - * \return true if the params were corrects and if the blit occurs. In debug build there's an assertion - */ - bool blit(const CBitmap *src, sint32 x, sint32 y) ; - /** - * Extended version of blit. The destinaion of the blit is 'this' bitmap - * Source and dest rect are clamped as necessary. - * For now, only RGBA is uspported (an asertion occurs otherwise) - * mipmap are not updated. - * IMPORTANT : copy to self is not handled correctly - */ - void blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY); - - - /** - * Get the color in the bitmap for the first mipmap - * The mipmaps must be built. If not just return the bilinear at the given point. - * NB: coordinates are clamped. - * \param tiled If false coordinate are clamped, else the bitmap is considered to tile - */ - CRGBAF getColor (float x, float y) const; - // Get Color with optional tiling on axis - CRGBAF getColor (float x, float y, bool tileU, bool tileV) const; - - - - - - /** Get the pixel at the given coorrdinate. - * Works in RGBA and DXTC modes. - * Outside of the bitmap it returns Black (or if mipmap is not found) - */ - CRGBA getPixelColor(sint x, sint y, uint32 numMipMap = 0) const; - /** - * Horizontal flip (all the columns are flipped) - * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) - */ - void flipH(); - - - /** - * Vertical flip (all the rows are flipped) - * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) - */ - void flipV(); - - /** - * Rotation of the bitmap of 90 degree in clockwise - */ - void rot90CW(); - - /** - * Rotation of the bitmap of 90 degree in counter clockwise - */ - void rot90CCW(); - - /** Set this bitmap as the result of the blend bewteen 2 bitmap - * REQUIRE : - Bm0 and Bm1 should have the same size. - * - Both bitmap should be convertible to RGBA pixel format. - * The result is a RGBA bitmap. - * NB: this just works with the first mipmaps - * \param factor The blend factor. 0 means the result is equal to Bm0, 256 means the result is equal to Bm1 - * \param inputBitmapIsMutable when true, bitmap can be converted in place when needed (no copy done) - */ - void blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable = false); - - void getData(uint8*& extractData); - - void getDibData(uint8*& extractData); - - CBitmap& operator= (const CBitmap& from) - { - if (&from == this) - return *this; - for (uint i=0; i!=MAX_MIPMAP; ++i) - { - _Data[i] = from._Data[i]; // requires more than a surface copy - } - _MipMapCount = from._MipMapCount; - _LoadGrayscaleAsAlpha = from._LoadGrayscaleAsAlpha; - _Width = from._Width; - _Height = from._Height; - PixelFormat = from.PixelFormat; - return *this; - } -}; - -} // NLMISC - - -#endif // NL_BITMAP_H - -/* End of bitmap.h */ +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + + +#ifndef NL_BITMAP_H +#define NL_BITMAP_H + + +#include "types_nl.h" +#include "rgba.h" +#include "debug.h" +#include +#include "object_vector.h" + + +namespace NLMISC +{ + + +class IStream; + +//------------------ DDS STUFFS -------------------- + +#define NL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ + ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 )) + +const uint32 DDS_HEADER = NL_MAKEFOURCC('D', 'D', 'S', ' '); +const uint32 DXT_HEADER = NL_MAKEFOURCC('D', 'X', 'T', '\0'); +const uint32 PNG_HEADER = NL_MAKEFOURCC(0x89, 'P', 'N', 'G'); +const uint32 JPG_HEADER = NL_MAKEFOURCC(0xff, 0xd8, 0xff, 0xe0); + + +// dwLinearSize is valid + #define DDSD_LINEARSIZE 0x00080000l + +//---------------- END OF DDS STUFFS ------------------ + + +const uint8 MAX_MIPMAP = 16; + + + + +/** + * Class Bitmap + * + * \author Stephane Coutelas + * \author Nevrax France + * \date 2000 + */ +/* *** IMPORTANT ******************** + * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL + * ********************************** + */ +class CBitmap +{ +protected : + CObjectVector _Data[MAX_MIPMAP]; + + // The number of mipmaps. base image IS a mipmap. 1 means a base image with no mipmaping. + uint8 _MipMapCount; + bool _LoadGrayscaleAsAlpha; + uint32 _Width; + uint32 _Height; + + // don't forget to update operator=() and swap() if adding a data member + +private : + + + /** + * blend 2 integers between 0 and 255 . + * \param n0 first integer + * \param n1 second integer + * \param coef coefficient for the first integer (must be in [0,256]) + */ + uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0); + + + /** + * Read a DDS from an IStream. + * The bitmap is readen as a set of bytes and stocked compressed. + * Width and Height are multiple of 4. + * \param IStream The stream must be in reading mode. + * \return image depth + * \throw EDDSBadHeader : surface is header is not valid. + */ + uint8 readDDS(NLMISC::IStream &f, uint mipMapSkip); + + + /** + * Read a TGA from an IStream. + * TGA pictures can be in 24 or 32 bits, RLE or uncompressed + * \param f IStream (must be a reading stream) + * \return image depth if succeed, 0 else + */ + uint8 readTGA( NLMISC::IStream &f); + + + /** + * Read a PNG from an IStream. + * PNG pictures can be in 24 or 32 bits + * \param f IStream (must be a reading stream) + * \return image depth if succeed, 0 else + */ + uint8 readPNG( NLMISC::IStream &f ); + + + /** + * Read a JPG from an IStream. + * JPG pictures can be in 24 + * \param f IStream (must be a reading stream) + * \return image depth if succeed, 0 else + */ + uint8 readJPG( NLMISC::IStream &f ); + + + /** + * Change bitmap format + * + * about DXTC1 to DXTC5 : + * Does nothing if the format is not DXTC1 + * about alpha encoding : + * alpha0 == alpha1 + * code(x,y) == 7 for every (x,y) + * + * about luminance to alpha and alpha to luminance : + * the buffer keeps unchanged + * + */ + ///@{ + bool convertToDXTC5(); + + bool convertToRGBA(); + bool luminanceToRGBA(); + bool alphaToRGBA(); + bool alphaLuminanceToRGBA(); + + bool convertToLuminance(); + bool rgbaToLuminance(); + bool alphaToLuminance(); + bool alphaLuminanceToLuminance(); + + bool convertToAlpha(); + bool rgbaToAlpha(); + bool luminanceToAlpha(); + bool alphaLuminanceToAlpha(); + + bool convertToAlphaLuminance(); + bool rgbaToAlphaLuminance(); + bool luminanceToAlphaLuminance(); + bool alphaToAlphaLuminance(); + + ///@} + + /** + * Decompress bitmap compressed with S3TC DXT1 algorithm. + * \param alpha if alpha is true there's alpha. + */ + bool decompressDXT1(bool alpha); + + /** + * Decompress bitmap compressed with S3TC DXT3 algorithm. + * \throw EAllocationFailure : can't allocate memory. + */ + bool decompressDXT3(); + + + /** + * Decompress bitmap compressed with S3TC DXT3 algorithm. + * \throw EAllocationFailure : can't allocate memory. + */ + bool decompressDXT5(); + + + /** + * Extracting RGBA infos from a 16bits word. (used by S3TC decompression) + * \param color a 16bits integer + * \param r a CRGBA + */ + static void uncompress(uint16 color, NLMISC::CRGBA &); + + + /** + * The resample function + * \param pSrc CRGBA array + * \param pDest CRGBA array for storing resampled texture + * \param nSrcWidth original width + * \param nSrcHeight original height + * \param nDestWidth width after resample + * \param nDestHeight height after resample + */ + void resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, + sint32 nSrcWidth, sint32 nSrcHeight, + sint32 nDestWidth, sint32 nDestHeight); + + /** + * The FAST resample function : works only when reducing the size by two + * and when the image is square + * \param pSrc CRGBA array + * \param pDest CRGBA array for storing resampled texture + * \param nSrcWidth original width + * \param nSrcHeight original height + * \param nDestWidth width after resample + * \param nDestHeight height after resample + */ + void resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, + sint32 nSrcWidth, sint32 nSrcHeight, + sint32 nDestWidth, sint32 nDestHeight); + + + /** + * Quadratic interpolator + * \return the interpolation in (x,y) of the values (xy**) + */ + float getColorInterp (float x, float y, float xy00, float xy01, float xy10, float xy11) const; + + + /// name DXTC single texel read + //@{ + static CRGBA getDXTCColorFromBlock(const uint8 *block, sint x, sint y); + CRGBA getDXTC1Texel(sint x, sint y, uint32 numMipMap) const; + CRGBA getDXTC3Texel(sint x, sint y, uint32 numMipMap) const; + CRGBA getDXTC5Texel(sint x, sint y, uint32 numMipMap) const; + //@} + + + CRGBA getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const; + + + // Make a dummy from a bitfield + void makeDummyFromBitField(const uint8 bitmap[1024]); + + // Flip DXTC + void flipHDXTCBlockColor(uint8 *bitColor, uint32 w); + void flipVDXTCBlockColor(uint8 *bitColor, uint32 h); + void flipHDXTCBlockAlpha3(uint8 *bitColor, uint32 w); + void flipVDXTCBlockAlpha3(uint8 *bitColor, uint32 h); + void flipHDXTCBlockAlpha5(uint8 *bitColor, uint32 w); + void flipVDXTCBlockAlpha5(uint8 *bitColor, uint32 h); + void flipDXTC(bool vertical); + void flipDXTCMipMap(bool vertical, uint mm, uint type); + +public: + + enum TType + { + RGBA=0, + Luminance, + Alpha, + AlphaLuminance, + DXTC1, + DXTC1Alpha, + DXTC3, + DXTC5, + DsDt, + ModeCount, + DonTKnow=0xffffffff + } PixelFormat; + + static const uint32 bitPerPixels[ModeCount]; + static const uint32 DXTC1HEADER; + static const uint32 DXTC3HEADER; + static const uint32 DXTC5HEADER; + + // don't forget to update operator=() and swap() if adding a data member + + CBitmap() + { + _MipMapCount = 1; + _Width = 0; + _Height = 0; + PixelFormat = RGBA; + _LoadGrayscaleAsAlpha = true; + } + + virtual ~CBitmap() { } + + // swap 2 bitmaps contents + void swap(CBitmap &other); + + /** + * Read a bitmap(TGA or DDS) from an IStream. + * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5, and + * uncompressed TGA (24 and 32 bits). + * \param IStream The stream must be in reading mode. + * \param mipMapSkip if the file is a DDS with mipMap. N=mipMapSkip mipmaps are skipped. + * \return image depth (24 or 32), or 0 if load failed + * \throw ESeekFailed : seek has failed + */ + uint8 load(NLMISC::IStream &f, uint mipMapSkip=0); + + + /** + * Determinate the bitmap size from a bitmap(TGA or DDS) from an IStream. load just header of the file. + * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5, and + * uncompressed TGA (24 and 32 bits). + * NB: at the end, f is seeked to begin. + * \param IStream The stream must be in reading mode. + * \param width the width of the image. 0 if fails. + * \param height the height of the image. 0 if fails. + * \throw ESeekFailed : seek has failed + */ + static void loadSize(NLMISC::IStream &f, uint32 &width, uint32 &height); + + + /** same than other loadSize(), but with a pathName. + * \see loadSize() + */ + static void loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight); + + + /** + * Make a dummy "?" texture. Useful for file not found. Mode is rgba. + */ + void makeDummy(); + + + /** + * Make a dummy "2" texture. Useful for file not power of 2. Mode is rgba. + */ + void makeNonPowerOf2Dummy(); + + /** + * Return the pixels buffer of the image, or of one of its mipmap. + * Return a reference of an array in pixel format get with getPixelFormat(). + * \return CObjectVector& RGBA pixels + */ + ///@{ + CObjectVector& getPixels(uint32 numMipMap = 0) + { + //nlassert (numMipMap<=_MipMapCount); + return _Data[numMipMap]; + } + const CObjectVector& getPixels(uint32 numMipMap = 0) const + { + //nlassert (numMipMap<=_MipMapCount); + return _Data[numMipMap]; + } + /** Gain ownership of this texture datas. As a result, the bitmap is reseted (put in the same state than when ctor is called, e.g a single mipmap with null size) + * The CObjectVector objects that contains the bitmap (one per mipmap) datas are 'swapped' with those in the array provided by the caller. + * NB : The user must provide at least min(getMipMapCount(), maxMipMapCount) entries in the array + * \param mipmapArray Array of mipmap that receive the bitmap datas + * \param maxMipMapCount Max number of mipmap to be copied in the destination array. + */ + void unattachPixels(CObjectVector *mipmapDestArray, uint maxMipMapCount = MAX_MIPMAP); + + ///@} + + + /** + * Convert bitmap to another type + * conversion to rgba always work. No-op if already rgba. + * \param type new type for the bitmap + * \return true if conversion succeeded, false else + */ + bool convertToType (TType type); + + + + /** + * Return the format of pixels stored at the present time in the object buffer. + * \return Pixel format (rgba luminance alpha alphaLuminance dxtc1 dxtc1Alpha dxtc3 dxtc5) + */ + TType getPixelFormat() const + { + return PixelFormat; + } + + + /** + * Return the image width, or a mipmap width. + * \param mipMap mipmap level + * \return image width (0 if mipmap not found) + */ + virtual uint32 getWidth(uint32 numMipMap = 0) const; + + + /** + * Return the image height, or a mipmap height. + * \param mipMap mipmap level + * \return image height (0 if mipmap not found) + */ + virtual uint32 getHeight(uint32 numMipMap = 0) const; + + + /** + * Return the size (in pixels) of the image: <=> getHeight()*getWidth(). + * \param mipMap mipmap level + * \return image size (0 if mipmap not found) + */ + uint32 getSize(uint32 numMipMap = 0) const; + + + /** + * Return the number of mipmaps. Level0 is a mipmap... + * \return number of mipmaps. 0 if no image at all. 1 if no mipmaping (for the base level). + */ + uint32 getMipMapCount() const + { + return _MipMapCount; + } + + // Compute the number of mipmap needed for that bitmap (independently from the current number of mipmaps that have been set) + uint32 computeNeededMipMapCount() const; + + /** + * Rotate a bitmap in CCW mode. + * + * \see releaseMipMaps(). + */ + void rotateCCW(); + + /** + * Build the mipmaps of the bitmap if they don't exist. + * Work only in RGBA mode... + * \see releaseMipMaps(). + */ + void buildMipMaps(); + + /** + * Release the mipmaps of the bitmap if they exist. + * Work for any mode. + * \see buildMipMaps(). + */ + void releaseMipMaps(); + + /** + * Reset the buffer. Mipmaps are deleted and bitmap is not valid anymore. + * + * \param type is the new type used for this texture + */ + void reset(TType type=RGBA); + + + /** + * Resample the bitmap. If mipmaps exist they are deleted, then rebuilt + * after resampling. + * \param nNewWidth width after resample + * \param nNewHeight height after resample + */ + void resample (sint32 nNewWidth, sint32 nNewHeight); + + + /** + * Resize the bitmap. If mipmaps exist they are deleted and not rebuilt. + * This is not a crop. Pixels are lost after resize. + * + * \param nNewWidth width after resize + * \param nNewHeight height after resize + * \param newType is the new type of the bitmap. If don_t_know, keep the same pixel format that before. + * \param resetTo0 by default the vector are filled by 0. set false to gain performances. + */ + void resize (sint32 nNewWidth, sint32 nNewHeight, TType newType=DonTKnow, bool resetTo0= true); + + + /** ADVANCED USE + * Resize a single mipmap level. resize() should have been called before. + * This is not a crop. Pixels are lost after resize. + * No validity check is made. It is the user responsabitility fo setup correct mipmap size. + * + * \param numMipMap id of the mipmap + * \param nNewWidth width after resize + * \param nNewHeight height after resize + * \param resetTo0 by default the vector are filled by 0. set false to gain performances. + */ + void resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0= true); + + + /** ADVANCED USE + * To use in conjunction with resizeMipMap. Setup the correct total number of mipmap + * No validity check is made. It is the user responsabitility fo setup correct mipmap count. + */ + void setMipMapCount(uint32 mmc); + + + /** + * Write a TGA (24 or 32 bits) from the object pixels buffer. + * If the current pixel format is not rgba then the method does nothing + * If the pixel format is Alpha then we save in 8 bpp + * \param f IStream (must be a reading stream) + * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) + * \param upsideDown if true, the bitmap will be saved with the upside down + * \return true if succeed, false else + */ + bool writeTGA(NLMISC::IStream &f, uint32 d=0, bool upsideDown = false); + + /** + * Write a PNG (24 or 32 bits) from the object pixels buffer. + * If the current pixel format is not rgba then the method does nothing + * If the pixel format is Alpha then we save in 8 bpp + * \param f IStream (must be a reading stream) + * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) + * \return true if succeed, false else + */ + bool writePNG(NLMISC::IStream &f, uint32 d=0); + + /** + * Write a JPG from the object pixels buffer. + * If the current pixel format is not rgba then the method does nothing + * If the pixel format is Alpha then we save in 8 bpp + * \param f IStream (must be a reading stream) + * \param quality 0=very bad quality 100=best quality + * \return true if succeed, false else + */ + bool writeJPG(NLMISC::IStream &f, uint8 quality = 80); + + /** + * Tell the bitmap to load grayscale bitmap as alpha or luminance format. + * + * \param loadAsAlpha is true to load grayscale bitmaps as alpha. false to load grayscale bitmaps as luminance. + * default value is true. + */ + void loadGrayscaleAsAlpha (bool loadAsAlpha) + { + _LoadGrayscaleAsAlpha=loadAsAlpha; + } + + + /** + * Tell if the bitmap loads grayscale bitmap as alpha or luminance format. + * + * \return true if the bitmap loads grayscale bitmaps as alpha, false if it loads grayscale bitmaps as luminance. + */ + bool isGrayscaleAsAlpha () const + { + return _LoadGrayscaleAsAlpha; + } + + + /** + * Perform a simple blit from the source to this bitmap at the (x, y) pos + * The dimension of the original bitmap are preserved + * For now, this texture and the source must have the same format + * With DXTC format, the dest coordinates must be a multiple of 4 + * mipmap are not rebuild when present + * IMPORTANT : copy to self is not handled correctly + * \return true if the params were corrects and if the blit occurs. In debug build there's an assertion + */ + bool blit(const CBitmap *src, sint32 x, sint32 y) ; + /** + * Extended version of blit. The destinaion of the blit is 'this' bitmap + * Source and dest rect are clamped as necessary. + * For now, only RGBA is uspported (an asertion occurs otherwise) + * mipmap are not updated. + * IMPORTANT : copy to self is not handled correctly + */ + void blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY); + + + /** + * Get the color in the bitmap for the first mipmap + * The mipmaps must be built. If not just return the bilinear at the given point. + * NB: coordinates are clamped. + * \param tiled If false coordinate are clamped, else the bitmap is considered to tile + */ + CRGBAF getColor (float x, float y) const; + // Get Color with optional tiling on axis + CRGBAF getColor (float x, float y, bool tileU, bool tileV) const; + + + + + + /** Get the pixel at the given coorrdinate. + * Works in RGBA and DXTC modes. + * Outside of the bitmap it returns Black (or if mipmap is not found) + */ + CRGBA getPixelColor(sint x, sint y, uint32 numMipMap = 0) const; + /** + * Horizontal flip (all the columns are flipped) + * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) + */ + void flipH(); + + + /** + * Vertical flip (all the rows are flipped) + * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) + */ + void flipV(); + + /** + * Rotation of the bitmap of 90 degree in clockwise + */ + void rot90CW(); + + /** + * Rotation of the bitmap of 90 degree in counter clockwise + */ + void rot90CCW(); + + /** Set this bitmap as the result of the blend bewteen 2 bitmap + * REQUIRE : - Bm0 and Bm1 should have the same size. + * - Both bitmap should be convertible to RGBA pixel format. + * The result is a RGBA bitmap. + * NB: this just works with the first mipmaps + * \param factor The blend factor. 0 means the result is equal to Bm0, 256 means the result is equal to Bm1 + * \param inputBitmapIsMutable when true, bitmap can be converted in place when needed (no copy done) + */ + void blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable = false); + + void getData(uint8*& extractData); + + void getDibData(uint8*& extractData); + + CBitmap& operator= (const CBitmap& from) + { + if (&from == this) + return *this; + for (uint i=0; i!=MAX_MIPMAP; ++i) + { + _Data[i] = from._Data[i]; // requires more than a surface copy + } + _MipMapCount = from._MipMapCount; + _LoadGrayscaleAsAlpha = from._LoadGrayscaleAsAlpha; + _Width = from._Width; + _Height = from._Height; + PixelFormat = from.PixelFormat; + return *this; + } +}; + +} // NLMISC + + +#endif // NL_BITMAP_H + +/* End of bitmap.h */