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

		I3DShLightSource.h

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

		I3DShLightSource definition

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		6/10/99		Ian			Array API changes.
		04/15/99	Charles		Created ( remove dependencies)

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

#ifndef __I3DSHLIGHT__
#define __I3DSHLIGHT__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"
#include "Transforms.h"
#include "Id.h"

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

MCDEFINE_GUID_H(IID_I3DShLightsource);

// Classes always available
MCDEFINE_GUID_H(CLSID_StandardExternalLight);
MCDEFINE_GUID_H(CLSID_StandardSpotLight);
MCDEFINE_GUID_H(CLSID_StandardBulbLight);
MCDEFINE_GUID_H(CLSID_StandardDistantLight);

/*****************************************************************************\
*  I3DShLightsource                                                           *
*                                                                             *
*    I3DShLightsource defines the light sources as tree elements              *
*    It can return a I3DShTreeElement interface on demand.                    *
*                                                                             *
\*****************************************************************************/

struct TLightTraceElement;
struct I3DShLightsourceGel;
struct I3DShShadowFeature;
struct I3DExShadowFeature;
struct I3DShCamera;
struct IShComponent;
struct I3DExLightsource;
struct TStandardLight;
struct Ray3D;
struct I3DShTreeElement;
class TBBox2D;

typedef void (*ForEachShadowBufferCallback)				(boolean			lightType, 
														 TTransform3D*		transform, 
														 real				halfAngle, 
														 void*				priv);

template<class T> class TMCArray;

/// \addtogroup ShellInterface
/// \{

/// <P>Light sources define the lighting in a 3D scene. All kind of light sources can be
/// designed: spot lights, bulb lights, distant lights (sun, moon), etc. Various features
/// can be coded in a Light Source Extension, because the Light Source has complete control
/// of the light intensity returned to the 3D Shell.</P>
///
/// <P>Light sources create light that illuminate object surfaces. The user can combine lights
/// with gels to make additional lighting effects (see the I3DExLightsourceGel interface).</P>
///
/// <P>The structure of a light is a little bit more complex that the typical component. It is
/// similar to the structure of Cameras and Primitives.</P>
///
/// <P>There are 2 COM objects to consider:</P>
///  - The <B>Light Instance</B> that supports I3DShLightsource, I3DShInstance and I3DShTreeElement.
///  - The <B>Light Component</B> that supports IShComponent, I3DExLightsource and I3DShTreeElementMember
///
/// <P>For advanced users: You should note that there are actually 3 C++ object (The light instance,
/// the light component and the external light). However the light component and the external
/// light are aggregated by COM which means that you can be considered as one single COM object).
///
/// <P>To get a pointer to a I3DShLightsource from a I3DExLightsource, you can use the following code:</P>
///
/// \code
///
/// TMCCountedPtr<I3DShTreeElementMember> lightComponent;
/// exLight->QueryInterface(IID_I3DShTreeElementMember,(void**)&lightComponent);
/// ThrowIfNil(lightComponent);
///
/// TMCCountedPtr<I3DShTreeElement> lightTree;
/// lightComponent->GetTreeElement(&lightTree);
/// ThrowIfNil(lightTree);
///
/// TMCCountedPtr<I3DShLightsource> shLight;
/// lightTree->QueryInterface(IID_I3DShLightsource.(void**)&shLight);
///
/// \endcode
///
/// <P>To access I3DExLightsource from I3DShLightsource, you can use the following code: </P>
///
/// \code
///
/// TMCCountedPtr<IShComponent> lightComponent;
/// shLight->GetLightComponent(&lightComponent);
/// ThrowIfNil(lightComponent);
///
/// TMCCountedPtr<I3DExLightsource> exLight;
/// lightComponent->QueryInterface(IID_I3DExLightsource,(void**)&exLight);
///
/// \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. I3DShLightsource::GetLightComponent() 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 (I3DShLightsource) to access the light
/// 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 I3DExLightsource
///
struct I3DShLightsource : public IMCUnknown
{
	// ****************************************************************************
	//								GetLightGlobalTransform
	// 
	/// Returns the global transform of the light.
	/// 
	/// \param transform  The global transform of the light.
	/// 
	virtual MCCOMErr			MCCOMAPI GetLightGlobalTransform	(TTransform3D* transform) = 0;		// A little bit like GetGlobalTransform(), but without the scaling factor
	
