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


		#include "ui/ui_sprite.h"
		#include "gpu/gpu_triangle_batch.h"
		#include "core/renderer.h"

		using namespace GS::Render;
		using namespace GS::S2D;


//------------------------------------------------------------------------------
void				Sprite::Render(Renderer &render, GS::GPU::TriangleBatch *batch)
{
	if	(render_data.IsNull())
		return;
	if	(opacity < 0.003f)
		return;

	ComputeMatrix();

	// Test visibility.
	bool should_show = true;

	float final_opacity = opacity;
	for	(Item *p = GetParent(); p; p = p->GetParent())
		if	(Sprite *sp = (Sprite *)p)
			final_opacity *= sp->opacity;

	if	(final_opacity < 0.003f)
		should_show = false;

	// Compute hierarchy matrix, opacity and visibility.
	if	(sprite_flags.IsSet(FlagSnapToPixel))
	{
		matrix.m[0][2] = Math::Floor(matrix.m[0][2]);
		matrix.m[1][2] = Math::Floor(matrix.m[1][2]);
	}

	if	(!should_show)	// [EJ] do not move before matrix is updated
		return;
	
	Texture *t = render_data->texture;
	if (t && t->format != Texture::FormatInvalid)
	{
		Vector4 vtx[4];
		vtx[0].Set(0, 0, 1);
		vtx[1].Set(size.x, 0, 1);
		vtx[2].Set(size.x, size.y, 1);
		vtx[3].Set(0, size.y, 1);

		Vector4 vtx_attr[4];
		matrix.Apply(vtx_attr, vtx, 4);	// transform on the CPU for the batch system

		Color color_attr[4];
		for	(uint n = 0; n < 4; ++n)
			color_attr[n].Set(1, 1, 1, final_opacity);

		Vector2 uv_attr[4];

		float	su = uv_origin.x / float(t->GetWidth()),
				sv = uv_origin.y / float(t->GetHeight()),
				eu = (uv_origin.x + size.x) / float(t->GetWidth()),
				ev = (uv_origin.y + size.y) / float(t->GetHeight());

		if	(sprite_flags.IsSet(FlagFlipU)) Types::swap(su, eu);
		if	(sprite_flags.IsSet(FlagFlipV)) Types::swap(sv, ev);

		if	(sprite_flags.IsSet(FlagTransformUV))
		{
			Vector4 s_uv[4], o_uv[4];

			s_uv[0].Set(su, sv, 1);
			s_uv[1].Set(eu, sv, 1);
			s_uv[2].Set(eu, ev, 1);
			s_uv[3].Set(su, ev, 1);

			uv_matrix.Apply(o_uv, s_uv, 4);
			for	(int n = 0; n < 4; ++n)
				uv_attr[n].Set(o_uv[n].x, o_uv[n].y);
		}
		else
		{
			uv_attr[0].Set(su, sv);
			uv_attr[1].Set(eu, sv);
			uv_attr[2].Set(eu, ev);
			uv_attr[3].Set(su, ev);
		}

		// Blend mode.
		using Core::Material;

		Material::BlendOperator blend_op;

		if	(sprite_flags.IsSet(FlagBlendOpaque))
				blend_op = final_opacity < 1.f ? Material::Blend_Alpha : Material::Blend_None;
		else	blend_op = sprite_flags.IsSet(FlagBlendAdditive) ? Material::Blend_Add : Material::Blend_Alpha;

		Material::RenderWord render_word = Material::RenderWord(Material::Render_NoZWrite | Material::Render_NoZTest);

		// Draw.
		ushort idx[6] = { 0, 1, 2, 0, 2, 3 };

		if	(batch)
			batch->DrawTriangle(2, 4, vtx_attr, idx, color_attr, uv_attr, render_data->texture, blend_op, render_word);
		else
			render.DrawTriangle(2, vtx_attr, idx, color_attr, uv_attr, render_data->texture, blend_op, render_word);
	}
}
//------------------------------------------------------------------------------
