//header file to load .dds files
//these use dxtc texture compression

#ifndef __DDS_H
#define __DDS_H

#include "globalincs/pstypes.h"
#include "cfile/cfile.h"


#define DDS_ERROR_NONE					0		// everything went fine
#define DDS_ERROR_INVALID_FILENAME		1		// bad or missing file
#define DDS_ERROR_UNSUPPORTED			2		// a known format but one we don't support
#define DDS_ERROR_INVALID_FORMAT		3		// format that's not supported
#define DDS_ERROR_BAD_HEADER			4		// header was not "DDS "
#define DDS_ERROR_NO_COMPRESSION		5		// file is compressed, compression isn't supported
#define DDS_ERROR_NON_POWER_OF_2		6		// file is not a power of 2 in dimensions
#define DDS_ERROR_CUBEMAP_FACES			7		// file is a cubemap, but doesn't have all six faces


#define DDS_DXT_INVALID                -1
#define DDS_UNCOMPRESSED				0
#define DDS_DXT1						1
#define DDS_DXT3						3
#define DDS_DXT5						5
#define DDS_BC7							7
#define DDS_CUBEMAP_UNCOMPRESSED		10
#define DDS_CUBEMAP_DXT1				11
#define DDS_CUBEMAP_DXT3				13
#define DDS_CUBEMAP_DXT5				15

#ifndef MAKEFOURCC
	#define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
				((uint)(ubyte)(ch0) | ((uint)(ubyte)(ch1) << 8) |   \
				((uint)(ubyte)(ch2) << 16) | ((uint)(ubyte)(ch3) << 24 ))
#endif //defined(MAKEFOURCC)

// FOURCC codes for DX compressed-texture pixel formats
#define FOURCC_DXT1  (MAKEFOURCC('D','X','T','1'))
#define FOURCC_DXT2  (MAKEFOURCC('D','X','T','2'))
#define FOURCC_DXT3  (MAKEFOURCC('D','X','T','3'))
#define FOURCC_DXT4  (MAKEFOURCC('D','X','T','4'))
#define FOURCC_DXT5  (MAKEFOURCC('D','X','T','5'))
#define FOURCC_DX10  (MAKEFOURCC('D','X','1','0'))

#define DDS_FILECODE	0x20534444	// "DDS " in file

// DDS format stuff ...
#define DDSD_LINEARSIZE			0x00080000
#define DDSD_PITCH				0x00000008
#define DDPF_ALPHAPIXELS		0x00000001
#define DDPF_FOURCC				0x00000004
#define DDPF_PALETTEINDEXED4	0x00000008
#define DDPF_PALETTEINDEXEDTO8	0x00000010
#define DDPF_PALETTEINDEXED8	0x00000020
#define DDPF_RGB				0x00000040
#define DDSD_PIXELFORMAT		0x00001000
#define DDSD_WIDTH				0x00000004
#define DDSD_HEIGHT				0x00000002
#define DDSD_CAPS				0x00000001
#define DDSD_MIPMAPCOUNT		0x00020000
#define DDSD_DEPTH				0x00800000

#define DDSCAPS_COMPLEX			0x00000008
#define DDSCAPS_PRIMARYSURFACE	0x00000200
#define DDSCAPS_MIPMAP			0x00400000
#define DDSCAPS_TEXTURE			0x00001000

#define DDSCAPS2_CUBEMAP				0x00000200
#define DDSCAPS2_VOLUME					0x00200000
#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_CUBEMAP_ALLFACES	( DDSCAPS2_CUBEMAP_POSITIVEX |	\
									  DDSCAPS2_CUBEMAP_NEGATIVEX |	\
									  DDSCAPS2_CUBEMAP_POSITIVEY |	\
									  DDSCAPS2_CUBEMAP_NEGATIVEY |	\
									  DDSCAPS2_CUBEMAP_POSITIVEZ |	\
									  DDSCAPS2_CUBEMAP_NEGATIVEZ )