	// ****************************************************************************
	//								ForEachShadowBuffer
	// 
	/// \deprecated Use GetShadowBuffer() instead.
	/// 
	virtual MCCOMErr			MCCOMAPI ForEachShadowBuffer		(ForEachShadowBufferCallback proc, void* priv) = 0;
	
	// ****************************************************************************
	//								GetLightParameter
	// 
	/// Returns the value of a given parameter of the light.
	/// 
	/// \param keyword    The identifier of the parameter
	/// \param parameter  A point to a buffer that can store the parameter value.
	/// 
	virtual MCCOMErr			MCCOMAPI GetLightParameter			(int32 keyword, void* parameter) = 0;
	
	// ****************************************************************************
	//								GetPrimitiveID
	// 
	/// Returns the ID of the primitive that is displayed in place of the light.
	/// 
	/// \param primID  The ID of the primitive that is displayed in place of the light.
	/// 
	virtual MCCOMErr			MCCOMAPI GetPrimitiveID			(int32 &primID) = 0;
	
	// ****************************************************************************
	//								GetNewTrace
	// 
	/// \deprecated
	/// 
	virtual MCCOMErr			MCCOMAPI GetNewTrace				(int16 &nb,TLightTraceElement *&traceElem) = 0;

	// ****************************************************************************
	//								GetValidExLightNoAddRef
	// 
	/// Returns a valid external light 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.
	/// 
	/// \return A pointer to a valid external light source. Not that it returns null if the light is
	/// not active in the current scene.
	///
	virtual I3DExLightsource*	MCCOMAPI GetValidExLightNoAddRef	() =0;

	// ****************************************************************************
	//								GetDirection
	// 
	/// 
	/// 
	/// <P>Returns the direction from the point to the light source as well as the distance between
	/// the surface point and light source. GetDirection() is called prior to GetColor() to perform
	/// preliminary calculations. The surface point is the point on the object where the light is
	/// about to be calculated.</P>
	///
	/// <P>A light bulb typically calculates resultDirection by subtracting the position point to the
	/// light source origin, then normalizes the results. A simulated sun light returns its light 
	/// direction in resultDirection, and the maximum possible value in resultDistance.</P>
	///
	/// \param position         The point on the surface for which the lighting is going to be calculated
	/// \param resultDirection  The direction from which the light arrives on the point
	/// \param resultDistance   The distance from the point to the light
	/// 
	virtual boolean				MCCOMAPI GetDirection				(const TVector3 &position,TVector3 &resultDirection, real &resultDistance) = 0;
	
	// ****************************************************************************
	//								GetColor
	// 
	/// 
	/// <P>Returns the color of light seen through a given point.</P>
	///
	/// <P>When using a spot, use the position parameter and the light source position
	/// and orientation to determine whether a point is in the light beam or not. 
	/// When using a sun, use the direction parameter to calculate the intensity.
	/// When lighting is based on distance, (such as distance fall-off), use the distance parameter.</P>
	///
	/// \param position         The point on the surface for which the lighting is going to be calculated.
	/// \param direction        The direction from which the light arrives on the point (as calculated in GetDirection()).
	/// \param distance         The distance from the point to the light (as calculated in GetDirection()).
	/// \param result           The color of the light that reaches this point.
	/// \param shadowIntensity  The intensity of the shadow cast by that light.
	/// 
	virtual boolean				MCCOMAPI GetColor					(const TVector3 &position,const TVector3 &direction,const real distance,TMCColorRGB &result,real &shadowIntensity)=0;

	// ****************************************************************************
	//								SetGelComponentByID
	// 
	/// Sets the type of Gel component attached to this light.
	/// 
	/// \param kindID  The class ID of the Gel attached to this light
	/// 
	virtual MCCOMErr			MCCOMAPI SetGelComponentByID		(int32 kindID) = 0;
	
	// ****************************************************************************
	//								SetGelComponent
	// 
	/// Sets the Gel component attached to this light.
	/// 
	/// \param gel        The gel component
	/// \param cloneMode  The clone mode (see ECloneMode)
	/// 
	virtual MCCOMErr			MCCOMAPI SetGelComponent			(I3DShLightsourceGel* gel, ECloneMode cloneMode) = 0;
	
