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

		I3DShCamera.h

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

		I3DShCamera definition

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		08/09/99	Guillaume	Removed unused Clip3D() and ClipLine3D() methods
		04/15/99	Charles		Created ( remove dependencies)

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

#ifndef __I3DSHCAMERA__
#define __I3DSHCAMERA__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"
#include "Transforms.h"
#include "TBBox.h"
#include "ComTypes.h"
#include "Vector4Fwd.h"

struct I3DExCamera;
struct IShComponent;
struct Ray3D;
struct I3DShTreeElement;

class TMCPixelBucket;
class TMCPoint;

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

MCDEFINE_GUID(IID_I3DShCamera, 0xE76CA120L, 0x3A02, 0x101C, 0x88, 0x5F, 0x04, 0x02, 0x1C, 0x00, 0x70, 0x02);

// Classes always available
MCDEFINE_GUID(CLSID_StandardExternalCamera, 0x4ee334f4, 0x1624, 0x11d2, 0x84, 0x6a, 0x0, 0x60, 0x97, 0xb, 0xc5, 0x21);
MCDEFINE_GUID(CLSID_StandardConicalCamera, 0x2E971880L, 0x3A05, 0x101C, 0x88, 0x5F, 0x04, 0x02, 0x1C, 0x00, 0x70, 0x02);
MCDEFINE_GUID(CLSID_StandardIsometricCamera, 0x3063E940L, 0x3A05, 0x101C, 0x88, 0x5F, 0x04, 0x02, 0x1C, 0x00, 0x70, 0x02);

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


/*****************************************************************************\
*  I3DShCamera                                                                *
*                                                                             *
*    I3DShCamera defines the cameras as tree elements                         *
*    It can return a I3DShTreeElement interface on demand.                    *
*                                                                             *
\*****************************************************************************/

/// Preset codes for I3DShCamera::Preset()
///
enum ECameraPreset
{
	kReferencePreset,
	kTopPreset, 
	kBottomPreset, 
	kLeftPreset, 
	kRightPreset, 
	kFrontPreset,
	kBackPreset
};


/// Describes the projection type of a camera
///
enum EProjectionType
{
	kProjectionType_kOrthographic = 0,
	kProjectionType_kPerspective
};

/// Is the camera one of the predefined ortho views (left, top...) or not (kCanonicalCameraType_NotCanonical)
///
enum ECanonicalCameraType
{
	kCanonicalCameraType_NotCanonical=0,
	kCanonicalCameraType_Left,
	kCanonicalCameraType_Right,
	kCanonicalCameraType_Top,
	kCanonicalCameraType_Bottom,
	kCanonicalCameraType_Front,
	kCanonicalCameraType_Back,
	kCanonicalCameraType_UV
};

/// Describes a general camera using standard camera parameters
///
struct TStandardCameraInfo : public TMCObject
{
	EProjectionType			fProjectionType; 		///< can only be ortho or persp.
	ECanonicalCameraType	fCanonicalCameraType;	///< Is the camera one of the predefined ortho views (left, top...)
	real					fHalfWidthAtOneUnit;	///< for ortho/perspective cameras
	boolean					fIsMatching;			///< whether standard camera matches true camera
	real32					fNearPlane;				///< Distance to near plane
};


/// \addtogroup ShellInterface
/// \{

/// <P>Cameras define the projection from the 3D world to the 2D screen on which the image
/// is rendered.</P>
///
/// <P>The structure of a camera is a little bit more complex that the typical component. It is
/// similar to the structure of Lights and Primitives.</P>
///
/// <P>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 I3DExCamera
///
struct I3DShCamera: public IMCUnknown
{
	// Gives the transformation from the Global Coordinate System to the Screen Coordinate System
	// ****************************************************************************
	//								GetGlobalToCameraTransform
	// 
	/// Returns the transform from Global coordinates to Camera Coordinates. Note that
	/// this not the same thing as asking the transform of the camera on the corresponding
	/// tree element because the scaling is taken out in this case.
	/// 
	/// \param transform  A structure where the transform can be stored.
	/// 
	virtual MCCOMErr	MCCOMAPI GetGlobalToCameraTransform	(TTransform3D* transform) const = 0;

	// ****************************************************************************
	//								Preset
	// 
	/// Sends the camera to a reference position.
	/// 
	/// \param preset      A present orientation (see #ECameraPreset)
	/// \param aimedPoint  A target point for the camera
	/// \param distance    The distance from the camera to the point.
	/// 
	virtual MCCOMErr	MCCOMAPI Preset				(uint32 preset, const TVector3& aimedPoint, real distance) = 0;

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

	// ****************************************************************************
	//								PreProject3DTo2D
	// 
	/// \deprecated Do not implement this method.
	/// 
	virtual boolean		MCCOMAPI PreProject3DTo2D		(const TVector3& cameraPosition, TVector4& projectedPosition) const = 0;
	
