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

#include "PhBPerfectSpecularRefractor.H"

namespace xrml {

void PhBPerfectSpecularRefractor::render(void)
{
  //
}

float PhBPerfectSpecularRefractor::albedo(const Vec3& inDir,
				  const complex& IndexIn,
				  const complex& IndexOut,
				  int modes)
{
  return (modes & SM_SPECULAR_REFRACTION)
    ? 1.
    : 0.;
}

static Vec3 IdealRefractedDirection(const Vec3& inDir,
				    const complex& IndexIn,
				    const complex& IndexOut)
{
  // Ref: Glassner PDI, part II, page 577-578.
  double n = (inDir.z > 0.) ? IndexOut.r / IndexIn.r : IndexIn.r / IndexOut.r;
  double zz = 1. - (1. - inDir.z * inDir.z) * (n * n);
  return (zz > 0.)
    ? Vec3(-inDir.x * n, -inDir.y * n, (inDir.z > 0.) ? -sqrt(zz) : sqrt(zz))
    : Vec3(-inDir.x, -inDir.y, inDir.z);  // total internal reflection
}

Vec3 PhBPerfectSpecularRefractor::sample(const Vec3& inDir,
				 const complex& IndexIn,
				 const complex& IndexOut,
				 float xi1, float xi2,
				 int modes)
{
  return IdealRefractedDirection(inDir, IndexIn, IndexOut);
}

float PhBPerfectSpecularRefractor::eval(const Vec3& inDir,
				const Vec3& outDir,
				const complex& IndexIn,
				const complex& IndexOut,
				int modes,
				float *pdf)
{
  if (pdf) *pdf = 0.;
  if (!(modes & SM_SPECULAR_REFRACTION))
    return 0.;

  if ((IdealRefractedDirection(inDir, IndexIn, IndexOut) - outDir) |= EPSILON) {
    // outDir is ideal refracted direction
    if (pdf) *pdf = 1e10;
    return 1e10 / fabs(outDir.z);
  } else
    return 0.;
}

}  // namespace xrml
