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


		#include "core/geometry.h"
		#include "log/log.h"

		using namespace GS::Core;


//------------------------------------------------------------------------------
bool				Geometry::ComputePolygonTangent(uint uv_index, bool force)
{
	if	(!pol.GetCount() || !vtx.GetCount())
		return false;

	if	(!force && (pol_tangent.GetCount() == pol.GetCount()))
		return true;

	if	(!ComputePolygonNormal())
		return false;

	if	((uv_index >= __UV_PER_GEOMETRY__) || !uv[uv_index])
		return false;

	// Allocate polygon tangents.
	if	(!pol_tangent.Allocate(pol.GetCount()))
		__ERR__(__LOG_W__ << "Geometry::ComputePolygonTangent() failed to allocate buffer!\n", false)

	Array <uint> pol_index;
	ComputePolygonIndex(pol_index);

	for	(uint c = 0; c < pol.GetCount(); c++)
		if (pol[c].vtx_count > 2)
		{
			// Compute tangent frame for this polygon.
			Vector4	side_0 = vtx[pol[c].binding[0]] - vtx[pol[c].binding[1]],
					side_1 = vtx[pol[c].binding[2]] - vtx[pol[c].binding[1]];

			float	delta_U_0 = uv[uv_index][pol_index[c] + 0].x - uv[uv_index][pol_index[c] + 1].x,
					delta_U_1 = uv[uv_index][pol_index[c] + 2].x - uv[uv_index][pol_index[c] + 1].x,
					delta_V_0 = uv[uv_index][pol_index[c] + 0].y - uv[uv_index][pol_index[c] + 1].y,
					delta_V_1 = uv[uv_index][pol_index[c] + 2].y - uv[uv_index][pol_index[c] + 1].y;

			Vector4	T = (side_0 * delta_V_1 - side_1 * delta_V_0).Normalized().Reversed(),
					B = (side_0 * delta_U_1 - side_1 * delta_U_0).Normalized();

			if	(T.Cross(B).Dot(pol_normal[c]) < 0)
			{
				T.Reverse();
				B.Reverse();
			}

			pol_tangent[c].B = B;
			pol_tangent[c].T = T;
		}

	return true;
}
bool				Geometry::ComputeVertexTangent(bool rev_t, bool rev_b, bool force)
{
	if	(!pol.GetCount() || !vtx.GetCount())
		return false;

	if	(!force && (vtx_tangent.GetCount() == binding.GetCount()))
		return true;

	if	(!ComputeVertexNormal() || !ComputePolygonTangent())
		return false;

	Array <VertexToPolygon> vtx_to_pol;
	ComputeVertexToPolygon(vtx_to_pol);

	// Allocate full blown edge normal array.
	if	(vtx_tangent.Allocate(binding.GetCount()))
		for	(uint cp = 0, ttp = 0; cp < pol.GetCount(); ++cp)
			for	(uint cv = 0; cv < pol[cp].vtx_count; ++cv)
			{
				uint gv = pol[cp].binding[cv];

				Vector4	T(0, 0, 0), B(0, 0, 0);
				for	(uint cg = 0; cg < vtx_to_pol[gv].pol_count; cg++)
				{
					Vector4	_T = pol_tangent[vtx_to_pol[gv].pol_index[cg]].T,
							_B = pol_tangent[vtx_to_pol[gv].pol_index[cg]].B;

					if	(pol_tangent[cp].T.Dot(_T) < 0.f)
						_T = _T.Reversed();
					if	(pol_tangent[cp].B.Dot(_B) < 0.f)
						_B = _B.Reversed();

					T += _T;
					B += _B;
				}

				T -= vtx_normal[ttp] * vtx_normal[ttp].Dot(T);
				T = T.Normalized();
				B = vtx_normal[ttp].Cross(T);

				vtx_tangent[ttp].T = rev_t ? T.Reversed() : T;
				vtx_tangent[ttp].B = rev_b ? B.Reversed() : B;

				++ttp;
			}

	return true;
}
//------------------------------------------------------------------------------
