// ===================================================================
// $Id: refrsurf.cpp,v 1.5 2003/11/04 15:27:18 havran Exp $
//
// refrsurf.cpp
//     Implementation basic refractors.
//
// 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 Jaroslav Krivanek (Nov 2000) under supervision
// of Vlastimil Havran.
//
// Given to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.
// ===================================================================

// BRDFLIB headers
#include "config.h"
#include "refrsurf.h"
#include "texture.h"

__BEGIN_BRDFLIB_SOURCE


typedef vector<double> rnd_array;
rnd_array CIdealDielectric::specular_rnd;
rnd_array CIdealDielectric::refraction_rnd;

/****************************************************************************
 *
 *             Ideal diffuse refractor
 *
 ***************************************************************************/

int
CIdealDiffuseRefractor::SpawnStochasticRays(CContributionArray  &carray,
					    const CHitPointInfo &hitInfo,
					    CSamplingInfo       &samplingInfo,
					    EDistributionType distType) const
{
  int maxRays = samplingInfo.GetMaxSamples();  
  assert(_kd);
  
  if ( !(distType & EE_REFRACTED_DIFFUSE) ||
       (maxRays < 1) )
    return 0;

  // build coordinate system
  CVector3D N = hitInfo.GetNormal();
  if (hitInfo.GetDotProd() < 0.0)
    N = -N;

  // spawn the rays
  int spawned =
    SpawnStochasticRaysStratify(carray, hitInfo, EE_REFRACTED_DIFFUSE,
				samplingInfo, N);

#ifdef __TRAVERSAL_STATISTICS
  world->_statistics->refractedRays += spawned;
#endif
  
  return spawned;
}

/**
   Returns the transparency at the specified point, possibly taking the
   incoming direction of the ray into account
*/
bool
CIdealDiffuseRefractor::GetTransparency(CValues &transparency,
					const CHitPointInfo &hitInfo) const
{
  transparency.Set(0.0);

  if (_kd) {
    hitInfo.GetTextureValue(transparency, *_kd, CMappingBase::EE_KD);
    if (transparency.AbsSum() > 0.0)
      return false; // transparent surface - maybe
    return true; // opaque surface
  }
  
  transparency.Set(0.0);  
  return true; // opaque surface
}

const char* 
CIdealDiffuseRefractor::GetHelp() const
{
	return BrdfStrings::KIdealDiffuseRefrDesc;
}


/************************************************************************
 *                                                                      *
 *   Ideal refractor.                                                   *
 *                                                                      *
 ************************************************************************/
