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


#ifndef	__NCAMERA__
#define	__NCAMERA__


		#include "core/item.h"
		#include "geometry/frustum.h"
		#include "geometry/rect.h"


namespace GS {
	namespace Core {
		class Light;

/*!
	@short	Camera.

	- World space:
		Described by the world_matrix,
		transform from object space to world space.<br>
	- Camera space:
		Described by the camera_matrix,
		transform from world space to camera space.<br>
	- Projection matrix:
		Transform from a given space (usually camera space)
		to a 2D orthonormal space.<br>
	- View matrix:
		Transform from the 2D orthonormal space
		to the view (screen) space.<br>

	This class is not managed, the user is responsible for freeing it.
	For a managed implementation please see S3D::Scene::nMCamera.

	@author Emmanuel Julien (ejulien@gsworks.fr)
*/
class	Camera : public Item
{
public:
/*!
	@name	Aspect ratio system.

	@note	On a 16/9 display using a PC resolution the display	is stretched
			horizontally to fill the whole display area, in such case calling
			using ASPECTRATIO_16_9 as the aspect ratio correction will shrink
			the render to compensate for the distortion.
	@{
*/
		/// Compute the aspect ration based on the output dimensions.
#define	AR_Auto							(-1.f)
#define	AR_Square						(1.f)

#define	AR_Television					(1.33f)
#define	AR_Pc							AR_Television
#define	AR_35mm							(1.37f)
#define	AR_Widescreen					(1.78f)
#define	AR_EuropeanTheatricalStandard	(1.66f)
#define	AR_AmericanTheatricalStandard	(1.85f)
#define	AR_AnamorphicWidescreen			(2.35f)

		float			aspect_ratio;				///< Aspect ratio horizontal correction.
		bool			aspect_ratio_ref_yaxis;		///< Reference (fixed) axis for aspect ratio correction.

		/// Compute the current aspect ratio correction coefficients.
		Vector4			ComputeAspectRatioCorrection(const fRect &viewport, float global_ar = 1.f) const;
/// @}

		/// Setup render object.
virtual	void			RenderSetup(ResourceFactories * = 0) {}

		/// Convert from world coordinate to normalized screen coordinate.
		bool			WorldToScreen(const fRect &viewport, const Vector4 &in, Vector4 &out, bool normalize = true);
		/// Convert from normalized screen coordinate to world.
		Vector4			ScreenToWorld(const fRect &viewport, float x, float y, float z = 1, float ar = -1);

		/// Compute camera projection matrix.
		void			ComputeProjectionMatrix(const fRect &viewport, Matrix4 &m) const;
		/// Compute camera view frustum.
		void			ComputeFrustum(Frustum &, const fRect &viewport, float z_near = -1, float z_far = -1) const;

		/// Adjust this camera so that its viewport matches the viewport of a given light.
		void			AlignTo(const Light &);

		/// Compute world hierarchy matrix.
virtual	void			ComputeMatrix();

		/// Get near clipping plane.
		float			GetNearClippingPlane() const { return z_near; }
		/// Get far clipping plane.
		float			GetFarClippingPlane() const { return z_far; }
		/// Set near clipping plane.
		void			SetNearClippingPlane(float z) { z_near = z; }
		/// Set far clipping plane.
		void			SetFarClippingPlane(float z) { z_far = z; }

		/// Set the camera zoom factor, relative to z = 1 meter.
		void			SetZoomFactor(float zf = Units::Mtr(1.9f));
		/*!
			@short	Set the camera field of view.
			@note	FOV must be in the [Deg(0),Deg(180)[ range.
			@see	GetFov().
		*/
		void			SetFov(float fov = Units::Deg(60));
		/*!
			@short	Get camera fov.

			@note	This value is converted on the fly from the current zoom factor.
					If you need it frequently and as this class only store fov as the
					zoom factor you may want to cache the fov value in your application
					to avoid possible numerical drift.
		*/
		float			GetFov() const;

		/// Set viewport (all values in range [0,1]).
		void			SetViewport(float origin_x, float origin_y, float width, float height);

		Frustum			frustum;					///< View frustum.
		float			z_near;						///< Z near clipping plane.
		float			z_far;						///< Z far clipping plane.

		bool			is_orthographic;			///< Is the camera using an orthographic projection.
		float			ortho_w;					///< Orthographic view width.
		float			ortho_h;					///< Orthographic view height.

		float			zoom_factor;

		Matrix4		custom_projection;

		bool is_occulus_camera;
		float tan_up, tan_down, tan_left, tan_right;

/*!
	@name	Serialization.
	@{
*/
		bool			FromMetaTag(NML::Tag &);
		NML::Tag		*AsMetaTag();
/// @}

		Camera();
};

	} // Core
} // GS


#endif	//__NCAMERA__

