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


		ShaderTypes.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.
 
		Author:	Ray Dream
		Date:	10/21/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/14/98	EricB		Moved an enum from ShapeShaders.h to ShaderTypes.h

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

#ifndef __ShaderTypes__
#define __ShaderTypes__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "APITypes.h"
#include "MCRealRect.h"
#include "MCColorRGBA.h"
#include "MCString.h"
#include "MCBasicDefines.h"
#include "MCAssert.h"
#include "MCPtrArray.h"
#include "Matrix33.h"
#include "RealQuat.h"


struct I3DShInstance;
struct I3DExLightsource;
//struct I3DExLightingModel;
struct IllumSettings;


#define kShaderFamily					 'shdr'

#define kValueShdr						 'sval'
#define kColorShdr						 'sclr'
#define kColorGradientShdr				 'clgr'
#define kCurveShdr						 'curv'
#define kInstanceShdr					 'sins'

#define kTextureMapShdr					 'smap'

#define kCompositeShdr					 'scmp'
#define kAddOperatorShdr				 'sadd'
#define kSubOperatorShdr				 'smin'
#define kMulOperatorShdr				 'smul'
#define kIncOperatorShdr				 'sinc'
#define kMixShdr						 'smix'
#define kGlobalMixShdr					 'sgmx'

#define kPhongLightingModel				'phog'
#define kShadowCatcherShdr				'shwc'

#define kShadingDomain					 'smod'
#define kShadingDomainSphericalMapping   'ssph'
#define kShadingDomainCylindricalMapping 'scyl'
#define kShadingDomainBoxMapping		 'sbox'
#define kShadingDomainParametricMapping  'sprm'

#define kLayeredShader					 'slay'

#define kRectShapeShader				 'srec'
#define kPolygonShapeShader				 'spol'
#define kOvalShapeShader				 'sova'
#define kRegionShapeShader				 'sreg'

#define kWoodShdr						 'swod'
#define kWiresShdr						 'swir'
#define kMarbleShdr						 'smrb'
#define kCellularShdr					 'fcel'
#define kEnvironmentShdr				 'senv'
#define kFractalNoiseShdr				 'snoi'

#define kReferenceShdr					 'sref'

#define kCheckerShdr					 'schk'
#define kSpotsShdr						 'sspt'
#define kGradientShdr					 'grad'
#define kPsychedelicShdr				 'psyc'
#define kJuliaShdr						 'juli'
#define kMandelbrotShdr					 'mndl'

#define kSquaringShdr					 'sqSh'

#define kRippleShdr						 'RfRI'
#define kWaveShdr						 'RfWA'
#define kFireShdr						 'RfFR'
#define kSnowShdr						 'RfSN'


// - PMap entry's token
// Use those tokens to retrieve a parameter in the PMap of one of the shaders described above.
// Call IShParameterComponent::GetParameter()

// Shading domain:
#define	kUVSpaceIDPmapElem				 'uvid'	// PMap entry of type uint32

// List of layers:
#define kLayerList						 'shly'	// PMap entry of type TMCCountedPtrArray<IShParameterComponent>*

// Layers
#define kLayerSubShader					'Shad'	// PMap entry of type IShParameterComponent
#define kLayerMask   					'Mask'	// PMap entry of type IShParameterComponent
#define kLayerShadingDomain				'uvid'	// PMap entry of type uint32

#define kLayerSizeTop					 'top '	// PMap entry of type real
#define kLayerSizeLeft					 'left'	// PMap entry of type real
#define kLayerSizeBottom				 'bott'	// PMap entry of type real
#define kLayerSizeRight					 'rght'	// PMap entry of type real

// Operators
#define kOperatorsSubShdr				 'Sh00' // PMap entry of type IShParameterComponent
#define kCompositeSubShdr				 'Shc0' // PMap entry of type IShParameterComponent

// Polygon Shape layer:
// That will return the number of vertices for that polygon.
// Note : to access the vertices of the polygon layer, use the index of the vertex as ID. 
// (Reminder : the first vertex is at index 0)
#define kPolyShdrNbVertices				 'spnv'	// PMap entry of type uint32
#define kPolyVertexToken				 'svrt'	// PMap entry of type TVector2




//** Shading defines **********************************************************

/// Constants that define the methods that are implemented by a given shader.
///
enum  EShaderOutput 
{
	kNotImplemented		= 0,
	kUsesGetValue		= (1<<1),
	kUsesGetColor		= (1<<2),
	kUsesGetVector		= (1<<3),
	kUsesDoShade		= (1<<4),
	kUsesGetBump		= (1<<5),
	kUsesGetReflection  = (1<<6),
	kUsesGetTransparency= (1<<7),