//========================================================================
int
CIdealRefractor::SpawnDeterministicRays(CContributionArray  &carray,
                                     const CHitPointInfo &hitInfo,
                                     EDistributionType distributionType) const
{
  if (!((distributionType & EE_REFRACTED_PERFECT) || _kr))
    return 0;

  CContributionItem *contrib = carray.AllocateNext();
  contrib->weigth.SetRepresentation(CValues::EE_Weigth3);

  CVector3D N = hitInfo.GetNormal();
  CVector3D dirInit = hitInfo.GetRay()->GetDir();
  CVector3D dir;
  float dot   = hitInfo.GetDotProd();
  float gamma, sqrterm;
  int cases = 0;

  CValues ior(CValues::EE_Weigth1);
  // get value of index of refraction  coefficient for intersection point
  hitInfo.GetTextureValue(ior, *_ior, CMappingBase::EE_KRI);

  // Incident ray - eyeRay (from the eye to the surface) and dot(N,eye) < 0
  // (if normal is oriented in opposite to the eyeRay direction). In this
  // case eyeRay falls from the air onto the object and refracts in the
  // object. And gamma should be equal to n2 (object's index of refraction)
  // Otherwise, if dot(N,eye) < 0 => gamma = 1/n2
  //======================================================================
  if(fabs(dot) > 1e-10 && fabs(dot) < 1.0f-1e-10) // angle in the range (0..90)
  {
    if (dot < 0.0) {
      // Look from the outside into the inside of object
      gamma = 1.0 / ior.Get(0);
    }
    else {
      // Look from the inside into the outside of object
      gamma = ior.Get(0);
      N = -N;
    }
    // eta        = n2/n1 - relative index of refraction
    // gamma      = 1/eta
    // sin_refr   = sin_inc/eta = sin_inc * gamma
    // cos_refr^2 = 1 - sin_refr^2 = 1 - sin_inc^2 * gamma^2 =
    //            = 1 - gamma^2 * (1 - dot_inc * dot_inc)
    sqrterm = 1.0 - gamma * gamma * (1.0 - dot * dot);

    // Check for total internal reflection
    //--------------------------------------------------------------------
    if (sqrterm <= 0.0)  {
      // Incoming angle is close to Brewster angle.  Refracted ray goes
      // along the boundary of these media.
      if(sqrterm > -1e-10)
      {
        // Reflected/Transmitted ray is on the boundary of two mediums, [6]
        dir = (dirInit + fabs(dot)*N)*(1.0/sqrt(1.0-dot*dot));
        contrib->interaction = EE_REFRACTED_PERFECT;
        // set the reflected ray, direction is normalized here
        contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
        contrib->SetFlags(CContributionItem::EE_RefractedRay);
	cases = 11;
      }
      else
      {
        // Total internal reflection. Compute mirror-reflected direction
        dir = N*2.0*fabs(dot) + dirInit;
        contrib->interaction = EE_REFLECTED_PERFECT;
        // set the reflected ray, direction is normalized here
         contrib->ray.Init(hitInfo.GetPoint(), dir , REFLECTED_RAY);
        contrib->SetFlags(CContributionItem::EE_ReflectedRay);
	cases = 12;
      }
      //assert(dot >= 0.0);
    }
    else {
      // Ordinary refraction
      sqrterm = -fabs(dot) * gamma + sqrt(sqrterm);
      dir = -sqrterm * N + gamma * dirInit;
      contrib->interaction = EE_REFRACTED_PERFECT;
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_RefractedRay);
      // type of interaction
      cases = 21;
    }
    //--------------------------------------------------------------------
  }
  else // angle is 0 or 90
  {
    dir = dirInit;
    if(fabs(dot) <= 1e-10) // angle is 90 -> reflection
    {
      contrib->interaction = EE_REFLECTED_PERFECT;
      // set the reflected ray, direction is normalized here
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFLECTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_ReflectedRay);
      cases = 31;
    }
    else  // angle is 0 -> transmittion without refraction
    {
      contrib->interaction = EE_REFRACTED_PERFECT;
      // set the reflected ray, direction is normalized here
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_RefractedRay);
      cases = 32;
    }
  }
  //======================================================================
  float len = Magnitude(dir);
  assert(len <= 1.0 + 1e-05);
  // diffuseness of the bounce
  contrib->diffuseness = 0.0;
  // the reflection probabity is 1 for this type of reflection
  contrib->prob = 1.0;
  // The weight corresponds to BSDF multiplied by cosine.
  // where cosine = cos(normal,eye) =>
  //
  //    BRDF * cos(normal, ray.dir)/pdf =
  //                     = [ps*Dirac()/cos(normal, eye)]*cos(normal, eye)/1
  //                     = ps
  //  24/11/03 KP.

  contrib->weigth = kr(hitInfo);
  assert(carray.GetUsedItems() > 0);

#ifdef __TRAVERSAL_STATISTICS
  world->_statistics->IncReflectedRays();
#endif

  return 1; // one ray is shot
}

/* Returns the transparency at the specified point, possibly taking the
   incoming direction of the ray into account
*/
bool
CIdealRefractor::GetTransparency(CValues &transparency,
				 const CHitPointInfo &hitInfo) const
{
  transparency.Set(0.0);

  if (_kr) {
    hitInfo.GetTextureValue(transparency, *_kr, CMappingBase::EE_KR);
    if (transparency.AbsSum() > 0.0)
      return false; // transparent surface - maybe
    return true; // opaque surface
  }

  transparency.Set(0.0);
  return true; // opaque surface
}


bool
CIdealRefractor::GetDefaultColor(CValues &defaultColor,
				 const CHitPointInfo &hitInfo) const
{
  // let us consider _kr color to be the default one
  if (_kr) {
    hitInfo.GetTextureValue(defaultColor, *_kr, CMappingBase::EE_KR);
    return false;
  }

  defaultColor.Set(0.0);
  return true;
}
//========================================================================

const char* 
CIdealRefractor::GetHelp() const
{
	return BrdfStrings::KIdealRefractorDesc;
}
//========================================================================

int 
CIdealRefractor::GetNumParameters() const
{
	return 2; // refraction coefficient, ior
}
//========================================================================

