// ===================================================================
// $Id$
//
// surface_microfacet.h
//    Implementation of microfacet-based surface interface.
//
// Class: CSlopeMicrofacets, CSurfaceMicrofacet
//
// Initial coding by Jaroslav Krivanek, January 2004
// Corrected, enriched and organized by Jiri Nekola within diploma thesis, October 2011


#ifndef __SURFACE_MICROFACET_H__
#define __SURFACE_MICROFACET_H__


#include "configh.h"
#include "surface.h"
#include <vector>

__BEGIN_BRDFLIB_HEADER

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

/**
	Class for slopes. It contains vector of slope+weight tuples and therefore
	can be used by BRDFs containing any number of slope parameters.
*/
class CSlopeMicrofacets
{
  public:
  CSlopeMicrofacets();
  CSlopeMicrofacets(CTexture *slopeX);
  CSlopeMicrofacets(CTexture *slopeX, CTexture *slopeY);
  CSlopeMicrofacets(vector<CTexture *> slopes);
  CSlopeMicrofacets(vector<CTexture *> slopes, vector<float> weights);
  virtual ~CSlopeMicrofacets();

  virtual void Set(CTexture *slopeX);
  virtual void Set(CTexture *slopeX, int index);
  virtual void Set(CTexture *slopeX, CTexture *slopeY);
  virtual void Set(vector<CTexture *> slopes);

  virtual void SetWeight(float weight,int index);
  virtual void SetWeights(vector<float> weights);

  virtual void Set(vector<CTexture *> slopes, vector<float> weights);

  virtual void Clear();

  virtual CTexture* GetSlope();
  virtual CTexture* GetSlope(float &weight);
  virtual CTexture* GetSlope(int index);
  virtual CTexture* GetSlope(int index, float &weight);
  virtual CTexture* GetSlopeX();
  virtual CTexture* GetSlopeY();

  virtual void AddSlope(CTexture* slope, float weight);

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

  virtual bool GetType()        {return _anisotropic;}
  virtual int  GetSlopesSize()  {return (int)_slopes.size();}
  virtual int  GetWeightsSize() {return (int)_weights.size();}

  protected:
    vector<CTexture *> _slopes;
    vector<float>      _weights;
    bool _anisotropic;
};

// ------------------------------------------------------------------------
/** 
   This is the Ward surface abstract class. We further assume that
   it holds for any point on the Ward's surface:
   k_a + k_d + k_s <= 1.0 that is necessary to allow the surface
   to be physically plausible.
*/
class CSurfaceMicrofacet:
  public CSurface
{
public:
  /// Standard constructor
  CSurfaceMicrofacet();

  virtual ~CSurfaceMicrofacet();

  virtual void Describe(ostream &app, int ind) const = 0;
  virtual char* GetName() const = 0;

  /// Deep copy
  virtual CSurface *Dup() const;
  virtual CSurfaceMicrofacet* CreateNewObject() const = 0;

  /// Returns diffuse texture of the surface
  inline CTexture* GetDiffuse() { return _diffuse;}

  /// Returns specular texture of the surface
  inline CTexture* GetSpecular() { return _specular; }

  /// Returns slope of the surface
  inline CSlopeMicrofacets* GetSlope() { return _slope; }

  /// Sets diffuse texture of the surface
  inline void SetDiffuse(CTexture *texture)
  {
	AssignPointer(_diffuse,texture);
    if (texture)
    {
     _setSupportedType(EE_REFLECTED_DIFFUSE);
    }
    else
      _unsetSupportedType(EE_REFLECTED_DIFFUSE);
  }

  /// Sets specular texture of the surface
  inline void SetSpecular(CTexture *ks)
  {
     AssignPointer(_specular,ks);
     if (ks)
     {   
       _setSupportedType(_microfacetReflectionType());
     }
     else
       _unsetSupportedType(_microfacetReflectionType());
  }

  /// Sets slope texture of the surface
  inline void SetSlope(CSlopeMicrofacets *slope)
  {
    AssignPointer(_slope,slope);
    if(slope)
    {
      _setSupportedType(_microfacetReflectionType());
    }
    else
      _unsetSupportedType(_microfacetReflectionType());
  }

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

  /// Implements CSurface
  virtual bool
  GetAlbedoMax(CValues &albedo,
	       const CHitPointInfo &hitInfo,
	       EDistributionType   distType=EE_ALL) const;

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

  virtual float GetAverageDiffuseness(void) const = 0;

  virtual float GetDiffuseness(const CHitPointInfo &hitinfo,
			       EDistributionType distType=EE_ALL) const = 0;

  /// Implements CSurface
  virtual bool GetDefaultColor(CValues &defaultColor,
			       const CHitPointInfo &hitInfo) const;

  /// Implements CSurface
  virtual const char* GetParameterTitle(int parameterIndex) const;

  /// Implements CSurface
  virtual const char* GetParameterDescription(int parameterIndex) const;

  /// Implements CSurface
  virtual EParameterUIType GetParameterSyntax(int parameterIndex) const;

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

  /// Implements CSurface
  virtual CValues GetParameter(int parameterIndex) const;

  /// Implements CSurface
  virtual CValues GetParameterConstraints(int parameterIndex) const;

  /// Implements CSurface
  virtual int GetNumParameters() const;

  /// Implements CSurface
  virtual const char* GetHelp() const;


private:
  CSurfaceMicrofacet& operator=(const CSurfaceMicrofacet&);
  CSurfaceMicrofacet(const CSurfaceMicrofacet&);

protected:
  CTexture *_diffuse;			/// Diffuse color of the object
  CTexture *_specular;			/// specular color of the object

  CSlopeMicrofacets *_slope;	/// Slope of the surface

  // This must be implemented by every phong surface and must return
  // either EE_REFLECTED_PERFECT or EE_REFLECTED_GLOSSY according
  // to the way in which the reflected rays are actually spawned
  virtual EDistributionType _microfacetReflectionType() const = 0;

protected:
  // the auxiliary storage of random variable
  typedef vector<double> rnd_array;
  //static double aux_rnd;
  static rnd_array diffuse_rnd;
  static rnd_array specular_rnd;
};

__END_BRDFLIB_HEADER

#endif // __SURFACE_MICROFACET_H__