// ===================================================================
// $Id$
//
// ward.h
//    Implementation of Ward's BRDF and all of its modifications.
//
// Edited by Jiri Nekola within diploma thesis project, October 2011 :
//		-	Ward surface interface was made for use by any of Ward BRDF modifications 
//			-	Ward's anisotropic BRDF implements this interface
//				-	Isotropic Ward BRDF derived from anisotropic
//		-	Ward's sampling corrected according to Ward-Dür paper
//		-	Implemented anisotropic Ward-Dür BRDF via Ward surface interface
//			-	Isotropic Ward-Dür BRDF derived from anisotropic
//		-	Implemented anisotropic Moroder-Dür BRDF via Ward surface interface
//			-	Isotropic Moroder-Dür BRDF derived from anisotropic
//
// Class: CSurfaceWard, CSurfaceWardAnisotropic, CSurfaceWardDuerAnisotropic, CSurfaceMoroderDuerAnisotropic,
//			            CSurfaceWardIsotropic, CSurfaceWardDuerIsotropic, CSurfaceMoroderDuerIsotropic,  
//
// Initial coding by Jaroslav Krivanek, January 2004
// Corrected and enriched by Jiri Nekola, October 2011

#ifndef __SURFACEWARD_H__
#define __SURFACEWARD_H__

// GOLEM headers
#include "configh.h"
#include "surface.h"
#include "surface_microfacet.h"
#include <vector>

// standard headers

__BEGIN_BRDFLIB_HEADER

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


// ------------------------------------------------------------------------------
/// Ward BRDF - anisotropic interface for all ward modifications
// ------------------------------------------------------------------------------
class CSurfaceWard :
  public CSurfaceMicrofacet
{
public:
  /**
     Constructs the Ward isotropic surface.
     @param rho_d (in)  The diffuse reflectance texture.
     @param rho_s (in)  The glossy reflectance texture.
     @param slopeX (in)  Standard deviation (RMS) of the surface slope.
  */
  CSurfaceWard(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceMicrofacet()
  {

    if(rho_d != NULL)
    {
      _diffuse  = rho_d;
      _setSupportedType(EE_REFLECTED_DIFFUSE);
    }

    if(rho_s != NULL)
    {
      if(slope && slope->GetSlopesSize() > 0)
      {
        _specular = rho_s;
        _slope    = slope;
	_setSupportedType(EE_REFLECTED_GLOSSY);
      }
      else
      {
	    WARNING_INFO("Ward model: Glossy term requires 'slope' texture\n");
        return;
      }
    }
  }

  CSurfaceWard():
    CSurfaceMicrofacet()
  {}

  virtual ~CSurfaceWard() 
  {
  }; 

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

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

  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  {
    WARNING_INFO("No idea how to estimate diffusenes of the Ward model.\n\
It is a function of slope.");
	return 0.0;
  }

  virtual float GetDiffuseness(const CHitPointInfo &,
			       EDistributionType distType = EE_ALL) const
  {
    WARNING_INFO("No idea how to estimate diffusenes of the Ward model.\n\
It is a function of slope.");
	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;

protected:

  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }
   virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          CVector2D           &slopeXY,
				          CVector2D           &slopeXY_sq,
                                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const = 0;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         CVector2D            &slopeXY,
				         CVector2D            &slopeXY_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const = 0;

};


// ----------------------------------------------------------------------------
// Ward BRDF - anisotropic version
//
// Note, this class requires anisotropic directions to be set for hit point.
// These directions should be given in World coordinate system.
// ----------------------------------------------------------------------------
class CSurfaceWardAnisotropic :
  public CSurfaceWard
{
public:
  /**
     Constructs the Ward anisotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slopeX(in)  Standard deviation (RMS) of the
     surface slope in x direction.
     @param slopeY(in)  Standard deviation (RMS) of the
     surface slope in y direction.
  */
  CSurfaceWardAnisotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceWard(rho_d, rho_s, slope)
  {
	  _max = false;
    // Check whether slope has 'anisotropic' type.
    if(!(slope->GetType()))
    {
      WARNING_INFO("CSurfaceWardAnisotropic::CSurfaceWardAnisotropic():\n\
Glossy term requires structure 'slope' which consists of\n\
'slopeX' and 'slopeY' terms.");
    }
  }

  CSurfaceWardAnisotropic():
    CSurfaceWard()
  { _max = false;}

  virtual ~CSurfaceWardAnisotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceWardAnisotropic; }

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

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

  //  Deep copy this object.
  //virtual CSurface *Dup() const;

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

  virtual void SetMaxWard(bool max) { _max = max; }

  virtual bool GetMaxWard(void) const { return _max; }

  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:
  bool	_max;	// maxWard modification (albedo pumping) by Neumann
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          CVector2D           &slopeXY,
				          CVector2D           &slopeXY_sq,
                                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         CVector2D            &slopeXY,
				         CVector2D            &slopeXY_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

  

};

class CSurfaceWardIsotropic :
  public CSurfaceWardAnisotropic
{
public:
  /**
     Constructs the Ward isotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slope(in)  Standard deviation (RMS) of the
     surface slope in x direction.
  */
  CSurfaceWardIsotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceWardAnisotropic(rho_d, rho_s, slope)
  {
  }

  CSurfaceWardIsotropic():
    CSurfaceWardAnisotropic()
  {}

  virtual ~CSurfaceWardIsotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceWardIsotropic; }

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

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

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

  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:
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          float				  &slope,
				          float               &slope_sq,
                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         float		          &slope,
				         float			      &slope_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

};


