/*	kd:

	Here's how to do projections and deprojections. You'd use the subclasses
	to do anything worthwhile. You may project world to screen and backwards.

	*/

class dtLe_ProjScreen {

	// kd: Screen info
	protected vector2				resolution;
	protected vector2				origin;
	protected vector2				tan_fov_2;
	protected double				pixel_stretch;
	protected double				aspect_ratio;

	// kd: Setup calls which you'll need to call at least once.
	void CacheResolution () {
		CacheCustomResolution((Screen.GetWidth(), Screen.GetHeight()) );
	}

	void CacheCustomResolution (vector2 new_resolution) {

		// kd: This is for convenience and converting normal <-> screen pos.
		resolution = new_resolution;

		// kd: This isn't really necessary but I kinda like it.
		pixel_stretch = level.pixelstretch;

		// kd: Get the aspect ratio. 5:4 is handled just like 4:3... I GUESS
		// this'll do.
		aspect_ratio = max(4.0 / 3, Screen.GetAspectRatio());
	}

	double AspectRatio () const {
		return aspect_ratio;
	}

	// kd: Once you know you got screen info, you can call this whenever your
	// fov changes. Like CacheFov(player.fov) will do.
	void CacheFov (double hor_fov = 90) {

		// kd: This holds: aspect ratio = tan(horizontal fov) / tan(ver fov).
		// gzd always uses hor fov, but the fov only holds in 4:3 (in a 4:3 box
		// in your screen centre), so we just extend it.
		tan_fov_2.x	= tan(hor_fov / 2) * aspect_ratio / (4.0 / 3);
		tan_fov_2.y	= tan_fov_2.x / aspect_ratio;
	}

	// kd: Also need some view info. Angle is yaw, pitch, roll in world format
	// so positive pitch is up. Call one of the following functions.
	protected vector3				view_ang;
	protected vector3				view_pos;

	ui void OrientForRenderOverlay (RenderEvent event) {
		Reorient(
			event.viewpos, (
			event.viewangle,
			event.viewpitch,
			event.viewroll));
	}

	ui void OrientForRenderUnderlay (RenderEvent event) {
		Reorient(
			event.viewpos, (
			event.viewangle,
			event.viewpitch,
			event.viewroll));
	}

	void OrientForPlayer (PlayerInfo player) {
		Reorient(
			player.mo.vec3offset(0, 0, player.viewheight), (
			player.mo.angle,
			player.mo.pitch,
			player.mo.roll));
	}

	virtual void Reorient (vector3 world_view_pos, vector3 world_ang) {
		view_ang = world_ang;
		view_pos = world_view_pos;
	}

	// kd: Now we can do projections and such (position in the level, go to
	// your screen).
	protected double				depth;
	protected vector2				proj_pos;
	protected vector3				diff;

	virtual void	BeginProjection	() {}
	virtual void	ProjectWorldPos	(vector3 world_pos) {}
	virtual void	ProjectActorPos (
	Actor	mo,
	vector3	offset = (0,0,0),
	double	t = 1) {}

	// kd: Portal aware version.
	virtual void	ProjectActorPosPortal (
	Actor	mo,
	vector3	offset = (0,0,0),
	double	t = 1) {}

	virtual vector2	ProjectToNormal	() const { return (0, 0); }
	virtual vector2	ProjectToScreen	() const { return (0, 0); }

	virtual vector2 ProjectToCustom (
	vector2 origin,
	vector2 resolution) const {
		return (0, 0);
	}

	bool IsInFront () const {
		return 0 < depth;
	}

	bool IsInScreen () const {
		if(	proj_pos.x < -depth || depth < proj_pos.x ||
			proj_pos.y < -depth || depth < proj_pos.y) {
			return false;
		}

		return true;
	}

	// kd: Deprojection (point on screen, go into the world):
	virtual void	BeginDeprojection		() {}

	virtual vector3	DeprojectNormalToDiff	(
	vector2	normal_pos,
	double	depth = 1) const {
		return (0, 0, 0);
	}

	virtual vector3	DeprojectScreenToDiff	(
	vector2	screen_pos,
	double	depth = 1) const {
		return (0, 0, 0);
	}

	virtual vector3 DeprojectCustomToDiff (
	vector2	origin,
	vector2	resolution,
	vector2	screen_pos,
	double	depth = 1) const {
		return (0, 0, 0);
	}

	// kd: A normal position is in the -1 <= x, y <= 1 range on your screen.
	// This will be your screen no matter the resolution:

	/*

	(-1, -1) --	---	---	(0, -1) ---	---	---	---	(1, -1)
	|												|
	|												|
	|												|
	(-1, 0)				(0, 0)					(1, 0)
	|												|
	|												|
	|												|
	(-1, 1)	---	---	---	(0, 1)	---	---	---	---	(1, 1)

	*/

	// So this scales such a position back into your drawing resolution.

	vector2 NormalToScreen (vector2 normal_pos) const {
		normal_pos = 0.5 * (normal_pos + (1, 1));
		return (
			normal_pos.x * resolution.x,
			normal_pos.y * resolution.y);
	}

	// kd: And this brings a screen position to normal. Make sure the resolution
	// is the same for your cursor.

	vector2 ScreenToNormal (vector2 screen_pos) const {
		screen_pos = (
			screen_pos.x / resolution.x,
			screen_pos.y / resolution.y);
		return 2 * screen_pos - (1, 1);
	}

	// kd: Other interesting stuff.

	vector3 Difference () const {
		return diff;
	}

	double Distance () const {
		return diff.length();
	}
}
