/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "font_freetype/ft2_font.h"
		#include "picture/pict.h"
		#include "log/log.h"

		using namespace GS;


//------------------------------------------------------------------------------
int				Freetype2Font::GetAdvance() const
{	return face ? face->glyph->advance.x : 0;	}
bool			Freetype2Font::SetPixelSize(int size)
{
	if	(face == 0)
		return false;

	FT_Set_Pixel_Sizes(face, 0, size);
	return true;
}
int				Freetype2Font::GetHeight() const
{	return face ? face->size->metrics.height : 0;	}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool			Freetype2Font::HasKerning() const
{	return has_kerning;	}
int				Freetype2Font::GetKerning(uint previous_codepoint, uint codepoint) const
{
	if	(face == 0)
		return 0;

	FT_Vector delta;
	FT_UInt previous_glyph_index = FT_Get_Char_Index(face, previous_codepoint), glyph_index = FT_Get_Char_Index(face, codepoint);
	return FT_Get_Kerning(face, previous_glyph_index, glyph_index, FT_KERNING_DEFAULT, &delta) == 0 ? delta.x : 0;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool			Freetype2Font::LoadGlyph(uint codepoint, bool for_render)
{
	FT_UInt index = FT_Get_Char_Index(face, codepoint);
	return FT_Load_Glyph(face, index, for_render ? FT_LOAD_RENDER : FT_LOAD_DEFAULT) == 0;
}
bool			Freetype2Font::RenderCurrentGlyph(Picture &picture, const iPoint &position, const iRect &clip, const Color &color)
{
	if	(face == 0)
		return false;

	if	(position.x >= clip.ex)
		return true;

	int r_offset = picture.GetPixelFormat().rshift / 8, g_offset = picture.GetPixelFormat().gshift / 8, b_offset = picture.GetPixelFormat().bshift / 8, a_offset = picture.GetPixelFormat().ashift / 8;
	int ir = int(color.x), ig = int(color.y), ib = int(color.z), ia = int(color.w);

	FT_GlyphSlot slot = face->glyph;
	FT_Bitmap *bmp = &slot->bitmap;
	unsigned char *bpt = bmp->buffer;

	if	(!bpt)
		return false;

	int pos_x = position.x + slot->bitmap_left;
	int pos_y = position.y - slot->bitmap_top ;

	unsigned char *opt = picture.GetData() + (pos_y * picture.GetWidth() + pos_x) * 4;

	for	(int y = 0; y < bmp->rows; ++y)
	{
		if	((pos_y >= clip.sy) && (pos_y < clip.ey))
		{
			uchar *spt = opt;
			for	(int x = 0; x < bmp->width; ++x)
			{
				int tx = pos_x + x;

				if	((tx >= clip.sx) && (tx < clip.ex))
				{
				#if	1
					uchar alpha = (uchar)((bpt[x] * ia) >> 8);
					uchar a_blend = Picture::AlphaCompositeAlpha(spt[a_offset], alpha);

					spt[r_offset] = Picture::AlphaCompositeColor(spt[r_offset], ir, spt[a_offset], alpha, a_blend);
					spt[g_offset] = Picture::AlphaCompositeColor(spt[g_offset], ig, spt[a_offset], alpha, a_blend);
					spt[b_offset] = Picture::AlphaCompositeColor(spt[b_offset], ib, spt[a_offset], alpha, a_blend);
					spt[a_offset] = a_blend;
				#else
					uchar alpha = (bpt[x] * (uchar)state.a) >> 8;
					spt[r_offset] = (uchar)state.r;
					spt[g_offset] = (uchar)state.g;
					spt[b_offset] = (uchar)state.b;
					spt[a_offset] = Types::Max(spt[a_offset], alpha);
				#endif
				}
				spt += 4;
			}
		}
		bpt += bmp->pitch;
		opt += picture.GetWidth() * 4;

		pos_y++;
		if	(pos_y >= (int)clip.ey)
			break;
	}
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
iRect			Freetype2Font::GetTextBoundRect(const char *text) const
{
	FT_GlyphSlot slot = face->glyph;
	FT_UInt previous = 0;

	iRect rc(0, 0, 0, 0);
	if	(!text)
		return rc;

	forever
	{
		char c = *text++;
		if	(c == 0)
			break;
		if	(c == '\n')
			continue;

		FT_UInt glyph_index = FT_Get_Char_Index(face, c);

		if	(has_kerning && previous && glyph_index)
		{
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
			rc.ex += delta.x;
		}
		if	(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
			continue;

		rc.ex += slot->advance.x;
		if	(slot->metrics.height > rc.ey)
			rc.ey = slot->metrics.height;
		previous = glyph_index;
	}

	rc.ex >>= 6;
	rc.ey >>= 6;
	return rc;
}
//------------------------------------------------------------------------------

Freetype2Font::~Freetype2Font()
{	FT_Done_Face(face);	}
