///////////////////////////////////////////////////////////////////////////////
/// @file deCamera.hpp
///
/// @brief Viewport & Rendering Data
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jan 2002
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DECAMERA_HPP
#define DECAMERA_HPP

#include "deGlobalTypes.hpp"
#include "deMath.hpp"
#include "deScene.hpp"

#define DECAMERA_API DESCENE_API

class IdeCamera;
class IdePlaneFrustum;

// factory functions
/// Create an instance of IdeCamera
DECAMERA_API IdeCamera * IdeCamera_CreateCamera();
DECAMERA_API IdeCamera * IdeCamera_CreateCameraFromRef(IdeCamera* ref);
/// Create an instance of IdePlaneFrustum
DECAMERA_API IdePlaneFrustum * IdeFrustum_CreatePlaneFrustum();

typedef IdeCamera * (*fIdeCamera_CreateCamera)();
typedef IdeCamera * (*fIdeCamera_CreateCameraFromRef)(IdeCamera* ref);

/// Essentially a storage class to interface deRender & deScene - stores things related to the screen view.
/// Related functions: IdeCamera_CreateCamera
//class IdeCamera
DE3D_INTERFACE_(IdeCamera)
{
protected:
	virtual ~IdeCamera(void) {}
public:
	/// deletes the object
	virtual long Release() = 0;

	/// Match the camera with a window handle. Multiple cameras may share a window handle
	virtual void SetWindow(HWND window) = 0;
	/// Set the client rect of the camera's viewport, which the scene will be rendered into
	virtual void SetRect(deRect rect) = 0;
	/// Set the horizontal Field-of-View of the camera, in degrees
	virtual void SetFOV(deDouble Degrees) = 0;
	/// Set the screen aspect ratio (AspectRatio = 4/3 or 16/9, defaults to 4/3)
	virtual void SetScreenAspect(long PixelWidth, long PixelHeight, deDouble AspectRatio) = 0;
	/// Set the near and far clip planes of the camera's viewport
	virtual void SetClip(deDouble Near, deDouble Far) = 0;
	virtual void FogEnable(deBoolean Enable) = 0;
	virtual void SetFog(deFloat Near, deFloat Far, deARGB Color, deBoolean RangeFog = deFALSE) = 0;
	/// Set the width of the camera, if it will be an orthographic projection
	virtual void SetOrthoWidth(deDouble Width) = 0;
	/// Enable or disable an orthographic (parallel) projection mode
	virtual void EnableOrtho(deBoolean OrthoEnable) = 0;
	/// Build a frustum from this camera based on its rect and transform
//	virtual void BuildRootFrustum(deFrustum &f) = 0;
	/// Build a frustum from this camera based on its rect and transform
	virtual deBoolean BuildRootFrustum(IdePlaneFrustum * pFrustum) = 0;
	/// Retrieve a vector in world-space corresponding to a screen position.
	/// @return a vector (with Z=1) pointing from the camera's translation along the
	///          ray that coincides with the point selected on the near clip plane
	/// @param a pointer to a vector in which to store the start point of the ray
	virtual deVec3d ScreenPointToWorldVec(int x, int y, deVec3d *StartPosition) = 0;
	/// Transforms a 3D world position into an (x,y) pair on the screen
	virtual deBoolean WorldPosToScreenPos(const deVec3d &pos, int &x, int &y) = 0;
	/// Clips a screen rect to the input frustum
	/// @return deTrue if successful, deFalse otherwise
	/// @param Frustum a valid deFrustum object to be used in clipping a screen-rect
	/// @param ScreenRect a deRect filled with valid screen positions, to be clipped down to
	///                   the screen-size of Frustum
//	virtual deBoolean FrustumRect(const deFrustum & Frustum, deRect & ScreenRect) = 0;
	virtual deBoolean FrustumRect(const IdePlaneFrustum * pFrustum, deRect & ScreenRect) = 0;

	/// Retrieve the associated window handle
	virtual HWND GetWindow() = 0;
	/// Retrieve the screenrect the camera is using
	virtual deRect GetRect() = 0;
	/// Retrieve the horizontal Field-of-View of the camera, in degrees
	virtual deDouble GetFOV() = 0;
	/// Retrieve the vertical Field-of-View of the camera, in radians
	/// @param Aspect the aspect ratio of the viewport being used. (Aspect = Width/Height).
	///               This will be filled with the current "Locked" Aspect if one is set
	virtual deDouble GetFOVy(deDouble &Aspect) = 0;
	/// Retrieve the near clip plane distance
	virtual deDouble GetNearClip() = 0;
	/// Retrieve the far clip plane distance
	virtual deDouble GetFarClip() = 0;
	/// Retrieve the orthogrpahic width of the camera
	virtual deDouble GetOrthoWidth() = 0;
	/// Tell whether the camera is using an orthographic projection or not
	/// @return deTrue if an orthographic projection is in use
	virtual deBoolean IsOrtho() = 0;
	virtual deBoolean GetFog(deFloat& Near, deFloat& Far, deARGB& Color, deBoolean& RangeFog) = 0;

	/// Used to lock the aspect of a camera in order to cause a distorted image to render.
	/// The return value from GetFOVy will be unaffected by the Aspect actually fed to it.
	/// @param Aspect An aspect ratio to lock the camera into using. Use a negative value to unlock.
	virtual void LockAspect(deDouble Aspect) = 0;

	/// The current transformation of the camera
	/// @return a reference to the camera's internal transform, instead of a Get/Set pair.
	virtual deTransformInfo & Position() = 0;
};

/// class for storing a view frustum with arbitrary planes forming a convex view volume.
/// Related functions: IdeFrustum_CreatePlaneFrustum.
//class IdePlaneFrustum
DE3D_INTERFACE_(IdePlaneFrustum)
{
protected:
	virtual ~IdePlaneFrustum() {}
public:
	virtual long Release() = 0;

	virtual deBoolean CreateFromPolygon(const deVec3d * PointArray, long NumPoints, const deVec3d & Position) = 0;
	virtual deBoolean CopyFromFrustum(const IdePlaneFrustum* Ref) = 0;

	virtual deBoolean Optimize() = 0;

	virtual deBoolean IsOrtho() const = 0;
	virtual void SetOrtho(deBoolean Ortho) = 0;

	virtual u32  GetNumPlanes() const = 0;
	virtual void SetNumPlanes(u32 NumPlanes) = 0;

	virtual void AddPlane(const dePlane & plane) = 0;

	virtual void GetPlane(u32 index, dePlane & plane) const = 0;
	virtual void SetPlane(u32 index, const dePlane & plane) = 0;

	virtual void SetInVec(const deVec3d & InVec) = 0;
	virtual void SetPosVec(const deVec3d & PosVec) = 0;
	virtual void SetDists(const deDouble & Min, const deDouble & Max) = 0;
	virtual deDouble GetMinDist() const = 0;
	virtual deDouble GetMaxDist() const = 0;

	virtual deBoolean TestSphereInside(const deBoundSphere& Sphere, const deVec3d& WorldPos, deBoolean & AllInside) const = 0;
	virtual deBoolean TestAABBInside(const deAABB& BBox, const deVec3d& WorldPos, deBoolean & AllInside) const = 0;
};

#endif
