// ===========================================================================
// $Id$
//
// minnaert.h
//    Implementation of Minnaert Limb Darkening BRDF model.
//
// Class: CSurfaceMinnaert
//
// Initial coding by Jiri Nekola within diploma thesis project, November 2011
//
// Reference:
//  1. Minnaert M. "The reciprocity principle in lunar photometry", 1941
//
// ============================================================================


#ifndef __SURFACE_MINNAERT_H__
#define __SURFACE_MINNAERT_H__

#include "configh.h"
#include "surface.h"

__BEGIN_BRDFLIB_HEADER

// Forward-declare classes
class CHitPointInfo;
class CTexture;

// ------------------------------------------------------------------------------
/// Minnaert BRDF class implemented according to original paper [1]
// ------------------------------------------------------------------------------
class CSurfaceMinnaert :
  public CSurface
{
public:
	/**
		 Constructs the Minnaert surface.
		 @param rho_d (in)  The diffuse reflectance texture.
		 @param k (in)		The limb darkening parameter.
	*/
	CSurfaceMinnaert(CTexture *rho_d, CTexture *k):
	  CSurface(EE_NONE)
	{
		if(rho_d != NULL)
		{
			_kd  = rho_d;
			_setSupportedType(EE_REFLECTED_DIFFUSE);
		}

		if(k != NULL)
		{
			_k = k;
		}
		else
		{
			WARNING_INFO("CSurfaceMinnaert : this surface needs limb darkening parameter!");
			return;
		}
	}

	CSurfaceMinnaert():
		CSurface(EE_NONE),
		_kd(0),
		_k(0)
	{
	}

	virtual ~CSurfaceMinnaert() 
	{
		if (_kd)
		{
			delete _kd;
		}
		if (_k)
		{
			delete _k;
		}
	}

	/**
	 Returns the value of diffuse coefficient at given point.
	 (kd is albedo)
	*/
	inline CValues kd(const CHitPointInfo &hitInfo) const
	{
		CValues ret(CValues::EE_Weigth3);
		hitInfo.GetTextureValue(ret, *_kd, CMappingBase::EE_KD);
		return ret;
	}

	inline void SetKd(CTexture* kd)
	{
		AssignPointer(_kd,kd);
	}

	inline void SetK(CTexture* k)
	{
		AssignPointer(_k,k);
	}

	virtual void Describe(ostream &app, int ind) const;

	/**
		Deep copy this object.
	*/
	virtual CSurface *Dup() const
	{
		CValues value;
		_kd->GetValue(value,CHitPointInfo::constMapInfo);
		CConstantTexture* diffuse = new CConstantTexture(value);

		_k->GetValue(value,CHitPointInfo::constMapInfo);
		CConstantTexture* k = new CConstantTexture(value);

		return new CSurfaceMinnaert(diffuse,k);
	}

	virtual bool
	GetAlbedoMax(CValues &albedo,
		const CHitPointInfo &hitInfo,
		EDistributionType   distType = EE_ALL) const
	{
		assert(_kd);
		if (distType & EE_REFLECTED_DIFFUSE) {
		  albedo = kd(hitInfo);
		  return true;
		}
		return false;
	}

	virtual bool GetDefaultColor(CValues &defaultColor,
			       const CHitPointInfo &hitInfo) const	   
	{
		// let us consider _kd color to be the default one
		if (_kd) 
		{
			hitInfo.GetTextureValue(defaultColor, *_kd, CMappingBase::EE_KD);
			return false;
		}
		defaultColor.Set(0.0);
		return true;
	}

	virtual char* GetName() const
	{return "CSurfaceMinnaert";}

	virtual bool
	EvaluateBSDF(CValues             &result,
	       const CHitPointInfo &hitInfo,
	       const CVector3D     &dirIn,
	       EDistributionType   distType = EE_ALL) const;

	virtual bool
	GetAlbedo(CValues &albedo,
	       const CHitPointInfo &hitInfo,
	       EDistributionType   distType=EE_ALL) const;

	virtual int
	SpawnDeterministicRays(CContributionArray  &carray,
		         const CHitPointInfo &hitInfo,
       		         EDistributionType   distType = EE_ALL) const
	{
		return 0;
	}

	virtual float GetAverageDiffuseness(void) const  {
		// not implemented
		return 0.0;
	}

	virtual float GetDiffuseness(const CHitPointInfo &,
			       EDistributionType distType = EE_ALL) const
	{
		// not implemented
		return 0.0;
	}

	virtual int
	SpawnStochasticRays(CContributionArray  &carray,
		      const CHitPointInfo &hitInfo,
		      CSamplingInfo       &samplingInfo,
		      EDistributionType    distType = EE_ALL) const;

	virtual inline EType GetType() const { return  EE_BSDFMicrofacetRefl; }

	virtual const char* GetParameterTitle(int parameterIndex) const;

	virtual const char* GetParameterDescription(int parameterIndex) const;

	virtual EParameterUIType GetParameterSyntax(int parameterIndex) const;

	virtual void SetParameter(int parameterIndex, 
							const CValues& value);

	virtual CValues GetParameter(int parameterIndex) const;

	virtual CValues GetParameterConstraints(int parameterIndex) const;

	virtual int GetNumParameters() const;

	virtual const char* GetHelp() const;

protected:
	CTexture			*_kd;	// Albedo of the object
	CTexture			*_k;	// limb darkening parameter

	virtual EDistributionType _microfacetReflectionType() const
	{ return EE_REFLECTED_DIFFUSE; }
	// Function that spawns the rays using stratified sampling around a
	// given hemisphere. Can be used for reflection and for refraction
	// (just by inverting the passed normal).
	// distType MUST be either EE_REFLECTED_kd or EE_REFRACTED_kd
	int SpawnStochasticRaysStratify(CContributionArray  &carray,
				  const CHitPointInfo &hitInfo,
				  EDistributionType distType,
				  CSamplingInfo       &samplingInfo,
				  const CVector3D &N) const;

};

__END_BRDFLIB_HEADER

#endif // __SURFACE_MINNAERT_H__