#include <math.h>
#include "pvr.h"
#include "rspix.h"

// todo missing from dreamsdk include folder?
#include <kmg/kmg.h>

/// <summary>
/// Constructor
/// </summary>
PVR::cTextureTile::cTextureTile(cKmgImg *pPvrKosImg, bool isAlpha)
{	
	kos_img_t *pKimg = &pPvrKosImg->m_KosImg;
	m_pPvrTexture = pvr_mem_malloc(pKimg->byte_count);
			
	pvr_txr_load_kimg(&pPvrKosImg->m_KosImg, m_pPvrTexture, PVR_TXRLOAD_16BPP | PVR_TXRLOAD_FMT_VQ | PVR_TXRLOAD_FMT_TWIDDLED);
	
	m_szImageWidth = pKimg->w;
	m_szImageHeight = pKimg->h;
	m_szTileWidth = pKimg->w;
	m_szTileHeight = pKimg->h;
	m_ucImageType = cTexture::RGB16;
	m_bIsVQ = true;

	m_bIsARGB4 = isAlpha;

	pvr_poly_cxt_txr(
		&cxtOP,
		PVR_LIST_OP_POLY,
		(isAlpha ? PVR_TXRFMT_ARGB4444 : PVR_TXRFMT_RGB565) | PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_TWIDDLED,
		m_szTileWidth,
		m_szTileHeight,
		m_pPvrTexture,
		PVR_FILTER_BILINEAR);

	cxtOP.txr.uv_clamp = PVR_UVCLAMP_UV;
	pvr_poly_compile(&hdrOP, &cxtOP);

	pvr_poly_cxt_txr(
		&cxtTR,
		PVR_LIST_TR_POLY,
		(isAlpha ? PVR_TXRFMT_ARGB4444 : PVR_TXRFMT_RGB565) | PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_TWIDDLED,
		m_szTileWidth,
		m_szTileHeight,
		m_pPvrTexture,
		PVR_FILTER_BILINEAR);

	cxtTR.txr.uv_clamp = PVR_UVCLAMP_UV;
	pvr_poly_compile(&hdrTR, &cxtTR);
	
}

/// <summary>
/// Constructor
/// </summary>
PVR::cTextureTile::cTextureTile(RImage *pImage, uint8_t ucImageType, uint8_t ucPaletteNum) : PVR::cTextureTile(pImage->m_sWidth, pImage->m_sHeight, ucImageType, ucPaletteNum)
{
	m_ucPaletteNum = ucPaletteNum;
	PasteImage(pImage);
}

/// <summary>
/// Constructor
/// </summary>
PVR::cTextureTile::cTextureTile(uint16_t width, uint16_t height, uint8_t ucImageType, uint8_t ucPaletteNum)
{
	m_szImageWidth = width;
	m_szImageHeight = height;	
	m_szTileWidth = pow(2, ceil(log(width) / log(2)));
	m_szTileHeight = pow(2, ceil(log(height) / log(2)));

	m_ucPaletteNum = ucPaletteNum;
	m_ucImageType = ucImageType;

	// TODO - needed?...
	if (m_szTileWidth > MAX_TEX_DIMENSION)
	{
		m_szTileWidth = MAX_TEX_DIMENSION;
	}

	if (m_szTileWidth < MIN_TEX_DIMENSION)
	{
		m_szTileWidth = MIN_TEX_DIMENSION;
	}

	if (m_szTileHeight > MAX_TEX_DIMENSION)
	{
		m_szTileHeight = MAX_TEX_DIMENSION;
	}

	if (m_szTileHeight < MIN_TEX_DIMENSION)
	{
		m_szTileHeight = MIN_TEX_DIMENSION;
	}
}

/// <summary>
/// Destructor
/// </summary>
PVR::cTextureTile::~cTextureTile()
{
	if (m_pPvrTexture != nullptr)
	{
		pvr_mem_free(m_pPvrTexture);
		m_pPvrTexture = nullptr;
	}
}

