/*********************************************************************//**
*	\brief Freetype font definition.
*	Funkce freetype fontu, coz zahrnuje nacteni a vykreslovani textu.
*
*	\author Michal Jirous
*	\date 14.7.2008
*	\file freetypefont.cpp
**********************************************************************/

#include "fonts.h"
#include "mathematic.h"
//FreeType Headers
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

using namespace std;
///Create a display list coresponding to the give character.
//vraci sirku znaku
GLuint make_dlist ( FT_Face face, unsigned char ch, GLuint list_base, GLuint * tex_base ) {

	//The first thing we do is get FreeType to render our character
	//into a bitmap.  This actually requires a couple of FreeType commands:

	//Load the Glyph for our character.
	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_DEFAULT ))
		throw std::runtime_error("FT_Load_Glyph failed");

	//Move the face's glyph into a Glyph object.
    FT_Glyph glyph;
    if(FT_Get_Glyph( face->glyph, &glyph ))
		throw std::runtime_error("FT_Get_Glyph failed");

	//Convert the glyph to a bitmap.
	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;

	//Use our helper function to get the widths of
	//the bitmap data that we will need in order to create
	//our texture.
	int width = getMaximumPowerOf( bitmap.width );
	int height = getMaximumPowerOf( bitmap.rows );

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

	//Here we fill in the data for the expanded bitmap.
	//Notice that we are using two channel bitmap (one for
	//luminocity and one for alpha), but we assign
	//both luminocity and alpha to the value that we
	//find in the FreeType bitmap. 
	//We use the ?: operator so that value which we use
	//will be 0 if we are in the padding zone, and whatever
	//is the the Freetype bitmap otherwise.
	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;

	//So now we can create the display list
	glNewList(list_base+ch,GL_COMPILE);

	glBindTexture(GL_TEXTURE_2D,tex_base[ch]);

	//first we need to move over a little so that
	//the character has the right amount of space
	//between it and the one before it.
	//glTranslatef(bitmap_glyph->left,0,0);

	//Now we move down a little in the case that the
	//bitmap extends past the bottom of the line 
	//(this is only true for characters like 'g' or 'y'.
	glTranslatef(0,(float)bitmap_glyph->top-bitmap.rows,0);

	//Now we need to account for the fact that many of
	//our textures are filled with empty padding space.
	//We figure what portion of the texture is used by 
	//the actual character and store that information in 
	//the x and y variables, then when we draw the
	//quad, we will only reference the parts of the texture
	//that we contain the character itself.
	float	x=(float)bitmap.width / (float)width,
			y=(float)bitmap.rows / (float)height;

	//Here we draw the texturemaped quads.
	//The bitmap that we got from FreeType was not 
	//oriented quite like we would like it to be,
	//so we need to link the texture to the quad
	//so that the result will be properly aligned.
	if( !isspace( ch ) )
	{
		glBegin(GL_QUADS);
		glTexCoord2f(0,0); glVertex2i(0,bitmap.rows);
		glTexCoord2f(0,y); glVertex2f(0,0);
		glTexCoord2f(x,y); glVertex2i(bitmap.width,0);
		glTexCoord2f(x,0); glVertex2i(bitmap.width,bitmap.rows);
		glEnd();
	}
	if( ch == '\t' )
		glTranslatef((float)(face->glyph->advance.x >> 3) , -(float)bitmap_glyph->top+bitmap.rows, 0);
	else
		glTranslatef((float)(face->glyph->advance.x >> 6) , -(float)bitmap_glyph->top+bitmap.rows, 0);
	

	//increment the raster position as if we were a bitmap font.
	//(only needed if you want to calculate text length)
	//glBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL);

	//Finnish the display list
	glEndList();

	if( ch == '\t' )
		return (face->glyph->advance.x >> 3);
	else
		return  (face->glyph->advance.x >> 6);
}



void FreeTypeFont::setParameters( map<string,string> &params )
{
	for( map<string,string>::iterator i = params.begin(); i != params.end(); i++ )
	{
		if( (*i).first == "filename" )
			m_sFileName = "Fonts/" + (*i).second;
		else if( (*i).first == "height" )
			m_iLetterHeight = stringToInt( (*i).second );
	}
}

void FreeTypeFont::decompile()
{
	glDeleteLists( m_iCharacterTable, FREETYPE_FONT_NUM_CHARS );
	glDeleteTextures( FREETYPE_FONT_NUM_CHARS, m_uiTextureIds );
}

bool FreeTypeFont::compile()
{
	if( m_sFileName.empty() )
		return false;

	FT_Library library;
	if (FT_Init_FreeType( &library )) 
		throw std::runtime_error("FT_Init_FreeType failed");
	
	//The object in which Freetype holds information on a given
	//font is called a "face".
	FT_Face face;

	//This is where we load in the font information from the file.
	//Of all the places where the code might die, this is the most likely,
	//as FT_New_Face will die if the font file does not exist or is somehow broken.
	if (FT_New_Face( library, m_sFileName.c_str(), 0, &face )) 
		throw std::runtime_error("FT_New_Face failed (there is probably a problem with your font file)");

	//For some twisted reason, Freetype measures font size
	//in terms of 1/64ths of pixels.  Thus, to make a font
	//h pixels high, we need to request a size of h*64.
	//(h << 6 is just a prettier way of writting h*64)
	FT_Set_Char_Size( face, m_iLetterHeight << 6, m_iLetterHeight << 6, 96, 96);
	
	m_iCharacterTable = glGenLists( FREETYPE_FONT_NUM_CHARS );
	glGenTextures( FREETYPE_FONT_NUM_CHARS, m_uiTextureIds );

	//This is where we actually create each of the fonts display lists.
	for( unsigned int i = 0; i < FREETYPE_FONT_NUM_CHARS; i++ )
	{
		m_uiWidths[i] = make_dlist( face, i, m_iCharacterTable, m_uiTextureIds );
	}

	//We don't need the face information now that the display
	//lists have been created, so we free the assosiated resources.
	FT_Done_Face(face);

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

	return true;
}

int FreeTypeFont::draw( string &text, float x_pos, float y_pos)
{
	glPushMatrix();
	glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	float iStartXPosition = x_pos;

	int height = 0;
	unsigned char character = 0;
	glTranslatef( iStartXPosition, y_pos, 0 );
	for( size_t i = 0; i < text.length(); i++)
	{
		height += this->getCharacterWidth( (unsigned char)i );
		character = text.at( i );
		if( character < 0 || character >= FREETYPE_FONT_NUM_CHARS )
			continue;
		glCallList( m_iCharacterTable + character );
	}


	glPopAttrib();
	glPopMatrix();
	return height;
}