	// ****************************************************************************
	//								Project3DTo2D
	// 
	/// Projects a point in camera coordinates on the screen.
	/// 
	/// \param position                The point to project (in Camera Coordinates)
	/// \param resultScreenPosition    The projection on the screen.
	/// \param resultDistanceToScreen  The distance to the screen.
	/// 
	virtual boolean		MCCOMAPI Project3DTo2D			(const TVector3* position, TVector2* resultScreenPosition, real* resultDistanceToScreen) const = 0;

	// ****************************************************************************
	//								CreateRay
	// 
	/// 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 resultOrigin		The origin of the ray that is returned.
	/// \param resultDirection	The direction of the ray that is returned.
	/// 
	virtual boolean		MCCOMAPI CreateRay				(const TVector2* screenPosition, TVector3* resultOrigin, TVector3* resultDirection) const = 0;
	
	// ****************************************************************************
	//								CreateRay
	// 
	/// 
	/// 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;

	// ****************************************************************************
	//								GetValidExCameraNoAddRef
	// 
	/// Returns a valid external camera for the current time (to by pass the app for speed)
	/// You should use this call with extreme caution: It assumes nothing will be changed
	/// in the scene while you use the external interface. In particular, if the time is
	/// changed you should call this function to get a new pointer.
	/// 
	virtual I3DExCamera*MCCOMAPI GetValidExCameraNoAddRef() =0;

	// ****************************************************************************
	//								GetRenderUVBox
	// 
	/// Returns the production frame in screen coordinates.
	/// 
	/// \param uvBox             The production frame in screen coordinates that is returned.
	/// \param width             The width of the image to render
	/// \param height            The height of the image to render
	/// \param pixelAspectRatio  The pixel ratio that should be used.
	/// 
	virtual MCCOMErr	MCCOMAPI GetRenderUVBox		(TBBox2D* uvBox, uint32 width, uint32 height, real pixelAspectRatio) const = 0;

	// ****************************************************************************
	//								SetCameraComponent
	// 
	/// Sets the kind of this camera.
	/// 
	/// \param kindID  The class ID of the camera.
	/// 
	virtual MCCOMErr	MCCOMAPI SetCameraComponent	(int32 kindID) = 0;
	
	// ****************************************************************************
	//								SetCameraComponent
	// 
	/// Sets the camera component.
	/// 
	/// \param cameraComponent  A pointer to the camera component.
	/// \param cloneMode        The way the camera component should be changed (see ECloneMode)
	/// 
	virtual MCCOMErr	MCCOMAPI SetCameraComponent	(IShComponent* cameraComponent, ECloneMode cloneMode) = 0;								
	
	// ****************************************************************************
	//								GetCameraComponent
	// 
	/// Returns a pointer to the camera component.
	/// 
	/// \param cameraComponent  A pointer to the camera component.
	/// 
	virtual MCCOMErr	MCCOMAPI GetCameraComponent	(IShComponent** cameraComponent) = 0;
	
	// ****************************************************************************
	//								GetStandardCameraInfo
	// 
	/// 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;

	// ****************************************************************************
	//								SetCanonicalCameraType
	// 
	/// Sets the type of camera when it is a canonical camera (see I3DEditorHostPart).
	/// 
	/// \param canonicalCameraType  The type of camera (see ECanonicalCameraType).
	///	\param canonicalScale		The scale to apply to the position preset of canonical cameras (for others pass NULL)
	/// 
	virtual void		MCCOMAPI SetCanonicalCameraType(ECanonicalCameraType canonicalCameraType, real* canonicalScale) = 0;
	
	// ****************************************************************************
	//								GetCanonicalCameraType
	// 
	/// Returns the type of camera (see I3DEditorHostPart for more info on canonical cameras).
	/// 
	virtual ECanonicalCameraType MCCOMAPI GetCanonicalCameraType() = 0;

	// ****************************************************************************
	//								SetProductionOffset
	// 
	/// Sets the offset of the production frame.
	/// 
	/// \param inOffset  The offsent in screen coordinates.
	/// 
	virtual void		MCCOMAPI SetProductionOffset	(const TVector2& inOffset) = 0;
	
	// ****************************************************************************
	//								GetProductionOffset
	// 
	/// Returns the product offset.
	/// 
	virtual TVector2	MCCOMAPI GetProductionOffset	() const = 0;

	// ****************************************************************************
	//								SetProductionZoom
	// 
	/// Sets the size of the production frame.
	/// 
	/// \param zoom  The size of the production frame.
	/// 
	virtual void		MCCOMAPI SetProductionZoom		(real zoom) = 0;
	
	// ****************************************************************************
	//								GetProductionZoom
	// 
	/// Returns the size (zoom) of the production frame.
	/// 
	virtual real		MCCOMAPI GetProductionZoom		() const = 0;

	// ****************************************************************************
	//								GetTreeElement
	// 
	/// Returns the I3DShTreeElement interface. This call is faster than calling
	/// QueryInterface.
	/// 
	virtual I3DShTreeElement* MCCOMAPI GetTreeElement	() = 0;

	// ****************************************************************************
	//								SetRenderingUVBox
	// 
	/// Notifies the external 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 uvbox of the screen.
	/// 
	virtual void	 MCCOMAPI SetRenderingUVBox		(	const TBBox2D& inUVBox) = 0;
};

/// \}

#endif