	kUseCalculateDirectLighting			= (1<<8),
	kUseCalculateReflection				= (1<<9),
	kUseCalculateCaustics				= (1<<10),
	kUseCalculateIndirectLighting		= (1<<11),
	kUseCalculateTransparency			= (1<<12),
	kUseCalculateAlpha					= (1<<13),
	kUseCalculateSubsurfaceScattering	= (1<<14),
	kUsesGetShaderApprox				= (1<<15),
	kUsesGetShaderApproxColor			= (1<<16)
};

//pascalc: if you add a new channel, don't forget to add it to the kAllChannels
enum EChannelIndices
{
	kColorChannel		= 0,
	kAlphaChannel		= 1,
	kSpecularityChannel	= 2,
	kShininessChannel	= 3,
	kNormalChannel		= 4,
	kReflectionChannel	= 5,
	kTransparencyChannel= 6,
	kRefractionChannel	= 7,
	kGlowChannel		= 8,
	kSubSurfaceChannel  = 9,
	kTranslucencyChannel= 10,

	kNumChannels,
	kMiscChannel,			// Not a real channel, used in GetShadersForChannel to get shader not part of any channels
	kDisplacementChannel,	// Not a real channel

	kMaxChannels,
};

enum EChannelMask
{
	kColorChannelMask			= 1<<kColorChannel,
	kAlphaChannelMask			= 1<<kAlphaChannel,
	kSpecularityChannelMask		= 1<<kSpecularityChannel,
	kShininessChannelMask		= 1<<kShininessChannel,
	kNormalChannelMask			= 1<<kNormalChannel,
	kReflectionChannelMask		= 1<<kReflectionChannel,
	kTransparencyChannelMask	= 1<<kTransparencyChannel,
	kRefractionChannelMask		= 1<<kRefractionChannel,
	kGlowChannelMask			= 1<<kGlowChannel,
	kSubSurfaceChannelMask		= 1<<kSubSurfaceChannel,
	kTranslucencyChannelMask	= 1<<kTranslucencyChannel,
	kAllChannelMask = (1<<20)-1
};


enum  EShaderCompletionMask 
{
	kNoChannel			= 0,
	kAllChannels		= 1+2+4+8+16+32+64+128+256+512+1024
};

// used for ShadingIn.fUVSpaceID
enum 
{
	kAllUVSpaces  = -2,
	kMaxUVSpace   = 0x7FFFFFFF
};

enum  EShaderFunctionType
{
	kUnknownFunctionType,	// the type depends on the parent
	kFullShader,	// complete shader (ie. MultiChannel)
	kColorFunction,
	kGrayscaleFunction,
	kBumpFunction,
	kDisplacementShader,
};


/// Stores information about a Shading Domain (badly named UV space).
/// A shading domain covers several polygons.
/// A polygon currently has a single UV space but will have several at some point...
///
struct UVSpaceInfo : public TMCObject
{
	uint32		 fID;				///< UV Space ID 
	boolean 	 fWraparound[2];	///< Tells if the UV Space is closed in the U or V direction
	TMCString31  fName;				///< UV Space Name
};

/// Raydream UV info (not between 0 and 1)
///
struct UVSpaceInfoRDS5 : public UVSpaceInfo
{
	UVSpaceInfoRDS5 &operator=(const UVSpaceInfo &info);

	TVector2	 fMin;				///< UV Space minimum boundaries
	TVector2	 fMax;				///< UV Space maximum boundaries	
};

inline UVSpaceInfoRDS5 &UVSpaceInfoRDS5::operator=(const UVSpaceInfo &info)
{
	fID=info.fID;
	fWraparound[0]=info.fWraparound[0];
	fWraparound[1]=info.fWraparound[1];
	fName=info.fName;

	// Undefined fMin & fMax :
	fMin[0] = fMin[1] = kRealZero;
	fMax[0] = fMax[1] = kRealOne;
	
	return *this;
};

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

/// \addtogroup Data
/// \{

/// Defines the shading transform associated with a shader.
///
struct ShaderTransformData : public TMCObject
{
	ShaderTransformData()
	{
		fEnabled		= false;
		fUniformScale	= false;
		fOverallScale	= 1.0f;
		fXScale			= 1.0f;
		fYScale			= 1.0f;
		fZScale			= 1.0f;
		fXCenter		= 0.0f;
		fYCenter		= 0.0f;
		fZCenter		= 0.0f;
	}
	boolean fEnabled;
	boolean	fUniformScale;
	real32	fOverallScale;
	real32	fXScale;
	real32	fYScale;
	real32	fZScale;
	real32	fXCenter;
	real32	fYCenter;
	real32	fZCenter;
	TMatrix33SymQuaternion fRotation;
};

/// \}

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

