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

		RenderTypes.h

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

		Basic types used by the rendering APIs

		Author:	Charles
		Date:	12/31/98

		Revision History

		when		who					what & why
		==========	==========	======================================================
		08/10/99	Arnaud		FacetMesh is now counted.
		12-31-98	Charles		Created

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

#ifndef __RENDERTYPES__
#define __RENDERTYPES__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"
#include "Transforms.h"
#include "ShaderTypes.h"
#include "MCColorRGBA.h"
#include "TBBox.h"
#include "MCClassArray.h"
#include "MCPoint.h"


struct RendEnv;
struct I3DExRaytracer;
struct I3DShLightsource;
struct ReflectionIO;
struct RefractionIO;

/** Ray-tracing defines **************************************************/

/// Information about a 3D Ray (for raytracing)
///
struct Ray3D : public TMCObject
{
	inline Ray3D() : 
			fOrigin(TVector3::kZero),
			fDirection(TVector3::kZero),
			fOx(TVector3::kZero),
			fOy(TVector3::kZero),
			fDx(TVector3::kZero),
			fDy(TVector3::kZero),
			fIsSelectionRay(false),
			fOnlyFacets(false),
			fReserved(0)
	{
	}
	
	inline Ray3D(const TVector3& origin,const TVector3& direction) : 
					fOrigin(origin),
					fDirection(direction),
					fOx(TVector3::kZero),
					fOy(TVector3::kZero),
					fDx(TVector3::kZero),
					fDy(TVector3::kZero),
					fIsSelectionRay(false),
					fOnlyFacets(false),
					fReserved(0)
	{
	}

	inline void Init()
	{
		fOrigin		= TVector3::kZero;
		fDirection	= TVector3::kZero;
		fDy = fDx = fOy = fOx = TVector3::kZero;
		fIsSelectionRay = false;
		fOnlyFacets = false;
		fReserved = 0;
	}

	TVector3	fOrigin;			///< Origin of the ray
	TVector3	fDirection;			///< Direction of the ray

	TVector3	fOx;				///< Partial derivative of the origin relatively to X
	TVector3	fOy;				///< Partial derivative of the origin relatively to Y

	TVector3	fDx;				///< Partial derivates of the direction relatively to X
	TVector3	fDy;				///< Partial derivates of the direction relatively to Y

#if WIN
	boolean		fIsSelectionRay:1;	///< rendering or selection ( for selection use best available LOD )
	boolean		fOnlyFacets:1;		///< compute intersection with facets only (no self-raytraceable)
	boolean		fReserved:6;
#elif MAC
	boolean		fReserved:6;
	boolean		fOnlyFacets:1;		///< compute intersection with facets only (no self-raytraceable)
	boolean		fIsSelectionRay:1;	///< rendering or selection ( for selection use best available LOD )
#else
	#error - unknown platform
#endif
};


struct FacetInfo;
struct FacetMesh;
struct I3DShGroup;
struct I3DShEnvironment;

/// Parameters for the rayhit calcinfo method
struct TCalcInfoParams {
	// ****************************************************************************
	//								GetType
	// 
	/// return an IDType to be sure the CalcInfo gets the right parameters
	/// 
	/// 
	virtual IDType GetType() = 0;
};

/// \addtogroup Data
/// \{

/// Stores the information about the intersection of a ray and an object
///
struct RayHit3D : public ShadingIn
{
	RayHit3D(MicroTick inTime = kInvalidTime)
	{
		fShouldSetUV=true;
		fShouldSetIsoUV=true;
		fShouldSetNormalDerivative=false;
		fTime = inTime;
		fCalcInfoParam = nil;
		fEdgeSize = TVector3(0, 0, 0);
		fInstance=NULL;
		fFacetMesh=NULL;
	}
	void Reset()
	{
		fShouldSetUV=true;
		fShouldSetIsoUV=true;

		fInstance=NULL;
		fFacetMesh=NULL;
	}
	void CalcInfo(ShadingFlags &shadingFlags,boolean calcDerivatives,const Ray3D &ray);

	real64			ft;					///< t parameter along the ray: fPosition = RayOrigin + t * RayDirection
	TVector3		fReflectDir;		///< direction of reflection of the ray
	TTransform3D	fT;
	TTransform3D	fInvT;
	TMatrix33		fNormalDerivative;	///< derivative of the normal depending on the position in local coordinates
	TVector3		fUVDerivative[2];	///< derivative of the UV depending on the position in local coordinates
	MicroTick		fTime;				///< local time in microticks of the object hit, in most case should not be modified

