/****************************************************************************************

		I3dExCamera.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		I3DExCamera definition

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		07/09/99	Guillaume	Removed unused Clip3D() and ClipLine3D() methods
		08/26/99	cph			Added family ids
		08/06/99	cph			modified interface to inherit from IMCUnknown instead of DataExchanger
		03/09/99	EricG		Set scale for isometric cameras
		10/20/98	Alec		revised camera interfaces

*****************************************************************************************/

#ifndef __I3DEXCAMERA__
#define __I3DEXCAMERA__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"
#include "IExtension.h"
#include "I3DShCamera.h"	// need this for APIStandardCameraInfo
#include "InterfaceIDs.h"

//****** Globally Unique Ids *************************************************

MCDEFINE_GUID2	(IID_I3DExCamera, R_IID_I3DExCamera);

//****** Family Id *************************************************

const FourCharT kCameraFamilyID = kRID_CameraFamilyID;

/*****************************************************************************\
*  I3DExCamera                                                                *
*                                                                             *
*  Cameras                                                                    *
*                                                                             *
\*****************************************************************************/

/// \addtogroup ExternalInterface
/// \{

/// <P>Cameras define the projection from the 3D world to the 2D screen on which the image
/// is rendered. There are two common forms of projection: orthographic and perspective.  
/// An orthographic camera takes rays parallel to the z-axis and projects them on the x-y 
/// plane by removing z.</P>
///
/// <P>A perspective camera takes all rays coming to a point and intersects those rays with a
/// plane some distance from the point. The distance to this plane is the focal length.  As
/// with a real camera, it is possible to implement various lenses, focal values, zoom effects, etc. 
/// Projection is not restricted to the conical projection (the natural projection in your eye),
/// so isometric or fish-eye cameras can be designed.</P>
///
/// <P>There are three basic methods.  Project3DTo2D() is used to create the projection from 3D space
/// onto the screen. This call is used by the hybrid raytracer.  The two CreateRay() function calls
/// create a 3D ray from a screen point. These calls are used for the ray-tracing.
/// (You need to implement both CreateRay() calls.)</P>
///
/// <P>For your camera to be used by the interactive renderer, you must implement GetStandardCameraInfo().
/// For performance reasons, the interactive renderer requires a standard isometric or canonical camera.
/// The parameters for this standard camera are supplied by GetStandardCameraInfo().</P>
///
/// <P>There are two interfaces to access a component: The shell interface (ISh. or I3DSh.) and
/// the external interface (IEx. or I3DEx.)</P>
///
/// <P>The structure of a camera is a little bit more complex that the typical component:
/// There are 2 COM objects to consider:</P>
///  - The <B>Camera Instance</B> that supports I3DShCamera, I3DShInstance and I3DShTreeElement.
///  - The <B>Camera Component</B> that supports IShComponent, IExCamera and I3DShTreeElementMember
///
/// <P>For advanced users: You should note that there are actually 3 C++ object (The camera instance,
/// the camera component and the external camera). However the camera component and the external
/// camera are aggregated by COM which means that you can be considered as one single COM object).
///
/// <P>To get a pointer to a I3DShCamera from a I3DExCamera, you can use the following code:</P>
///
/// \code
///
/// TMCCountedPtr<I3DShTreeElementMember> cameraComponent;
/// exCamera->QueryInterface(IID_I3DShTreeElementMember,(void**)&cameraComponent);
/// ThrowIfNil(cameraComponent);
///
/// TMCCountedPtr<I3DShTreeElement> cameraTree;
/// cameraComponent->GetTreeElement(&cameraTree);
/// ThrowIfNil(cameraTree);
///
/// TMCCountedPtr<I3DShCamera> shCamera;
/// cameraTree->QueryInterface(IID_I3DShCamera.(void**)&shCamera);
///
/// \endcode
///
/// <P>To access I3DExCamera from I3DShCamera, you can use the following code: </P>
///
/// \code
///
/// TMCCountedPtr<IShComponent> cameraComponent;
/// shCamera->GetCameraComponent(&cameraComponent);
/// ThrowIfNil(cameraComponent);
///
/// TMCCountedPtr<I3DExCamera> exCamera;
/// cameraComponent->QueryInterface(IID_I3DExCamera,(void**)&exCamera);
///
/// \endcode
///
/// <P>This code might seem a bit complicated at first but it is actually simple. You have two COM objects
/// that point on each other. I3DShCamera::GetCameraComponent() and I3DShTreeElementMember::GetTreeElement()
/// allow you to get a pointer from one object to the other. The rest is only calling QueryInterface to get
/// the right interface on each object.</P>
///
/// <P>Whenever it is possible you should use the Shell interface (I3DShCamera) to access the camera
/// because the Shell will make sure that the parameter map of the external component is valid.
/// This is especially important if the component is animated. For more information on components
/// see the Overview of the SDK.</P>
///
/// \see I3DShCamera
///
struct I3DExCamera: public IMCUnknown
{
	/// Gives the camera its global transform. This can be used to create a cache to speed
	/// up the calculation in CreateRay for instance.
	///
	/// \param transform	A reference to the Global Transform of the camera. You should not keep
	///						a pointer but copy it.
	///
	virtual MCCOMErr MCCOMAPI SetTransform		(const TTransform3D& transform ) = 0;
	