/// Deprecated, use TMCRealRect instead
///
class ShRect :public TMCRealRect
{
public:
				ShRect(void) {fTop = kRealZero;fLeft = kRealZero;fBottom = kRealZero;fRight = kRealZero;}
				ShRect(real itop,real ilft,real ibot,real irgt) {fTop = itop;fLeft = ilft;fBottom = ibot;fRight = irgt;}
	
	ShRect&		operator+=(const TVector2& pt);
	ShRect&		operator= (const TVector2& pt);
	ShRect		operator| (const TVector2&) const; // Expands the rect to include the point
	
	boolean		Contains(TVector2& PP);
	boolean		NonEmpty(void)	{ return ((fTop != fBottom) && (fLeft!= fRight));}

private:
	real		Min(real a, real b) const {return a < b ? a : b;}
	real		Max(real a, real b) const {return a > b ? a : b;}
};

#define kMaxTexture Int16ToReal(16000)

inline void WrapAround(TVector2& thePoint)
{
	if (thePoint[0] < kRealZero)	thePoint[0]+=kMaxTexture;
	if (thePoint[0] > kMaxTexture)	thePoint[0]-=kMaxTexture;
	if (thePoint[1] < kRealZero)	thePoint[1]+=kMaxTexture;
 	if (thePoint[1] > kMaxTexture)	thePoint[1]-=kMaxTexture;
}

inline ShRect& ShRect::operator+=(const TVector2& pt)
{
	fTop    += pt[1];
	fLeft   += pt[0];
	fBottom += pt[1];
	fRight  += pt[0]; 
	return *this;
}

inline ShRect& ShRect::operator=(const TVector2& pt)
{
	fTop    = pt[1];
	fLeft   = pt[0];
	fBottom = pt[1];
	fRight  = pt[0]; 
	return *this;
}

inline ShRect ShRect::operator|(const TVector2& pt) const
{
	ShRect returnRect;
	
	returnRect.fTop		= Min(fTop,   pt[1]);
	returnRect.fLeft	= Min(fLeft,  pt[0]);
	returnRect.fBottom	= Max(fBottom,pt[1]);
	returnRect.fRight	= Max(fRight, pt[0]);
	
	return returnRect;
}


inline boolean ShRect::Contains(TVector2& PP)
{ 
	boolean result;

	if (fLeft < kRealZero)	result =  (PP[0] <= fRight) || (PP[0] > kMaxTexture + fLeft);
	else					result =  (PP[0] <= fRight) && (PP[0] > fLeft);
	if (fTop < kRealZero)	result &= (PP[1] <= fBottom)|| (PP[1] > kMaxTexture + fTop);
	else					result &= (PP[1] <= fBottom)&& (PP[1] > fTop);

	return result;
}

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

/// \addtogroup Data
/// \{

/// Specifies which information should be provided to a given shaders. For instance,
/// whether the shader needs texture coordinates.
///
struct ShadingFlags : public TMCObject
{
#if WIN

	ShadingFlags()
	{		
		*((uint16 *)this)	  = 0;
		fConstantChannelsMask = 0xffff;
	}

	void	CombineFlagsWith( ShadingFlags &flags )
	{
			*((uint16 *)this)	   |= *((uint16 *)&flags);
			fConstantChannelsMask  &= flags.fConstantChannelsMask;
	}
	
	uint16	fNeedsColor:1,				///< Needs Color - Not used
			fNeedsPoint:1,				///< Needs surface point in Global Coordinates
			fNeedsNormal:1,				///< Needs surface Normal in Global Coordinates
			fNeedsNormalDerivative:1,	///< Needs surface Normal in Global Coordinates
			fNeedsIsoUV:1,				///< Needs U iso-parametric vector in Local Coordinates
			fNeedsUV:1,					///< Needs u,v texture values
			fNeedsPointLoc:1,			///< Needs surface point in Local Coordinates
			fNeedsNormalLoc:1,			///< Needs surface Normal in Local Coordinates
			fNeedsNormalLocDerivative:1,///< Needs surface Normal derivative in Local Coordinates
			fNeedsPixelRatio:1,			///< Needs Pixel Ratio - Not used yet - Future use
			fChangesNormal:1,			///< The shader changes the Normal. The new Normal will have to be read in ShadingOut::fChangedNormal
			fUVSpaceShaders:1,			///< true if we have differents shaders in UVSpaceId.

			fNotUsed12:1,				///< Not Used.
			fNotUsed13:1,
			fNotUsed14:1,
			fNotUsed15:1;

	uint16	fConstantChannelsMask;		///< use these enum: 	kColorChannel,kSpecularityChannel,kShininessChannel,kNormalChannel...	

#else // because CodeWarrioir on MAC Sucks...

