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

		I3DExLight.h

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

		I3DExLightsource definition

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		11/16/99	Charles		removed ShadowEffect method
		11/116/99	Charles		added a parameter to I3DShLightsource::GetColor for shadow attenuation
		08/26/99	cph			Added family ids
		08/06/99	cph			modified interface to inherit from IMCUnknown instead of DataExchanger
		04/08/99	Alec		added TStandardLight

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

#ifndef __I3DEXLIGHT__
#define __I3DEXLIGHT__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "IExtension.h"
#include "APITypes.h"
#include "MCColorRGB.h"
#include "InterfaceIDs.h"
#include "TransformsFwd.h"

class TBBox2D;
class TBBox3D;
struct I3DShScene;

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

MCDEFINE_GUID2(IID_I3DExLightsource, R_IID_I3DExLightsource);
MCDEFINE_GUID_H(IID_I3DExDistantLight);

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

const FourCharT kLightsourceFamilyID = kRID_LightsourceFamilyID;


/// A simple description of a light for fast lighting during interactive rendering.
/// Diffuse/specular terms are a combination of color and intensity (may be negative)
/// Point lights use only position, distant lights use only direction, spots both
///
struct TStandardLight
{
	
	enum EType
	{
		kAmbientLight,
		kDistantLight,
		kPointLight,
		kSpotLight
	};

	EType		fLightType;
	
	TMCColorRGB	fDiffuse;
	TMCColorRGB	fSpecular;

	
	TVector3	fPosition;
	TVector3	fDirection;
	
	real		fConeAngleDegreesMin,	///< this is the cone attenuation (spot only)
				fConeAngleDegreesMax;

	
	real		fFalloffDistanceMin,	///< Start of the distance falloff (point/spot only)
				fFalloffDistanceMax;	///< End of the distance falloff (point/spot only)
};

// forward declarations

struct Ray3D;
struct I3DShCamera;


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

/*****************************************************************************\
*  I3DExLightsource                                                           *
*                                                                             *
*  Light Sources                                                              *
*                                                                             *
\*****************************************************************************/

#ifndef qDemoVersion //regular interface

/// \addtogroup ExternalInterface
///
/// \{

/// <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 I3DExLightsource : public IMCUnknown
{
	/// Called to tell a light source its position and orientation in space. This function is used
	/// to cache transform information to speed up GetDirection() and GetColor().
	///
	/// \param transform A pointer to the Global Transform of the light
	///
	virtual MCCOMErr MCCOMAPI SetTransform				(TTransform3D* transform)=0;

	/// <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 postion 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 point 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 MCCOMErr MCCOMAPI GetDirection				(const TVector3&	point,
														 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 point 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&	point,					// point to be light
														 const TVector3&	direction,				// direction from point to the light
												 		 const real			distance,				// distance from light to the point
														 TMCColorRGB&		result,					// resulting color
														 real&				ShadowIntensity) = 0;	// between 0.0f (no shadows) and 1.0f (no light in shadow)

	// ****************************************************************************
	//								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;


	// ****************************************************************************
	//								GetPrimitiveID
	//
	/// Returns the ID of the primitive that is displayed in place of the light.
	///
	virtual uint32   MCCOMAPI GetPrimitiveID			() = 0;

	// ****************************************************************************
	//								ForEachShadowBuffer
	//
	/// \deprecated
	///
	virtual MCCOMErr MCCOMAPI ForEachShadowBuffer		(ForEachShadowBufferCallback proc, void* priv) = 0;

	// ****************************************************************************
	//								GetLightParameter
	//
	/// \deprecated
	///
	virtual MCCOMErr MCCOMAPI GetLightParameter			(int32 keyword, void* parameter) = 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;
	
	// ****************************************************************************
	//								GetLightInfo
	//
	/// returns the uv for the gel given a direction
	///
	/// \param uv			The uv that are returned.
	/// \param direction	The direction as calculated in GetDirection()
	///
	virtual boolean	 MCCOMAPI GetUVfromDirection		(TVector2 &uv, const TVector3 &direction) const = 0;


	// ****************************************************************************
	//								GetNewTrace
	//
	/// \deprecated
	///
	/// \param nb not used
	///
	virtual LightTraceElement* MCCOMAPI GetNewTrace		(int16* nb) = 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;

	// ****************************************************************************
	//								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 ray			A reference to the ray that should be returned
	/// \param regionIndex	Index of the region in which the ray should be picked
	///
	virtual void	 MCCOMAPI GetRandomRay				(int32 regionIndex,Ray3D& ray) const =0;

	// ****************************************************************************
	//								GetShadowBufferCount
	// 
	/// Returns the number of shadow buffer needed for this light
	///
	virtual int32	 MCCOMAPI GetShadowBufferCount		() const=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) const = 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;

	// ****************************************************************************
	//							UpdateAtmosphere
	// 
	/// This function should update the atmosphere in the current scene according to
	///	the light data, if needed (useful for atmospheric lights : sun, moon)
	///
	/// \param inScene a pointer to the current scene
	/// 
	virtual MCCOMErr MCCOMAPI UpdateAtmosphere			(I3DShScene* inScene) = 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) const = 0;

};


