
#include "stdafx.h"
#include "CTextureManager.h"
//#include <fstream>

// FreeImage
#include "FreeImage.h"
#pragma comment (lib,"FreeImaged.lib")

// GL
//#pragma comment (lib,"opengl32.lib")
//#pragma comment (lib,"glu32.lib")
//#pragma comment (lib,"glaux.lib")
#include <gl\gl.h>			
#include <gl\glu.h>	
#include "bmp.h"

static uint g_pocetTManager = 0;
MBMP BMP;

C_TEXTURE_MANAGER_0::C_TEXTURE_MANAGER_0()
{
	_citac=0;

	std::string log_file_name = "GfxLog";
	char cislo[10];
	sprintf(cislo, "%d", g_pocetTManager);
	log_file_name += cislo;
	log_file_name += ".txt";
	_logFile.Create( log_file_name.c_str() );
	g_pocetTManager++;
	
	// alfa se nastavi na green
	_rgb_alpha.r = 0;
	_rgb_alpha.g = 255;
	_rgb_alpha.b = 0;
	_roz = 0;
	_raptMemory = 0;
	_completTime = 0.0f;
}

C_TEXTURE_MANAGER_0::~C_TEXTURE_MANAGER_0()
{
	DeleteAll();
}

int FindExp(int num)
{
	if(num < 1) return 0;
    int e=1;
	int cit=1;
	while(e < num)
	{
		e = e*2; 
		if(num == e) return 0;
	}
	if(num-(e/2) <= e-num) return e/2; // zakomentaruj tento radek pro lepsi kvalitu textur
	
	return e;
}