	ShadingFlags()
	{				
		fConstantChannelsMask = 0xffff;
		
		fNeedsColor				= false;				
		fNeedsPoint				= false;				
		fNeedsNormal			= false;				
		fNeedsNormalDerivative	= false;		
		fNeedsIsoUV				= false;				
		fNeedsUV				= false;					
		fNeedsPointLoc			= false;				
		fNeedsNormalLoc			= false;			
		fNeedsNormalLocDerivative=false;	
		fNeedsPixelRatio		= false;			
		fChangesNormal			= false;				
		fUVSpaceShaders			= false;
	}

	void	CombineFlagsWith( ShadingFlags &flags )
	{
			fNeedsColor				|= flags.fNeedsColor;
			fNeedsPoint				|= flags.fNeedsPoint;				
			fNeedsNormal			|= flags.fNeedsNormal;				
			fNeedsNormalDerivative	|= flags.fNeedsNormalDerivative;		
			fNeedsIsoUV				|= flags.fNeedsIsoUV;				
			fNeedsUV				|= flags.fNeedsUV;					
			fNeedsPointLoc			|= flags.fNeedsPointLoc;				
			fNeedsNormalLoc			|= flags.fNeedsNormalLoc;			
			fNeedsNormalLocDerivative|=flags.fNeedsNormalLocDerivative;
			fNeedsPixelRatio		|= flags.fNeedsPixelRatio;			
			fChangesNormal			|= flags.fChangesNormal;				
			fUVSpaceShaders			|= flags.fUVSpaceShaders;

			fConstantChannelsMask  &= flags.fConstantChannelsMask;
	}
	
	boolean	fNeedsColor,				// Needs Color - Not used
			fNeedsPoint,				// Needs surface point in Global Coordinates
			fNeedsNormal,				// Needs surface Normal in Global Coordinates
			fNeedsNormalDerivative,		// Needs surface Normal in Global Coordinates
			fNeedsIsoUV,				// Needs U iso-parametric vector in Local Coordinates
			fNeedsUV,					// Needs u,v texture values
			fNeedsPointLoc,				// Needs surface point in Local Coordinates
			fNeedsNormalLoc,			// Needs surface Normal in Local Coordinates
			fNeedsNormalLocDerivative,	// Needs surface Normal derivative in Local Coordinates
			fNeedsPixelRatio,			// Needs Pixel Ratio - Not used yet - Future use
			fChangesNormal,				// The shader changes the Normal. The new Normal will have to be read in ShadingOut::fChangedNormal
			fUVSpaceShaders;			// true if we have differents shaders in UVSpaceId.

	uint16	fConstantChannelsMask;		// use these enum: 	kColorChannel,kSpecularityChannel,kShininessChannel,kNormalChannel...	

#endif
};

/// \}


/// \addtogroup Data
/// \{

/// All the information that are passed to a shader for a given point.
///
struct ShadingIn : public TMCObject
{

public:

	ShadingIn();

	static	void Average(ShadingIn &out,ShadingIn &in1,ShadingIn &in2,ShadingFlags flags);

	TVector3	fPoint;					///< Surface point in Global Coordinates
	TVector3	fGNormal;				///< Surface Normal in Global Coordinates

	TVector3	fPointLoc;				///< Surface point in Local Coordinates
	TVector3	fNormalLoc;				///< Surface Normal in Local Coordinates

	TVector2	fUV;					///< u,v texture values

	TVector3	fPointx,fPointy;		///< Surface point derivatives in Global Coordinates
	TVector3	fNormalx,fNormaly;		///< Surface Normal derivatives in Global Coordinates

	TVector2	fUVx,fUVy;				///< texture derivatives

	TVector3	fPointLocx,fPointLocy;	///< Surface point derivatives in Local Coordinates
	TVector3	fNormalLocx,fNormalLocy;///< Surface Normal derivatives in Local Coordinates

	TVector3	fIsoU; 					///< U iso-parametric vector in Local Coordinates
	TVector3	fIsoV;					///< V iso-parametric vector in Local Coordinates
	
	uint32		fUVSpaceID;				///< UV Space ID; can use UVSpaceID enum
	boolean		fBumpOn;				///< global bump setting

	EChannelMask	fChannelMask;		///< bit mask that determines which channel must be evaluated

	mutable uint32		fCurrentCompletionMask;	///< Internal flags for shaders. Must be set to zero before calling DoShade

	I3DShInstance *fInstance;			///< Used by ShadingMode to calculate bounding Box.	

	const UVSpaceInfo*	fUVInfo;			///< UV Space information (filled by I3DShInstance::DoShade())

	TVector3	fSurfaceNormalLoc;		///< normal to the real geometry surface (before smoothing) in Local Coordinates
	TVector3	fGSurfaceNormal;		///< normal to the real geometry surface (before smoothing) in Global Coordinates
};

/// \}

void MCmemfill(int32 data, void* dst, int32 size);

