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


		#include <math.h>
		#include "gpu/gpu_renderer.h"
		#include "gpu/gpu_triangle_batch.h"
		#include "core/raster_font.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::GPU;


//------------------------------------------------------------------------------
void				Renderer::Write(const Render::RasterFont &f, const char *t, float &x, float &y, const WriterConfig &config, float s, const Color *c, WriterAlignment a, bool mirrored)
{
	Render::Texture *page = f.GetPage(0);
	if	(!page)
		__ERRRAW__(__LOG_E__ << "No glyph page in raster font '" << f.name << "'.\n")

	float scale_width = s;
	if(mirrored)
		scale_width = -s;
	
	// Aspect ratio, texel/pixel mapping.
	float ar = config.correct_ar ? viewport.GetHeight() / viewport.GetWidth() : 1.f;		// w / h

	Vector2 glyph_mapping((float)page->GetWidth() / viewport.GetWidth(), (float)page->GetHeight() / viewport.GetHeight()),
			 pixel_mapping(1.f / viewport.GetWidth(), 1.f / viewport.GetHeight());

	if	(!config.normalized)
	{
		x *= pixel_mapping.x;
		y *= pixel_mapping.y;
		y = floor(y * viewport.GetHeight()) / viewport.GetHeight();		// Stay on a pixel boundary.
	}
	float in_x = x;

	Vector4 vtx[4];
	Vector2 uv[4];

	Color col[4];
	for (uint n = 0; n < 4; ++n)
		col[n] = c ? *c : Color(1, 1, 1, 1);

	// Draw glyphs.
	Render::Texture *t_page = NULL;
	bool aligned = false;

	TriangleBatch batch(*this);

	for	( ; t[0]; ++t)
	{
		// Catch line feed.
		if	(t[0] == '\n')
		{
			x = in_x;
			if	(config.normalized)
				y += f.GetHeight() * s;
			else
			{
				y += f.GetHeight() * glyph_mapping.y * s;
				y = floor(y * viewport.GetHeight()) / viewport.GetHeight();		// Avoid float drift, stay on pixel boundary.
			}

			aligned = false;
			continue;
		}

		// Compute alignment.
		if	(!aligned)
		{
			switch (a)
			{
				case AlignMiddle:
					if	(config.normalized)
							x -= f.ComputeLineRect(t).x * scale_width * 0.5f * ar;
					else	x -= f.ComputeLineRect(t).x * scale_width * 0.5f * glyph_mapping.x;
					break;

				case AlignRight:
					if	(config.normalized)
							x -= f.ComputeLineRect(t).x * scale_width * ar;
					else	x -= f.ComputeLineRect(t).x * scale_width * glyph_mapping.x;
					break;

				default:
					break;
			}

			// Make sure we stay as close as possible to a pixel boundary for non-normalized modes.
			if	(!config.normalized)
				x = floor(x * viewport.GetWidth()) / viewport.GetWidth();

			aligned = true;
		}

		// Output glyph.
		if	(const Render::RasterFont::Glyph *glyph = f.GetGlyphInfos(t[0]))
		{
			if	((t_page = f.GetPage(glyph->page)) != NULL)
			{
				float _x, _y, _w, _h;

				if	(config.normalized)
				{
					_x = x * 2.f - 1.f + glyph->offx * 1.f * scale_width;
					_y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * s;
					_w = glyph->w * 2.f * scale_width * ar;
					_h = glyph->h * 2.f * s;

					_x *= GetGlobalAspectRatio();
					_w *= GetGlobalAspectRatio();
				}
				else
				{
					_x = x * 2.f - 1.f + glyph->offx * 2.f * glyph_mapping.x * scale_width;
					_y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * glyph_mapping.y * s;
					_w = glyph->w * 2.f * glyph_mapping.x * scale_width;
					_h = glyph->h * 2.f * glyph_mapping.y * s;
				}

				vtx[0].Set(_x, _y, 0.5);
				vtx[1].Set(_x + _w, _y, 0.5);
				vtx[2].Set(_x + _w, _y - _h, 0.5);
				vtx[3].Set(_x, _y - _h, 0.5);

				uv[0].Set(glyph->u, glyph->v);
				uv[1].Set(glyph->u + glyph->w, glyph->v);
				uv[2].Set(glyph->u + glyph->w, glyph->v + glyph->h);
				uv[3].Set(glyph->u, glyph->v + glyph->h);

				const ushort indice[] = { 0, 1, 2, 0, 2, 3 };	// order is reversed because the quad is drawn from the baseline (bottom to top)
				batch.DrawTriangle(2, 4, vtx, indice, col, uv, t_page, Core::Material::Blend_Alpha, (Core::Material::RenderWord)(Core::Material::Render_NoZTest | Core::Material::Render_NoZWrite | Core::Material::Render_DoubleSided));
			}

			if	(config.normalized)
					x += glyph->step * scale_width * ar;
			else	x += glyph->step * glyph_mapping.x * scale_width;
		}
	}

	batch.Flush();

	if	(!config.normalized)
	{
		x /= pixel_mapping.x;
		y /= pixel_mapping.y;
	}
}
//------------------------------------------------------------------------------
