// Image.cpp: implementation of the CImage class.
//
//////////////////////////////////////////////////////////////////////

#include "Image.h"

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

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

CImage::CImage()
{
	m_pszClassName = "CImage";

	///////////////////////////////////////////////////////////////////////////
	m_pBuffer = NULL;
	m_pPalBuffer = NULL;

	m_bCompressed = false;
}

CImage::~CImage()
{
	Destroy();
}

void CImage::Destroy()
{
	if (m_pPalBuffer)
	{
		delete [] m_pPalBuffer;
		m_pPalBuffer = NULL;
	}

	if (m_pBuffer)
	{
		delete [] m_pBuffer;
		m_pBuffer = NULL;
	}

	CUnknown::Destroy();
}

bool CImage::Create(DWORD dwWidth, DWORD dwHeight, FORMAT format)
{
	DWORD dwBitsPerPel;
	switch (format)
	{
	case FMT_COLOR_INDEX:
	case FMT_LUMINANCE:
		dwBitsPerPel = 1;
		break;

	case FMT_RGB:
		dwBitsPerPel = 3;
		break;
	case FMT_RGBA:
		dwBitsPerPel = 4;
		break;
	}

	///////////////////////////////////////////////////////////////////////////
	m_dwWidth  = dwWidth;
	m_dwHeight = dwHeight;

	m_dwBufferLength = dwWidth * dwHeight * dwBitsPerPel;
	m_pBuffer = new BYTE [m_dwBufferLength];
	if (!m_pBuffer)
		return false;

	return true;
}

bool CImage::Load(LPSTR lpszFileName)
{
	return false;
}

void CImage::Mirror()
{
	LONG lPitch;
	switch (m_format)
	{
	case FMT_COLOR_INDEX:
	case FMT_LUMINANCE:
		lPitch = m_dwWidth;
		break;
	case FMT_RGB:
		lPitch = m_dwWidth * 3;
		break;
	case FMT_RGBA:
		lPitch = m_dwWidth * 4;
		break;

	default:
		return;
	}

	///////////////////////////////////////////////////////////////////////////
	LPBYTE pBuffer = new BYTE [lPitch];
	if (!pBuffer)
		return;

	LPBYTE pUpBuffer     = m_pBuffer;
	LPBYTE pBottomBuffer = m_pBuffer + (m_dwHeight - 1) * lPitch;

	for (int i = 0; i < (int) m_dwHeight >> 1; i ++)
	{
		memcpy(pBuffer, pBottomBuffer, lPitch);
		memcpy(pBottomBuffer, pUpBuffer, lPitch);
		memcpy(pUpBuffer, pBuffer, lPitch);

		pBottomBuffer -= lPitch;
		pUpBuffer     += lPitch;
	}

	delete [] pBuffer;
}

void CImage::Flip()
{
	LONG lPitch;
	switch (m_format)
	{
	case FMT_COLOR_INDEX:
	case FMT_LUMINANCE:
		lPitch = m_dwWidth;
		break;
	case FMT_RGB:
		lPitch = m_dwWidth * 3;
		break;
	case FMT_RGBA:
		lPitch = m_dwWidth * 4;
		break;

	default:
		return;
	}

	///////////////////////////////////////////////////////////////////////////
	LPBYTE pBuffer = new BYTE [lPitch];
	if (!pBuffer)
		return;

	LPBYTE pUpBuffer     = m_pBuffer;
	LPBYTE pBottomBuffer = m_pBuffer + (m_dwHeight - 1) * lPitch;

	for (int i = 0; i < (int) m_dwHeight >> 1; i ++)
	{
		memcpy(pBuffer, pBottomBuffer, lPitch);
		memcpy(pBottomBuffer, pUpBuffer, lPitch);
		memcpy(pUpBuffer, pBuffer, lPitch);

		pBottomBuffer -= lPitch;
		pUpBuffer     += lPitch;
	}

	delete [] pBuffer;
}

bool CImage::CompressS3TC(FORMAT format)
{
#if 0
	if (m_bCompressed)
		return true;

	switch (m_format)
	{
	case FMT_COLOR_INDEX:
	case FMT_LUMINANCE:
		return false;
	}

	// Setup descIn
	DDSURFACEDESC descIn;
	ZeroMemory(&descIn, sizeof(DDSURFACEDESC));

	descIn.dwSize		= sizeof(DDSURFACEDESC);
	descIn.dwFlags		= DDSD_WIDTH | 
		                  DDSD_HEIGHT | 
						  DDSD_LPSURFACE | 
						  DDSD_PITCH | 
						  DDSD_PIXELFORMAT;
	descIn.dwWidth		= m_dwWidth;
	descIn.dwHeight		= m_dwHeight;
	descIn.lpSurface	= (LPVOID) m_pBuffer;

	if (m_format == FMT_RGBA)
		descIn.lPitch = m_dwWidth * 4;
	else
		descIn.lPitch = m_dwWidth * 3;

	descIn.ddpfPixelFormat.dwSize	  = sizeof(DDPIXELFORMAT);
	descIn.ddpfPixelFormat.dwRBitMask = 0x0000ff;
	descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
	descIn.ddpfPixelFormat.dwBBitMask = 0xff0000;
	
	if (m_format == FMT_RGBA)
	{
		descIn.ddpfPixelFormat.dwRGBBitCount = 32;
		descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
	}
	else
		descIn.ddpfPixelFormat.dwRGBBitCount = 24;
	
	descIn.ddpfPixelFormat.dwFlags = DDPF_RGB;
	if (m_format == FMT_RGBA)
		descIn.ddpfPixelFormat.dwFlags |= DDPF_ALPHAPIXELS;

	// Setup descOut
	DDSURFACEDESC descOut;
	ZeroMemory(&descOut, sizeof(DDSURFACEDESC));

	descOut.dwSize = sizeof(DDSURFACEDESC);
	

	DWORD dwEncodeType = S3TC_ENCODE_RGB_FULL;
	switch (format)
	{
	case FMT_DXT1:
		dwEncodeType |= S3TC_ENCODE_ALPHA_NONE;
		break;
	case FMT_DXT3:
		dwEncodeType |= S3TC_ENCODE_ALPHA_EXPLICIT;
		break;
	case FMT_DXT5:
		dwEncodeType |= S3TC_ENCODE_ALPHA_INTERPOLATED;
		break;
	}

	// Allocate memory for compressed texture
	m_dwCompressedSize = S3TCgetEncodeSize(&descIn, dwEncodeType);
	LPBYTE pCompressedBuffer = new unsigned char [m_dwCompressedSize];
	if (!pCompressedBuffer)
		return false;

	// Compress the texture
	float weight[3] = { 0.3086f, 0.6094f, 0.0820f };
	S3TCencode(&descIn, NULL, &descOut, pCompressedBuffer, dwEncodeType, weight);

	///////////////////////////////////////////////////////////////////////////
	m_format = format;
	m_bCompressed = true;

	delete [] m_pBuffer;
	m_pBuffer = pCompressedBuffer;
#endif

	return true;
}