inline ShadingIn::ShadingIn()
{
	MCmemfill(0,this,sizeof(ShadingIn));

	fGNormal.x   = 1;
	fNormalLoc.x = 1;

	fSurfaceNormalLoc.x	= 1;
	fGSurfaceNormal.x	= 1;
	fChannelMask = kAllChannelMask;
}

inline void ShadingIn::Average(ShadingIn &out,ShadingIn &in1,ShadingIn &in2,ShadingFlags flags)
{
	MCAssert(in1.fChannelMask == in2.fChannelMask);
	out.fChannelMask = in1.fChannelMask;

	out.fUVSpaceID				=	in1.fUVSpaceID;
	out.fCurrentCompletionMask	=	in1.fCurrentCompletionMask;
	out.fUVInfo					=	in1.fUVInfo;
	out.fInstance				=	in1.fInstance;

	if (flags.fNeedsUV)
	{
		for (int32 ii = 0; ii < 2; ii++)
		{
			real left    = in1.fUV[ii];
			real right   = in2.fUV[ii];

			if (out.fUVInfo && out.fUVInfo->fWraparound[ii]) //do the wraparound at the pixel level (vs triangle level) for vertex modeler
			{
				 if (left>right+ 0.5f) right   += 1.0f;
				 if (left<right- 0.5f) right   -= 1.0f;

			}
			out.fUV[ii]	= (left+right)*0.5f;
		}
		out.fUVx	= (in1.fUVx+in2.fUVx)*0.5f;
		out.fUVy	= (in1.fUVy+in2.fUVy)*0.5f;
	}
	out.fPoint		= (in1.fPoint		+	in2.fPoint)*0.5f;

	if (flags.fNeedsPoint)
	{
		out.fPointx		= (in1.fPointx		+	in2.fPointx)*0.5f;
		out.fPointy		= (in1.fPointy		+	in2.fPointy)*0.5f;
	}
	out.fGNormal			= (in1.fGNormal			+	in2.fGNormal		)*0.5f;
	out.fGSurfaceNormal		= (in1.fGSurfaceNormal	+	in2.fGSurfaceNormal	)*0.5f;

	if (flags.fNeedsNormalDerivative)
	{
		out.fNormalx	= (in1.fNormalx	+	in2.fNormalx)*0.5f;
		out.fNormaly	= (in1.fNormaly	+	in2.fNormaly)*0.5f;
	}
	out.fIsoU		= (in1.fIsoU		+	in2.fIsoU)*0.5f;
	out.fIsoV		= (in1.fIsoV		+	in2.fIsoV)*0.5f;

	if (flags.fNeedsPointLoc)
	{
		out.fPointLoc	= (in1.fPointLoc	+	in2.fPointLoc)*0.5f;
		out.fPointLocx	= (in1.fPointLocx	+	in2.fPointLocx)*0.5f;
		out.fPointLocy	= (in1.fPointLocy	+	in2.fPointLocy)*0.5f;
	}
	out.fNormalLoc			= (in1.fNormalLoc			+	in2.fNormalLoc)*0.5f;
	out.fSurfaceNormalLoc	= (in1.fSurfaceNormalLoc	+	in2.fSurfaceNormalLoc)*0.5f;

	if (flags.fNeedsNormalLocDerivative)
	{
		out.fNormalLocx	= (in1.fNormalLocx	+	in2.fNormalLocx)*0.5f;
		out.fNormalLocy	= (in1.fNormalLocy	+	in2.fNormalLocy)*0.5f;
	}
}

// *****************************************************
//			struct ShadingOut
// *****************************************************

#define kSpecularPowerCoef 4096.0f

struct I3DShInstance;

// Inscattering constants
#define kFastInScattering 'fast'
#define kAverageInScattering 'avrg'
#define kSlowInScattering 'slow'

struct TTransparencyParameters
{
	TTransparencyParameters()
	{
		SetDefaultValues();
	}

