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


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

		using namespace GS;


//------------------------------------------------------------------------------
void				Picture::Sample(float u, float v, Color &out, uint _w, uint _h) const
{
	if	(!GetData())
	{
		out.Set(1, 0, 1);
		return;
	}

	if	(!GetPixelFormat().IsReal())
	{
		uint _out;
		Sample(u, v, _out, _w, _h);
		out.FromInteger(_out);
	}
	else
	{
		if	(!_w) _w = GetWidth();
		if	(!_h) _h = GetHeight();
		u *= _w; v *= _h;

		if	(u < 0) u = 0;
		if	(v < 0) v = 0;
		if	(u >= _w) u = (float)(_w - 1);
		if	(v >= _h) v = (float)(_h - 1);

		uint iu = (uint)u, iv = (uint)v;

		Color sample[4];

		float *pdata = (float *)GetData();
		pdata += (iu + iv * _w) * 3;

		//---------------------------------------
		#define		EXTRACT_FSAMPLE(_S_, _P_)	\
		{										\
			(_S_).z = (_P_)[2];					\
			(_S_).y = (_P_)[1];					\
			(_S_).x = (_P_)[0];					\
		}
		//---------------------------------------

		EXTRACT_FSAMPLE(sample[0], pdata + 0);
		if	(iu < (_w - 1))
				EXTRACT_FSAMPLE(sample[1], pdata + 3)
		else	sample[1] = sample[0];
		if	(iv < (_h - 1))
				EXTRACT_FSAMPLE(sample[2], pdata + _w * 3)
		else	sample[2] = sample[0];
		if	((iu < (_w - 1)) && (iv < (_h - 1)))
				EXTRACT_FSAMPLE(sample[3], pdata + (_w + 1) * 3)
		else	sample[3] = sample[0];

		// Bilinear sample.
		float k[4], uf = u - (float)iu, vf = v - (float)iv;

		k[0] = (1.f - uf) * (1.f - vf);
		k[1] = uf * (1.f - vf);
		k[2] = (1.f - uf) * vf;
		k[3] = uf * vf;

		out = sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3];
		out.w = sample[0].w * k[0] + sample[1].w * k[1] + sample[2].w * k[2] + sample[3].w * k[3];
	}
}
void				Picture::Sample(float u, float v, uint &out, uint _w, uint _h) const
{
	if	(!GetData())
	{
		out = 0xffff00ff;
		return;
	}

	if	(GetPixelFormat().IsReal())
	{
		Color _out;
		Sample(u, v, _out, _w, _h);
		out = _out.AsInteger();
	}
	else
	{
		if	(!_w) _w = GetWidth();
		if	(!_h) _h = GetHeight();
		u *= _w; v *= _h;

		if	(u < 0) u = 0;
		if	(v < 0) v = 0;
		if	(u >= _w) u = (float)(_w - 1);
		if	(v >= _h) v = (float)(_h - 1);

		uint iu = (uint)u, iv = (uint)v;

		struct	iVector
		{
			int x, y, z, w;

			iVector		operator + (const iVector &b) const
			{	return iVector(x + b.x, y + b.y, z + b.z, w + b.w);	}
			iVector		operator * (const int v) const
			{	return iVector(x * v, y * v, z * v, w * v);	}
			iVector		operator >> (const int v) const
			{	return iVector(x >> v, y >> v, z >> v, w >> v);	}

			iVector(int _x, int _y, int _z, int _w = 255)
			{	x = _x; y = _y; z = _z; w = _w;	}
			iVector()
			{}
		};
		iVector sample[4];

		uint *pdata = (uint *)GetData();
		pdata += iu + iv * _w;

		//----------------------------------------------------------------------
		#define	EXTRACT_SAMPLE(_S_, _P_)										\
		{																		\
			const uchar	*_t_p = (const uchar *)&(_P_);							\
			(_S_).x = _t_p[0];													\
			(_S_).y = _t_p[1];													\
			(_S_).z = _t_p[2];													\
			(_S_).w = _t_p[3];													\
		}
		//----------------------------------------------------------------------

		EXTRACT_SAMPLE(sample[0], pdata[0]);
		if	(iu < (_w - 1))
				EXTRACT_SAMPLE(sample[1], pdata[1])
		else	sample[1] = sample[0];
		if	(iv < (_h - 1))
				EXTRACT_SAMPLE(sample[2], pdata[_w])
		else	sample[2] = sample[0];
		if	((iu < (_w - 1)) && (iv < (_h - 1)))
				EXTRACT_SAMPLE(sample[3], pdata[_w + 1])
		else	sample[3] = sample[0];

		int k[4], uf = int((u - (float)iu) * 256), vf = int((v - (float)iv) * 256);

		k[0] = (256 - uf) * (256 - vf);		// 16bit fixed point.
		k[1] = uf * (256 - vf);
		k[2] = (256 - uf) * vf;
		k[3] = uf * vf;

		iVector r = (sample[0] * k[0] + sample[1] * k[1] + sample[2] * k[2] + sample[3] * k[3]) >> 16;

		uchar *_out = (uchar *)&out;
		_out[0] = (uchar)r.x;
		_out[1] = (uchar)r.y;
		_out[2] = (uchar)r.z;
		_out[3] = (uchar)r.w;
	}
}
void				Picture::SampleRGBA(float u, float v, Color &o, uint _w, uint _h) const
{
	Color s;
	Sample(u, v, s, _w, _h);

	o[0] = s[pxformat.rshift >> 3];
	o[1] = s[pxformat.gshift >> 3];
	o[2] = s[pxformat.bshift >> 3];
	o[3] = s[pxformat.ashift >> 3];
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
uint				Picture::SampleInteger(float u, float v, uint _w, uint _h) const
{	uint s; Sample(u, v, s, _w, _h); return s;	}
Color				Picture::SampleColor(float u, float v, uint _w, uint _h) const
{	Color s; Sample(u, v, s, _w, _h); return s;	}
Color				Picture::SampleRGBAColor(float u, float v, uint _w, uint _h) const
{	Color s; SampleRGBA(u, v, s, _w, _h); return s;	}
//------------------------------------------------------------------------------