	// ****************************************************************************
	//								GetGelComponent
	// 
	/// Returns the Gel component attached to this light.
	/// 
	/// \param gel  The gel component.
	/// 
	virtual void				MCCOMAPI GetGelComponent			(I3DShLightsourceGel**  gel) = 0;

	// ****************************************************************************
	//								SetShadowFeatureByID
	// 
	/// Sets the type of Shadow feature attached to this light.
	/// 
	/// \param kindID  The class ID of the Shadow feature attached to this light
	/// 
	virtual MCCOMErr			MCCOMAPI SetShadowFeatureByID		(int32 kindID) = 0;
	
	// ****************************************************************************
	//								SetShadowFeature
	// 
	/// Sets the Shadow feature attached to this light.
	/// 
	/// \param feature    A pointer to the shadow feature.
	/// \param cloneMode  The clone mode (see ECloneMode)
	/// 
	virtual MCCOMErr			MCCOMAPI SetShadowFeature			(I3DShShadowFeature*  feature, ECloneMode cloneMode) = 0;
	
	// ****************************************************************************
	//								GetShShadowFeature
	// 
	/// Returns the Shadow feature attached to this light.
	/// 
	/// \param feature  A pointer to the shadow feature.
	/// 
	virtual void				MCCOMAPI GetShShadowFeature		(I3DShShadowFeature** feature) =0;
	
	// ****************************************************************************
	//								GetExShadowFeature
	// 
	/// Returns a pointer to the external Shadow feature. This call is equivalent to
	/// calling GetShShadowFeature and then QueryInterface(IID_I3DExShadowFeature,...)
	/// on the result.
	/// 
	/// \param feature  A pointer to the shadow feature.
	/// 
	virtual void				MCCOMAPI GetExShadowFeature		(I3DExShadowFeature** feature) =0;

	// ****************************************************************************
	//								SetLightComponentByID
	// 
	/// Sets the type of the light (Buld, Distance, Spot...).
	/// 
	/// \param kindID  The Class ID of the light.
	/// 
	virtual MCCOMErr			MCCOMAPI SetLightComponentByID		(int32 kindID) = 0;
	
	// ****************************************************************************
	//								SetLightComponent
	// 
	/// Sets the light component associated with this instance.
	/// 
	/// \param component  A pointer to the light component.
	/// \param cloneMode  The clone mode (see ECloneMode).
	/// 
	virtual MCCOMErr			MCCOMAPI SetLightComponent			(IShComponent*  component, ECloneMode cloneMode) = 0;
	
	// ****************************************************************************
	//								GetLightComponent
	// 
	/// Returns a pointer to the light component associated with this instance.
	/// 
	/// \param component  A pointer to the light component.
	/// 
	virtual MCCOMErr			MCCOMAPI GetLightComponent			(IShComponent** component) = 0;

	// ****************************************************************************
	//								GetLightComponent
	// 
	/// Returns a pointer to the light component associated with this instance.
	/// (Note : no AddRef)
	/// 
	/// \return A pointer to the light component.
	/// 
	virtual IShComponent*	MCCOMAPI GetLightComponent	() = 0;

	// ****************************************************************************
	//								GetLightInfo
	// 
	/// Returns information about light cones and sphere...
	///
	/// \param hasLightCone True on exit if the light supports a light cone (spot lights)
	/// \param hasLightSphere True on ext if the light supports a light sphere (bulb lights)
	/// \param halfAngle Half angle of the light cone if there is one
	/// \param transform Global Transform of the light.
	/// 
	virtual MCCOMErr MCCOMAPI GetLightInfo				(boolean &hasLightCone,boolean &hasLightSphere,real &halfAngle,TTransform3D &transform)=0;

	// ****************************************************************************
	//								GetStandardLight
	//
	/// Retrieves a standard description of the light for use in the interactive renderer.
	///
	/// \param light A reference to the simplified description of the light for the interactive rendering
	///
	virtual MCCOMErr MCCOMAPI GetStandardLight			(TStandardLight& light ) const = 0;

	// must be called before GetRandomRay
	// initialize sampling of the light on the scene bounding box
	// returns the solid angle containing the sampling rays
	// ****************************************************************************
	//								InitSampling
	// 
	/// Initialize sampling of the light and returns the solid angle containing the sampling rays.
	/// It must be called before GetRandomRay
	///
	/// \param sceneBoundingBox  The bounding box of the scene
	/// \param solidAngle        Returns the solid Angle of the sampling rays
	/// \param regionCount       Returns the number of region for ray sampling (each region represent an equal number of rays)
	/// 
	virtual void	 MCCOMAPI InitSampling(const TBBox3D&	sceneBoundingBox,
										   real&			solidAngle,
										   int32&			regionCount)=0;