CValues
CIdealRefractor::GetParameter(int parameterIndex) const
{
	CValues c(0,0,0);
	switch (parameterIndex)
	{
		case 0 :
			_kr->GetValue(c,CHitPointInfo::constMapInfo);
			break;
		case 1 :
			_ior->GetValue(c,CHitPointInfo::constMapInfo);
			break;
	}
	return c;
}
//========================================================================

CValues
CIdealRefractor::GetParameterConstraints(int parameterIndex) const
{
	CValues c(3);
	switch (parameterIndex)
	{
		case 0 :
			_setBasicConstraints(EE_ColorRGB,c);
			break;
		case 1 :
			c.Set(0,1);
			c.Set(1,MAX_IOR);
			c.Set(2,1);
			break;
	}
	return c;
}
//========================================================================

const char* 
CIdealRefractor::GetParameterDescription(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 :
			return BrdfStrings::KRefractionDesc;
		case 1 :
			return BrdfStrings::KIORDesc;
		default :
			return BrdfStrings::KInvalidParameter;
	}
}
//========================================================================

CSurface::EParameterUIType
CIdealRefractor::GetParameterSyntax(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 : // refraction texture
			return EE_RGB_Components;
		case 1 : // IOR texture
			return EE_Float;
		default :
			return EE_Unknown;
	}
}
//========================================================================

const char*
CIdealRefractor::GetParameterTitle(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 : // refraction texture
			return BrdfStrings::KRefractionTitle;
		case 1 : // IOR texture
			return BrdfStrings::KIORTitle;
		default :
			return BrdfStrings::KInvalidParameter;
	}
}
//========================================================================

void
CIdealRefractor::SetParameter(int parameterIndex, const CValues& value)
{
	CConstantTexture* newTex = new CConstantTexture(value);
	switch (parameterIndex)
	{
		case 0 : // refraction texture
			SetKr(newTex);
			break;
		case 1 : // ior texture
			SetIor(newTex);
			break;
	}
}
//========================================================================



/************************************************************************
 *                                                                      *
 *   Ideal dielelectric refractor.                                      *
 *                                                                      *
 ************************************************************************/

//========================================================================
int CIdealDielectric::SpawnIdealReflectedRay(const CValues &ks_local,
			                    CContributionArray  &carray,
			                    const CHitPointInfo &hitInfo) const
{
  CContributionItem *contrib = carray.AllocateNext();
  contrib->weigth.SetRepresentation(CValues::EE_Weigth3);

  CVector3D N = hitInfo.GetNormal();
  CVector3D dir;
  float dot   = hitInfo.GetDotProd();
  float gamma, sqrterm;
  int cases = 0;

  contrib->ray.Init(hitInfo.GetPoint(), hitInfo.GetReflectedDir() ,
		    REFLECTED_RAY);

  // set the flags concerning ray type
  contrib->SetFlags(CContributionItem::EE_ReflectedRay);
  // type of interaction
  contrib->interaction = EE_REFLECTED_PERFECT;
  // diffuseness of the bounce
  contrib->diffuseness = 0.0;
  // the reflection probabity is 1 for this type of reflection
  contrib->prob = 1.0;
  // the weight of this ray is 1
  contrib->weigth = ks_local; 
  // The weight corresponds to BSDF multiplied by cosine.
  // where cosine = cos(normal,eye) =>
  //
  //    BRDF * cos(normal, ray.dir)/pdf =
  //                     = [ps*Dirac()/cos(normal, eye)]*cos(normal, eye)/1
  //                     = ps
  //  24/11/03 K.P.

  assert(carray.GetUsedItems() > 0);

#ifdef __TRAVERSAL_STATISTICS
  world->_statistics->IncReflectedRays();
#endif

  return 1; // one ray is shot
}


