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

		I3dExRenderFeature.h

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

		Render feature definition

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who					what & why
		==========	================	======================================================
		08/26/99	cph					Added family ids
		08/11/99	Guillaume&Christy	Added inheritance to all the Basic* classes
		07/11/98	Alec				Removed typedefs from structs, removed define for kVarLengthArray
										since it was causing a naming conflict with MacTypes.h
									
*****************************************************************************************/
#ifndef __I3DEXRENDERFEATURE__
#define __I3DEXRENDERFEATURE__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "RenderTypes.h"
#include "IExtension.h"
#include "I3DShUtilities.h"
#include "I3DShEnvironment.h"
#include "I3DShShader.h"
#include "MCCountedPtr.h"
#include "InterfaceIDs.h"
#include "I3DShGroup.h"

struct I3DShLightsource;
struct I3DImportData;

template <class T> class TMCArray;

//****** Globally Unique Id **************************************************
MCDEFINE_GUID2(IID_I3DExRaytracer, R_IID_I3DExRaytracer);
MCDEFINE_GUID2(IID_I3DExShadowFeature, R_IID_I3DExShadowFeature);
MCDEFINE_GUID2(IID_I3DExReflectionFeature, R_IID_I3DExReflectionFeature);
MCDEFINE_GUID2(IID_I3DExRefractionFeature, R_IID_I3DExRefractionFeature);
MCDEFINE_GUID2(IID_I3DExDataComponent, R_IID_I3DExDataComponent);

//****** Family Id *************************************************
const FourCharT kShadowFeatureFamilyID = kRID_ShadowFeatureFamilyID;
const FourCharT kReflectionFeatureFamilyID = kRID_ReflectionFeatureFamilyID;
const FourCharT kRefractionFeatureFamilyID = kRID_RefractionFeatureFamilyID;
const FourCharT kDataComponentFamilyID = kRID_DataComponentFamilyID;
const FourCharT kGenericDataFamilyID   = kRID_DataComponentFamilyID;

/// \addtogroup Data
/// \{

/// Structure used to return direct lighting information.
///
struct DirectLighting
{
	DirectLighting() : fIsInShadow(true),fLightColor(0,0,0),fNoShadowLightColor(0,0,0),fLightDirection(0,0,0) {}

	TMCColorRGB			fLightColor;			/// Intensity of the light containing shadow.
	TMCColorRGB			fNoShadowLightColor;	/// Intensity of the light without shadow.
	TVector3			fLightDirection;		/// A vector pointing from the point to the light (not normalized).
	boolean				fIsInShadow;			/// True if a shadow is cast.
};
/// \}

/// Specifies how the lighting should be calculated (used in I3DExRaytracer::GetRayColor())
///
struct RayColorFlags
{
	RayColorFlags() : fComputeHitColor(true),fComputeSkyLight(true),fComputeGlow(true),fIndirectLight(false)
	{
	}

	boolean		fComputeHitColor;	// true if the color (shading+lighting) of hit points should be calculated
	boolean		fComputeSkyLight;	// true if the color of the sky/background  should be calculated
	boolean		fComputeGlow;		// true if the glow should be taken into account
	boolean		fIndirectLight;		// true if the ray is an indirect ray (in which case we use approximate sky calculation)
};

/// \addtogroup ExternalInterface
/// \{


/// Parameters of I3DExRaytracer::LightBeam()
struct LightBeamParams
{
	const RayHit3D*		origin;			///< The point from which the ray starts (used to avoid self shadowing)
	const Ray3D*		aR;				///< The ray
	real				tmin;			///< The start of the segment on the ray
	real				tmax;			///< The end of the segment on the ray
	TMCColorRGBA*		filterColor;	///< On input the color at the tmax point, on ouput the color after being filtered by the scene.
	uint32*				fNumberOfRays;	///<
	boolean				isSunLightShadowCasting;	///< True if the the light is a sun light
	I3DShLightsource*	fLight;				///< The light that launched the ray at first
	int32				fHitInstanceIndex;  ///< The index of the instance that intersected the ray, if any
	real				ft;				///< The value of t at the closest intersection, if any
};

