
#include "stdafx.h"
#include "FreeType.h"

const int MAX_ZNAKU = 383;

// najde neblizsi mocninu 2
inline int next_p2(int a)
{
	int rval=1;
	while(rval<a) rval<<=1;
	return rval;
}

//////////////////////////////////////////////////////////////////////////
// CONSTRUKTOR
//////////////////////////////////////////////////////////////////////////
C_FREETYPE_0::C_FREETYPE_0()
{
	_pr_delete=false;
	_align = TEXT_LEFT;
}

//////////////////////////////////////////////////////////////////////////
// CONSTRUKTOR
//////////////////////////////////////////////////////////////////////////
C_FREETYPE_0::C_FREETYPE_0(std::string file_name,unsigned int vel) :_vel(vel), _file_name(file_name)
{
	_pr_delete=false;
	_align = TEXT_LEFT;
}

//////////////////////////////////////////////////////////////////////////
// DESTRUKTOR
//////////////////////////////////////////////////////////////////////////
C_FREETYPE_0::~C_FREETYPE_0()
{
	if(_pr_delete) this->Delete();
}

//////////////////////////////////////////////////////////////////////////
// MAKE_DLIST - vytvori dispalay list znaku
//////////////////////////////////////////////////////////////////////////
void make_dlist ( FT_Face face,int ch, GLuint list_base, GLuint * tex_base ) 
{
	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_DEFAULT ))
		cError.ErrorMsg(ERROR_LOAD_FONT,true,true,"FT_Load_Glyph failed");

    FT_Glyph glyph;
    if(FT_Get_Glyph( face->glyph, &glyph ))
		cError.ErrorMsg(ERROR_LOAD_FONT,true,true,"FT_Load_Glyph failed");

	FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
    FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

	//This reference will make accessing the bitmap easier
	FT_Bitmap& bitmap=bitmap_glyph->bitmap;

	int width = next_p2( bitmap.width );
	int height = next_p2( bitmap.rows );

	//Allocate memory for the texture data.
	GLubyte* expanded_data = new GLubyte[ 2 * width * height];

	for(int j=0; j <height;j++) {
		for(int i=0; i < width; i++){
			expanded_data[2*(i+j*width)]= expanded_data[2*(i+j*width)+1] = 
				(i>=bitmap.width || j>=bitmap.rows) ?
				0 : bitmap.buffer[i + bitmap.width*j];
		}
	}


	//Now we just setup some texture paramaters.
    glBindTexture( GL_TEXTURE_2D, tex_base[ch]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	//Here we actually create the texture itself, notice
	//that we are using GL_LUMINANCE_ALPHA to indicate that
	//we are using 2 channel data.
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
		  0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );

	//With the texture created, we don't need to expanded data anymore
    delete [] expanded_data;

	// vytvoreni noveheo dispaly listu
	glNewList(list_base+ch,GL_COMPILE);

	glBindTexture(GL_TEXTURE_2D,tex_base[ch]);
	glPushMatrix();
	glTranslatef(bitmap_glyph->left,0,0);

	glTranslatef(0,bitmap_glyph->top-bitmap.rows,0);

	float	x=(float)bitmap.width / (float)width,
			y=(float)bitmap.rows / (float)height;
	//glRotatef(-90,0,0,1);
	glBegin(GL_QUADS);
	glTexCoord2d(0,0); glVertex2f(0,bitmap.rows);
	glTexCoord2d(0,y); glVertex2f(0,0);
	glTexCoord2d(x,y); glVertex2f(bitmap.width,0);
	glTexCoord2d(x,0); glVertex2f(bitmap.width,bitmap.rows);
	glEnd();
	glPopMatrix();
	glTranslatef(face->glyph->advance.x >> 6 ,0,0);
	glBitmap(0, 0, 0, 0, face->glyph->advance.x >> 6, 0, NULL);
	// konec listu
	glEndList();
}

//////////////////////////////////////////////////////////////////////////
// INIT - nacteni fontu
//////////////////////////////////////////////////////////////////////////
void font_data::init(const char * fname, unsigned int h) 
{
	// Vytvoreni pameti pro textury
	textures = new GLuint[MAX_ZNAKU];
	//h = next_p2( h );
	this->h=h;

	FT_Library library;
	if (FT_Init_FreeType( &library )) 
		cError.ErrorMsg(ERROR_LOAD_FONT,true,true,"FreeType Font","FT_Init_FreeType failed");
	
	FT_Face face;
	if (FT_New_Face( library, fname, 0, &face )) 	
		cError.ErrorMsg(ERROR_LOAD_FONT,true,true,fname,"FT_New_Face failed (there is probably a problem with your font file)");

	FT_Set_Char_Size( face, h << 6, h << 6, 92, 92);

	list_base=glGenLists(MAX_ZNAKU);
	glGenTextures(MAX_ZNAKU, textures );
	//This is where we actually create each of the fonts display lists.
	for(int i=0;i<MAX_ZNAKU;i++)
		make_dlist(face,i,list_base,textures);

	FT_Done_Face(face);

	//Ditto for the library.
	FT_Done_FreeType(library);
}

//////////////////////////////////////////////////////////////////////////
// CLEAN - 
//////////////////////////////////////////////////////////////////////////
void font_data::clean() 
{
	glDeleteLists(list_base,MAX_ZNAKU);
	glDeleteTextures(MAX_ZNAKU,textures);
	delete [] textures;
}

