// Texture.cpp: implementation of the CTexture class.
//
//////////////////////////////////////////////////////////////////////

#include "Texture.h"

#include <gl/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include <gl\glaux.h>
#pragma comment( lib, "glaux.lib" ) // incluye el glaux.lib en la vinculacion
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTexture::CTexture()
{
	m_bCreated = false;
}

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


// Carga BITMAP
AUX_RGBImageRec* CTexture::LoadBMP(const char *Filename)
{
	FILE *File=NULL;	// Handle del fichero
	if (!Filename)		// Nos aseguramos que 
	{
		// Devuelve NULL
		return NULL;
	}

	// Comprobamos que el fichero existe
	File=fopen(Filename,"r");				
	if (File)								
	{
		fclose(File); // Cerramos el fichero
		return auxDIBImageLoad(Filename); // Cargamos el bitmap y devolvemos el puntero
	}

	// No existe el fichero
	return NULL;
}

// Carga la textura de tres componentes RGB
bool CTexture::Create( const char *filename )
{
	assert (m_bCreated == false && "Textura ya creada, debe llamar a Destroy para reutilizar la textura");

	AUX_RGBImageRec *pImage; // Estructura de memoria para cargar la imagen
									
	pImage = LoadBMP( filename ); // Trata de cargar la imagen

	// Comprobamos que se ha cargado bien la imagen
	if ( pImage != NULL && pImage->data != NULL )
	{
		// Creamos y Seleccionamos el objeto textura
		glGenTextures(1, &m_nID);	
		glBindTexture(GL_TEXTURE_2D, m_nID);

		// Asignamos la textura al objeto textura
		glTexImage2D(GL_TEXTURE_2D, 0, 3, pImage->sizeX, pImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);

		// Seleccionamos el modo de filtrado
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

		// Liberamos la memoria
		free(pImage->data);
		free(pImage);	

		// Se ha creado con exito
		m_bCreated = true;
		m_bAlpha = false;
	}

	// Devolvemos true si se ha creado
	return m_bCreated;
}

// Carga la textura de cuatro componentes RGBA a partir de dos ficheros
bool CTexture::Create( const char *filenameRGB, const char *filenameAlpha )
{
	assert (m_bCreated == false && "Textura ya creada, debe llamar a Destroy para reutilizar la textura");

	AUX_RGBImageRec *pImageRGB;
	AUX_RGBImageRec *pImageA;
	unsigned char *rgba;

	GLint i,j;
	GLint irgba=0, irgb=0, ia=0;
	
	// Carga el fichero RGB
	pImageRGB = LoadBMP( filenameRGB );								

	// Comprobamos que se ha cargado
	if ( pImageRGB != NULL && pImageRGB->data != NULL )
	{
		// Carga el fichero Alpha
		pImageA = LoadBMP( filenameAlpha );

		// Comprobamos que se ha cargado
		if ( pImageA != NULL && pImageA->data != NULL )
		{
			assert (pImageRGB->sizeY == pImageA->sizeY && pImageRGB->sizeX == pImageA->sizeX && "El tamaņo de las dos imagenes debe ser el mismo");
			// Reservamos memoria
			rgba = new unsigned char[4*pImageRGB->sizeX*pImageRGB->sizeY];

			// Creamos y Seleccionamos el objeto textura
			glGenTextures(1, &m_nID);	
			glBindTexture(GL_TEXTURE_2D, m_nID);

			// Mezclamos los dos BMP
			// fichero RGB: RGB RGB RGB ......
			// fichero Alpha: AAA AAA AAA .....
			// resultado: RGBA RGBA RGBA ......
			irgba=0;
			irgb=0;
			ia=0;
			for(i=0;i<pImageRGB->sizeX;i++){
				for(j=0;j<pImageRGB->sizeY;j++){
					// Obtenemos R del fichero RGB
					rgba[irgba++]=pImageRGB->data[irgb++];
					// Obtenemos G del fichero RGB
					rgba[irgba++]=pImageRGB->data[irgb++];
					// Obtenemos B del fichero RGB
					rgba[irgba++]=pImageRGB->data[irgb++];
					// Obtenemos A del fichero Alpha
					rgba[irgba++] = (pImageA->data[ia++] + pImageA->data[ia++] + pImageA->data[ia++]) / 3;
				}
			}
			// Asignamos la textura al objeto textura
			glTexImage2D(GL_TEXTURE_2D, 0, 4, pImageRGB->sizeX, pImageRGB->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
		
			// Seleccionamos el modo de filtrado
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

			// Liberamos la memoria que hemos utilizado para formar RGBA
			delete rgba;
			// Liberamos la memoria de Alpha
			free(pImageA->data);
			free(pImageA);	

			// Se ha creado con exito
			m_bCreated = true;
			m_bAlpha = true;
		}
		// Liberamos la memoria de RGB
		free(pImageRGB->data);
		free(pImageRGB);	
	}

	// Devolvemos true si se ha creado
	return m_bCreated;
}

void CTexture::Destroy()
{
	if (m_bCreated)
	{
		// Libera el objeto textura
		glDeleteTextures(1, &m_nID);	
	}
	m_bCreated = false;
}

void CTexture::Enable()
{
	assert (m_bCreated && "Textura no creada");

	// Habilita texturizacion
	glEnable(GL_TEXTURE_2D);
	if (m_bAlpha)
	{
		// Si es una textura RGBA, habilita blending y selecciona la operacion
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	}
	// Mezcla el color del poligono con la textura
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

	// Seleccionamos la textura
	glBindTexture(GL_TEXTURE_2D, m_nID);
}

void CTexture::Disable()
{
	assert (m_bCreated && "Textura no creada");

	// Deshabilita la texturizacion
	glDisable(GL_TEXTURE_2D);
	if (m_bAlpha)
		// Si es RGBA deshabilita bliending
		glDisable(GL_BLEND);
}