struct BackgroundRenderingFlags
{
	BackgroundRenderingFlags() : fShowBackdrop(true),fShowBackground(true),fApplyVolumetrics(true),fIsIndirectRay(false) {}

	boolean		fShowBackdrop:1;		///< True if the backdrop should be taken into account (normally only for rays coming directly from that Camera)
	boolean		fShowBackground:1;		///< True if the backgroundshould be taken into account
	boolean		fApplyVolumetrics:1;	///< True if the atmosphere and/or volumetric effects should be applied
	boolean		fIsIndirectRay:1;		///< True if this is a ray used to calculate indirect lighting (for global illumination)
};

class TAbsorptionFunction : public TMCObject
{
public:
	virtual void FilterColor(TMCColorRGB& inOutcolor,TMCColorRGB& inScatteredColor,const LightingContext& lightingContext,const TVector3&	direction,real distance)=0;
};

// ****************************************************************************
//							I3DExRaytracer	
// 
/// This interface is usually implemented by a final renderer or by an object
/// created by a final renderer. It is passed to the shaders so that they can
/// use it to calculate the lighting.
///
struct I3DExRaytracer: public IMCUnknown
{
	// ****************************************************************************
	//								LightBeam
	// 
	/// Traces a ray between two points (tmax should be normally finite). This is used
	/// by the shadow feature to calculate the shadows.
	///
	/// \param params		: The parameters describing the beam
	///
	/// \return True if there was a hit
	///
	virtual boolean MCCOMAPI LightBeam(LightBeamParams& params) = 0;

	// ****************************************************************************
	//								GetRayColor
	// 
	///
	/// Returns the color of a ray given in RayHitParameters in resColor
	///
	/// \param resColor				: The color that is returned
	/// \param rayHitParams			: The parameters of the ray
	/// \param level				: The level of reflection/transparency
	/// \param screenCoordinates	: The coordinates of the point on the screen whose color depends on that ray.
	/// \param rendContext			: return the number of rays used to evaluate this sample and the current random seed
	/// \param flags				: Flags to control what should be taken into account in the shading of the hit point.
	/// 
	virtual boolean MCCOMAPI GetRayColor	(
													TMCColorRGBA&		resColor,				// result color
											  const	RayHitParameters&	rayHitParams,			// parameter of the raytracing
											  const	RTLevelInfo&		level,					// level of reflection/transparency
											  const	TVector2&			screenCoordinates,		// coordinates of the pixel being rendered ( for backdrops)
													RendContext&		rendContext,
													RayColorFlags		flags

											) = 0;

	// ****************************************************************************
	//								GetLightCount
	// 
	/// Returns the number of lights in the scene
	///
	virtual int32 GetLightCount() = 0;

	// ****************************************************************************
	//								GetLightIntensity
	// 
	/// Calculates the lighting from one light for the current point.
	///
	/// \param lighting				intensity of the lighting
	/// \param lightIndex			index of the light (should be inferior to the value returned by GetLightCount)
	/// \param lightingContext		information about the hit point
	/// \param withShadow			if true then the shadow are calculated
	/// \param lightFromBehind		if true the light is calculated even if the light is behind the surface
	/// 
	/// \return True if the light is emitting light in that direction (without taking the shadows into account)
	/// 
	virtual boolean	MCCOMAPI GetLightIntensity(DirectLighting&			lighting,
											   int32					lightIndex,
											   const LightingContext&	lightingContext,
											   boolean					withShadow,
											   boolean					lightFromBehind
											   ) = 0;