	FacetInfo*		fFacetInfo;			///< private data of the raytracer ( used in fCalcInfo )
	real			fBaryCoord[3];		///< barycentric coordinates of hit point on hot facet
	int32			fFacetIndex;		///< facet hit (index in facetMesh with best Level Of Detail)
	FacetMesh*		fFacetMesh;			///< pointer to the facet mesh
	TVector3		fEdgeSize;			///< A vector representing the longest edge of the face in local coordinates

	int32			fInstanceIndex;		///< index of the instance in the instance grid list (used to identify instance to avoid self shadowing effects)
	int32			fSubInstanceIndex;	///< index used in the by some some raytracable primitives to identify a sub instance (example: a leaf in a tree)
	
	void (*fCalcInfo)(RayHit3D &me);	///< function called by the renderer to finish filling this structure after a hit
	TCalcInfoParams* fCalcInfoParam;	///< a structure the primitive can initialize in rayHit and use in calcinfo

	boolean			fShouldSetUV;				///< true if fUV should be set
	boolean			fShouldSetIsoUV;			///< true if fIsoU and fIsoV should be set
	boolean			fShouldSetNormalDerivative;	///< true if fNormalDerivate should be set ( we only need it for reflection and transparency...)
	boolean			fNormalFlipped;				///< true if the normal has been flipped to face the incoming ray
};

/// \}

class TRayHitAccumulator;

/// \addtogroup Data
/// \{


/// Structure used when searching for the intersection of a ray and an object
///
/// The fields originInstanceIndex,originSubIndexIndex and originFacetIndex are
/// used to identify a particular triangle that is excluded from intersection
/// calculation (usually the origin of the ray for a reflected ray). If you do
/// not want to provide such a triangle, just use -1 in all those fields.
/// 
struct RayHitParameters : public TMCObject
{
	inline RayHitParameters()
	{
		tmin = 0;
		tmax = 1e30f;
		hit  = NULL;
		ray  = NULL;
		originInstanceIndex = -1;
		originSubIndexIndex = -1;
		originFacetIndex = -1;
		additionalInfos = NULL;
		rayHitAccumulator = NULL;
	}

	inline RayHitParameters(RayHit3D* theHit,Ray3D* theRay)
	{
		tmin = 0;
		tmax = 1e30f;
		hit  = theHit;
		ray  = theRay;
		originInstanceIndex = -1;
		originSubIndexIndex = -1;
		originFacetIndex = -1;
		additionalInfos = NULL;
		rayHitAccumulator = NULL;
	}
	inline RayHitParameters(real min,real max,RayHit3D* theHit,Ray3D* theRay)
	{
		tmin = min;
		tmax = max;
		hit  = theHit;
		ray  = theRay;
		originInstanceIndex = -1;
		originSubIndexIndex = -1;
		originFacetIndex = -1;
		additionalInfos = NULL;
		rayHitAccumulator = NULL;
	}

	real 			tmin;		///< start parameter of the ray.
	real 			tmax;		///< end parameter of the ray.
	Ray3D*			ray;		///< a pointer to the ray.
	RayHit3D*		hit;		///< a pointer to the result of the intersection.

	// this is used to exclude the origin of the ray (-1 means that there is no origin)
	int32			originInstanceIndex;		///< index used in the instance grid to identify each instance
	int32			originSubIndexIndex;		///< index used in the by some some raytracable primitive to identify a sub instance (example: a leaf in a tree)
	int32			originFacetIndex;			///< index of the facet of the instance that should excluded

	void*			additionalInfos;			///< used in TGrid to do something else than just finding the first rayhit. For example storing all the instances intersected by the ray.

	TRayHitAccumulator*		rayHitAccumulator;	///< Optional struture to store all the ray hits along a ray
};



/// Raytracing contexts are created by the renderer. There should be one raytracing context per thread
/// as they are not smp compliant.
///
class TRayTracingContext
{
	TRayTracingContext();
	~TRayTracingContext();

	/// Move the raytracing context to the next level
	void		IncrementLevel();

	// Move the raytracing context to the previous level
	void		DecrementLevel();