bool C_TEXTURE_MANAGER_0::ReloadTextures(bool all)
{
	// nactou se vsechny bitmapi za pomoci knihovny FreeImage
	// potom se prevedou z hdc do Texture pro openGL
	if(all) this->DeleteAll();
	for(std::vector<TTexture>::iterator i = _lTextures.begin(); i != _lTextures.end(); i++)
    {
		if( (*i).nacteno && all==0 ) continue;
		if( !i->enable ) continue;
		uint startTime = timeGetTime();
		(*i).nacteno = true;
		std::string pripona;
		if((*i).pripona.size() > 0)
		{
			pripona = (*i).pripona;
		}else
		if((*i).pripona.size() == 0)
		{
			pripona = _GetPripona(i->name);
		}
		FIBITMAP *dib = NULL;
		pripona = _strlwr((char *)pripona.c_str());

		char string[255];
		sprintf( string,"--------------------------------" );
		_logFile.Write(string);

		if(pripona == "bmp")
		{
			dib = FreeImage_Load(FIF_BMP, (*i).name.c_str(), BMP_DEFAULT);
		/*	char string[255];
			sprintf(string,"%s", i->name.c_str());
			TVel vel = BMP.GetVel( string );
			unsigned char *data = new unsigned char [vel.width*vel.height*4];
			BMP.LoadData( string, i->rgb_alpha, (unsigned char*)data );
			sprintf(string,"Image Name : %s",i->name.c_str());
			_logFile.Write(string);
			sprintf(string,"Image Memory : %f kb", (float)(vel.width*vel.height*4)/1000 );
			_logFile.Write(string);
			i->texture_id = _CreateGlTexture(vel.width, vel.height, 32, (unsigned char*)data, i->flags);
			sprintf(string,"Image Id : %d ", i->texture_id );
			_logFile.Write(string);

			float time = float(timeGetTime()-startTime)/1000.0f;
			sprintf(string,"Image loading : %fs ", time );
			_logFile.Write(string);
			_completTime += time;
			_raptMemory += vel.width*vel.height*4;
			delete [] data;
			continue;*/
		}
		else
		if(pripona == "jpg" || pripona == "jpeg") dib = FreeImage_Load(FIF_JPEG,(*i).name.c_str(), JPEG_DEFAULT);
		else
		if(pripona == "tga") dib = FreeImage_Load(FIF_TARGA,(*i).name.c_str(), TARGA_DEFAULT);
		else
		if(pripona == "pcx") dib = FreeImage_Load(FIF_PCX,(*i).name.c_str(), PCX_DEFAULT);
		else
		if(pripona == "gif") dib = FreeImage_Load(FIF_GIF,(*i).name.c_str(), GIF_DEFAULT);
		else
		if(pripona == "ico") dib = FreeImage_Load(FIF_ICO,(*i).name.c_str(), ICO_DEFAULT);
		else
		{
			// Log
			char string[255];
			sprintf(string,"Neznámá přípona u souboru \"%s\", pripona : %s",i->name.c_str(),pripona.c_str());
			_logFile.Write(string);
			// Error
			cError.ErrorMsg(1,true,true,"Error - nejde nacist soubor",string);
			return FALSE;
		}
		if(!dib)
		{
			// Error
			char string[255];
			sprintf(string,"Soubor %s nenalezen",i->name.c_str());
			cError.ErrorMsg(1,true,true,"Error - nemuze najit soubor",string);
		}
		/*char string2[255];
		sprintf(string2,"Nno create : %fs ", float(timeGetTime()-startTime)/1000.0f );
		_logFile.Write(string2);*/
		// Vytvoreni bitmapy
		int w = FreeImage_GetWidth(dib);
		int h = FreeImage_GetHeight(dib);
		unsigned char *data = new unsigned char [w*h*4];
	
		unsigned char iRoz = (*i).roz;	// rozmezi
		int bytespp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib);
			
			for(register unsigned int y=0; y < FreeImage_GetHeight(dib);y++)
			{
				BYTE *bits = FreeImage_GetScanLine(dib,y);
				for(register unsigned int x=0; x < FreeImage_GetWidth(dib);x++)
				{
					/*if( (unsigned char)bits[FI_RGBA_RED] == 255 && (unsigned char)bits[FI_RGBA_GREEN] == 0 &&
						(unsigned char)bits[FI_RGBA_BLUE] == 255 )
					{
						data[y*w*4 + x*4 +0] = (unsigned char)bits[FI_RGBA_RED];
						data[y*w*4 + x*4 +1] = (unsigned char)bits[FI_RGBA_GREEN];
						data[y*w*4 + x*4 +2] = (unsigned char)bits[FI_RGBA_BLUE];
					}else
					{
						data[y*w*4 + x*4 +0] = 255-(unsigned char)bits[FI_RGBA_RED];
						data[y*w*4 + x*4 +1] = 255-(unsigned char)bits[FI_RGBA_GREEN];
						data[y*w*4 + x*4 +2] = 255-(unsigned char)bits[FI_RGBA_BLUE];
					}*/

					unsigned char r = (unsigned char)bits[FI_RGBA_RED];
					unsigned char g = (unsigned char)bits[FI_RGBA_GREEN];
					unsigned char b = (unsigned char)bits[FI_RGBA_BLUE];
					/*int del = 2;
					if( r + r/del > 255 ) r = 255; else r = r + r/del;
					if( g + g/del > 255 ) g = 255; else g = g + g/del;
					if( b + b/del > 255 ) b = 255; else b = b + b/del;*/

					/*if( r == (*i).rgb_alpha.r && g == (*i).rgb_alpha.g && b==(*i).rgb_alpha.b )
					{*/
						data[y*w*4 + x*4 +0] = r;
						data[y*w*4 + x*4 +1] = g;
						data[y*w*4 + x*4 +2] = b;
					/*}else
					{
						if( (*i).snow_efekt )
						{
							data[y*w*4 + x*4 +0] = 255-r;
							data[y*w*4 + x*4 +1] = 255-g;
							data[y*w*4 + x*4 +2] = 255-b;
						}else
						{
							data[y*w*4 + x*4 +0] = r;
							data[y*w*4 + x*4 +1] = g;
							data[y*w*4 + x*4 +2] = b;
						}
					}*/

					//if((*i).alphaTest)
					{
						if( (data[y*w*4 + x*4 +0] >= int((*i).rgb_alpha.r-iRoz) && data[y*w*4 + x*4 +0] <= int((*i).rgb_alpha.r+iRoz) ) &&
							(data[y*w*4 + x*4 +1] >= int((*i).rgb_alpha.g-iRoz) && data[y*w*4 + x*4 +1] <= int((*i).rgb_alpha.g+iRoz) ) &&
							(data[y*w*4 + x*4 +2] >= int((*i).rgb_alpha.b-iRoz) && data[y*w*4 + x*4 +2] <= int((*i).rgb_alpha.b+iRoz) ))
						{
							data[y*w*4 + x*4 +3] = 0;
						}
						else data[y*w*4 + x*4 +3] = 255;
					}//else data[y*w*4 + x*4 +3] = 255;
					bits += bytespp;
				}
			}
		// Pricteni zabrane pameti
		_raptMemory += w*h*4;
		// Log do souboru
		//char string[255];
		sprintf(string,"Image Name : %s",i->name.c_str());
		_logFile.Write(string);
		sprintf(string,"Image Memory : %f kb", (float)(w*h*4)/1000 );
		_logFile.Write(string);
		// vytvoreni bitmapy
		i->texture_id = _CreateGlTexture(w, h, 32, (unsigned char*)data, i->flags);
		sprintf(string,"Image Id : %d ", i->texture_id );
		_logFile.Write(string);
		float time = float(timeGetTime()-startTime)/1000.0f;
		sprintf(string,"Image loading : %fs ", time );
		_logFile.Write(string);
		_completTime += time;
		FreeImage_Unload( dib );
		delete [] data;
	}
	return TRUE;
}