	// ****************************************************************************
	//								CalcReflections
	// 
	/// Calculates the light the comes from the reflection
	///
	/// \param reflectionIO		: the reflection data
	/// \param  lightingContext	: information about the hit point
	///
	virtual void MCCOMAPI CalcReflections(ReflectionIO& reflectionIO,const LightingContext& lightingContext) = 0;
	
	
	// ****************************************************************************
	//								CalcTransparency
	// 
	/// Calculates the light the comes from the transparency
	///
	/// \param transparencyIO	: the transparency data
	/// \param lightingContext	: information about the hit point
	///
	virtual void MCCOMAPI CalcTransparency(RefractionIO& transparencyIO,const LightingContext& lightingContext) = 0;

	// ****************************************************************************
	//								CalculateCaustic
	// 
	/// Calculates the caustics at a given point.
	///
	/// \param resColor			: the caustic light color.
	/// \param lightingContext	: information about the hit point.
	///
	virtual void MCCOMAPI CalculateCaustic(TMCColorRGB& resColor,const LightingContext& lightingContext) = 0;



	// ****************************************************************************
	//								GetIndirectLighting
	// 
	/// Computes the indirect lighting of a point by sampling the direction around its normal.
	///
	/// \param resColor					: the indirect diffuse lighting.
	/// \param ambientOcclusionFactor	: the ambient occlusion factor of the hit point.
	/// \param lightingContext			: information about the hit point.
	///
	virtual void MCCOMAPI GetIndirectLighting(TMCColorRGB& resColor, real& ambientOcclusionFactor, const LightingContext& lightingContext) = 0;


	// ****************************************************************************
	//								GetSubsurfaceScattering
	// 
	/// Computes the subsurface scattering in one point
	/// 
	/// \param subsurfaceColor  The resulting subsurface scattering color to add to the final color.
	/// \param currentColor		The current final color.
	/// \param lightingContext  Information about the hit point
	/// \param shading			The shading information at the hit point.
	/// 
	virtual void MCCOMAPI GetSubsurfaceScattering(TMCColorRGB& subsurfaceColor,const TMCColorRGB& currentColor,const LightingContext& lightingContext,const ShadingOut& shading) = 0;


	// ****************************************************************************
	//								GetBackGroundColor
	// 
	/// Calculate the color of the background/backdrop seen through a particular ray.
	/// Note that the backdrop should only be visible through direct ray from the
	/// camera.
	///
	/// <P>The atmosphere is also applied on the color along the ray.</P>
	///
	/// \param color			: the color returned
	/// \param fullAreaDone		: returns true if antialising has been performed
	/// \param ray				: the ray
	/// \param uv				: The screen coordinates
	/// \param showbackdrop		: True if the backdrop should be taken into account (normally only for rays coming directly from that Camera)
	/// \param showBackGround	: True if the backgroundshould be taken into account
	/// \param indirectLight	: True if this is a ray used to calculate indirect lighting (for global illumination)
	///
	virtual void MCCOMAPI GetBackGroundColor(TMCColorRGBA&		color,
											 boolean&			fullAreaDone,
											 const Ray3D&		ray,
											 const TVector2&	uv,
											 boolean			showbackdrop,
											 boolean			showBackGround,
											 boolean			indirectLight) = 0;

	// ****************************************************************************
	//								GetLightDirection
	// 
	/// Returns the direction of a given light
	/// 
	/// \param lightDirection		Direction from the point to the light source.
	/// \param lightIndex			Index of the light (should be inferior to the value returned by GetLightCount)
	/// \param lightingContext		Information about the hit point
	/// 
	virtual void MCCOMAPI GetLightDirection(TVector3&				lightDirection,
											int32					lightIndex,
											const LightingContext&	lightingContext
											) = 0;

	// ****************************************************************************
	//								GetLightInstance
	// 
	/// Returns the pointer to the instance of a light
	/// 
	/// \param source				return pointer
	/// \param lightIndex			Index of the light (should be inferior to the value returned by GetLightCount)
	/// 
	virtual void MCCOMAPI GetLightSource( I3DShLightsource** source,
											int32	lightIndex
										   ) = 0;




	// ****************************************************************************
	//								GetIllumSettings
	// 
	/// Returns the current illumination settings of the renderer
	/// 
	virtual const IllumSettings& MCCOMAPI GetIllumSettings() = 0;

