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

#include "PhBBackgroundLight.H"
#include "utils.H"
#include "renderer.H"
#include "world.H"

namespace xrml {
void PhBBackgroundLight::set_bind(const SFBool& set)
{
  Bindable::set_bind(set);
}

void PhBBackgroundLight::render(void)
{
  for(int i=0; i < spectralBasis.size; i++) { 
    spectralBasis[i]->render();
  }

  // render background
  world->renderer->phbBackgroundLight(this);
}

Spectrum PhBBackgroundLight::eval(const Vec3& /*position*/, 
				  const Vec3& direction, 
				  const Spectrum& specWeight, 
				  float *pdf)
{
  Spectrum spectrum(0.);
  if(pdf) *pdf = 0;
  
  // apply viewOrientation
  Mat3 rot = Mat3(Vec4(orientation));
  Vec3 dir = Vec3(1, 0, 0) * rot;

  if((dir & direction) >= (cos(angle) - EPSILON))
    {
      for (int i=0; i < spectralBasis.size; i++)
	spectrum += (spectralBasis[i]->value) * spectralWeights[i];

      if(pdf) *pdf = 1. / (2 * M_PI * angle * angle);
    }

  return(spectrum);
}

Vec3 PhBBackgroundLight::sample(const Spectrum& specWeight,
				const Vec3& position, 
				const float xi1, const float xi2,
				Spectrum *value, float *pdf)
{
  // apply viewOrientation
  Mat3 rot = Mat3(Vec4(orientation));

  // select point
  //
  // uniform sampling on projection of light on evironment sphere
  // pdf = 1 / area = 1 / (2pi * r^2) = 1 / (2pi * angle^2)
  // sampling in prohection =>  r = xi1^.5 * angle;  theta = 2pi * xi2
  //
  // create direction from this point on sphere:
  // x = cos(rho) = cos(r)  
  // y = sin(rho) * cos(theta)
  // z = sin(rho) * sin(theta)
  //
  double rho = sqrt(xi1) * angle;
  double cos_rho = cos(rho);
  double sin_rho = sin(rho);
  double theta = 2 * M_PI * xi2;
  double sin_theta = sin(theta);
  double cos_theta = cos(theta);

  Vec3 dir = Vec3(cos_rho, sin_rho*cos_theta, sin_rho*sin_theta) * rot;

  // get value and pdf
  if(value || pdf)
    {
      Spectrum v = eval(position, dir, specWeight, pdf);
      if(value) *value = v;
    }

  return(dir);
}

Spectrum PhBBackgroundLight::power(const Vec3& /*position*/)
{
  Spectrum spectrum(0.);
  double area = 2 * M_PI * angle * angle;

  for (int i=0; i < spectralBasis.size; i++)
    spectrum += (spectralBasis[i]->value) * spectralWeights[i] * area;

  return(spectrum);
}

}  // namespace xrml