/// \}


#else 	//(qDemoVersion) begin scrambled interface

struct I3DExLightsource : public IMCUnknown
{
	virtual void	 MCCOMAPI Method0				() {};
	virtual LightTraceElement* MCCOMAPI GetNewTrace		(int16* nb) = 0;
	virtual MCCOMErr MCCOMAPI SetTransform				(TTransform3D* transform)=0;
	virtual MCCOMErr MCCOMAPI GetDirection				(const TVector3&	point,
														 TVector3&			resultDirection,
														 real&				resultDistance) = 0;
	virtual int32	 MCCOMAPI GetShadowBufferCount		() const=0;
	virtual MCCOMErr MCCOMAPI GetLightParameter			(int32 keyword, void* parameter) = 0;
	virtual boolean  MCCOMAPI GetColor					(const TVector3&	point,					// point to be light
														 const TVector3&	direction,				// direction from point to the light
												 		 const real			distance,				// distance from light to the point
														 TMCColorRGB&		result,					// resulting color
														 real&				ShadowIntensity) = 0;	// between 0.0f (no shadows) and 1.0f (no light in shadow)
	virtual boolean  MCCOMAPI IsVisibleInPerspective	() = 0;
	virtual uint32   MCCOMAPI GetPrimitiveID			() = 0;
	virtual MCCOMErr MCCOMAPI ForEachShadowBuffer		(ForEachShadowBufferCallback proc, void* priv) = 0;	
	virtual void	 MCCOMAPI GetShadowBuffer			(int32				bufferIndex,
														 I3DShCamera**		camera,
														 TBBox2D&			uvBox) const = 0;
	virtual MCCOMErr MCCOMAPI GetLightInfo				(boolean&			hasLightCone,
														 boolean&			hasLightSphere,
														 real&				halfAngle,
														 TTransform3D&		transform)=0;
	virtual boolean	 MCCOMAPI GetUVfromDirection		(TVector2 &uv, const TVector3 &direction) const = 0;	
	virtual MCCOMErr MCCOMAPI GetStandardLight			(TStandardLight& light ) const = 0;
	
	virtual void	 MCCOMAPI InitSampling(const TBBox3D&	sceneBoundingBox,
										   real&			solidAngle,
										   int32&			regionCount) =0;

	virtual void	 MCCOMAPI GetRandomRay				(int32 regionIndex,Ray3D& ray) const =0;
};
#endif	//(qDemoVersion) end scrambled


/// \addtogroup ExternalInterface
///
/// \{

/// When this interface is implemented by a light, we know it is a distant light
///
struct I3DExDistantLight : public IMCUnknown
{
};

/// \}

#endif