//========================================================================
int CIdealDielectric::SpawnIdealRefractedRay(const CValues &kr_local,
                           const float &ior,
			   CContributionArray  &carray,
			   const CHitPointInfo &hitInfo) const
{
  CContributionItem *contrib = carray.AllocateNext();
  contrib->weigth.SetRepresentation(CValues::EE_Weigth3);

  CVector3D N = hitInfo.GetNormal();
  CVector3D dirInit = hitInfo.GetRay()->GetDir();
  CVector3D dir;
  float dot   = hitInfo.GetDotProd();
  float gamma, sqrterm;
  int cases = 0;

  // Incident ray - eyeRay (from the eye to the surface) and dot(N,eye) < 0
  // (if normal is oriented in opposite to the eyeRay direction). In this
  // case eyeRay falls from the air onto the object and refracts in the
  // object. And gamma should be equal to n2 (object's index of refraction)
  // Otherwise, if dot(N,eye) < 0 => gamma = 1/n2
  //======================================================================
  if(fabs(dot) > 1e-10 && fabs(dot) < 1.0f-1e-10) // angle in the range (0..90)
  {
    if (dot < 0.0) {
      // Look from the outside into the inside of object
      gamma = 1.0 / ior;
    }
    else {
      // Look from outside the inside into the outside of object
      gamma = ior;
      N = -N;
    }
    // eta        = n2/n1 - relative index of refraction
    // gamma      = 1/eta
    // sin_refr   = sin_inc/eta = sin_inc * gamma
    // cos_refr^2 = 1 - sin_refr^2 = 1 - sin_inc^2 * gamma^2 =
    //            = 1 - gamma^2 * (1 - dot_inc * dot_inc)
    sqrterm = 1.0 - gamma * gamma * (1.0 - dot * dot);

    // Check for total internal reflection
    //--------------------------------------------------------------------
    if (sqrterm <= 0.0)  {
      // Incoming angle is close to Brewster angle.  Refracted ray goes
      // along the boundary of these media.
      if(sqrterm > -1e-10)
      {
        // Reflected/Transmitted ray is on the boundary of two media [6], p.176
        dir = (dirInit + fabs(dot)*N)*(1.0/sqrt(1.0-dot*dot));
        contrib->interaction = EE_REFRACTED_PERFECT;
        // set the reflected ray, direction is normalized here
        contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
        contrib->SetFlags(CContributionItem::EE_RefractedRay);
	cases = 11;
      }
      else
      { // Total internal reflection
        dir = N*2.0*fabs(dot) + dirInit;
        contrib->interaction = EE_REFLECTED_PERFECT;
        // set the reflected ray, direction is normalized here
        contrib->ray.Init(hitInfo.GetPoint(), dir , REFLECTED_RAY);
        contrib->SetFlags(CContributionItem::EE_ReflectedRay);
	cases = 12;
      }
      assert(dot >= 0.0);
    }
    else {
      // Ordinary refraction
      sqrterm = -fabs(dot) * gamma + sqrt(sqrterm);
      dir = -sqrterm * N + gamma * dirInit;
      
      contrib->interaction = EE_REFRACTED_PERFECT;
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_RefractedRay);
      // type of interaction
      cases = 21;
    }
    //--------------------------------------------------------------------
  }
  else // angle is 0 or 90
  {
    dir = dirInit;
    if(fabs(dot) <= 1e-10) // angle is 90 -> reflection
    {
      contrib->interaction = EE_REFLECTED_PERFECT;
      // set the reflected ray, direction is normalized here
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFLECTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_ReflectedRay);
      cases = 31;
    }
    else  // angle is 0 -> transmittion without refraction
    {
      contrib->interaction = EE_REFRACTED_PERFECT;
      // set the reflected ray, direction is normalized here
      contrib->ray.Init(hitInfo.GetPoint(), dir, REFRACTED_RAY);
      // set the flags concerning ray type
      contrib->SetFlags(CContributionItem::EE_RefractedRay);
      cases = 32;
    }
  }
  //======================================================================
  float len = Magnitude(dir);
  assert(len <= 1.0 + 2e-05);
  // diffuseness of the bounce
  contrib->diffuseness = 0.0;
  // the reflection probabity is 1 for this type of reflection
  contrib->prob = 1.0;
  // The weight corresponds to BSDF multiplied by cosine.
  // where cosine = cos(normal,eye) =>
  //
  //    BRDF * cos(normal, ray.dir)/pdf =
  //                     = [ps*Dirac()/cos(normal, eye)]* cos(normal, eye)/1
  //                     = ps
  //  24/11/03 K.P.
  contrib->weigth = kr_local;

  assert(carray.GetUsedItems() > 0);

#ifdef __TRAVERSAL_STATISTICS
  world->_statistics->IncReflectedRays();
#endif

  return 1; // one ray is shot
}



