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


		#include "picture/pict.h"
		#include "color/color.h"

		using namespace GS;


//------------------------------------------------------------------------------
bool				Picture::Resize(uint nwidth, uint nheight)
{
	if	(!nwidth && !nheight)
		return false;

	if	(!nwidth)
		nwidth = (GetWidth() * nheight) / GetHeight();
	if	(!nheight)
		nheight = (GetHeight() * nwidth) / GetWidth();

	if	((nwidth == GetWidth()) && (nheight == GetHeight()))
		return true;

	if	(pxformat.IsReal())
	{
		float *new_data = (float *)AllocMemory(sizeof(float) * nwidth * nheight * 3);
		if	(!new_data)
			return false;

		float *pdst = (float *)new_data;
		float ku = 1.f / (float)nwidth,
			  kv = 1.f / (float)nheight;

		Color out;

		float v = kv * 0.5f - 0.5f / height;
		if	(data)
			for	(uint y = 0; y < nheight; ++y)
			{
				float u = ku * 0.5f - 0.5f / width;
				for	(uint x = 0; x < nwidth; ++x)
				{
					Sample(u, v, out);
					pdst[0] = out.x;
					pdst[1] = out.y;
					pdst[2] = out.z;
					pdst += 3;
					u += ku;
				}
				v += kv;
			}

		SetData(new_data, nwidth, nheight, PixelFormat::RGBAF, true);
		//SetData(new_data, nwidth, nheight, PixelFormat::RGBF, true);
	}
	else	if	(GetBpp() == 32)
	{
		uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4);
		if	(!new_data)
			return false;

		uint *pdst = (uint*)new_data;
		float ku = 1.f / (float)nwidth,
			  kv = 1.f / (float)nheight;

		float v = kv * 0.5f - 0.5f / height;
		if	(data)
			for	(uint y = 0; y < nheight; ++y)
			{
				float u = ku * 0.5f - 0.5f / width;
				for	(uint x = 0; x < nwidth; ++x)
				{
					Sample(u, v, *pdst++);
					u += ku;
				}
				v += kv;
			}

		SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true);
	}
	else
		return false;

	return true;
}
bool				Picture::Downscale(uint nwidth, uint nheight)
{
	if	(!nwidth && !nheight)
		return false;

	if	(!nwidth)
		nwidth = (GetWidth() * nheight) / GetHeight();
	if	(!nheight)
		nheight = (GetHeight() * nwidth) / GetWidth();

	if	((nwidth > GetWidth()) || (nheight > GetHeight()))
		return Resize(nwidth, nheight);

	if	(GetBpp() == 32)
	{
		uchar *new_data = (uchar *)AllocMemory(sizeof(uchar) * nwidth * nheight * 4);
		if	(!new_data)
			return false;

		uchar *pdst = new_data;
		Array <float> accu(nwidth * 4);

		if	(accu)
		{
			float ku = (float)GetWidth() / (float)nwidth,
				  kv = (float)GetHeight() / (float)nheight;
			float u, v;

			//
			v = 0.f;

			// Accumulate scan lines.
			uchar *psrc = GetData();

			for	(uint y = 0; y < nheight; y++)
			{
                uint n;
				for	(n = 0; n < (nwidth * 4); n++)
					accu[n] = 0.f;

				float tv = kv, nv = kv;

				for	(;;)
				{
					float k = GS::Math::Ceil(v) - v;
					tv -= k;
					if	(tv < 0.f)
						k += tv;			// readjust
					v += k;

					if	(v >= GetHeight())
					{
						nv -= k;
						break;
					}

					//
					u = 0.f;

					// Accumulate texels.
					uchar *lsrc = psrc;
					float *paccu = accu;
					float texel[4];

					for	(uint x = 0; x < nwidth; x++)
					{
						for	(n = 0; n < 4; n++)
							texel[n] = 0.f;

						float tu = ku, nu = ku;

						for	(;;)
						{
							float k = GS::Math::Ceil(u) - u;
							tu -= k;
							if	(tu < 0.f)
								k += tu;			// readjust
							u += k;

							if	(u >= GetWidth())
							{
								nu -= k;
								break;
							}

							for	(n = 0; n < 4; n++)
								texel[n] += (float)(lsrc[n]) * k;

							if	(tu < 0.f)
								break;

							lsrc += 4;
						}

						tu = k / nu;
						for	(n = 0; n < 4; n++)
							paccu[n] += texel[n] * tu;
						paccu += 4;
					}
					if	(tv < 0.f)
						break;

					psrc += GetWidth() * 4;
				}

				tv = 1.f / nv;
				for	(n = 0; n < (nwidth * 4); n++)
					pdst[n] = (uchar)(accu[n] * tv);
				pdst += nwidth * 4;
			}

			SetData(new_data, nwidth, nheight, GetPixelFormat().GetDesc(), true);
			return true;
		}
	}
	return false;
}
//------------------------------------------------------------------------------
