/*
 * $Id: imagedds.h 4270 2016-11-06 11:02:47Z antonin.misek-skoda-auto.cz $
 *
 * Description  : One line description of file.
 * Author       : Vaclav Kyba <mail/Jabber: vaseo1@gmail.com>  <ICQ: 98576293>
 * 
 * Purpose      :
 * DDS loader written by Jon Watte 2002
 * Permission granted to use freely, as long as Jon Watte
 * is held harmless for all possible damages resulting from
 * your use or failure to use this code.
 * No warranty is expressed or implied. Use at your own risk,
 * or not at all.
*/


#ifndef __IMAGEDDS_H__
#define __IMAGEDDS_H__


#include "image.h"
#include "common.h"

//using namespace VRUT;

//  little-endian, of course
#define DDS_MAGIC 0x20534444
//  DDS_header.dwFlags
#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 

//  DDS_header.sPixelFormat.dwFlags
#define DDPF_ALPHAPIXELS            0x00000001 
#define DDPF_FOURCC                 0x00000004 
#define DDPF_INDEXED                0x00000020 
#define DDPF_RGB                    0x00000040 

//  DDS_header.sCaps.dwCaps1
#define DDSCAPS_COMPLEX             0x00000008 
#define DDSCAPS_TEXTURE             0x00001000 
#define DDSCAPS_MIPMAP              0x00400000 

//  DDS_header.sCaps.dwCaps2
#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 

#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
	  (GLuint)( \
	    (((GLuint)(GLubyte)(ch3) << 24) & 0xFF000000) | \
	    (((GLuint)(GLubyte)(ch2) << 16) & 0x00FF0000) | \
	    (((GLuint)(GLubyte)(ch1) <<  8) & 0x0000FF00) | \
	     ((GLuint)(GLubyte)(ch0)        & 0x000000FF) )
#endif

#define D3DFMT_DXT1     MAKEFOURCC('D', 'X', 'T', '1')    //  DXT1 compression texture format 
#define D3DFMT_DXT2     MAKEFOURCC('D', 'X', 'T', '2')    //  DXT2 compression texture format 
#define D3DFMT_DXT3     MAKEFOURCC('D', 'X', 'T', '3')    //  DXT3 compression texture format 
#define D3DFMT_DXT4     MAKEFOURCC('D', 'X', 'T', '4')    //  DXT4 compression texture format 
#define D3DFMT_DXT5     MAKEFOURCC('D', 'X', 'T', '5')    //  DXT5 compression texture format 

#define PF_IS_DXT1(pf) \
  ((pf.dwFlags & DDPF_FOURCC) && \
   (pf.dwFourCC == D3DFMT_DXT1))

#define PF_IS_DXT3(pf) \
  ((pf.dwFlags & DDPF_FOURCC) && \
   (pf.dwFourCC == D3DFMT_DXT3))

#define PF_IS_DXT5(pf) \
  ((pf.dwFlags & DDPF_FOURCC) && \
   (pf.dwFourCC == D3DFMT_DXT5))

#define PF_IS_BGRA8(pf) \
  ((pf.dwFlags & DDPF_RGB) && \
   (pf.dwFlags & DDPF_ALPHAPIXELS) && \
   (pf.dwRGBBitCount == 32) && \
   (pf.dwRBitMask == 0xff0000) && \
   (pf.dwGBitMask == 0xff00) && \
   (pf.dwBBitMask == 0xff) && \
   (pf.dwAlphaBitMask == 0xff000000U))

#define PF_IS_BGR8(pf) \
  ((pf.dwFlags & DDPF_RGB) && \
  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
   (pf.dwRGBBitCount == 24) && \
   (pf.dwRBitMask == 0xff0000) && \
   (pf.dwGBitMask == 0xff00) && \
   (pf.dwBBitMask == 0xff))

#define PF_IS_BGR5A1(pf) \
  ((pf.dwFlags & DDPF_RGB) && \
   (pf.dwFlags & DDPF_ALPHAPIXELS) && \
   (pf.dwRGBBitCount == 16) && \
   (pf.dwRBitMask == 0x00007c00) && \
   (pf.dwGBitMask == 0x000003e0) && \
   (pf.dwBBitMask == 0x0000001f) && \
   (pf.dwAlphaBitMask == 0x00008000))

