// ===================================================================
// $Id$
//
// cook_torrance.h
//    Implementation of Cook-Torrance BRDF.
//
// Class: CCookTorrance
//
// Initial coding by Polina Kondratieva (PK), January 2004.
//
// Edited by Jiri Nekola within diploma thesis, September 2011
// ===================================================================

#ifndef __SURFCOOK_TORRANCE_H__
#define __SURFCOOK_TORRANCE_H__

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

// standard headers

__BEGIN_BRDFLIB_HEADER


// ----------------------------------------------------------------------------
//  Reference:
//  1. Cook, R., Torrance, K. "A Reflectance Model for Computer Graphics".
//     Computer Graphics, 15(3), 1981.
//  2. Kelemen, C., Szirmay-Kalos, L., "A Microfacet Based Coupled
//     Specular-Matte BRDF Model with Importance Sampling". Eurographics, 2001
//  3. Shirley, P. Wang, C. "Luminaire Sampling in Distribution Ray Tracing",
//     SIGGRAPH, Course Notes 44, 1993.
// ----------------------------------------------------------------------------
class CCookTorrance:
  public CSurfaceMicrofacet
{
public:
  /**
     Constructs the Cook-Torrance 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.
  */
  CCookTorrance(CTexture *rho_d, CTexture *rho_s, CSlopeMicrofacets *slope):
    CSurfaceMicrofacet()
  {
    if(rho_d != NULL)
    {
      _diffuse  = rho_d;
      _setSupportedType(EE_REFLECTED_DIFFUSE);
    }

    if(rho_s != NULL)
    {
      // Cook-Torrance model contains Fresnel coefficient as an albedo for
      // specular part. Therefore, rho_s should be of Fresnel type
      bool use_fresnel = rho_s->IsFresnel();
      if(!use_fresnel)
      {
        cout << "albedo for CCookTorrance must be of CFresnelTexture type\n";
        return;
      }

      if(slope && slope->GetSlopesSize() > 0)
      {
	if(slope->GetSlopesSize() != slope->GetWeightsSize())
        {
	  cout << "Cook-Torrance model: Glossy term requires 'slope'\n"
	       << " texture with specified 'weights'." << std::endl;
          return;
        }

        _specular = rho_s;
        _slope   = slope;
	_setSupportedType(EE_REFLECTED_GLOSSY);

      }
      else
      {
	cout << "Cook-Torrance model: Glossy term requires 'slope'\n"
	      << " texture with specified 'weights'." << std::endl;
        return;
      }
    }
  }

  CCookTorrance():
    CSurfaceMicrofacet()
  {
    _slopesCount = 1; // one slope as default
  }

  virtual ~CCookTorrance() {};

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


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

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

  virtual CCookTorrance* CreateNewObject() const
  { return new CCookTorrance; }

  // There is no deterministic rays for model
  virtual int
  SpawnDeterministicRays(CContributionArray  &carray,
		         const CHitPointInfo &hitInfo,
       		         EDistributionType   distType = EE_ALL) const
  {
     return 0;
  }

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

  virtual bool
  EvaluateBSDF(CValues             &res,
	       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 float GetAverageDiffuseness(void) const  {
    cout << "No idea how to estimate diffusenes of Cook-Torrance model."
	  << "It is a function of slope." << std::endl;
    return 1.0;
  }

  virtual float GetDiffuseness(const CHitPointInfo &,
			       EDistributionType distType = EE_ALL) const
  {
    cout << "No idea how to estimate diffusenes of  Cook-Torrance model."
          << "It is a function of slope." << std::endl;
    return 1.0;
  }


  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:

  int _slopesCount;

  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;

};


__END_BRDFLIB_HEADER

#endif // __SURFCOOK_TORRANCE_H__

