// DDSImage.cpp: implementation of the CDDSImage class.
//
//////////////////////////////////////////////////////////////////////

#include "DDSImage.h"

#include "FileStream.h"

/* needed for DirectX's DDSURFACEDESC2 structure definition */
#include <ddraw.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDDSImage::CDDSImage()
{
	m_pszClassName = "CDDSImage";
}

CDDSImage::~CDDSImage()
{

}

static const DWORD DDS_HEADER = MAKEFOURCC('D', 'D', 'S', ' ');
static const DWORD DDS_DXT1 = MAKEFOURCC('D','X', 'T', '1');
static const DWORD DDS_DXT2 = MAKEFOURCC('D','X', 'T', '2');
static const DWORD DDS_DXT3 = MAKEFOURCC('D','X', 'T', '3');
static const DWORD DDS_DXT4 = MAKEFOURCC('D','X', 'T', '4');
static const DWORD DDS_DXT5 = MAKEFOURCC('D','X', 'T', '5');
static const DWORD DDS_DXT_ = MAKEFOURCC('D','X', 'T', '\0');

bool CDDSImage::Load(LPSTR lpszFileName)
{
	CFileStream stream;
	if (!stream.Open(lpszFileName, CFileStream::READONLY))
		return false;

	DWORD dwFileHeader;
	stream.Read(&dwFileHeader, sizeof(DWORD), 1);
	if (dwFileHeader != DDS_HEADER)
		return false;

	DDSURFACEDESC2 ddsd;
	stream.Read(&ddsd, sizeof(DDSURFACEDESC2), 1);

	// 8bit PAL
	if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
		return false;

	if (ddsd.ddpfPixelFormat.dwRGBBitCount == 24 && ddsd.ddpfPixelFormat.dwRGBBitCount == 32)
		return false;

	if (ddsd.ddpfPixelFormat.dwFourCC == DDS_DXT2 || ddsd.ddpfPixelFormat.dwFourCC == DDS_DXT4)
		return false;

	// non-mipmapped
	if (ddsd.dwMipMapCount)
		return false;

	///////////////////////////////////////////////////////////////////////////
	m_dwWidth  = ddsd.dwWidth;
	m_dwHeight = ddsd.dwHeight;

	// Compressed, possible-mipmaps no-alpha
	if (ddsd.ddpfPixelFormat.dwFourCC & DDS_DXT_)
	{
		switch (ddsd.ddpfPixelFormat.dwFourCC)
		{
		case DDS_DXT1:
			m_format = FMT_DXT1;
			break;
		case DDS_DXT3:
			m_format = FMT_DXT3;
			break;
		case DDS_DXT5:
			m_format = FMT_DXT5;
			break;
		}
	
		// Calc Compressed size
		DWORD dwBlockSize = (m_format == FMT_DXT1) ? 8 : 16;
		m_dwBufferLength = ((m_dwWidth + 3) / 4) * ((m_dwHeight + 3) / 4) * dwBlockSize;

		///////////////////////////////////////////////////////////////////////
		m_pBuffer = new BYTE [m_dwBufferLength];
		if (!m_pBuffer)
			return false;

		stream.Read(m_pBuffer, m_dwBufferLength, sizeof(BYTE));

		m_bCompressed = true;
	}
	else
	{
		switch (ddsd.ddpfPixelFormat.dwRGBBitCount)
		{
		case 24:
			m_format = FMT_RGB;
			break;
		case 32:
			m_format = FMT_RGBA;
			break;
		}

		m_dwBufferLength = ddsd.dwWidth * ddsd.dwHeight * (ddsd.ddpfPixelFormat.dwRGBBitCount >> 3);
		m_pBuffer = new BYTE [m_dwBufferLength];
		if (!m_pBuffer)
			return false;

		stream.Read(m_pBuffer, m_dwBufferLength, sizeof(BYTE));

		// reverse BGRA->RGBA
		int nCount = m_dwWidth * m_dwHeight;
		LPBYTE pBuffer = m_pBuffer;
		for (int i = 0; i < nCount; i ++)
		{
			BYTE temp      = *(pBuffer + 2);
			*(pBuffer + 2) = *pBuffer;
			*pBuffer       = temp;

			switch (ddsd.ddpfPixelFormat.dwRGBBitCount)
			{
				case 24:
					pBuffer += 3;
					break;
				
				case 32:
					pBuffer += 4;
					break;
			}
		}
	}

	return true;
}