	TRayHitAccumulator&		GetRayHitAccumulator()  { MCAssert(fRayAccumulatorPerLevel[fCurrentLevel]); return *fRayAccumulatorPerLevel[fCurrentLevel]; }
protected:
	TMCPtrArray<TRayHitAccumulator>		fRayAccumulatorPerLevel;		// for each raytracing level the ray accumulator
	int32								fCurrentLevel;
};

/// \}

/// \addtogroup Data
/// \{


enum EGlobalIlluminationType
{
	eAmbientOcclusion	='Ambi',
	eIndirectLight		='IndL'
};

/// Defines the illumination settings for the current rendering.
///
struct IllumSettings : public TMCObject
{
	IllumSettings();

	boolean						fShadowsOn;							/// True if shadows should be calculated
	boolean						fReflectionOn;						/// True if reflection should be calculated
	boolean						fTransparencyOn;					/// True if transparency should be calculated
	boolean						fLightThroughTransp;				/// True if light should be go through transparent objects (for shadowing)
	boolean						fBumpOn;							/// True if bump mapping should be calculated
	boolean						fRefractionOn;						/// True if refraction should be calculated
	boolean 					fRadiosityOn;						/// True if indirect lighting should be calculated
	boolean						fCausticsOn;						/// True if caustics should be calculated
	boolean						fUsePhotonMap;						/// use photon map directly for indirect lighting
	boolean						fUseGammaCorrection;				/// on/off gamma correction
	boolean						fUseSkyLight;						/// use the sky as a light source
	boolean						fUseDoubleBounce;					/// use double bounce for indirect lighting
	boolean						fUseIrradianceCaching;				/// enable irradiance caching
	boolean						fComputeSeparatedShadow;			/// compute the shadow as separated (used for compositing)
	real						fGamma;								/// value of gamma
	int32						fMaxRayDepth;						/// maximum ray depth for reflections and transparency
	EGlobalIlluminationType		fGlobalIlluminationType;			/// type of global illumination (Ambient occlusion or Indirect Light)
	int32						fIndirectLightingQuality;			/// for sampling of indirect lighting 0-3 (3 is best)
	real						fIndirectLightingIntensity;			/// intensity of indirect lighting
	real						fSkyLightIntensity;					/// intensity of the sky light
	real						fCausticIntensity;					/// intensity of caustics
	real						fInterpolationQuality;				/// quality of interpolation [0,1], 1 for maximum quality
	real						fAmbientRadius;						/// radius for ambient occlusion (3D units, inch by default)
};

struct IllumSettings2 : public IllumSettings
{
	IllumSettings2();

	boolean						fComputeAtmosphereDetails;			/// compute the atmosphere lighing details (used for compositing)
	boolean						fComputeVolumePrimitivesDetails;	/// compute the volume primitives lighing details (used for compositing)
	boolean						fComputeVolumetricEffectsDetails;	/// compute the volumetric effects lighing details (used for compositing)
};

/// \}

/// \addtogroup Data
/// \{

/// Stores the history of a ray
///
struct RTLevelInfo  : public TMCObject
{ 
	RTLevelInfo() : diff(0),ref(0),trans(0),refractionCount(0),refracted(false),
					attenuation(1.0f),lastPhotonRadius(0),samplingLevel(0) {}

	uint8		ref;				///< Number of reflections.
	uint8		trans;				///< Number of transparent surfaces traversed.
	uint8		refractionCount;	///< Number of refractions.
	uint8		diff;				///< Number of diffuse reflection (for monte carlo sampling).
	boolean		refracted;			///< True if the ray has been refracted.

	real		attenuation;		///< Effect of the current ray in the final pixel color (0 means that it has no effect)
	real		lastPhotonRadius;	///< radius of sphere containing the n closest photons at last intersection point
	uint8		samplingLevel;		///< Describes the current sampling level for this ray
};

/// \}


#define LIGHTING_HINT 1
#define INSTANCE_HINT 2


/// \addtogroup Data
/// \{

/// This class is used as a cache by the raytracer to store the lighting coming from a particular light.
///
struct BasicLightInfo : public TMCObject
{
	BasicLightInfo() : fInitialised(false) {}

	inline void ReInit() { fInitialised=false; }

	boolean			fInitialised;		/// Indicates if the value as already been computed
	TMCColorRGB		fColor;				/// Color of the light
};

/// This class is used as a cache by the raytracer to store the lighting coming from a particular light.
///
class LightingInfo : public BasicLightInfo
{
public:
	TVector3		fDirection;			/// direction from the light to the currentPoint
	TMCColorRGB		fNoShadowColor;
	boolean			fIsInShadow;
};