	// ****************************************************************************
	//								GetRendEnv
	// 
	/// Returns the current rendering environment
	/// 
	virtual const RendEnv& MCCOMAPI GetRendEnv() = 0;


	// ****************************************************************************
	//								GetSceneMagnitude
	// 
	/// Returns the magnitude of the scene. (right now it is a number between 1 and 1200).
	/// This can be used to determine the precision needed for the rendering. For instance,
	/// if you displace the point by a small displacement (epsilon) for precision reasons, you should
	/// multiply this small constant by the scene magnitude.
	/// 
	virtual real MCCOMAPI GetSceneMagnitude() = 0;

	// ****************************************************************************
	//								GetRandomSeed
	// 
	/// Returns the current random seed. If it is used to generate random numbers,
	/// you have to update the seed in the raytracer via SetRandomSeed().
	/// 
	virtual uint32	MCCOMAPI GetRandomSeed() = 0;

	// ****************************************************************************
	//								SetRandomSeed
	// 
	/// Sets the random seed in the raytracer.
	///
	/// \param seed		the new seed
	/// 
	virtual void	MCCOMAPI SetRandomSeed(const uint32 seed) = 0;

	// ****************************************************************************
	//								CalcTransparency2
	// 
	/// Calculates the light the comes from the transparency
	///
	/// \param transparencyIO	: the transparency data
	/// \param lightingContext	: information about the hit point
	///
	virtual void MCCOMAPI CalcTransparency2(	RefractionIO&			transparencyIO,
											const LightingContext&	lightingContext,
											TAbsorptionFunction*	absorptionFunction) = 0;

	// ****************************************************************************
	//								GetRayColor2
	// 
	///
	/// Returns the color of a ray given in RayHitParameters in resColor
	///
	/// \param resColor				: The color that is returned
	/// \param rayHitParams			: The parameters of the ray
	/// \param level				: The level of reflection/transparency
	/// \param screenCoordinates	: The coordinates of the point on the screen whose color depends on that ray.
	/// \param rendContext			: return the number of rays used to evaluate this sample and the current random seed
	/// \param absorptionFunction	The absorption function along the ray (NULL if there is no absorption)
	/// \param flags				: Flags to control what should be taken into account in the shading of the hit point.
	/// 
	virtual boolean MCCOMAPI GetRayColor2	(
													TMCColorRGBA&			resColor,				// result color
											  const	RayHitParameters&		rayHitParams,			// parameter of the raytracing
											  const	RTLevelInfo&			level,					// level of reflection/transparency
											  const	TVector2&				screenCoordinates,		// coordinates of the pixel being rendered ( for backdrops)
													RendContext&			rendContext,
													TAbsorptionFunction*	absorptionFunction,
													RayColorFlags			flags

											) = 0;


	// ****************************************************************************
	//								GetBackGroundColor2
	// 
	/// Calculate the color of the backdrop (note that this can be the color of the
	/// background component). This function can only be called for direct rays from
	/// the camera.
	///
	/// <P>The atmosphere can also applied on the color along the ray (see flags).</P>
	///
	/// \param color			: the color returned
	/// \param fullAreaDone		: returns true if antialising has been performed
	/// \param ray				: the ray
	/// \param uv				: The screen coordinates
	/// \param flags			: Flags that determine what is rendered (see BackgroundRenderingFlags).
	///
	virtual void MCCOMAPI GetBackGroundColor2(	TMCColorRGBA&				color,
												boolean&					fullAreaDone,
												const Ray3D&				ray,
												const TVector2&				uv,
												BackgroundRenderingFlags	flags) = 0;