//========================================================================
int
CIdealDielectric::SpawnStochasticRays(
  CContributionArray   &carray,
  const CHitPointInfo  &hitInfo,
  CSamplingInfo        &samplingInfo,
  EDistributionType     distType) const
{
  int maxRays = samplingInfo.GetMaxSamples();
  assert(maxRays > 0);

  refraction_rnd.clear();
  specular_rnd.clear();

  float ior = 0;
  bool use_fresnel = _kr->IsFresnel();

  if(use_fresnel && (samplingInfo.GetMaxSamples() > 0))
  {
    // store the seed to remain the same if possible, depending
    // on the random generator.
    samplingInfo.StoreSeed();

    CValues kr_local(CValues::EE_Weigth3);
    CValues kr_max  (CValues::EE_Weigth3);
    CValues ks_local(CValues::EE_Weigth3);
    CValues iora    (CValues::EE_Weigth3);

    // compute diffuse, specular, and refractive albedos
    float aks = 0.0f, akr = 0.0f, albedo_whole = 0.0;

    // validate hitInfo.dotprod
    hitInfo.GetNormal();

    bool max = false;
    kr_local = kr(hitInfo, max);
    akr = kr_local.Luminance();
    hitInfo.GetTextureValue(kr_max, *_kr, CMappingBase::EE_KFR);
    hitInfo.GetTextureValue(iora, *_kr, CMappingBase::EE_KFI);
    ior = iora.Get(0);
    albedo_whole = kr_max.Luminance();

    ks_local = kr_max - kr_local;
    assert((kr_local[0] <= (kr_max[0]+1e-06) &&
            kr_local[1] <= (kr_max[1]+1e-06)) &&
	    kr_local[2] <= (kr_max[2]+1e-06));

    aks = albedo_whole - akr;

    if(albedo_whole < 1.e-05) {
	  WARNING_INFO("CIdealDielectric::SpawnStochasticRays() :\n\
Albedo of this surface is almost zero => it is the black body!");
      return 0;
    }
    if( albedo_whole >= 1.0 ) {
	WARNING_INFO("CIdealDielectric::SpawnStochasticRays() :\nAlbedo > 1.0\n\
      To keep the energy conservation requirement the total albedo\n\
(albedo_specularity + albedo_diffuse + albedo_transmittance) should be less than 1.\n\
(If it is equal to 1, termination of a random walk with\nRussian Roulette will be impossible)");
	}
    // Compute the number of rays to refract / reflect diffusely / specularly
    int numRefract = 0;
    int numMirror = 0;

    int count = maxRays;
    while(count--)
    {
      // This RND number is from the User's program. Actually, it should be
      // fit into the range 0..albedo_whole if some event besides absorbtion
      // was choosen. Therefore, we shoul make RND fall into the [0..1)
      float rnd_num = samplingInfo.Sample(0);

      if(count >= maxRays-1)
      {
        if(rnd_num <= albedo_whole)
          rnd_num /= albedo_whole;  // make first RND fall into the [0..1)
      }

      float alpha1 = akr/albedo_whole;
      float alpha2 = aks/albedo_whole;

      if(rnd_num < alpha1 && alpha1 > 1e-6) {
        // Reuse random number for generation of one component of the random
        // direction. Scale it to fall into the range [0..1)
        refraction_rnd.push_back(rnd_num/alpha1);
        numRefract++;
      }
      else {
  	  // Reuse random number for generation of one component of the random
          // direction. Scale it to fall into the range [0..1)
          specular_rnd.push_back((rnd_num-alpha1)/alpha2);
          numMirror++;
      }
      // For a now it does not work for Halton sequence.
      samplingInfo.IncDimension(2);
      samplingInfo.RecoverSeed();
    }

    if (numRefract)
    {
      SpawnIdealRefractedRay(kr_local, ior, carray, hitInfo);
    }

    // If there is refraction indexRefracted = 1
    int indexRefracted = carray.GetUsedItems();

    if (numMirror) {
      SpawnIdealReflectedRay(ks_local, carray, hitInfo);
    }

    int indexMax = carray.GetUsedItems();
    assert(indexMax > 0);

    for(int i = 0; i < indexMax; i++) {
      CContributionItem* ci = carray.GetItem(i);
      float mult;
      if(i < indexRefracted) {
        mult = akr;
      }
      else {
        mult = aks;
      }
      mult /= albedo_whole;
      ci->weigth *= (1.0/mult);
      ci->prob *= mult;
    } // for
    samplingInfo.IncDimension(2);

    // recover the seed for the next dimension to be sampled
    samplingInfo.RecoverSeed();
    assert(indexMax > 0);
  }
  else
  {
     cout << "albedo for CIdealDielectric must be of CFresnelTexture type\n";
     exit(0);
  }
  return 1; 
}
//========================================================================