#define PF_IS_BGR565(pf) \
  ((pf.dwFlags & DDPF_RGB) && \
  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
   (pf.dwRGBBitCount == 16) && \
   (pf.dwRBitMask == 0x0000f800) && \
   (pf.dwGBitMask == 0x000007e0) && \
   (pf.dwBBitMask == 0x0000001f))

#define PF_IS_INDEX8(pf) \
  ((pf.dwFlags & DDPF_INDEXED) && \
   (pf.dwRGBBitCount == 8))


namespace VRUT
{
	///Image container with support for many formats readable by \c wxImage
	class VRUT_CORE_API ImageDDS : public Image
	{
	public:
		///Texture header info
		struct DDS_header
		{
			unsigned int    dwMagic;
			unsigned int    dwSize;
			unsigned int    dwFlags;
			unsigned int    dwHeight;
			unsigned int    dwWidth;
			unsigned int    dwPitchOrLinearSize;
			unsigned int    dwDepth;
			unsigned int    dwMipMapCount;
			unsigned int    dwReserved1[ 11 ];

			//  DDPIXELFORMAT
			struct
			{
				unsigned int    dwSize;
				unsigned int    dwFlags;
				unsigned int    dwFourCC;
				unsigned int    dwRGBBitCount;
				unsigned int    dwRBitMask;
				unsigned int    dwGBitMask;
				unsigned int    dwBBitMask;
				unsigned int    dwAlphaBitMask;
			} sPixelFormat;

			//  DDCAPS2
			struct
			{
				unsigned int    dwCaps1;
				unsigned int    dwCaps2;
				unsigned int    dwDDSX;
				unsigned int    dwReserved;
			} sCaps;

			unsigned int    dwReserved2;
		};

	protected:
		///Image data
		struct DdsLoadInfo
		{
			bool compressed;
			bool swap;
			bool palette;
			unsigned int divSize;
			unsigned int blockBytes;		///< Number of bytes per block for a compressed texture, number of bytes per pixel for a common texture, or 1 for a pallete
			GLenum internalFormat;
			GLenum externalFormat;
			GLenum type;
			DDS_header header;
			unsigned long dataSize;
			unsigned char * data;

			///Constructor
			DdsLoadInfo() : compressed(false), swap(false), palette(false), divSize(0), blockBytes(0), dataSize(0), data((unsigned char *)NULL) {}
			///Destructor
			~DdsLoadInfo()
			{
				SAFE_DELETE_ARR(data);
			}
		} image;

		bool ParseHeader(wxString fname);

#ifndef VRUT_HPC
		///build and bind OpenGL one face of the texture from image in CURRENT OpenGL context
		///\return OpenGL ID for texture, \c GL_ID_NONE if failed
		bool BuildOglTextureFace(int imageTarget, unsigned size, unsigned &offset) const;
#endif
	public:
		///Class constructor
		ImageDDS();
		///Copy constructor
		ImageDDS(const ImageDDS &_image);
		///Class constructor
		ImageDDS(DDS_header *header, unsigned long dataSize, void *data, bool cube = false);
		///Class destructor
		virtual ~ImageDDS();

		///Is image properly loaded? - \c Image overload
		virtual bool IsOk() const override;
		///Load image data from file - \c Image overload
		virtual bool Load(const wxString & fname, int cubeSide=-1, int flip=0) override;
#ifndef VRUT_HPC
		///Updates tex_object texture from image in CURRENT OpenGL context. - \c Image overload
		virtual void UpdateOglTexture(GLuint tex_object, const TEXTURE_SAMPLER_TYPE buildAsType, bool create_mipmaps) const override;
#endif
		///Get \c true if image has alpha channel - \c Image overload
		virtual bool SetTransparencyAndSetAlphaUsage(bool testPixels=true) override;
		///Get the widht of the image
		virtual int GetWidth() const override;
		///Get the height of the image
		virtual int GetHeight() const override;

		const DdsLoadInfo &GetImage() const
		{
			return image;
		}
		///Save the image to file
		virtual bool Save(wxString filename) const override;
	};
}

#endif