	inline void SetDefaultValues()
	{
		fIntensity.Set(0,0,0);
		fAbsorption.Set(0,0,0);
		fInScattering.Set(0,0,0);
		fMaxTrans=4;
		fMaxAttenuation=0.85f;
		fFresnelTerm=0;
		fUseAbsorption = false;
		fAbsorptionCoeff=1.0f;
		fKdiffuseCoeff=0.0f;
		fInScatteringQuality=kAverageInScattering;
	}
	void Clear()
	{
		fIntensity.Set(0,0,0);
		fAbsorption.Set(0,0,0);
		fInScattering.Set(0,0,0);
		fMaxTrans=0;
		fMaxAttenuation=0;
		fFresnelTerm=0;
		fUseAbsorption = false;
		fAbsorptionCoeff=0;
		fKdiffuseCoeff=0.0f;
		fInScatteringQuality=kAverageInScattering;
	}
	TTransparencyParameters &operator +=(TTransparencyParameters &param)
	{
		fIntensity					+=param.fIntensity;
		fAbsorption					+=param.fAbsorption;
		fInScattering				+=param.fInScattering;
		fMaxTrans					+=param.fMaxTrans;
		fMaxAttenuation				+=param.fMaxAttenuation;
		fFresnelTerm				+=param.fFresnelTerm;
		fAbsorptionCoeff			+=param.fAbsorptionCoeff;
		fKdiffuseCoeff				+=param.fKdiffuseCoeff;

		return *this;
	}
	TTransparencyParameters &operator -=(TTransparencyParameters &param)
	{
		fIntensity					-=param.fIntensity;
		fAbsorption					-=param.fAbsorption;
		fInScattering				-=param.fInScattering;
		fMaxTrans					-=param.fMaxTrans;
		fMaxAttenuation				-=param.fMaxAttenuation;
		fFresnelTerm				-=param.fFresnelTerm;
		fAbsorptionCoeff			-=param.fAbsorptionCoeff;
		fKdiffuseCoeff				-=param.fKdiffuseCoeff;

		return *this;
	}
	TTransparencyParameters &operator *=(real t)
	{
		fIntensity					*=t;
		fAbsorption					*=t;
		fInScattering				*=t;
		ASSIGN_CAST( fMaxTrans, fMaxTrans *t );
		fMaxAttenuation				*=t;
		fFresnelTerm				*=t;
		fAbsorptionCoeff			*=t;
		fKdiffuseCoeff				*=t;

		return *this;
	}

	void Interpolate(const TTransparencyParameters& from,
					 const TTransparencyParameters& to,
					 const real t)
	{
		fIntensity.Interpolate(from.fIntensity,to.fIntensity, t);
		fAbsorption.Interpolate(from.fAbsorption,to.fAbsorption, t);
		fInScattering.Interpolate(from.fInScattering,to.fInScattering, t);

		fMaxTrans		= MC_Max(from.fMaxTrans,to.fMaxTrans);
		fMaxAttenuation = MC_Max(from.fMaxAttenuation,to.fMaxAttenuation);

		fUseAbsorption = from.fUseAbsorption;
		fFresnelTerm = from.fFresnelTerm * (1-t) + to.fFresnelTerm * t;
		fAbsorptionCoeff = from.fAbsorptionCoeff * (1-t) + to.fAbsorptionCoeff * t;
		fKdiffuseCoeff = from.fKdiffuseCoeff * (1-t) + to.fKdiffuseCoeff * t;
		fInScatteringQuality = from.fInScatteringQuality;
	}


	TMCColorRGB		fIntensity;
	TMCColorRGB		fAbsorption;
	TMCColorRGB		fInScattering;
	int32			fMaxTrans;
	real			fMaxAttenuation;
	real			fFresnelTerm;
	boolean			fUseAbsorption;
	real			fAbsorptionCoeff;
	real			fKdiffuseCoeff;
	int32			fInScatteringQuality;
};

struct TReflectionParameters
{
	TReflectionParameters()
	{
		SetDefaultValues();
	}

	inline void SetDefaultValues()
	{
		fReflection.Set(0,0,0);
		fMaxReflectionCount=2;
		fMaxAttenuation=0.85f;
		fEnableBluryReflections=false;
		fQuality=0;
		fBlur=1.0f;
		fFresnelTerm=0.0f;
	}

	void Clear()
	{
		fReflection.Set(0,0,0);
		fMaxReflectionCount=0;
		fMaxAttenuation=0;
		fEnableBluryReflections=false;
		fQuality=0;
		fBlur=0.0f;
		fFresnelTerm=0.0f;
	}

	TReflectionParameters &operator +=(TReflectionParameters &param)
	{
		fReflection					+=param.fReflection;
		fMaxReflectionCount			+=param.fMaxReflectionCount;
		fMaxAttenuation				+=param.fMaxAttenuation;
		fEnableBluryReflections		+=param.fEnableBluryReflections;
		fQuality					+=param.fQuality;
		fBlur						+=param.fBlur;
		fFresnelTerm				+=param.fFresnelTerm;

		return *this;
	}
	TReflectionParameters &operator -=(TReflectionParameters &param)
	{
		fReflection					-=param.fReflection;
		fMaxReflectionCount			-=param.fMaxReflectionCount;
		fMaxAttenuation				-=param.fMaxAttenuation;
		fEnableBluryReflections		-=param.fEnableBluryReflections;
		fQuality					-=param.fQuality;
		fBlur						-=param.fBlur;
		fFresnelTerm				-=param.fFresnelTerm;

		return *this;
	}
	TReflectionParameters &operator *=(real t)
	{
		fReflection					*=t;
		ASSIGN_CAST( fMaxReflectionCount,		fMaxReflectionCount * t );
		fMaxAttenuation				*=t;
		ASSIGN_CAST( fEnableBluryReflections,	fEnableBluryReflections * t );
		ASSIGN_CAST( fQuality,					fQuality * t );
		fBlur						*=t;
		fFresnelTerm				*=t;

		return *this;
	}