unsigned int C_TEXTURE_MANAGER_0::_CreateGlTexture(int width, int height, int bpp, unsigned char *data, int flags)
{
	GLuint ret=0;
	glGenTextures(1, &ret);
	glBindTexture(GL_TEXTURE_2D, ret);
	if((flags & TM_NONE) == TM_NONE)
	{
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	}
	if((flags & TM_MIN_NEAREST) == TM_MIN_NEAREST) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	if((flags & TM_MAX_NEAREST) == TM_MAX_NEAREST) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	if((flags & TM_MIN_LINEAR) == TM_MIN_LINEAR) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	if((flags & TM_MAX_LINEAR) == TM_MAX_LINEAR) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	if((flags & TM_MIP_NEAREST) == TM_MIP_NEAREST)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
	}
	if((flags & TM_MIP_LINEAR) == TM_MIP_LINEAR)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	}
	
	int n_width = FindExp(width);
	int n_height =FindExp(height);
	bool log_scale = 0;

	if((n_width > 0) || (n_height > 0))
	{
		log_scale = 1;
		if(n_width == 0) n_width = width;
		if(n_height == 0) n_height = height;
		unsigned char *dataOut = new unsigned char[n_width*n_height*4];
		int error = gluScaleImage(GL_RGBA, width, height, GL_UNSIGNED_BYTE, data, n_width, n_height, GL_UNSIGNED_BYTE, dataOut);
	
		/*if(error != 0) 
		{
			const char *text = (const char*) gluErrorString(error);
			cError.ErrorMsg(0, true, true, "Texture Manager", text);
		}*/
		if(((flags & TM_MIP_LINEAR) == TM_MIP_LINEAR) || ((flags & TM_MIP_NEAREST) == TM_MIP_NEAREST))
		gluBuild2DMipmaps(GL_TEXTURE_2D, 4, n_width, n_height, GL_RGBA, GL_UNSIGNED_BYTE, dataOut);
		else
		glTexImage2D(GL_TEXTURE_2D, 0, 4, n_width, n_height,0, GL_RGBA, GL_UNSIGNED_BYTE, dataOut);
		delete [] dataOut;
	}else
	{
		if(((flags & TM_MIP_LINEAR) == TM_MIP_LINEAR) || ((flags & TM_MIP_NEAREST) == TM_MIP_NEAREST))
		gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
		else
		glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height,0, GL_RGBA, GL_UNSIGNED_BYTE, data);
	}
	
	// Log
	char string[255];
	sprintf(string," Width : %d \n Height : %d \n Bpp : %d \n Filter : %#x",width, height, bpp, flags);
	_logFile.Write(string);
	
	if(log_scale) 
	{
		sprintf(string," ScaleW : %d\n ScaleH : %d",n_width, n_height);
		_logFile.Write(string);
	}

	return ret;
}

void C_TEXTURE_MANAGER_0::DeleteAll()
{
	char string[255];
	sprintf(string," !!! Delete All(%d) Texture !!! ", _lTextures.size());
	_logFile.Write(string);
	
	for(std::vector<TTexture>::iterator i = _lTextures.begin(); i != _lTextures.end(); i++)
    {
		glDeleteTextures(1,&(*i).texture_id);
	}

	sprintf(string," Complet memory : %f kb", ((float)_raptMemory/1000.0f));
	_logFile.Write(string);

	sprintf(string,"Complet time loading: %fs ", _completTime );
	_logFile.Write(string);

	_lTextures.clear();
	_raptMemory = 0;
	_citac = 0;
	
}

void C_TEXTURE_MANAGER_0::DeleteTexture( int id )
{
	int citac = id;
	if(citac >= _lTextures.size() || citac < 0) return;
	uint id_texture = _lTextures[citac].texture_id;
	_logFile.Write( W_GetString("Delete texture s id : %d ", (int)id_texture ).c_str() );
	_lTextures[citac].enable = 0;
	glDeleteTextures( 1, &id_texture );
}

