/* PhBFresnelBSDF.C: PhBFresnelBSDF nodes (public source) */

#include "PhBFresnelBSDF.H"
#include "PhBLxySpectrum.H"
#include "PhBDiffuseReflector.H"

namespace xrml {

void PhBFresnelBSDF::render(void)
{
  static PhBSpectrum *unitNeutralSpectrum = new PhBLxySpectrum;
  static PhBScatterer *diffuseReflector = new PhBDiffuseReflector;

  if (!spectrum) spectrum = unitNeutralSpectrum;
  spectrum->render();

  if (!scatterer) scatterer = diffuseReflector;
  scatterer->render();
}

// Christophe Schlicks rational factor approximation for the
// Fresnel factor. 
// See Schlick, "An Inexpensive BRDF model ...", EuroGraphics'94
// proceedings (Computer graphics Forum Vol 13 nr 3).
static Spectrum FresnelFactor(const Spectrum& C, const double u)
{
  double v = fabs(1-u);
  double v5 = v*v; v5 *= v5 * v;
  return (Spectrum)C + (Spectrum(1) - C) * v5;
}

Spectrum PhBFresnelBSDF::eval(const Vec3& inDir,
			     const Vec3& outDir,
			     const complex& indexIn,
			     const complex& indexOut,
			     int modes,
			     float *pdf)
{
  Vec3 h = Vec3(inDir + outDir); h.normalize();
  double u = (h & inDir);
  return FresnelFactor(spectrum->value * intensity, fabs(u))
    * scatterer->eval(inDir, outDir, indexIn, indexOut, modes, pdf);
}

Vec3 PhBFresnelBSDF::sample(const Vec3& inDir,
			   const complex& indexIn,
			   const complex& indexOut,
			   float xi1, float xi2,
			   int modes)
{
  return scatterer->sample(inDir, indexIn, indexOut, xi1, xi2, modes);
}

Spectrum PhBFresnelBSDF::albedo(const Vec3& inDir,
			       const complex& indexIn,
			       const complex& indexOut,
			       int modes)
{
  return FresnelFactor(spectrum->value * intensity, inDir.z)
    * scatterer->albedo(inDir, indexIn, indexOut, modes);
}

}  // namespace xrml