#pragma pack(1)
enum class DXGI_FORMAT : uint {
	DXGI_FORMAT_UNKNOWN,
	DXGI_FORMAT_R32G32B32A32_TYPELESS,
	DXGI_FORMAT_R32G32B32A32_FLOAT,
	DXGI_FORMAT_R32G32B32A32_UINT,
	DXGI_FORMAT_R32G32B32A32_SINT,
	DXGI_FORMAT_R32G32B32_TYPELESS,
	DXGI_FORMAT_R32G32B32_FLOAT,
	DXGI_FORMAT_R32G32B32_UINT,
	DXGI_FORMAT_R32G32B32_SINT,
	DXGI_FORMAT_R16G16B16A16_TYPELESS,
	DXGI_FORMAT_R16G16B16A16_FLOAT,
	DXGI_FORMAT_R16G16B16A16_UNORM,
	DXGI_FORMAT_R16G16B16A16_UINT,
	DXGI_FORMAT_R16G16B16A16_SNORM,
	DXGI_FORMAT_R16G16B16A16_SINT,
	DXGI_FORMAT_R32G32_TYPELESS,
	DXGI_FORMAT_R32G32_FLOAT,
	DXGI_FORMAT_R32G32_UINT,
	DXGI_FORMAT_R32G32_SINT,
	DXGI_FORMAT_R32G8X24_TYPELESS,
	DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
	DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
	DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,
	DXGI_FORMAT_R10G10B10A2_TYPELESS,
	DXGI_FORMAT_R10G10B10A2_UNORM,
	DXGI_FORMAT_R10G10B10A2_UINT,
	DXGI_FORMAT_R11G11B10_FLOAT,
	DXGI_FORMAT_R8G8B8A8_TYPELESS,
	DXGI_FORMAT_R8G8B8A8_UNORM,
	DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
	DXGI_FORMAT_R8G8B8A8_UINT,
	DXGI_FORMAT_R8G8B8A8_SNORM,
	DXGI_FORMAT_R8G8B8A8_SINT,
	DXGI_FORMAT_R16G16_TYPELESS,
	DXGI_FORMAT_R16G16_FLOAT,
	DXGI_FORMAT_R16G16_UNORM,
	DXGI_FORMAT_R16G16_UINT,
	DXGI_FORMAT_R16G16_SNORM,
	DXGI_FORMAT_R16G16_SINT,
	DXGI_FORMAT_R32_TYPELESS,
	DXGI_FORMAT_D32_FLOAT,
	DXGI_FORMAT_R32_FLOAT,
	DXGI_FORMAT_R32_UINT,
	DXGI_FORMAT_R32_SINT,
	DXGI_FORMAT_R24G8_TYPELESS,
	DXGI_FORMAT_D24_UNORM_S8_UINT,
	DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
	DXGI_FORMAT_X24_TYPELESS_G8_UINT,
	DXGI_FORMAT_R8G8_TYPELESS,
	DXGI_FORMAT_R8G8_UNORM,
	DXGI_FORMAT_R8G8_UINT,
	DXGI_FORMAT_R8G8_SNORM,
	DXGI_FORMAT_R8G8_SINT,
	DXGI_FORMAT_R16_TYPELESS,
	DXGI_FORMAT_R16_FLOAT,
	DXGI_FORMAT_D16_UNORM,
	DXGI_FORMAT_R16_UNORM,
	DXGI_FORMAT_R16_UINT,
	DXGI_FORMAT_R16_SNORM,
	DXGI_FORMAT_R16_SINT,
	DXGI_FORMAT_R8_TYPELESS,
	DXGI_FORMAT_R8_UNORM,
	DXGI_FORMAT_R8_UINT,
	DXGI_FORMAT_R8_SNORM,
	DXGI_FORMAT_R8_SINT,
	DXGI_FORMAT_A8_UNORM,
	DXGI_FORMAT_R1_UNORM,
	DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
	DXGI_FORMAT_R8G8_B8G8_UNORM,
	DXGI_FORMAT_G8R8_G8B8_UNORM,
	DXGI_FORMAT_BC1_TYPELESS,
	DXGI_FORMAT_BC1_UNORM,
	DXGI_FORMAT_BC1_UNORM_SRGB,
	DXGI_FORMAT_BC2_TYPELESS,
	DXGI_FORMAT_BC2_UNORM,
	DXGI_FORMAT_BC2_UNORM_SRGB,
	DXGI_FORMAT_BC3_TYPELESS,
	DXGI_FORMAT_BC3_UNORM,
	DXGI_FORMAT_BC3_UNORM_SRGB,
	DXGI_FORMAT_BC4_TYPELESS,
	DXGI_FORMAT_BC4_UNORM,
	DXGI_FORMAT_BC4_SNORM,
	DXGI_FORMAT_BC5_TYPELESS,
	DXGI_FORMAT_BC5_UNORM,
	DXGI_FORMAT_BC5_SNORM,
	DXGI_FORMAT_B5G6R5_UNORM,
	DXGI_FORMAT_B5G5R5A1_UNORM,
	DXGI_FORMAT_B8G8R8A8_UNORM,
	DXGI_FORMAT_B8G8R8X8_UNORM,
	DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,
	DXGI_FORMAT_B8G8R8A8_TYPELESS,
	DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
	DXGI_FORMAT_B8G8R8X8_TYPELESS,
	DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,
	DXGI_FORMAT_BC6H_TYPELESS,
	DXGI_FORMAT_BC6H_UF16,
	DXGI_FORMAT_BC6H_SF16,
	DXGI_FORMAT_BC7_TYPELESS,
	DXGI_FORMAT_BC7_UNORM,
	DXGI_FORMAT_BC7_UNORM_SRGB,
	DXGI_FORMAT_AYUV,
	DXGI_FORMAT_Y410,
	DXGI_FORMAT_Y416,
	DXGI_FORMAT_NV12,
	DXGI_FORMAT_P010,
	DXGI_FORMAT_P016,
	DXGI_FORMAT_420_OPAQUE,
	DXGI_FORMAT_YUY2,
	DXGI_FORMAT_Y210,
	DXGI_FORMAT_Y216,
	DXGI_FORMAT_NV11,
	DXGI_FORMAT_AI44,
	DXGI_FORMAT_IA44,
	DXGI_FORMAT_P8,
	DXGI_FORMAT_A8P8,
	DXGI_FORMAT_B4G4R4A4_UNORM,
	DXGI_FORMAT_P208,
	DXGI_FORMAT_V208,
	DXGI_FORMAT_V408,
	DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
	DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
	DXGI_FORMAT_FORCE_UINT
};