// ----------------------------------------------------------------------------
// Anisotropic Ward Dür BRDF
// ----------------------------------------------------------------------------
class CSurfaceWardDuerAnisotropic :
  public CSurfaceWard
{
public:
  /**
     Constructs the Ward Duer anisotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slopeX(in)  Standard deviation (RMS) of the
     surface slope in x direction.
     @param slopeY(in)  Standard deviation (RMS) of the
     surface slope in y direction.
  */
  CSurfaceWardDuerAnisotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceWard(rho_d, rho_s, slope)
  {
    // Check whether slope has 'anisotropic' type.
    if(!(slope->GetType()))
    {
      WARNING_INFO("CSurfaceWardDuerAnisotropic::CSurfaceWardDuerAnisotropic():\n\
Glossy term requires structure 'slope' which consists of\n\
'slopeX' and 'slopeY' terms.");
    }
  }

  CSurfaceWardDuerAnisotropic():
    CSurfaceWard()
  {}

  virtual ~CSurfaceWardDuerAnisotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceWardDuerAnisotropic; }

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

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

  virtual const char* GetHelp() const;

protected:
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          CVector2D           &slopeXY,
				          CVector2D           &slopeXY_sq,
                                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         CVector2D            &slopeXY,
				         CVector2D            &slopeXY_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

};


// ----------------------------------------------------------------------------
// Isotropic Ward Dür BRDF
// ----------------------------------------------------------------------------


class CSurfaceWardDuerIsotropic :
  public CSurfaceWardDuerAnisotropic
{
public:
  /**
     Constructs the Ward-Duer isotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slope(in)  Standard deviation (RMS) of the
     surface slope in x direction.
  */
  CSurfaceWardDuerIsotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceWardDuerAnisotropic(rho_d, rho_s, slope)
  {
  }

  CSurfaceWardDuerIsotropic():
    CSurfaceWardDuerAnisotropic()
  {}

  virtual ~CSurfaceWardDuerIsotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceWardDuerIsotropic; }

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

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

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

  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:
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          float				  &slope,
				          float               &slope_sq,
                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         float		          &slope,
				         float			      &slope_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

};

// ----------------------------------------------------------------------------
// Anisotropic Moroder-Dür BRDF 
// implemented according to paper :
//
// D. Geisler-Moroder and A. Dür, "A New Ward BRDF Model with Bounded Albedo", 
// Computer Graphics Forum, Volume 29, Issue 4 (Proc. of EGSR 2010), pp. 1391-1398, 2010
//
// ----------------------------------------------------------------------------
class CSurfaceMoroderDuerAnisotropic :
  public CSurfaceWard
{
public:
  /**
     Constructs the Ward isotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slopeX(in)  Standard deviation (RMS) of the
     surface slope in x direction.
     @param slopeY(in)  Standard deviation (RMS) of the
     surface slope in y direction.
  */
  CSurfaceMoroderDuerAnisotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceWard(rho_d, rho_s, slope)
  {
    // Check whether slope has 'anisotropic' type.
    if(!(slope->GetType()))
    {
      WARNING_INFO("CSurfaceMoroderDuerAnisotropic::CSurfaceMoroderDuerAnisotropic():\n\
Glossy term requires structure 'slope' which consists of\n\
'slopeX' and 'slopeY' terms.");
    }
  }

  CSurfaceMoroderDuerAnisotropic():
    CSurfaceWard()
  {}

  virtual ~CSurfaceMoroderDuerAnisotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceMoroderDuerAnisotropic; }

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

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

  //  Deep copy this object.
  //virtual CSurface *Dup() const;

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

  virtual const char* GetHelp() const;

protected:
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          CVector2D           &slopeXY,
				          CVector2D           &slopeXY_sq,
                                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         CVector2D            &slopeXY,
				         CVector2D            &slopeXY_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

};


// ----------------------------------------------------------------------------
// Isotropic Moroder-Dür BRDF
// ----------------------------------------------------------------------------


class CSurfaceMoroderDuerIsotropic :
  public CSurfaceMoroderDuerAnisotropic
{
public:
  /**
     Constructs the Moroder-Duer isotropic surface.
     @param rho_d(in)  The diffuse reflectance texture.
     @param rho_s(in)  The glossy reflectance texture.
     @param slope(in)  Standard deviation (RMS) of the
     surface slope in x direction.
  */
  CSurfaceMoroderDuerIsotropic(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceMoroderDuerAnisotropic(rho_d, rho_s, slope)
  {
  }

  CSurfaceMoroderDuerIsotropic():
    CSurfaceMoroderDuerAnisotropic()
  {}

  virtual ~CSurfaceMoroderDuerIsotropic() {};

  virtual CSurfaceMicrofacet* CreateNewObject() const
  { return new CSurfaceMoroderDuerIsotropic; }

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

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

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

  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:
  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

  virtual int SpawnStochasticSpecularRays(const CValues       &ks_local,
				          float				  &slope,
				          float               &slope_sq,
                          const CValues       &kd_local,
				          CContributionArray  &carray,
				          const CHitPointInfo &hitInfo,
				          CSamplingInfo       &samplingInfo,
				          int                 maxRays) const;

  virtual int SpawnStochasticDiffuseRays(const CValues        &kd_local,
                                         const CValues        &ks_local,
				         float		          &slope,
				         float			      &slope_sq,
				         CContributionArray   &carray,
				         const CHitPointInfo  &hitInfo,
				         CSamplingInfo        &samplingInfo,
				         int                  maxRays) const;

};






__END_BRDFLIB_HEADER

#endif // __SURFACEWARD_H__