	/// Generates a ray through a given screen location. Note that in this case the ray has no width.
	/// To get a ray with a width you should use the next call.
	///
	/// \param screenPosition	The position in screen coordinates.
	/// \param worldOrigin		The origin of the ray that is returned.
	/// \param worldDirection	The direction of the ray that is returned.
	///
	virtual boolean	MCCOMAPI CreateRay			(const TVector2& screenPosition, TVector3& worldOrigin, TVector3& worldDirection) const = 0;
	
	/// Generates a ray through a given screen location with a given thickness (screenDerivate).
	///
	/// \param screenPosition	The position in screen coordinates.
	/// \param screenDerivate	The delta of the position in screen coordinates (the derivate of the ray should be proportional to that).
	/// \param ray				The ray that is returned.
	///
	virtual boolean MCCOMAPI CreateRay			(const TVector2& screenPosition, const TVector2& screenDerivate, Ray3D& ray) const = 0;

	/// Returns true if the projection is affine (if w component from projection is always 1.0)
	///
	virtual boolean MCCOMAPI IsProjectionAffine	(void) const = 0;

	/// \deprecated Do not implement this method.
	///
	virtual boolean MCCOMAPI PreProject3DTo2D	(const TVector3& cameraPosition, TVector4& projectedPosition ) const = 0;

	/// Projects a point on the screen.
	///
	/// \param cameraPosition The point to project on the screen. (in Camera Coordinates)
	/// \param screenPosition The projection on the screen, the third coordinates is the z coordinates of the point in camera coordinates.
	///
	/// \return true if the point has a projection on the screen, false otherwise.
	///
	virtual boolean MCCOMAPI Project3DTo2D		(const TVector3& cameraPosition, TVector3& screenPosition ) const = 0;
								
	/// Returns an identificator for the camera.
	///
	virtual uint32 MCCOMAPI	GetPrimitiveID		() const = 0;
	
	/// Returns the standard camera info used in the interactive renderers (in the 3D View). For
	/// perfomance reasons the interactive renderers use this function to get an approximation
	/// of the camera that is used to perform the rendering.
	///
	/// \param cameraInfo A reference to a structure where the definition of the camera is stored.
	///
	virtual void MCCOMAPI GetStandardCameraInfo	(TStandardCameraInfo& cameraInfo) const = 0;

	/// Sets the half width of a camera
	/// (Used by modelers)
	///
	virtual MCCOMErr MCCOMAPI SetHalfWidth		(real value) = 0;

	/// Sets the near clipping plane of the camera 
	///
	virtual MCCOMErr MCCOMAPI SetNearPlane		(real32 value) = 0;

	/// Notifies the camera of the screen coordinates bounding box that is going to be used during the rendering.
	/// The Camera should store that information and use it if needed in CreateRay()/PreProject3DTo2D()/Project3DTo2D()
	/// So far only the spherical camera needs this
	///
	/// \param inUVBox	The extent of the screen.
	///
	virtual void	 MCCOMAPI SetRenderingUVBox		(	const TBBox2D& inUVBox) = 0;


	// ****************************************************************************
	//							InitDepthOfField	
	// 
	/// Inits the depth of field at the beginning of the rendering of a frame.
	/// Returns true if the camera has depth of field enabled.
	///
	virtual boolean	 MCCOMAPI InitDepthOfField		(int32& samplingQuality ) = 0;
		
	// ****************************************************************************
	//								CreateRay
	// 
	/// Creates a ray for depth of field rendering. Note that you should call
	/// InitDepthOfField() first (and for every frame)
	///
	/// \param screenPosition	The position in screen coordinates.
	/// \param screenDerivate	The delta of the position in screen coordinates (the derivate of the ray should be proportional to that).
	/// \param lensPosition		The position on the lens (in [0,1]x[0,1])
	/// \param ray				The ray that is returned.
	///
	virtual boolean MCCOMAPI CreateRay				(const TVector2&	screenPosition,
													 const TVector2&	screenDerivate,
													const TVector2&	lensPosition,	// for depth of field
													Ray3D&				ray) = 0;

	// ****************************************************************************
	//								GetScalingFactor
	// 
	/// Returns the scaling that should be applied to the object, i.e. the
	/// number of inches in the primitive's unit.
	/// 
	virtual real32	MCCOMAPI GetScalingFactor() const = 0;

	// ****************************************************************************
	//								SetScalingFactor
	// 
	///  Sets the scaling factor of the object
	///
	/// \param inValue	the number of inches to which the primitive's unit is 
	///					equivalent
	/// 
	virtual void	MCCOMAPI SetScalingFactor(real32 inValue) = 0;
};


/// \}

#endif