/// This class is used as a cache by the raytracer to store the indirect lighting.
///
struct IndirectLightingInfo : public BasicLightInfo
{
	TVector3		fNormal;			/// Normal used for indirect lighting calculation
	real			fAmbientOcclusionFactor;
};

/// \}

/// Struct used to get linear details about a color effect applied to an input color:
/// ResultColor = fColorMult * InputColor + fColorAdd
///
struct TColorRGBLinearEffect : public TMCObject
{
	TColorRGBLinearEffect() { Reset(); }

	TMCColorRGB		fColorMult;			///< Linear multiplicative component (composited as multiplicative)
	TMCColorRGB		fColorAdd;			///< Linear additive component (composited as additive)

	void			Reset()
	{
		fColorMult.Set(1, 1, 1);
		fColorAdd.Set(0, 0, 0);
	}

	void			Apply(TMCColorRGB& inOutColor) const
	{
		inOutColor = (inOutColor % fColorMult) + fColorAdd;
	}

	void			ApplyInverse(TMCColorRGB& inOutColor) const
	{
		inOutColor -= fColorAdd;
		for (int32 i=0; i<3; ++i)
		{
			if (fColorMult[i] > 0) inOutColor[i] /= fColorMult[i];
			else inOutColor[i] = 0;
		}
	}
};

/// Struct used to get details information about the lighting of a point regarding multi-passes.
/// The content need to be filled in order to be supported correctly by the multi-pass rendering
/// module.
///

struct LightingCompositingDetail : public TMCObject
{
	LightingCompositingDetail();

	void				Reset();

	// Final color
	TMCColorRGBA		fResColor;					///< resulting color from lighting & shading (alpha should be premultiplied)

	// Image compositing details
	TMCColorRGB			fBackground;				///< Background component (composited as normal)
	TMCColorRGB			fAmbient;					///< Ambient containing ambient occlusion factor if any (composited as additive : C = C + C_this, for each component (red, green and blue) )
	TMCColorRGB			fDiffuseLight;				///< Diffuse (composited as additive). NOTE: It should contains shadowing except if the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB			fSpecularLight;				///< Specular (composited as additive). NOTE: It should contains shadowing except if the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB			fLightShadow;				///< Shadow (multiplies fDiffuseLight + fSpecularLight). NOTE: It should only be computed when the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB			fGlow;						///< Glow (compisted as additive)
	TMCColorRGB			fReflection;				///< Reflection (compoisted as additive)
	TMCColorRGB			fRefraction;				///< Refraction and transparency (composited as additive)
	TMCColorRGB			fGlobalIllumination;		///< Global illumination (composited as additive)
	TMCColorRGB			fCaustics;					///< Caustics (composited as additive)
	TMCColorRGB			fSubsurfaceScattering;		///< Subsurface scattering (composited as additive)
	TMCColorRGB			fAtmosphere;				///< Should not be used

	// Lighting details (not depending on the surface)
	real				fAmbientOcclusionFactor;	///< Ambient occlusion factor (this is not composited as it should already be included in the fAmbient field)
};

struct FullLightingCompositingDetail : public TMCObject
{
	FullLightingCompositingDetail();

	void					Reset();
	void					Set(const LightingCompositingDetail& detail);
	void					InterpolateDetails(const FullLightingCompositingDetail& a, const FullLightingCompositingDetail& b, real32 t, boolean computeShadow, boolean computeAtmosphere, boolean computeVolumePrimitive);

	// Final color
	TMCColorRGBA			fResColor;					///< Resulting color from lighting & shading (alpha should be premultiplied)

