module vs.action.camera;



private import std.math;
private import std.cstream;
private import gedo.video.ggl;
private import gedo.math.direction;
private import vs.action.task;



private enum Mode
{
	TPS,
	FOCUS,
}



alias void delegate(Vector p, Vector v, out float lz) GetEye;



public class Camera : ActionTask
{
public:
	static this()
	{
		NEAR = (sqrt(DY*DY + DZ*DZ) - 2.0)*4.0;
	}


	this(GetEye dg)
	{
		_position[] = 0.0;

		_direction  = new Direction();

		_getEye     = dg;

		_mode       = Mode.TPS;
	}


	void focus(GetEye dg)
	{
		_getEye = dg;

		_mode = Mode.FOCUS;
	}


	override void update()
	{
		Vector pn;
		Vector dn;

		switch(_mode)
		{
		case Mode.TPS:
			{
				float  lz;

				_getEye(pn, dn, lz);

				//Vector pn = (0.5*u[]) - f[];
				Vector a;

				_direction.toVector(0.0, DY*lz, DZ*lz, a);

				.gedo.math.vector.add(pn, a);
			}
			break;

		case Mode.FOCUS:
			{
				Vector a;
				float  lz;

				_getEye(pn, a, lz);

				.gedo.math.vector.subtract(dn, pn, _position);
				.gedo.math.vector.normalize(dn);

				//Vector pn = _target.position[] - (h*dn[]);
				.gedo.math.vector.multiply(a, dn, -4.0*lz);

				.gedo.math.vector.add(pn, a);
			}
			break;
		}

		_direction.homing(dn, .std.math.PI/64.0);

		.gedo.math.vector.lerp(_position, pn, 4.0);
	}


	override void draw()
	{
		Vector eye;

		_direction.getFront(eye);

		Vector u;

		_direction.getUp(u);

		switch(_mode)
		{
		case Mode.TPS:
			{
				//eye[] = f[] - (tan(FOV*0.5*.std.math.PI/180.0) * u[]);

				Vector a;

				.gedo.math.vector.multiply(a, u, -7.0/8.0*tan(FOV*0.5*.std.math.PI/180.0));

				.gedo.math.vector.add(eye, a);
			}
			break;

		case Mode.FOCUS:
			break;
		}

		Vector vt;
		
		.gedo.math.vector.add(vt, _position, eye);

		GGL_setPerspective(FOV, NEAR, 1000.0);

		GGL_lookAt(_position.ptr, vt.ptr, u.ptr);
	}


	void toWorld(Vector2D a, Vector b)
	{
		Vector front;

		_direction.getFront(front);

		auto c = a[1];
		auto s = -a[0];

		b[0] = front[0]*c - front[1]*s;
		b[1] = front[0]*s + front[1]*c;
		b[2] = 0.0;

		.gedo.math.vector.normalize(b);
	}


	bool isEye(GetEye e)
	{
		return _getEye is e;
	}


	const float FOV = 60.0;
	const float DY  = -3.25;
	const float DZ  =  1.75;
	static double NEAR = 0.0;


	/*
	~this()
	{
		dout.writefln("FOV, DY, DZ = %f, %f, %f", FOV, DY, DZ);
	}
	*/


private:
	Direction _direction;
	GetEye    _getEye;
	Vector    _position;
	Mode      _mode;
}
