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


		#include "picture/pict.h"
		#include "math/nmath.h"

		using namespace GS;


//------------------------------------------------------------------------------
void		Picture::LowLevelDrawLine(bool hq, float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
{
	// Output validity.
	if	(!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
		return;

	// Clip primitive.
	float dx = ex - sx, dy = ey - sy;

	// Sub pixel correction.
	if	(Types::Abs(dy) > Types::Abs(dx))
	{
		float fsy = Math::Floor(sy);
		if	(dy)
			sx -= dx * (sy - fsy) / dy;		// Sub-pixel correction.
		sy = fsy;
	}
	else
	{
		float fsx = Math::Floor(sx);
		if	(dx)
			sy -= dy * (sx - fsx) / dx;		// Sub-pixel correction.
		sx = fsx;
	}

	// Clipping.
	if	(clip_rect)
	{
		//---------------------------------------------------------------
		#define	__SwapFloat(A, B)	{	float swp = A; A = B; B = swp;	}
		//---------------------------------------------------------------

		if	(dx)
		{
			// Flip line if it is going backward.
			if	(dx < 0)
			{
				__SwapFloat(sx, ex)
				__SwapFloat(sy, ey)
				dx = ex - sx; dy = ey - sy;
			}
			float	idx = 1 / dx;

			// Clip on X axis.
			if	(ex < clip_rect->sx)
				return;

			float	kee = (clip_rect->ex - sx) * idx;
			if	(kee < 1)
			{
				ex = clip_rect->ex;
				ey = dy * kee + sy;
			}

			if	(sx > clip_rect->ex)
				return;

			float	kss = (clip_rect->sx - sx) * idx;
			if	(kss > 0)
			{
				sx = clip_rect->sx;
				sy += dy * kss;
			}
			dx = ex - sx; dy = ey - sy;
		}
		else
			if	((sx < clip_rect->sx) || (sx > clip_rect->ex))
				return;

		if	(dy)
		{
			// Flip line if it is going backward.
			if	(dy < 0)
			{
				__SwapFloat(sx, ex)
				__SwapFloat(sy, ey)
				dx = ex - sx; dy = ey - sy;
			}
			float	idy = 1 / dy;

			// Clip on Y axis.
			if	(ey < clip_rect->sy)
				return;

			float	kee = (clip_rect->ey - sy) * idy;
			if	(kee < 1)
			{
				ey = clip_rect->ey;
				ex = dx * kee + sx;
			}

			if	(sy > clip_rect->ey)
				return;

			float	kss = (clip_rect->sy - sy) * idy;
			if	(kss > 0)
			{
				sy = clip_rect->sy;
				sx += dx * kss;
			}
			dx = ex - sx; dy = ey - sy;
		}
		else
			if	((sy < clip_rect->sy) || (sy > clip_rect->ey))
				return;
	}

	// Draw line.
	if	(Types::Abs(dy) > Types::Abs(dx))
	{
		if	(dy < 0)
		{
			dy = -dy; dx = -dx;
			float	swp = ey;
			ey = sy; sy = swp; sx = ex;
		}

		float slope = dy ? dx / dy : 0.f;
		for	(; sy < ey; sy += 1.f)
		{
			if	(hq)
					DrawPlotHQ(sx, sy, r, g, b, a);
			else	DrawPlot(sx, sy, r, g, b, a);
			sx += slope;
		}
	}
	else
	{
		if	(dx < 0)
		{
			dx = -dx; dy = -dy;
			float	swp = ex;
			ex = sx; sx = swp; sy = ey;
		}

		float slope = dx ? dy / dx : 0.f;
		for	(; sx < ex; sx += 1.f)
		{
			if	(hq)
					DrawPlotHQ(sx, sy, r, g, b, a);
			else	DrawPlot(sx, sy, r, g, b, a);
			sy += slope;
		}
	}
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void		Picture::DrawLine(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
{	LowLevelDrawLine(false, sx, sy, ex, ey, r, g, b, a, clip_rect);		}
void		Picture::DrawLineHQ(float sx, float sy, float ex, float ey, float r, float g, float b, float a, const Rect <float> *clip_rect)
{	LowLevelDrawLine(true, sx, sy, ex, ey, r, g, b, a, clip_rect);		}
//------------------------------------------------------------------------------