	// Image compositing details
	TMCColorRGB				fBackground;				///< Background component (composited as normal)
	TMCColorRGB				fAmbient;					///< Ambient containing ambient occlusion factor if any (composited as additive : C = C + C_this, for each component (red, green and blue) )
	TMCColorRGB				fDiffuseLight;				///< Diffuse (composited as additive). NOTE: It should contains shadowing except if the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB				fSpecularLight;				///< Specular (composited as additive). NOTE: It should contains shadowing except if the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB				fLightShadow;				///< Shadow (multiplies fDiffuseLight + fSpecularLight). NOTE: It should only be computed when the fComputeSeparatedShadow flag is set on the the IllumSettings.
	TMCColorRGB				fGlow;						///< Glow (composited as additive)
	TMCColorRGB				fReflection;				///< Reflection (composited as additive)
	TMCColorRGB				fRefraction;				///< Refraction and transparency (composited as additive)
	TMCColorRGB				fGlobalIllumination;		///< Global illumination (composited as additive)
	TMCColorRGB				fCaustics;					///< Caustics (composited as additive)
	TMCColorRGB				fSubsurfaceScattering;		///< Subsurface scattering (composited as additive)
	TColorRGBLinearEffect	fAtmosphere;				///< Atmosphere linear components. NOTE: It should only be computed when the fComputeAtmosphereDetails flag is set on the the IllumSettings.
	TColorRGBLinearEffect	fVolumePrimitives;			///< Volume primitives linear components. NOTE: It should only be computed when the fComputeVolumePrimitivesDetails flag is set on the the IllumSettings.
	TMCColorRGB				fVolumetricEffects;			///< Volume effects linear components. NOTE: It should only be computed when the fComputeVolumetricEffectsDetails flag is set on the the IllumSettings.

	// Lighting details (not depending on the surface)
	real					fAmbientOcclusionFactor;	///< Ambient occlusion factor (this is not composited as it should already be included in the fAmbient field)
};


inline LightingCompositingDetail::LightingCompositingDetail()
{
	Reset();
}

inline void LightingCompositingDetail::Reset()
{
	fResColor.Set(0,0,0,0);

	fBackground.Set(0,0,0);
	fAmbient.Set(0,0,0);
	fDiffuseLight.Set(0,0,0);
	fSpecularLight.Set(0,0,0);
	fLightShadow.Set(0,0,0);
	fGlow.Set(0,0,0);
	fReflection.Set(0,0,0);
	fRefraction.Set(0,0,0);
	fGlobalIllumination.Set(0,0,0);
	fCaustics.Set(0,0,0);
	fSubsurfaceScattering.Set(0,0,0);
	fAtmosphere.Set(0,0,0);

	fAmbientOcclusionFactor = 0;
}

inline FullLightingCompositingDetail::FullLightingCompositingDetail()
{
	Reset();
}

inline void	FullLightingCompositingDetail::Set(const LightingCompositingDetail& detail)
{
	fResColor = detail.fResColor;
	fBackground = detail.fBackground;
	fAmbient = detail.fAmbient;
	fDiffuseLight = detail.fDiffuseLight;
	fSpecularLight = detail.fSpecularLight;
	fLightShadow = detail.fLightShadow;
	fGlow = detail.fGlow;
	fReflection = detail.fReflection;
	fRefraction = detail.fRefraction;
	fGlobalIllumination = detail.fGlobalIllumination;
	fCaustics = detail.fCaustics;
	fSubsurfaceScattering = detail.fSubsurfaceScattering;
	fAmbientOcclusionFactor = detail.fAmbientOcclusionFactor;

	fAtmosphere.Reset();
	fVolumePrimitives.Reset();
	fVolumetricEffects.Set(0,0,0);
}

inline void FullLightingCompositingDetail::Reset()
{
	fResColor.Set(0,0,0,0);

	fBackground.Set(0,0,0);
	fAmbient.Set(0,0,0);
	fDiffuseLight.Set(0,0,0);
	fSpecularLight.Set(0,0,0);
	fLightShadow.Set(0,0,0);
	fGlow.Set(0,0,0);
	fReflection.Set(0,0,0);
	fRefraction.Set(0,0,0);
	fGlobalIllumination.Set(0,0,0);
	fCaustics.Set(0,0,0);
	fSubsurfaceScattering.Set(0,0,0);
	fAtmosphere.Reset();
	fVolumePrimitives.Reset();
	fVolumetricEffects.Set(0,0,0);

	fAmbientOcclusionFactor = 0;
}


/// Struct used to get details information about the lighting of a point.
///
struct LightingDetail : public LightingCompositingDetail
{
	LightingDetail(ShadingOut& shadingOut);

	boolean						fIsInShadow;

	ShadingOut*					fShadingOut;	///< a pointer to the shading to return

	real						fLayerMask;		///< used only in Layer Shader
};

inline LightingDetail::LightingDetail(ShadingOut& shadingOut) : fShadingOut(&shadingOut)
{
	fIsInShadow=false;

	fLayerMask = 0;
}