/* Potentially useful for later stuff - (DahBlount)
typedef enum D3D10_RESOURCE_MISC_FLAG : uint {
	D3D10_RESOURCE_MISC_GENERATE_MIPS,
	D3D10_RESOURCE_MISC_SHARED,
	D3D10_RESOURCE_MISC_TEXTURECUBE,
	D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX,
	D3D10_RESOURCE_MISC_GDI_COMPATIBLE
};
*/

enum class D3D10_RESOURCE_DIMENSION : uint {
	D3D10_RESOURCE_DIMENSION_UNKNOWN,
	D3D10_RESOURCE_DIMENSION_BUFFER,
	D3D10_RESOURCE_DIMENSION_TEXTURE1D,
	D3D10_RESOURCE_DIMENSION_TEXTURE2D,
	D3D10_RESOURCE_DIMENSION_TEXTURE3D
};

/* This is set in shaders for the most part - (DahBlount)
typedef enum DDS_ALPHA_MODE : uint {
	DDS_ALPHA_MODE_UNKNOWN,
	DDS_ALPHA_MODE_STRAIGHT,
	DDS_ALPHA_MODE_PREMULTIPLIED,
	DDS_ALPHA_MODE_OPAQUE,
	DDS_ALPHA_MODE_CUSTOM
};
*/

typedef struct {
	uint           dwSize;
	uint           dwFlags;
	uint           dwHeight;
	uint           dwWidth;
	uint           dwPitchOrLinearSize;
	uint           dwDepth;
	uint           dwMipMapCount;
	uint           dwReserved1[11];

	struct {
		uint dwSize;
		uint dwFlags;
		uint dwFourCC;
		uint dwRGBBitCount;
		uint dwRBitMask;
		uint dwGBitMask;
		uint dwBBitMask;
		uint dwABitMask;
	} ddspf;

	uint           dwCaps;
	uint           dwCaps2;
	uint           dwCaps3;
	uint           dwCaps4;
	uint           dwReserved2;
} DDS_HEADER;

typedef struct {
	DXGI_FORMAT              dxgiFormat;
	D3D10_RESOURCE_DIMENSION resourceDimension;
	uint                     miscFlag;
	uint                     arraySize;
	uint                     miscFlags2;
} DDS_HEADER_DXT10;
#pragma pack()

#define DDS_OFFSET						4+sizeof(DDS_HEADER)		//place where the data starts -- should be 128
#define DX10_OFFSET						DDS_OFFSET+sizeof(DDS_HEADER_DXT10)		// Unless a DX10 header is present

//reads a dds header
//returns one of the error values
//'compression_type' comes back as one of the DDS_DXTC* defines
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0);

//reads bitmap
//size of the data it stored in size
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp = NULL, int cf_type = CF_TYPE_ANY);

// writes a DDS file using given data
void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data = NULL, int cubemap = 0, const char *filename = NULL);

//returns a string from a DDS error code
const char *dds_error_string(int code);

#endif //__DDS_H