	// ****************************************************************************
	//								CalculateInScattering
	// 
	/// Calculates the inScattering along a ray.
	/// 
	/// \param outInScatteredColor  The resulting scattering color.
	/// \param absorptionCoef		The coefficient of absorption.
	/// \param lightingContext		The lighting context at the starting point of the ray.
	/// \param direction			Direction of the ray.
	/// \param distance				Distance along the ray.
	///
	virtual void MCCOMAPI CalculateInScattering(TMCColorRGBA& outInScatteredColor,
		real absorptionCoef, const LightingContext& lightingContext,const TTransparencyParameters&	transparencyParams,const TVector3& direction,const real distance) = 0;
};
/// \}

/// \addtogroup Data
/// \{

/// The parameters of the shadow feature.
///
struct ShadowIO
{
	TVector3		   *fLightDir;			///< direction from light to current point
	TMCColorRGB		   *fLightColor;		///< color of the light coming from the light
	
	real				fDistToLight;		///< distance to the light
	real				fShadowIntensity;	///< Intensity of the shadow (0 means that there is no shadow)
	boolean				fIsSunLight;		///< True if the light is a sun light (used by atmosphere)

	I3DShLightsource*	fLight;				///< The lightsource to take inclusion/exclusion list into account (null if no exclusion)
};

/// \}

/// \addtogroup ExternalInterface
/// \{

/// A shadow feature controls the way shadows are calculated on an object. For instance,
/// you could trace rays through the scene or used a precalated shadow maps...
///
struct I3DExShadowFeature: public IMCUnknown
{
	// ****************************************************************************
	//								BeginRenderFrame
	// 
	/// Called by the shell at the beginning of the rendering of each frame. This
	/// fonction can be used to calculate a cache (shadow buffer for instance)
	///
	/// \param light		: the light on which the shadow feature is applied
	///
	virtual MCCOMErr MCCOMAPI BeginRenderFrame(I3DShLightsource *light)=0;
	
	// ****************************************************************************
	//								EndRenderFrame
	// 
	/// Called by the shell at the end of the rendering of each frame. This fonction
	/// can be used to delete caches.
	///
	virtual MCCOMErr MCCOMAPI EndRenderFrame()=0;
	
	// ****************************************************************************
	//								CalcShadow
	// 
	/// Calculate the light reaching a point from a light source
	///
	/// \note This function must be SMP compliant (= reentrant) !
	///
	/// \param shadowIO				: a structure containing all the parameters of this call
	/// \param lightingContext		: info about the point being lit
	///
	/// True if a shadow was cast
	///
	virtual boolean MCCOMAPI CalcShadow(ShadowIO& shadowIO,const LightingContext& lightingContext) = 0;
};
/// \}

/// \addtogroup Data
/// \{

/// The parameters of the reflection feature.
///
struct ReflectionIO
{
	ReflectionIO() : fReflectionParams(NULL) {}

	TMCColorRGBA					fResColor;				///< result color
	boolean 						fGotColor;				///< true if there was a reflection

	const TReflectionParameters*	fReflectionParams;		///< the reflection parameters from the shader
	real							fSpecularSize;			///< for blury reflections
	real							fAttenuation;			///< attenutation due to shading
};	

/// \}

/// \addtogroup ExternalInterface
/// \{

/// A reflection feature controls the way reflection is calculated on an object. For instance,
/// you could trace rays through the scene to determine the effect or directly get a value
/// for a precalculated map (reflection mapping)...
///
struct I3DExReflectionFeature: public IMCUnknown
{
	/// Calculates the reflection given a particular lighting context (point, shading, incoming ray...)
	///
	/// \param reflectionIO		Info specific to the reflection features
	/// \param lightingContext	The ligthing context (point, shading, incoming ray...)
	///
	virtual MCCOMErr MCCOMAPI CalcReflection(ReflectionIO& reflectionIO,const LightingContext& lightingContext) = 0;
};

/// \}

/// \addtogroup Data
/// \{

/// The parameters of the refraction feature.
///
struct RefractionIO
{
	inline RefractionIO() : fTransparencyParams(NULL),fDistance(-1) {}