/// Bit field that specifies what lighting component should be calculated.
///
struct LightingFlags : public TMCObject
{
	LightingFlags()
	{
		fComputeDiffuseDirectLighting = 1;
		fComputeDiffuseIndirectLighting = 1;
		fComputeReflections = 1;
		fLightThroughTransparency = 1;
	}

	uint32 fComputeDiffuseDirectLighting:1;
	uint32 fComputeDiffuseIndirectLighting:1;
	uint32 fComputeReflections:1;
	uint32 fLightThroughTransparency:1;
};

/// \addtogroup Data
/// \{

/// Rendering cache for first hits.
///
struct FirstHitInfo : public TMCObject
{
public:
	enum { kSampled=1, kFinalColor=2, kReflection=4, kTransparency=8, kCaustic=16, kInterpolated=32 };

	boolean HasBeenSampled() const		{ return fFlags & kSampled; }
	boolean HasFinalColor()	const		{ return fFlags & kFinalColor; }
	boolean HasReflection()	const		{ return fFlags & kReflection; }
	boolean HasTransparency() const		{ return fFlags & kTransparency; }
	boolean HasCaustics() const			{ return fFlags & kCaustic; }
	boolean HasBeenInterpolated() const	{ return fFlags & kInterpolated; }

	void    SetHasBeenSampled()		{ fFlags|=kSampled; }
	void    SetHasFinalColor()		{ fFlags|=kFinalColor; }
	void    SetHasReflection()		{ fFlags|=kReflection; }
	void    SetHasTransparency()	{ fFlags|=kTransparency; }
	void    SetHasCaustics()		{ fFlags|=kCaustic; }
	void	SetInterpolated()		{ fFlags|=kInterpolated; }

public:
	uint32							fFlags;
	TMCColorRGB						fReflectionColor;
	TMCColorRGB						fTransparencyColor;
	TMCColorRGB						fCausticColor;

	TMCClassArray<LightingInfo>		fLightInfo;					// array holding the lighting for each light
	IndirectLightingInfo			fIndirectLightingInfo;		// indirect lighting calculated
	BasicLightInfo					fInscatteredLightingInfo;	// inscattered light info
};

/// \}


/// \addtogroup Data
/// \{

/// The rendering environement for the final renderer (see I3DExFinalRenderer)
///
struct RendEnv : public TMCObject
{
	TMCCountedPtr<I3DShGroup>		fTree;			///< The root of the scene being rendered.
	TMCCountedPtr<I3DShEnvironment>	fBackground;	///< A pointer to the environement
	TMCCountedPtr<I3DShEnvironment>	fBackdrop;		///< A pointer to the environement
	TMCCountedPtr<I3DShEnvironment>	fAtmosphere;	///< A pointer to the environement.
	TMCColorRGBA					fAmbient;		///< The color of the ambient light.
	TBBox2D							fuvMinMax;		///< The production frame in screen coordinates
} ;

/// \}

/// \addtogroup Data
/// \{

/// The rendering context that must be propagated from one ray to another
///
struct RendContext : public TMCObject
{
	RendContext(uint32 numRays, uint32 seed) : fNumberOfRays(numRays), fRandomSeed(seed) {}

	void ReInit(uint32 numRays, uint32 seed) { fNumberOfRays=numRays; fRandomSeed = seed; }

	uint32	fNumberOfRays;
	uint32	fRandomSeed;	///< random seed (used for random sampling)	
} ;

/// \}

/// \addtogroup Data
/// \{

/// Info about the point being shaded and the lighting of the scene. Used for shaders
/// that implement their own lighting.
///
struct LightingContext : public TMCObject
{
	LightingContext() : fRendContext(0,0)
	{
		fRaytracer = NULL;
		fCalculateTransparency = true;
		fIllumSettings = NULL;
		fRendEnv = NULL;
		fLevel = NULL;
		
	}

	LightingContext(I3DExRaytracer*			raytracer,
					const IllumSettings&	illum,
					const RendEnv&			rendEnv,
					const RTLevelInfo&		level,
					const uint32			seed) : 
	fRaytracer(raytracer),fCalculateTransparency(true),fIllumSettings(&illum),fRendEnv(&rendEnv),fLevel(&level),fRendContext(0,seed),
	fFirstHitInfo(NULL)
	{}

	//					methods