/**
   Returns the transparency at the specified point, possibly taking the
   incoming direction of the ray into account
*/
bool
CIdealDielectric::GetTransparency(CValues &transparency,
				 const CHitPointInfo &hitInfo) const
{
  transparency.Set(0.0);

  if (_kr) {
    bool use_fresnel = _kr->IsFresnel();

    if(use_fresnel)
      hitInfo.GetTextureValue(transparency, *_kr, CMappingBase::EE_KFR);
    else
      hitInfo.GetTextureValue(transparency, *_kr, CMappingBase::EE_KR);

    if (transparency.AbsSum() > 0.0)
      return false; // transparent surface - maybe
    return true; // opaque surface
  }

  transparency.Set(0.0);
  return true; // opaque surface
}


//========================================================================
bool
CIdealDielectric::GetDefaultColor(CValues &defaultColor,
				 const CHitPointInfo &hitInfo) const
{
  // let us consider _kr color to be the default one
  if (_kr) {
    bool use_fresnel = _kr->IsFresnel();

    if(use_fresnel)
      hitInfo.GetTextureValue(defaultColor, *_kr, CMappingBase::EE_KFR);
    else
      hitInfo.GetTextureValue(defaultColor, *_kr, CMappingBase::EE_KR);

    return false;
  }

  defaultColor.Set(0.0);
  return true;
}
//========================================================================

const char* 
CIdealDielectric::GetHelp() const
{
	return BrdfStrings::KIdealDielectricDesc;
}
//========================================================================

int 
CIdealDielectric::GetNumParameters() const
{
	return 1; // Fresnel term
}
//========================================================================

CValues
CIdealDielectric::GetParameter(int parameterIndex) const
{
	CValues c(CValues::EE_WeigthN);
	if (!_kr)
	{
		return c;
	}
	switch (parameterIndex)
	{
		case 0 :
			CFresnelTexture* tex = static_cast<CFresnelTexture*>(_kr);
			CValues aux(CValues::EE_Weigth3);
			tex->GetColor(aux);
			c.Set(0,aux.Get(0));
			c.Set(1,aux.Get(1));
			c.Set(2,aux.Get(2));
			tex->GetIndexR(aux);
			c.Set(3,aux.Get(0));
			tex->GetExtinction(aux);
			c.Set(4,aux.Get(0));
			bool schlick;
			tex->GetApproxSchlick(schlick);
			c.Set(5,schlick);
			break;
	}
	return c;
}
//========================================================================

CValues
CIdealDielectric::GetParameterConstraints(int parameterIndex) const
{
	CValues c(CValues::EE_WeigthN);
	switch (parameterIndex)
	{
		case 0 :
			_setBasicConstraints(EE_Fresnel,c);
			break;
	}
	return c;
}
//========================================================================

const char* 
CIdealDielectric::GetParameterDescription(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 :
			return BrdfStrings::KFresnelDesc;
		default :
			return BrdfStrings::KInvalidParameter;
	}
}
//========================================================================

CSurface::EParameterUIType
CIdealDielectric::GetParameterSyntax(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 :
			return EE_Fresnel;
		default :
			return EE_Unknown;
	}
}
//========================================================================

const char*
CIdealDielectric::GetParameterTitle(int parameterIndex) const
{
	switch (parameterIndex)
	{
		case 0 :
			return BrdfStrings::KFresnelTitle;
		default :
			return BrdfStrings::KInvalidParameter;
	}
}
//========================================================================

void
CIdealDielectric::SetParameter(int parameterIndex, const CValues& value)
{
	if (!_kr)
	{
		_kr = new CFresnelTexture(CValues(0,0,0));
	}
	CFresnelTexture* tex = dynamic_cast<CFresnelTexture*>(_kr);
	switch (parameterIndex)
	{
		case 0 :
			CValues auxVal(CValues::EE_Weigth3);
			auxVal.Set(0,value.Get(0));
			auxVal.Set(1,value.Get(1));
			auxVal.Set(2,value.Get(2));
			tex->SetColor(auxVal);
			auxVal.SetRepresentation(CValues::EE_Weigth1);
			auxVal.Set(value.Get(3));
			tex->SetIndexR(auxVal);
			auxVal.Set(value.Get(4));
			tex->SetExtinction(auxVal);
			bool useSchlick = value.Get(5);
			tex->SetApproxSchlick(useSchlick);
			break;
	}
}
//========================================================================



__END_BRDFLIB_SOURCE