std::string C_TEXTURE_MANAGER_0::_GetPripona(std::string name)
{
	int delka = name.size();
	char koncovka[255];
	int num_kon=0;

	for(int i=delka-1;i >= 0;i--)
	{
		//koncovka[num_kon] = name[i];
		if(name[i] == '.') 
		{
			register k=i+1;
			while(name[k] != '\0')
			{
				koncovka[num_kon] = name[k];
				num_kon++;
				k++;
			}
			break;
		}
	}
	koncovka[num_kon] = '\0';
	return koncovka;
}

bool C_TEXTURE_MANAGER_0::SaveScreenShotTga(std::string file_name,int width,int height)
{
	FILE *fout;
    int i, j, k;
	unsigned char tgaHeader[18]={0x00,              // typ hlavicky TGA
                        0x00,                       // nepouzivame paletu
                        0x02,                       // typ obrazku je RGB TrueColor
                        0x00, 0x00,                 // delka palety je nulova
                        0x00, 0x00, 0x00,           // pozice v palete nas nezajima
                        0x00, 0x00, 0x00, 0x00,     // obrazek je umisteny na pozici [0, 0]
                        0x00, 0x00, 0x00, 0x00,     // sirka a vyska obrazku (dva byty na polozku)
                        0x18,                       // format je 24 bitu na pixel
                        0x20                        // orientace bitmapy v obrazku
    };
	unsigned char *pole;
	pole = new unsigned char[width*height*3];

    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pole);
    memcpy(tgaHeader+12, &width, 2);                // do hlavicky TGA zapsat velikost obrazku
    memcpy(tgaHeader+14, &height, 2);
    fout=fopen(file_name.c_str(), "wb");
	if (!fout)
	{
		cError.ErrorMsg(ERROR_SAVE,false,false,file_name.c_str(),"Nepodařilo se uložit TGA ScreenShot.");
		return FALSE;
	}
    if (fout) 
	{
        fwrite(tgaHeader, 18, 1, fout);             // zapsat hlavicku TGA do souboru
        for (j=height-1; j>=0; j--) 
		{        
            for (i=0; i<width; i++) 
			{        
                for (k=0; k<3; k++) 
				{              
                    fputc(pole[j*width*3 + i*3 + (2-k)], fout); // a zapsat do souboru
                }
            }
        }
        fclose(fout);
    }
	delete [] pole;

	// Log File
	char string[255];
	sprintf(string,"## Save image TGA screenshot : %s ",file_name.c_str());
	_logFile.Write(string);

	return TRUE;
}

bool C_TEXTURE_MANAGER_0::SaveImage(std::string file_name,int width,int height,unsigned int flags)
{
	FIBITMAP *dib = NULL;
	dib = FreeImage_Allocate(width,height, 24);
	unsigned char *pole;
	pole = new unsigned char[width*height*3];
	glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pole);

	int bytespp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib);
	for(unsigned int y=0; y < height;y++)
	{
		BYTE *bits = FreeImage_GetScanLine(dib,y);
		for(unsigned int x=0; x < width;x++)
		{
			bits[FI_RGBA_RED] = pole[y*height*4 + x*3 + 0];
			bits[FI_RGBA_GREEN] = pole[y*height*4 + x*3 + 1];
			bits[FI_RGBA_BLUE] = pole[y*height*4 + x*3 + 2];
								
			bits += bytespp;
		}
	}
	delete [] pole;
	int im_flags=BMP_DEFAULT;
	FREE_IMAGE_FORMAT format=FIF_JPEG;

	if(flags == TM_BMP)				im_flags = BMP_DEFAULT;
	if(flags == TM_BMP_RLE)			im_flags = BMP_SAVE_RLE;
	if(flags == TM_JPEG_QSUPER)		im_flags = JPEG_QUALITYSUPERB;
	if(flags == TM_JPEG_QGOOD)		im_flags = JPEG_QUALITYGOOD;
	if(flags == TM_JPEG_QNORMAL)	im_flags = JPEG_QUALITYNORMAL;
	if(flags == TM_JPEG_QAVERAGE)	im_flags = JPEG_QUALITYAVERAGE;
	if(flags == TM_JPEG_QBAD)		im_flags = JPEG_QUALITYBAD;

	if(flags == TM_BMP || flags == TM_BMP_RLE) format = FIF_BMP;
	
	if(!FreeImage_Save(format,dib,file_name.c_str(),im_flags))
	{
		cError.ErrorMsg(ERROR_SAVE,false,false,file_name.c_str(),"Nepodařilo se uložit ScreenShot.");
		return FALSE;
	}

	// Log File
	char string[255];
	sprintf(string,"## Save image screenshot : %s ",file_name.c_str());
	_logFile.Write(string);

	return TRUE;
}
