/*
 * ExNihilo 3D Engine
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Please read AUTHORS file !!!
 * 
 * $Id: ExCTexture.cpp,v 1.17 2002/12/13 11:45:03 data Exp $
 *
 */

#include "ExCTexture.h"


ExCTexture::ExCTexture(void)
{
Guard(ExCTexture::ExCTexture(void))
	SetName("ExCTexture");
	SetType(typeid(this).name());
	m_Anisotropy_level=-1;
	m_Anisotropy=true;
	m_SGIS_Mimap=true;
	m_ARB_Texture_Compression=true;
UnGuard
}

ExCTexture::ExCTexture(std::string FileName)
{
Guard(ExCTexture::ExCTexture(std::string FileName))
	SetName("ExCTexture");
	SetType(typeid(this).name());
	LoadFile(FileName);
UnGuard
}

ExCTexture::~ExCTexture(void)
{
Guard(ExCTexture::~ExCTexture(void))
UnGuard
}

void ExCTexture::SetName(std::string	 Name)
{
Guard(void ExCTexture::SetName(std::string	 Name))
	if(Name.find(".")<Name.length())//if extension remove them
	{
		Name.erase(Name.find("."),Name.length()-Name.find("."));
		m_ObjectName=Name;
	}else
	{
		m_ObjectName=Name;
	}
UnGuard
}

void ExCTexture::SetActive(void)
{
Guard(ExCTexture::SetActive(void))
	
	glBindTexture(GL_TEXTURE_2D,m_Texture);
UnGuard
}


bool ExCTexture::SaveFile(std::string FileName,int width,int height)
{
	Guard(ExCTexture::SaveFile(std::string FileName,int width,int height))
	m_Image= new ExCImageLoader;
	return m_Image->SaveImage(FileName,width,height);
	delete m_Image;
	UnGuard
}

