// ===================================================================
// $Id$
//
// beard_maxwell.h
//    Implementation of Beard-Maxwell's BRDF.
//
// Class: CBeardMaxwell
//
// Initial coding by Polina Kondratieva (PK), August 2004.
//
// Edited by Jiri Nekola within diploma thesis, September 2011
// ===================================================================

#ifndef __BEARD_MAXWELL_H__
#define __BEARD_MAXWELL_H__

// Framework headers
#include "configh.h"
#include "surface.h"
#include "surface_microfacet.h"

#ifndef COS_MIN_BM
#define COS_MIN_BM 0.08715574274765817   // cos(85°) for Beard-Maxwell model
#endif
// standard headers

__BEGIN_BRDFLIB_HEADER

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

//-----------------------------------------------------------------------------
// Reference:
//  1. Beard, J., Maxwell, J.R. "Bidirectional Reflectance Model Validation 
//     and Utilization", Tech. Report, AFAL-TR-73-303, Oct. 1973
//  2. Westlund, H.B., Meyer, G.W.: "A BRDF Database Employing the
//     Beard-Maxwell Reflection Model", University of Oregon, 2002
//  3. Westlund, H.B.: "Appearance Based Rendering", Ph.D., 2002
//  4. Walker, P.A.: "A Visuzalization System for Bidirectional Reflectance
//     Reflectance Distribution Functions", Master Thesis, University of
//     Oregon, 1999
//  5. Shirley, P. Wang, C. "Luminaire Sampling in Distribution Ray Tracing",
//     SIGGRAPH, Course Notes 44, 1993.
//-----------------------------------------------------------------------------
class CBeardMaxwell :
   public CSurfaceMicrofacet
{

public:
  /**
     Constructs the Beard-Maxwell surface.
     @param _diffuse   (in)  diffuse reflectance texture.
     @param _specular  (in)  first surface reflectance texture.
     @param _volume    (in)  volumetric component of the BRDF.
     @param _fresnel   (in)  Fresnel texture for specular part of the BRDF.
     @param _slope     (in)  parameters of shadowing and obstruction functions
                             (omega and tau).
  */
  //---------------------------------------------------------------------------
  CBeardMaxwell(CTexture *rho_d, CTexture *specular, CTexture *volume,
                CFresnelTexture *fresnel, CSlopeMicrofacets *slope):
  CSurfaceMicrofacet()
  {
    if(rho_d != NULL)
    {
       _diffuse  = rho_d;
       _setSupportedType(EE_REFLECTED_DIFFUSE);
    }

    if(specular != NULL)
    {
       if(slope && slope->GetSlopesSize() == 2)
       {
          _specular = specular;
          _slope    = slope;
	  _setSupportedType(EE_REFLECTED_GLOSSY);
       }
       else
       {
		   WARNING_INFO("BeardMaxwell::BeardMaxwell() :\n\
Glossy term requires two 'slope' textures (parameters omega\n\
and tau for shadowing. resp obscuration function");
		   return;
       }

       if(fresnel != NULL)
       {
          _fresnel  = fresnel;
       }
       else
       {
 		  WARNING_INFO("CBeardMaxwell::CBeardMaxwell() :\nGlossy term requires parameter for Fresnel reflection.");
		  return;
       }
    }

    if(volume != NULL)
    {
       _volume  = volume;
       if(!(IsTypeSupported(EE_REFLECTED_GLOSSY)))
          _setSupportedType(EE_REFLECTED_GLOSSY);
    }
    //cout << "111\n";
  }

  // default constructor
  CBeardMaxwell():
    CSurfaceMicrofacet(),
	_volume(0),
	_fresnel(0)
  {}

  virtual ~CBeardMaxwell() 
  {
	  if (_volume) delete _volume;
	  if (_fresnel) delete _fresnel;
  }

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

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

  //  Deep copy of the class entity
  virtual CSurface *Dup() const;

  // Create new entity of the class
  virtual CBeardMaxwell* CreateNewObject() const
  { return new CBeardMaxwell; }

  // There is no deterministic rays for Beard-Maxwell model
  // (it contains diffuse, volume, and specular terms, which
  // are non-deterministic)
  virtual int
  SpawnDeterministicRays(CContributionArray  &carray,
		         const CHitPointInfo &hitInfo,
       		         EDistributionType   distType = EE_ALL) const
  {
     return 0;
  }

  virtual void SetVolume(CTexture *newVolume)
  {
	  AssignPointer(_volume,newVolume);
  }

  virtual void SetFresnel(CTexture *newFresnel)
  {
	  AssignPointer(_fresnel, newFresnel);
  }

  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 bool
  GetAlbedoMax(CValues &albedo,
	    const CHitPointInfo &hitInfo,
	    EDistributionType   distType = EE_ALL) const;


  virtual float GetAverageDiffuseness(void) const  {
    WARNING_INFO("No idea how to estimate diffusenes of the Beard Maxwell 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 Beard Maxwell model.\n\
It is a function of slope.");
    return 0.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:
  CTexture *_volume;	         // coefficient for volumetric part of the BRDF
  CTexture *_fresnel;	         // Fresnel reflection part of the BRDF

  static rnd_array volume_rnd;   // random numbers' storage for stochastic
                                 // sampling of volumetric part

  virtual EDistributionType _microfacetReflectionType() const
  { return EE_REFLECTED_GLOSSY; }

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

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

  virtual int SpawnStochasticVolumeRays(const CValues        &kv_local,
				        CVector2D            &omega_tau,
                                        const CValues        &kd_local,
                                        const CValues        &ks_local,
                                        const CValues        &kf0_local,
					CContributionArray   &carray,
				        const CHitPointInfo  &hitInfo,
				        CSamplingInfo        &samplingInfo,
				        int                  maxRays) const;
};





__END_BRDFLIB_HEADER

#endif // __BEARD_MAXWELL_H__

