// ===================================================================
// $Id: mgfsurf.h,v 1.3 2003/10/30 16:36:35 havran Exp $
//
// mgfsurf.h
//     Header file for CSurfaceMGF class.
//
// Class: CSurfaceMGF
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Vlastimil Havran, 2002.
//
// Given to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.
// ===================================================================

#ifndef __MGFSURF_H__
#define __MGFSURF_H__

// BRDFLIB library
#include "configh.h"
#include "surface.h"

__BEGIN_BRDFLIB_HEADER

// Forward-declare classes

// ------------------------------------------------------------------------
// This is class representing the surface material according to MGF
// This allows to have at the same time diffuse and specular reflection
// using Phong and diffuse and specular transmission using MAX-Phong model.
// Model is physically plausible, but not physically based !
// ------------------------------------------------------------------------

// This is the MGF surface according to Greg Ward.
class CSurfaceMGF:
  public CSurface
{
public:
  CSurfaceMGF():
    CSurface(EE_NONE),
    _diffuseReflection(0),
    _specularReflection(0),
    _specnumReflection(0),
    _diffuseTransmission(0),
    _specularTransmission(0),
    _specnumTransmission(0),
    _iorReal(0),
    _iorImag(0)
  { }
  
  virtual ~CSurfaceMGF()
  {
	  if (_diffuseReflection) delete _diffuseReflection;
	  if (_specularReflection) delete _specularReflection;
	  if (_specnumReflection) delete _specnumReflection;
	  if (_diffuseTransmission) delete _diffuseTransmission;
	  if (_specularTransmission) delete _specularTransmission;
	  if (_specnumTransmission) delete _specnumTransmission;
	  if (_iorReal) delete _iorReal;
 	  if (_iorImag) delete _iorImag;
  }
  
  // this is deep copy 
  virtual CSurface *Dup() const;

  // Setting the parameters for reflection
  inline void SetDiffuseReflection(CTexture *texture)
  {
	AssignPointer(_diffuseReflection,texture);
    if (texture)
      _setSupportedType(EE_REFLECTED_DIFFUSE);
    else
      _unsetSupportedType(EE_REFLECTED_DIFFUSE);
  }
  
  inline CTexture* GetDiffuseReflection() { return _diffuseReflection;}

  inline void SetSpecularReflection(CTexture *ks)
  {
     AssignPointer(_specularReflection,ks);
     if (ks)
       _setSupportedType(EE_REFLECTED_GLOSSY);
     else
       _unsetSupportedType(EE_REFLECTED_GLOSSY);
  }

  inline void SetSpecnumReflection(CTexture *shine)
  {
     AssignPointer(_specnumReflection,shine);
  }
  
  inline CTexture* GetKsReflection() { return _specularReflection; }
  inline CTexture* GetShininessReflection() { return _specnumReflection; }

  // Setting the parameters for transmission
  inline void SetDiffuseTransmission(CTexture *texture)
  {
    AssignPointer(_diffuseTransmission,texture);
    if (texture)
      _setSupportedType(EE_REFRACTED_DIFFUSE);
    else
      _unsetSupportedType(EE_REFRACTED_DIFFUSE);
  }
  
  inline CTexture* GetDiffuseTransmission() { return _diffuseTransmission;}

  inline void SetSpecularTransmission(CTexture *ks)
  {
	AssignPointer(_specularTransmission,ks);
     if (ks)
       _setSupportedType(EE_REFRACTED_GLOSSY);
     else
       _unsetSupportedType(EE_REFRACTED_GLOSSY);
  }

  inline void SetSpecnumTransmission(CTexture *shine)
  {
	 AssignPointer(_specnumTransmission,shine);
  }
  
  inline CTexture* GetKsTransmission() { return _specularTransmission; }
  inline CTexture* GetShininessTransmission() { return _specnumTransmission; }

  // Index of refraction for transmission coefficient
  inline void SetIOR(CTexture *iorReal, CTexture *iorImag)
  {
    AssignPointer(_iorReal,iorReal);
	AssignPointer(_iorImag,iorImag);
  }
  inline void SetIORReal(CTexture *iorReal)
  {
    AssignPointer(_iorReal,iorReal);
  }
  inline void SetIORImag(CTexture *iorImag)
  {
    AssignPointer(_iorImag,iorImag);
  }
  inline CTexture* GetIorReal()     { return _iorReal; }
  inline CTexture* GetIorImag()     { return _iorImag; }
  virtual EType GetType() const { return EE_MGF;}

  // This surface practically never computes refraction/refraction
  // of rays in deterministic way.
  virtual int
  SpawnDeterministicRays(CContributionArray  & /*carray*/,
			 const CHitPointInfo & /*hitInfo*/,
			 EDistributionType   distType = EE_ALL) const;

  virtual int
  SpawnStochasticRays(CContributionArray  &carray,
		      const CHitPointInfo &hitInfo,
		      CSamplingInfo       &samplingInfo,
      		      EDistributionType   distType = EE_ALL) const;
  
  virtual bool
  EvaluateBSDF(CValues &brdf,
	       const CHitPointInfo &hitInfo,
	       const CVector3D     &out,
	       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;
  
  virtual float GetDiffuseness(const CHitPointInfo &hitinfo,
			       EDistributionType distType = EE_ALL) const;

  // !!!!! TO BE IMPLEMENTED
  virtual bool GetTransparency(CValues &transparency,
			       const CHitPointInfo &hitinfo) const {
    return false;
  }

  virtual bool GetDefaultColor(CValues &defaultColor,
			       const CHitPointInfo &hitinfo) const {
    return false;
  }
  
  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;
  
private:
  CSurfaceMGF& operator=(const CSurfaceMGF&);
  CSurfaceMGF(const CSurfaceMGF&);
protected:
  CTexture *_diffuseReflection; // Diffuse color for reflection
  CTexture *_specularReflection; // Specular color for reflection
  CTexture *_specnumReflection; // Power Index for specular reflection (shineness)
  CTexture *_diffuseTransmission; // Diffuse color for transmission
  CTexture *_specularTransmission; // Specular color for transmission
  CTexture *_specnumTransmission; // Power index for specular transmission
  CTexture *_iorReal;             // index of refraction - real component
  CTexture *_iorImag;             // index of refraction - imaginary component

  int SpawnStochasticSpecularRays(const CValues       &ks_local,
				  const CValues       &shininess,
				  const CVector3D     &direction,
				  const bool          &transmissionFlag,
				  CContributionArray  &carray,
				  const CHitPointInfo &hitInfo,
				  CSamplingInfo       &samplingInfo,
				  int                 maxRays) const;
  
  int SpawnStochasticDiffuseRays(const CValues        &kd_local,
				 const bool           &transmissionFlag,
				 CContributionArray   &carray,
				 const CHitPointInfo  &hitInfo,
				 CSamplingInfo       &samplingInfo,
				 int                  maxRays) const;
  // the auxiliary storage of random variable
  mutable double aux_rnd;
  void SetAuxRnd(double rnd_num, float min, float max) const {
    assert( (rnd_num >= min) && (rnd_num <= max));
    aux_rnd = (rnd_num - min) / (max - min);
  }
};

__END_BRDFLIB_HEADER

#endif // __MGFSURF_H__