bool ExCTexture::LoadFile(std::string FileName)
{
Guard(ExCTexture::LoadFile(std::string FileName))
	//std::cout<<"Fichier:"<<FileName<<std::endl;
	m_ObjectFileName=FileName;
	m_Image= new ExCImageLoader;
	int Type = GL_RGB;
	int offset = 0;
	int size=0;
	int blockSize =0; 
	std::string		StrPath;
	SetName(FileName);
	#ifdef UNIX_SRC
		StrPath=PREFIX "/ExNihilo/Data/Textures/";
	#else
		StrPath="../Data/Textures/";
	#endif
	
	
		glCompressedTexImage3DARB		= (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)wglGetProcAddress("glCompressedTexImage3DARB");
		glCompressedTexImage2DARB		= (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)wglGetProcAddress("glCompressedTexImage2DARB");
		glCompressedTexImage1DARB	    = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)wglGetProcAddress("glCompressedTexImage1DARB");
		glCompressedTexSubImage3DARB	= (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)wglGetProcAddress("glCompressedTexSubImage3DARB");
		glCompressedTexSubImage2DARB	= (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)wglGetProcAddress("glCompressedTexSubImage2DARB");
		glCompressedTexSubImage1DARB	= (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)wglGetProcAddress("glCompressedTexSubImage1DARB");
		glGetCompressedTexImageARB		= (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)wglGetProcAddress("glGetCompressedTexImageARB");
	
	if(m_Image->LoadImage(StrPath+FileName))
	{
		SetName(FileName);
		glGenTextures(1,&m_Texture);
		glBindTexture(GL_TEXTURE_2D,m_Texture);
	
 		
		switch (m_Image->m_TextureType)
		{ 
		case BMP:
			//std::cout<<"Extension:BMP"<<std::endl;
			gluBuild2DMipmaps(GL_TEXTURE_2D, GL_COMPRESSED_RGB_ARB, m_Image->m_sizeX, m_Image->m_sizeY, 
				GL_RGB, GL_UNSIGNED_BYTE, m_Image->m_data);
			m_ARB_Texture_Compression=true;
			break;
		case PCX:
			//std::cout<<"Extension:PCX"<<std::endl;
			gluBuild2DMipmaps(GL_TEXTURE_2D, GL_COMPRESSED_RGBA_ARB, m_Image->m_sizeX,m_Image->m_sizeY,
				GL_RGBA, GL_UNSIGNED_BYTE, m_Image->m_data);
			break;
		case TGA:
			//std::cout<<"Extension:TGA"<<std::endl;
			 gluBuild2DMipmaps(GL_TEXTURE_2D, 
               (m_Image->m_channels == 4) ? GL_COMPRESSED_RGBA_ARB : GL_COMPRESSED_RGB_ARB, 
               m_Image->m_sizeX, m_Image->m_sizeY,
               Type, GL_UNSIGNED_BYTE, m_Image->m_data);
			 m_ARB_Texture_Compression=true;
			 break;
		case PPM:
			//std::cout<<"Extension:PPM"<<std::endl;
			gluBuild2DMipmaps(GL_TEXTURE_2D,GL_COMPRESSED_RGB_ARB, m_Image->m_sizeX, m_Image->m_sizeY,
				GL_RGB, GL_UNSIGNED_BYTE, m_Image->m_data);
            break;
		case DDS:
			//std::cout<<"Extension:DDS"<<std::endl;
			/* load the mipmaps */
			blockSize = (m_Image->m_ddsFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;//if not dxt1 blocksize = 16
			for (int i = 0; i < m_Image->m_ddsNumMipmaps&& (m_Image->m_sizeX || m_Image->m_sizeY); ++i)
			{
				
				if (m_Image->m_sizeX == 0)m_Image->m_sizeX = 1;
				if (m_Image->m_sizeY == 0)m_Image->m_sizeY = 1;
				size = ((m_Image->m_sizeX+3)/4)*((m_Image->m_sizeY+3)/4)*blockSize;
								
				glCompressedTexImage2DARB(GL_TEXTURE_2D, i, m_Image->m_ddsFormat, m_Image->m_sizeX, m_Image->m_sizeY, 
					0, size, m_Image->m_data );
				
				offset += size;
				m_Image->m_sizeX>>= 1;
				m_Image->m_sizeY >>= 1;
				m_ARB_Texture_Compression=false;
				//std::cout<<"Compression :"<<i<<" ";ExNihilo::ShowGlError();
			}
			break;
		default:
			break;
		}
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		//--------------------------------
		//MIMAP SGIS EXTENSION
		//--------------------------------
		if(m_SGIS_Mimap)
		{
			glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
			//std::cout<<"glHint m_SGIS_Mimap :"<<" ";ExNihilo::ShowGlError();
			glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, true);
			//std::cout<<"GL_GENERATE_MIPMAP_SGIS :"<<" ";ExNihilo::ShowGlError();
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
			//std::cout<<"GL_TEXTURE_MIN_FILTER :"<<" ";ExNihilo::ShowGlError();
		}else
		{
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
		}
		
		//std::cout<<"Tex ID :"<<m_Texture<<std::endl;

		
		//--------------------------------
		//ANISOTROPIC EXTENSION
		//--------------------------------
		if(m_Anisotropy)
		{
			glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&m_Anisotropy_level);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_Anisotropy_level);
			//std::cout<<"m_Anisotropy :"<<" ";ExNihilo::ShowGlError();
		}

		//--------------------------------
		//TEXTURE COMPRESSION EXTENSION
		//--------------------------------
		
		if(m_ARB_Texture_Compression)
		{ 

			int compressed_size;
			int num_compressed_format;
			int * compressed_format = NULL;
			int compressed;
			int internalformat;
			unsigned char * img = NULL;
			glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, &num_compressed_format);
			compressed_format = (int*)malloc(num_compressed_format * sizeof(int));
			glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS_ARB, compressed_format);

			// Check if the image has been compressed by GL
			glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &compressed);

			// Query for the compressed internal format 
			glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);

			// Query for the size of the compressed data texture buffer 
			//glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_IMAGE_SIZE_ARB, &compressed_size);
			glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &compressed_size);
				
			//std::cout<<"FileNAme:"<<FileName<<" Compressed: "<<compressed<<" Internal format: "<<internalformat<<" Compressed size: "<<compressed_size<<std::endl;
			// Allocate a buffer to host a copy of the compressed image data 
			img = (unsigned char *)malloc(compressed_size * sizeof(unsigned char));

			// get the compressed data buffer 
			glGetCompressedTexImageARB(GL_TEXTURE_2D, 0, img);
			//glBindTexture(GL_TEXTURE_2D,m_Texture);
			glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, internalformat, m_Image->m_sizeX, m_Image->m_sizeY, 0, compressed_size, img);

			delete img;
			delete compressed_format;
			//std::cout<<"m_ARB_Texture_Compression :"<<" ";ExNihilo::ShowGlError();
		}
		delete m_Image->m_data;
		//ExNihilo::ShowGlError();
		//std::cout<<"---------------------------------------------------------------"<<std::endl;
		return true;
	}

	*Consol<<"ExCTexture Exception::unable to load file "<<FileName<<std::endl;
	delete m_Image;
return false;
UnGuard
}