	void Interpolate(const TReflectionParameters& from,
					 const TReflectionParameters& to,
					 const real t)
	{
		fReflection.Interpolate(from.fReflection,to.fReflection, t);

		fMaxReflectionCount = MC_Max(from.fMaxReflectionCount,to.fMaxReflectionCount);

		fMaxAttenuation = MC_Max(from.fMaxAttenuation,to.fMaxAttenuation);
		fEnableBluryReflections = MC_Max(from.fEnableBluryReflections,to.fEnableBluryReflections);
		fQuality = MC_Max(from.fQuality,to.fQuality);
		
		fBlur = from.fBlur * (1-t) + to.fBlur * t;
		fFresnelTerm = from.fFresnelTerm * (1-t) + to.fFresnelTerm * t;
	}


	TMCColorRGB			fReflection;		///< Reflectivity (Rx)
	int32				fMaxReflectionCount;
	real				fMaxAttenuation;
	boolean				fEnableBluryReflections;
	int32				fQuality;
	real				fBlur;
	real				fFresnelTerm;	// 0 to 1

};

struct TSubsurfaceParameters
{
	TSubsurfaceParameters()
	{
		SetDefaultValues();
	}

	inline void SetDefaultValues()
	{
		//fScalingFactor=1;
		fFresnel=0;
		fRefractionIndex=0;
		fTranslucency.Set(0,0,0);
		fReflectivity.Set(0,0,0);
		fIntensity=1.0f;
		fLocal=false;
	}

	void Clear()
	{
		//fScalingFactor=0;
		fFresnel=0;
		fRefractionIndex=0;
		fTranslucency.Set(0,0,0);
		fReflectivity.Set(0,0,0);
		fIntensity=0.0f;
		fLocal=false;
	}

	TSubsurfaceParameters &operator +=(TSubsurfaceParameters &param)
	{
		//fScalingFactor			+=param.fScalingFactor;
		fFresnel				+=param.fFresnel;
		fRefractionIndex		+=param.fRefractionIndex;
		fTranslucency			+=param.fTranslucency;
		fReflectivity			+=param.fReflectivity;
		fIntensity				+=param.fIntensity;
		MCAssert(fLocal	== param.fLocal);
		return *this;
	}
	TSubsurfaceParameters &operator -=(TSubsurfaceParameters &param)
	{
		//fScalingFactor			-=param.fScalingFactor;
		fFresnel				-=param.fFresnel;
		fRefractionIndex		-=param.fRefractionIndex;
		fTranslucency			-=param.fTranslucency;
		fReflectivity			-=param.fReflectivity;
		fIntensity				-=param.fIntensity;
		MCAssert(fLocal	== param.fLocal);
		return *this;
	}
	TSubsurfaceParameters &operator *=(real t)
	{
		//fScalingFactor			*=t;
		fFresnel				*=t;
		fRefractionIndex		*=t;
		fTranslucency			*=t;
		fReflectivity			*=t;
		fIntensity				*=t;
		return *this;
	}

	TMCColorRGB		fTranslucency;
	TMCColorRGB		fReflectivity;
	//real			fScalingFactor;
	real			fFresnel;
	real			fRefractionIndex;
	real			fIntensity;
	boolean			fLocal;
};

/// \addtogroup Data
/// \{