	// ****************************************************************************
	//								Init
	// 
	/// Inits the lighting context
	/// 
	/// 
	void	Init(	I3DExRaytracer*			raytracer,
					const IllumSettings&	illum,
					const RendEnv&			rendEnv,
					const RTLevelInfo&		level,
					const uint32			seed)
	{
		fRaytracer = raytracer;
		fCalculateTransparency = true;
		fIllumSettings = &illum;
		fRendEnv = &rendEnv;
		fLevel = &level;
		fRendContext.ReInit(0,seed);
		fFirstHitInfo = NULL;
	}
	
	// ****************************************************************************
	//								GetAmbientLight
	// 
	/// Returns the intensity of the ambient light in the scene
	/// 
	/// 
	const TMCColorRGBA& GetAmbientLight() const
	{ 
		return fRendEnv->fAmbient;
	}

	// ****************************************************************************
	//								CalcReflectDir
	// 
	/// Computes the direction in which a ray reflects on a surface.
	/// The result is stored in fReflectDir
	/// 
	/// \param rayDir  is the direction of the incomming ray
	/// \param normal  is the normal at the intersection point between ray and surface
	/// 
	inline void CalcReflectDir(const TVector3 &rayDir,const TVector3 &normal) const
	{
		real t=2.0f*rayDir * normal;

		fReflectDir = rayDir - (normal*t);
	}



	//					info for first hit points

	FirstHitInfo*						fFirstHitInfo;
	TVector2							fScreenCoordinates;

	//					general data
	LightingFlags						fLightingFlags;

	const IllumSettings*				fIllumSettings;		///< lighting flags
	const RendEnv*						fRendEnv;
	I3DExRaytracer*						fRaytracer;

	const RTLevelInfo*					fLevel;
	const Ray3D*						fIncomingRay;
	RayHit3D*							fHit;
	boolean								fNormalFlipped;				///< if the normal has been flipped
	
	/// If fCalculateTransparency is true, the lighting model must calculate the alpha channel and
	/// the straight transparency (by opposition to refracted transparency)
	boolean								fCalculateTransparency;

	//		things that should be filled before calling any lighting functions

	mutable	TVector3					fNormal;		///< normal on current point after bump is applied (in global coord)
	mutable	TVector3					fReflectDir;
	mutable RendContext					fRendContext;
};

/// \}

// ***************************************************************************
//						struct TRenderArea
//
/// Describes a rendering rectangle (used in I3DRenderHelper)
///
struct TRenderArea : public TMCObject
{
	TRenderArea(real w,real h,TBBox2D uvbox) : fWidth(w),fHeight(h),fuv(uvbox) {}
	
	TBBox2D	fuv;		///< camera coordinates
	real	fWidth;		///< width in pixels
	real	fHeight;	///< height in pixels
	
	// ****************************************************************************
	//								PosToUV
	// 
	/// Converts a point in pixel coordinates (fWidth, fHeight) into camera coordinates
	/// \note The uv y coordinate varies "oppositely" to the pixel y coord.
	/// 
	/// \param inPos  point in pixel coordinates
	/// \param outUV  result in camera coordinates
	/// 
	void PosToUV(const TMCPoint& inPos, TVector2& outUV)
	{
		outUV.x= fuv.fMin.x + fuv.GetWidth()*inPos.x/fWidth;
		outUV.y= fuv.fMax.y - fuv.GetHeight()*inPos.y/fHeight;
	}

	
	// ****************************************************************************
	//								UVToPos
	// 
	/// Converts a point in camera coordinates into pixel coordinates (fWidth, fHeight) 
	/// \note The uv y coordinate varies "oppositely" to the pixel y coord.
	/// 
	/// \param inUV    point in camera coordinates
	/// \param outPos  result in pixel coordinates
	/// 
	void UVToPos(const TVector2& inUV, TMCPoint& outPos)
	{
		ASSIGN_CAST( outPos.x, (inUV.x - fuv.fMin.x)*fWidth/fuv.GetWidth() );
		ASSIGN_CAST( outPos.y, (fuv.fMax.y - inUV.y)*fHeight/fuv.GetHeight() );
	}

	// ****************************************************************************
	// -Description:
	//		operator equal
	// -Parameters:
	//		rhs : other renderarea to compare "this" to
	// -Returns:
	//		true if all fields are the same
	inline boolean  operator== (const TRenderArea& rhs)
		{ return ((fuv==rhs.fuv)&&(fWidth==rhs.fWidth)&&(fHeight==rhs.fHeight)); }
};

typedef void (*RayHitCallback)(Ray3D* aR, real tmin, real tmax, RayHit3D* hit, void* privData);


#endif