#include "xentax.h"

BOOL CreateUncompressedDDSHeader(DWORD dx, DWORD dy, DWORD mipmaps, DWORD maskR, DWORD maskG, DWORD maskB, DWORD maskA, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set pitch
 DWORD bpp = 0;
 if(maskR) bpp += 8;
 if(maskG) bpp += 8;
 if(maskB) bpp += 8;
 if(maskA) bpp += 8;
 header->dwPitchOrLinearSize = (bpp*dx + 7)/8;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_RGB;
 if(maskA) header->ddspf.dwFlags |= DDPF_ALPHAPIXELS;
 header->ddspf.dwFourCC = 0;
 header->ddspf.dwRGBBitCount = bpp;
 header->ddspf.dwRBitMask = maskR;
 header->ddspf.dwGBitMask = maskG;
 header->ddspf.dwBBitMask = maskB;
 header->ddspf.dwABitMask = maskA;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

BOOL CreateDXT1Header(DWORD dx, DWORD dy, DWORD mipmaps, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LINEARSIZE | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set linear size
 DWORD blocksize = 8;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));
 header->dwPitchOrLinearSize = rows*cols*blocksize;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_FOURCC;
 header->ddspf.dwFourCC = 0x31545844;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

BOOL CreateDXT2Header(DWORD dx, DWORD dy, DWORD mipmaps, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LINEARSIZE | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));
 header->dwPitchOrLinearSize = rows*cols*blocksize;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_FOURCC;
 header->ddspf.dwFourCC = 0x32545844;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

BOOL CreateDXT3Header(DWORD dx, DWORD dy, DWORD mipmaps, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LINEARSIZE | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));
 header->dwPitchOrLinearSize = rows*cols*blocksize;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_FOURCC;
 header->ddspf.dwFourCC = 0x33545844;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

BOOL CreateDXT4Header(DWORD dx, DWORD dy, DWORD mipmaps, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LINEARSIZE | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));
 header->dwPitchOrLinearSize = rows*cols*blocksize;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_FOURCC;
 header->ddspf.dwFourCC = 0x34545844;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

BOOL CreateDXT5Header(DWORD dx, DWORD dy, DWORD mipmaps, BOOL cubemap, DDS_HEADER* header)
{
 // validate
 if(!header) return FALSE;
 if(dx == 0) return FALSE;
 if(dy == 0) return FALSE;

 // set header size
 header->dwSize = 124;

 // set flags
 header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LINEARSIZE | DDSD_PIXELFORMAT;
 if(mipmaps) header->dwFlags |= DDSD_MIPMAPCOUNT;

 // set dimensions
 header->dwHeight = dy;
 header->dwWidth  = dx;
 header->dwDepth  = 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));
 header->dwPitchOrLinearSize = 0;//rows*cols*blocksize;

 // set mipmap count
 header->dwMipMapCount = mipmaps;

 // set reserved data
 header->dwReserved01 = 0;
 header->dwReserved02 = 0;
 header->dwReserved03 = 0;
 header->dwReserved04 = 0;
 header->dwReserved05 = 0;
 header->dwReserved06 = 0;
 header->dwReserved07 = 0;
 header->dwReserved08 = 0;
 header->dwReserved09 = 0;
 header->dwReserved10 = 0;
 header->dwReserved11 = 0;

 // set pixel format
 header->ddspf.dwSize = 32;
 header->ddspf.dwFlags = DDPF_FOURCC;
 header->ddspf.dwFourCC = 0x35545844;

 // set capabilities
 DWORD DDS_CUBEMAP_ALLFACES = 0xFC00;
 header->dwCaps1 = DDSCAPS_TEXTURE;
 if(mipmaps) header->dwCaps1 |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 header->dwCaps2 = 0;
 if(mipmaps) header->dwCaps2 |= (DDSCAPS2_CUBEMAP | DDS_CUBEMAP_ALLFACES);
 header->dwCaps3 = 0;
 header->dwCaps4 = 0;
 header->dwReserved12 = 0;

 return TRUE;
}

DWORD UncompressedDDSFileSize(DWORD dx, DWORD dy, DWORD mipmaps, DWORD maskR, DWORD maskG, DWORD maskB, DWORD maskA)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // compute filesize
 DWORD bpp = 0;
 if(maskR) bpp += 8;
 if(maskG) bpp += 8;
 if(maskB) bpp += 8;
 if(maskA) bpp += 8;

 // TODO: handle mipmaps
 return ((bpp*dx + 7)/8)*dy;
}

DWORD DXT1Filesize(DWORD dx, DWORD dy, DWORD mipmaps)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // set linear size
 DWORD blocksize = 8;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));

 // TODO: handle mipmaps
 return rows*cols*blocksize;
}

DWORD DXT2Filesize(DWORD dx, DWORD dy, DWORD mipmaps)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));

 // TODO: handle mipmaps
 return rows*cols*blocksize;
}

DWORD DXT3Filesize(DWORD dx, DWORD dy, DWORD mipmaps)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));

 // TODO: handle mipmaps
 return rows*cols*blocksize;
}

DWORD DXT4Filesize(DWORD dx, DWORD dy, DWORD mipmaps)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));

 // TODO: handle mipmaps
 return rows*cols*blocksize;
}

DWORD DXT5Filesize(DWORD dx, DWORD dy, DWORD mipmaps)
{
 // validate
 if(dx == 0) return 0;
 if(dy == 0) return 0;

 // set linear size
 DWORD blocksize = 16;
 DWORD rows = std::max((DWORD)1, (DWORD)((dy + 3)/4));
 DWORD cols = std::max((DWORD)1, (DWORD)((dx + 3)/4));

 // TODO: handle mipmaps
 return rows*cols*blocksize;
}