/// <summary>
///
/// </summary>
void PVR::cTextureTile::PasteImage(RImage *image, int16_t sX, int16_t sY, uint8_t type)
{
	RImage *paddedTexture = new RImage();
	int16_t res = 0;
	res = paddedTexture->CreateImage(
		m_szTileWidth,
		m_szTileHeight,
		RImage::BMP8);

	uint8_t *dst;
	uint8_t *src;
	uint16_t size;

	if (image->m_sWidth > 8)
	{
		rspBlit(image,
				paddedTexture,
				0, 0,
				sX,
				sY,
				image->m_sWidth,
				image->m_sHeight);
	}
	else
	{
		uint8_t *data = image->m_pData;
		uint8_t *dst = paddedTexture->m_pData;
		int width = image->m_sWidth;
		int pitch = image->m_lPitch;

		if (pitch > m_szTileWidth)
		{
			m_szTileWidth = pitch;
		}

		for (int row = 0; row < image->m_sHeight; row++)
		{
			for (int col = 0; col < m_szTileWidth; col++)
			{
				if (col < pitch)
				{
					*dst = (uint8_t)(*data);
					data++;
				}
				dst++;
			}
		}
	}

	switch (type)
	{
	case PVR::cTexture::PAL4:
		size = (m_szTileWidth * m_szTileHeight) / 2;
		dst = (uint8_t *)malloc(size);
		src = paddedTexture->m_pData;

		for (uint16_t index = 0; index < size; index++)
		{
			dst[index] = ((*src & 0x0F) | ((*(src + 1) & 0x0F) << 4));
			src += 2;
		}

		m_pPvrTexture = pvr_mem_malloc(size);	
		pvr_txr_load_ex(dst, m_pPvrTexture, m_szTileWidth, m_szTileHeight, PVR_TXRLOAD_4BPP);
		delete dst;
		break;

	case PVR::cTexture::PAL8:
		if (res == 0)
		{			
			m_pPvrTexture = pvr_mem_malloc((m_szTileWidth * m_szTileHeight) * type);
			pvr_txr_load_ex(paddedTexture->m_pData, m_pPvrTexture, m_szTileWidth, m_szTileHeight, PVR_TXRLOAD_8BPP);
		}
		break;
	}
	
	delete paddedTexture;

	if (type == PVR::cTexture::RGB16)
	{
		pvr_poly_cxt_txr(
			&cxtTR,
			PVR_LIST_TR_POLY,
			(m_bIsARGB4 ? PVR_TXRFMT_ARGB4444 : PVR_TXRFMT_ARGB1555) | PVR_TXRFMT_NONTWIDDLED,
			m_szTileWidth,
			m_szTileHeight,
			m_pPvrTexture,
			PVR_FILTER_BILINEAR);
	}
	else
	{
		if (m_bIsVQ)
		{
			pvr_poly_cxt_txr(
				&cxtTR,
				PVR_LIST_TR_POLY,
				(m_bIsARGB4 ? PVR_TXRFMT_ARGB4444 : PVR_TXRFMT_RGB565) | PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_TWIDDLED,
				m_szTileWidth,
				m_szTileHeight,
				m_pPvrTexture,
				PVR_FILTER_BILINEAR);
		}
		else
		{
			pvr_poly_cxt_txr(
				&cxtTR,
				PVR_LIST_TR_POLY,
				(type == PVR::cTexture::PAL4 ? PVR_TXRFMT_PAL4BPP : PVR_TXRFMT_PAL8BPP) | PVR_TXRFMT_8BPP_PAL(m_ucPaletteNum),
				m_szTileWidth,
				m_szTileHeight,
				m_pPvrTexture, PVR_FILTER_BILINEAR);

			pvr_poly_cxt_txr(
				&cxtOP,
				PVR_LIST_OP_POLY,
				(type == PVR::cTexture::PAL4 ? PVR_TXRFMT_PAL4BPP : PVR_TXRFMT_PAL8BPP) | PVR_TXRFMT_8BPP_PAL(m_ucPaletteNum),
				m_szTileWidth,
				m_szTileHeight,
				m_pPvrTexture,
				PVR_FILTER_BILINEAR);		
		}
	}

	cxtOP.txr.uv_clamp = PVR_UVCLAMP_UV;
	cxtTR.txr.uv_clamp = PVR_UVCLAMP_UV;
	pvr_poly_compile(&hdrTR, &cxtTR);
	pvr_poly_compile(&hdrOP, &cxtOP);
}
