#include "CTgaImg.h"

CTgaImg::CTgaImg()
{

}
	
CTgaImg::~CTgaImg()
{
	delete[] m_ImgData;	
	delete[] m_GrayScaleData;
}

int CTgaImg::loadTGAImg( const char* filename)
{
	
	FILE *file;
	int mode,total;

	// open the file for reading (binary mode)
	file = fopen(filename, "rb");
	if (file == NULL) 
	{
		m_status = TGA_ERROR_FILE_OPEN;
		return m_status;
	}

	// load the header
	tgaLoadHeader(file);

	// check for errors when loading the header
	if (ferror(file)) 
	{
		m_status = TGA_ERROR_READING_FILE;
		fclose(file);
		return m_status;
	}

	// check if the image is color indexed
	if (m_ImgType == 1) 
	{
		m_status = TGA_ERROR_INDEXED_COLOR;
		fclose(file);
		return m_status;
	}
	
	// check for other types (compressed images)
	if ((m_ImgType != 2) && (m_ImgType != 3)) 
	{
		m_status = TGA_ERROR_COMPRESSED_FILE;
		fclose(file);
		return m_status;
	}

	// mode equals the number of image components
	mode = m_ImgPixelDepth / 8;
	// total is the number of bytes to read
	total = m_ImgHeight * m_ImgWidth * mode;
	// allocate memory for image pixels 
	m_ImgData = new unsigned char [( total*sizeof(unsigned char) )];
	// allocate memory for the grayscale data
	m_GrayScaleData = new unsigned char[ ((m_ImgHeight*m_ImgWidth)*sizeof(unsigned char)) ];
												
	// finally load the image pixels
	tgaLoadImageData(file);

	// check for errors when reading the pixels
	if (ferror(file)) 
	{
		m_status = TGA_ERROR_READING_FILE;
		fclose(file);
		return m_status;
	}

	// if the file is of type RGB or A , the just convert it into grayscale
	if(m_ImgPixelDepth == 24 || m_ImgPixelDepth == 32)
	{
		tgaRGBtoGreyscale();
	}
	else
	{
		for(int i=0; i<m_ImgHeight*m_ImgWidth; i++)
			m_GrayScaleData[i] = m_ImgData[i];
	}

	// if all goes well close the file pointer and return 0
	fclose(file);
	m_status = TGA_OK;
	return m_status;
}

// access methods
unsigned char CTgaImg::getImgType()
{
	return m_ImgType; 
}

unsigned char CTgaImg::getImgPixelDepth()
{
	return m_ImgPixelDepth;
}

int CTgaImg::getImgWidth()
{
	return m_ImgWidth;
}

int CTgaImg::getImgHeight()
{
	return m_ImgHeight;
}

unsigned char* CTgaImg::getImgPixelData()
{
	return m_ImgData;
}

unsigned char* CTgaImg::getGrayScaleData()
{
	return m_GrayScaleData;
}

// private functions , to read the header and pixel data of the given file

void CTgaImg::tgaLoadHeader(FILE* file) 
{
	unsigned char		cGarbage        = 3;
	short int			iGarbage		= 1;
	unsigned char		chartransfer	= 1;
	int					inttransfer		= 0;

	fread(&cGarbage, sizeof(unsigned char), 1, file);
	fread(&cGarbage, sizeof(unsigned char), 1, file);

// type must be 2 or 3
	fread(&chartransfer, sizeof(unsigned char), 1, file);
	m_ImgType = chartransfer;

	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&cGarbage, sizeof(unsigned char), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);
	fread(&iGarbage, sizeof(short int), 1, file);

	fread(&inttransfer, sizeof(short int), 1, file);
	m_ImgWidth = inttransfer;
	fread(&inttransfer, sizeof(short int), 1, file);
	m_ImgHeight = inttransfer;
	fread(&chartransfer, sizeof(unsigned char), 1, file);
	m_ImgPixelDepth = chartransfer;

	fread(&cGarbage, sizeof(unsigned char), 1, file);
}

void CTgaImg::tgaLoadImageData(FILE* file) 
{
	int mode,total,i;
	unsigned char aux = 3;

// mode equal the number of components for each pixel
	mode = m_ImgPixelDepth / 8;
// total is the number of bytes we'll have to read
	total = m_ImgHeight * m_ImgWidth * mode;
	
	fread(m_ImgData,sizeof(unsigned char),total,file);

// mode=3 or 4 implies that the image is RGB(A). However TGA
// stores it as BGR(A) so we'll have to swap R and B.
	if (mode >= 3)
	{
		for (i=0; i < total; i+= mode) 
		{
			aux = m_ImgData[i];
			m_ImgData[i] = m_ImgData[i+2];
			m_ImgData[i+2] = aux;
		}
	}
}

void CTgaImg::tgaRGBtoGreyscale() 
{

	int mode,i,j;
// compute the number of actual components
	mode = m_ImgPixelDepth / 8;

// allocate an array for the new image data
	int total = 0;
	total = m_ImgHeight * m_ImgWidth;

// convert pixels: greyscale = 0.30 * R + 0.59 * G + 0.11 * B
	for (i = 0,j = 0; j < m_ImgWidth * m_ImgHeight; i +=mode, j++)
		m_GrayScaleData[j] =	(unsigned char)(0.30 * m_ImgData[i]   + 
												0.59 * m_ImgData[i+1] +
												0.11 * m_ImgData[i+2]);
}