	TMCColorRGBA		fResColor;			///< result color
	boolean 			fGotColor;			///< true if there was a reflection
	boolean				fNormalFlipped;		///< true if the normal was flipped
	real				fDistance;			///< the distance to the nearest intersection (used for absorption)
	TVector3			fRefractedDir;		///< direction of the refracted ray (normalized)

	const TTransparencyParameters*		fTransparencyParams;	///< the parameters from the transparency shader
	real								fRefractiveIndex;		///< index of refraction
	real								fAttenuation;			///< attenutation due to shading
};

/// \}

/// \addtogroup ExternalInterface
/// \{

/// A refraction feature controls the way refraction is calculated on an object. For instance,
/// you could trace rays through the scene to determine the effect or directly get a value
/// for a precalculated map...
///
struct I3DExRefractionFeature: public IMCUnknown
{
	/// Calculates the refraction given a particular lighting context (point, shading, incoming ray...)
	///
	/// \param refractionIO		Info used for refraction features
	/// \param lightingContext	The ligthing context (point, shading, incoming ray...)
	///
	virtual MCCOMErr MCCOMAPI CalcRefraction(RefractionIO& refractionIO,const LightingContext& lightingContext) = 0;

	/// Calculates the refraction given a particular lighting context (point, shading, incoming ray...)
	///
	/// \param refractionIO		  Info used for refraction features
	/// \param lightingContext	  The ligthing context (point, shading, incoming ray...)
	/// \param absorptionFunction The absorption function
	///
	virtual MCCOMErr MCCOMAPI CalcRefraction2(RefractionIO& refractionIO,const LightingContext& lightingContext,TAbsorptionFunction* absorptionFunction) = 0;
};
/// \}


/// \addtogroup ExternalInterface
/// \{


/// <P>A data component is a component that is attached to an object (a light, a camera or an primitive...)
/// and is used to store static or animated parameters.</P>
/// <P>It call also be used to trigger a post rendering to take place that relies on the data stores
/// in the data component. This also for instance, a post rendering to affect only the objects on which
/// a particular data component is active.</P>
/// <P>Last it can be used to associate a volumetric effect with an object. For instance a light cone
/// with a given light or a volumetric aura on a primitive.</P>
///
/// <P>There are two interfaces to access a dataComponent: The shell interface (I3DShDataComponent) and
/// the external interface (I3DExDataComponent) . You can get one from the other using QueryInterface.</P>
///
/// <P>You should use the Shell interface (I3DShDataComponent) to access the component
/// 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 I3DShDataComponent
///
struct I3DExDataComponent: public IMCUnknown
{
	/// Fills the array with the class ID of the postrenderer that are enabled by this dataComponent
	///
	/// \param idArray	Reference to the array where the ids should added
	///
	virtual MCCOMErr MCCOMAPI GetPostRenderList(TMCArray<IDType> &idArray)=0;

	/// Returns false if the dataComponent has no effect on this object
	///
	virtual boolean  MCCOMAPI IsActive(I3DShTreeElement* tree)=0;

	/// Returns a list of class IDs of the Volumetric components to instantiate to render this effect
	///
	/// \param idArray	Reference to the array where the ids should added
	///
	virtual void MCCOMAPI GetVolumetricList(TMCArray<IDType>& idArray)=0;


	///return true if the component can perform the import operation
	virtual boolean	 MCCOMAPI CanImportData				(I3DImportData*	inImportData) = 0;

	///return true if the component performed the import operation
	virtual boolean	 MCCOMAPI ImportData				(I3DImportData* inImportData) = 0;

	// ****************************************************************************
	//								FullReRenderOfPreview
	// 
	/// Returns true if the associated preview needs to perform a full rendering (by
	/// opposition to just render the postrenderer).
	/// 
	virtual boolean MCCOMAPI FullReRenderOfPreview() = 0;
};
/// \}


//Private data for attachability list (stored in the 'Cmpp' resource of same ID)
struct ExAttachData
{
	uint32	fNumAttaches;
	uint32	fAttachType[1]; // variable length array
};

#endif