/// Specifies the shading of a given point
///
/// Here is how the specular color is computed from the light and shading:
///
/// \code
/// real Ns=(0.001f+fSpecularSize*fSpecularSize)*kSpecularPowerCoef;
/// specColorCoef= 2*RealPow(reflectDir*lightDirection, Ns);
/// specColor+= fSpecularColor * lightColor * specColorCoef;
/// \endcode
///
struct ShadingOut : public TMCObject
{
	inline void SetDefaultValues()
	{
		fChangedNormal		= TVector3::kZero;
		fChangedNormalLoc	= TVector3::kZero;

 		fSpecularSize 		= 0.5f;
 		fAmbient 			= 1.0f;
 		fLambert 			= 1.0f;
 		fRefractiveIndex 	= 0.0f;		// by defaut no refraction (Charles)
		fLayerMask			= 0.0f;
		
 		fColor			.Set(0, 0, 0,1);	// 1 for alpha channel
 		fSpecularColor	.Set(0, 0, 0);
 		fGlow			.Set(0.0f, 0.0f, 0.0f);
		
		fFullAreaDone=false;

		fTransparency.SetDefaultValues();
		fReflection.SetDefaultValues();
		fSubsurfaceScattering.SetDefaultValues();

		fTranslucency.Set(0, 0, 0);
	}
	inline void Clear()
	{
		fChangedNormal		= TVector3::kZero;
		fChangedNormalLoc	= TVector3::kZero;

 		fSpecularSize 		= 0.0f;
 		fAmbient 			= 0.0f;
 		fLambert 			= 0.0f;
 		fRefractiveIndex 	= 0.0f;		// by defaut no refraction (Charles)
		fLayerMask			= 0.0f;
		
 		fColor			.Set(0, 0, 0,0);
 		fSpecularColor	.Set(0, 0, 0);
 		fGlow			.Set(0.0f, 0.0f, 0.0f);
		
		fTransparency.Clear();
		fReflection.Clear();
		fSubsurfaceScattering.Clear();

		fTranslucency.Set(0, 0, 0);

		fFullAreaDone=false;
	}
	inline ShadingOut()
	{
		SetDefaultValues();
	}
	inline boolean CheckDefaultValues()
	{
		return (fSpecularSize == 0.5f && fAmbient == 1.0f && fLambert == 1.0f && 
				fRefractiveIndex == 0.0f && fLayerMask==0 &&
				fColor.R == 0.0f && fColor.G == 0.0f && fColor.B == 0.0f &&
				fSpecularColor.R == 0.0f && fSpecularColor.G==0.0f && fSpecularColor.B==0.0f &&
				fGlow == TMCColorRGB(0,0,0) &&
				fFullAreaDone == false);
	}


	ShadingOut &operator +=(ShadingOut &);
	ShadingOut &operator -=(ShadingOut &);
	ShadingOut &operator *=(real);
	//void		Clear();
		
	TMCColorRGBA	fColor;				///< Diffuse Color (Kd)
	TMCColorRGB		fSpecularColor;		///< Specular Color (Ks)
	real			fSpecularSize;		///< Specular highlight size (Ns)
	real			fAmbient;			///< Ambient factor (Fa)
	real			fLambert;			///< Diffuse factor (Fd)
	real			fRefractiveIndex;	///< Refraction index (Nr)
	TMCColorRGB		fGlow;				///< Glow color
	TVector3		fChangedNormal; 	///< Changed Normal in Global Coordinates (not evaluated by the shader!)
	real			fLayerMask;			///< Used in Layer List only !

	TTransparencyParameters		fTransparency;				///< Transparency (Tx)
	TReflectionParameters		fReflection;				///< Reflection
	TSubsurfaceParameters		fSubsurfaceScattering;		///< Subsurface scattering

	TMCColorRGB		fTranslucency;

	boolean			fFullAreaDone;		///< true if the shader was evaluated on the area
	TVector3		fChangedNormalLoc;  ///< Changed Normal in Local Coordinates (calculated by the shader)
};

/// \}


inline ShadingOut &ShadingOut::operator +=(ShadingOut &s)
{
	fColor				+=s.fColor;
	fSpecularColor		+=s.fSpecularColor;
	fSpecularSize		+=s.fSpecularSize;
	fAmbient			+=s.fAmbient;
	fLambert			+=s.fLambert;
	fReflection			+=s.fReflection;
	fTransparency		+=s.fTransparency;
	fRefractiveIndex	+=s.fRefractiveIndex;
	fGlow				+=s.fGlow;
	fChangedNormal		+=s.fChangedNormal;
	fChangedNormalLoc	+=s.fChangedNormalLoc;
	fSubsurfaceScattering += s.fSubsurfaceScattering;

	return *this;
}

inline ShadingOut &ShadingOut::operator -=(ShadingOut &s)
{
	fColor					-=s.fColor;
	fSpecularColor			-=s.fSpecularColor;
	fSpecularSize			-=s.fSpecularSize;
	fAmbient				-=s.fAmbient;
	fLambert				-=s.fLambert;
	fReflection				-=s.fReflection;
	fTransparency			-=s.fTransparency;
	fRefractiveIndex		-=s.fRefractiveIndex;
	fGlow					-=s.fGlow;
	fChangedNormal			-=s.fChangedNormal;
	fChangedNormalLoc		-=s.fChangedNormalLoc;
	fSubsurfaceScattering	-= s.fSubsurfaceScattering;
	return *this;
}

inline ShadingOut &ShadingOut::operator *=(real t)
{
	fColor					*=t;
	fSpecularColor			*=t;
	fSpecularSize			*=t;
	fAmbient				*=t;
	fLambert				*=t;
	fReflection				*=t;
	fTransparency			*=t;
	fRefractiveIndex		*=t;
	fChangedNormal			*=t;
	fChangedNormalLoc		*=t;
	fSubsurfaceScattering	*=t;

	return *this;
}




#endif