	// ****************************************************************************
	//								GetRandomRay
	// 
	/// Returns a random ray starting from the light
	/// The rays should sample uniformly a solid angle that contains at least the
	/// intersection of the light cone (or sphere) and the scene.
	///
	/// \note Must be called after InitSampling
	///
	/// \param regionIndex	Index of the region in which the ray should be picked
	/// \param ray			A reference to the ray that should be returned
	/// 
	virtual void	 MCCOMAPI GetRandomRay(int32 regionIndex,Ray3D& ray) =0;

	// ****************************************************************************
	//								GetShadowBufferCount
	// 
	/// Returns the number of shadow buffer needed for this light
	///
	virtual int32	 MCCOMAPI GetShadowBufferCount()=0;
	
	// ****************************************************************************
	//								GetShadowBuffer
	// 
	/// Returns a camera equivalent to a shadow buffer
	///
	/// \param bufferIndex	index of the shadow buffer (0 based)
	/// \param camera		returns a pointer to the camera corresponding to the shadow buffer
	/// \param uvBox		returns the box in screen coordinates corresponding to the shadow buffer
	///
	virtual void	 MCCOMAPI GetShadowBuffer(int32				bufferIndex,
											  I3DShCamera**		camera,
											  TBBox2D&			uvBox) = 0;

	// ****************************************************************************
	//								IsVisibleInPerspective
	//
	/// <P>Returns true if the light should be displayed in the 3D View. In this case,
	/// the lights is displayed with the geometry of the primitive given by GetPrimitiveID().</P>
	/// <P>If it returns false, then the light is not displayed, this is used for sun lights for example.</P>
	///
	virtual boolean  MCCOMAPI IsVisibleInPerspective() =0;

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

	// ****************************************************************************
	//								ShouldLightInstance
	// 
	/// Return true if the light should consider this instance for lighting.
	/// 
	/// \param instance  the instance that ask for light
	/// 
	virtual boolean MCCOMAPI ShouldLightInstance(I3DShInstance* instance) const = 0;

	// ****************************************************************************
	//								GetRestrictedList
	// 
	/// Return the list of the only instances that should get light or of the instances that won't
	/// 
	/// \param isExclusion  true if the instances listed are to be excluded
	/// 
	virtual const TTreeIdPathList& MCCOMAPI GetRestrictedList(boolean& isExclusion) const = 0;

	// ****************************************************************************
	//								SetRestrictedList
	// 
	/// Restrict the lightening to these instances if mode is inclusion, or restrict to all instances
	/// except these ones if mode is exclusion
	/// 
	/// \param newList  the list of instances
	/// 
	virtual void	MCCOMAPI SetRestrictedList(const TTreeIdPathList& newList) = 0;
	
	// ****************************************************************************
	//								SetIsExclusion
	// 
	/// Set the mode for the restricted list
	/// 
	/// \param isExclusion  
	/// 
	virtual void	MCCOMAPI SetIsExclusion(boolean isExclusion) = 0;

	// ****************************************************************************
	//								CouldExcludeInstance
	// 
	/// Return false if ShouldLightInstance will always return true
	/// 
	/// 
	virtual boolean	MCCOMAPI CouldExcludeInstance() const = 0;

	// ****************************************************************************
	//								UpdateLightRadius
	// 
	/// Calculates a corrected radius for soft shadows. This is used in particular
	/// for distant lights to rescale the parameter
	/// 
	/// \param radiusFromShadowFeature  radius of the light as specified by the user in the shadow feature
	/// 
	virtual real MCCOMAPI UpdateLightRadius(const real radiusFromShadowFeature) = 0;
};

/// \}

/// this encapsulates a light along with the flattened transforms.  
///
class TLightAndTfm : public TMCObject
{
public:
	I3DShLightsource*	fLight;					///< the light source
	TTransform3D 		fWorldFromModelTfm;
	TTransform3D 		fModelFromWorldTfm;
};

// the lights in the tree are flattened into an array
typedef TMCArray<TLightAndTfm> TLightAndTfmArray;


#endif