//////////////////////////////////////////////////////////////////////////
// PUSHSCREENCOORDINATEMATRIX - nastavy pravouhlou projekci [ortho-projection]
//////////////////////////////////////////////////////////////////////////
inline void pushScreenCoordinateMatrix() 
{
	glPushAttrib(GL_TRANSFORM_BIT);
	GLint viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
	glPopAttrib();
}

//////////////////////////////////////////////////////////////////////////
// POP_PROJECTION_MATRIX - prehodi zpet do projekci matice
//////////////////////////////////////////////////////////////////////////
inline void pop_projection_matrix() 
{
	glPushAttrib(GL_TRANSFORM_BIT);
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glPopAttrib();
}

//////////////////////////////////////////////////////////////////////////
// PRINT
//////////////////////////////////////////////////////////////////////////
void C_FREETYPE_0::Print(float x, float y, const char *fmt, ...)  
{
	font_data &ft_font = _ft_font;
	// We want a coordinate system where things coresponding to window pixels.
	pushScreenCoordinateMatrix();					
	
	GLuint font=ft_font.list_base;
	float h=ft_font.h/.63f;	
	
	// obraceni osy Y
	GLint viewport[3];
	glGetIntegerv(GL_VIEWPORT, viewport);
	y = (viewport[3] - y) - ft_font.h;
	
	char		text[1024];								// Holds Our String
	va_list		ap;										// Pointer To List Of Arguments

	if (fmt == NULL) *text=0;										
	else 
	{
	va_start(ap, fmt);								
	    vsprintf(text, fmt, ap);						
	va_end(ap);											
	}

	// -----
	wchar_t NEWtext[1024];

	wchar_t znak;
	for(int loop1=0; loop1<1024; loop1++)
	{
		switch(text[loop1])// V text je uložen tištěný řetězec, který je v původním kódování
		{
		case 'Č':
		znak=268;
		break;
		case 'č':
		znak=269;
		break;
		case 'Ď':
		znak=270;
		break;
		case 'ď':
		znak=271;
		break;
		case 'Ě':
		znak=282;
		break;
		case 'ě':
		znak=283;
		break;
		case 'Ň':
		znak=327;
		break;
		case 'ň':
		znak=328;
		break;
		case 'Ř':
		znak=344;
		break;
		case 'ř':
		znak=345;
		break;
		case 'Š':
		znak=352;
		break;
		case 'š':
		znak=353;
		break;
		case 'Ť':
		znak=356;
		break;
		case 'ť':
		znak=357;
		break;
		case 'Ů':
		znak=366;
		break;
		case 'ů':
		znak=367;
		break;
		case 'Ž':
		znak=381;
		break;
		case 'ž':
		znak=382;
		break;
		
		default :
		znak=(unsigned char) text[loop1];
		break;
		}
		NEWtext[loop1]=znak;
	}
// ----

	//const char *start_line=text;
	const wchar_t *start_line = NEWtext;
	std::vector<std::wstring> lines;
	for(const wchar_t * c=NEWtext;*c;c++) 
	{
		if(*c=='\n') 
		{
			std::wstring line;
			for(const wchar_t *n=start_line;n<c;n++) line.append(1,*n);
			lines.push_back(line);
			start_line=c+1;
		}
	}
	if(start_line) 
	{
		std::wstring line;
		for(const wchar_t *n=start_line;n<c;n++) line.append(1,*n);
		lines.push_back(line);
	}

	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);	
	glMatrixMode(GL_MODELVIEW);
	bool bLight = (bool)glIsEnabled(GL_LIGHTING);
	if(bLight) glDisable(GL_LIGHTING);
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_TEXTURE_2D);
	//glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);	

	glListBase(font);

	float modelview_matrix[16];	
	glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);
	this->lines = lines.size();
	for(int i=0;i<lines.size();i++) 
	{
		glPushMatrix();
		glLoadIdentity();
		glTranslatef(x,y - ft_font.h*i,0);
		
		//glMultMatrixf(modelview_matrix);  
		glRasterPos2f(0, 0);
		glCallLists(lines[i].length(), GL_UNSIGNED_SHORT, lines[i].c_str());
	
		float rpos[4];
		glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
		lenght[i] = x + rpos[0];
	
		glPopMatrix();
	}
	if(bLight) glEnable(GL_LIGHTING);
	glPopAttrib();	
	pop_projection_matrix();
}

//////////////////////////////////////////////////////////////////////////
// LOADFONT - 
//////////////////////////////////////////////////////////////////////////
void C_FREETYPE_0::LoadFont(std::string file_name,unsigned int vel)
{
	_ft_font.init(file_name.c_str(),vel);
}

//////////////////////////////////////////////////////////////////////////
// LOADFONT - 
//////////////////////////////////////////////////////////////////////////
void C_FREETYPE_0::LoadFont()
{
	_ft_font.init(_file_name.c_str(),_vel);
}

//////////////////////////////////////////////////////////////////////////
// DELETE - 
//////////////////////////////////////////////////////////////////////////
void C_FREETYPE_0::Delete()
{
	_ft_font.clean();
	_pr_delete = true;
}

//////////////////////////////////////////////////////////////////////////
// LOADFONT - 
//////////////////////////////////////////////////////////////////////////
void C_FREETYPE_0::LoadFont(font_data fd)
{
	_ft_font = fd;
}