
#include "dest.h"
#include "phong.h"
#include "scene.h"
#include "Common.h"
#include "SamplingStrategy.h"



double PhysicalBRDFSamplingStrategy::BounceRay(RAY &rin,HITREC &hin,RAY &rout,HITREC &hout)
{
  DENSITY_ESTIMATION_DATA_PTR thisData;
  BSDF                        *thisBsdf;
  PHONG_BRDF                  *phong;
  COORDSYS                    reflCoord;
  VECTOR                      reflDir;
  COLOR                       tmp;
  double                      probDiffuse,probNonDiffuse,probTot;
  double                      xi_1,xi_2,pdf1,pdf2;
  float                       tmpCos;
  int                         ns;
  
  // Access density estimation data more easily
  thisData  = (DENSITY_ESTIMATION_DATA_PTR) hin.patch->radiance_data;
  thisBsdf  = hin.patch->surface->material->bsdf;

  // Halton sampling
  xi_1 = drand48();
  xi_2 = drand48();

  // Determine probabilities...
  tmp = BsdfReflectance(thisBsdf, /*&(hin.patch->midpoint)*/ NULL, NULL/*TODO*/, DIFFUSE_COMPONENT);
  probDiffuse = COLORSUMABSCOMPONENTS(tmp);
  tmp = BsdfReflectance(thisBsdf, /*&(hin.patch->midpoint),*/ NULL, NULL /*TODO*/,
			ALL_COMPONENTS & (~DIFFUSE_COMPONENT));
  probNonDiffuse = COLORSUMABSCOMPONENTS(tmp);
  probTot = probDiffuse + probNonDiffuse;

  // Initiate cos theta n sampling
  phong = (PHONG_BRDF *) thisBsdf->data;
  ns = (int)phong->Ns;
  reflDir = IdealReflectedDirection(&rin.dir,&hin.normal);
  VectorCoordSys(&reflDir,&reflCoord);
  
  if (drand48()*probTot <= probDiffuse)
    {
      // Diffuse particle...

      // Initiate reflection ray
      rout.pos = hin.point;
      rout.dir = SampleHemisphereCosTheta(&(thisData->coordsys),xi_1,xi_2,&pdf1);

      tmpCos   = VECTORDOTPRODUCT(reflDir,rout.dir);
      pdf2 = ( (ns + 1.0) * pow(tmpCos,ns) * M_1_2PI );
    }
  else
    {
      // Specular particle...

      // Initiate reflection ray
      rout.pos = hin.point;
      rout.dir = SampleHemisphereCosNTheta(&reflCoord,(int)phong->Ns,xi_1,xi_2,&pdf2);

      // Check we are on the good side
      tmpCos   = VECTORDOTPRODUCT(rout.dir,hin.normal);
      if (tmpCos<0.0)
	return 0.0;

      pdf1     = tmpCos * M_1_PI;
    }
  
  // Send ray
  RayCastingFunction(hin.patch,&rout,hout);

  // SetProbability
  return (pdf1*probDiffuse + pdf2*probNonDiffuse) / probTot;
}



double PhysicalBRDFSamplingStrategy::EvalRay(RAY &rin,HITREC &hin,RAY &rout,HITREC &,const double cosTheta)
{ 
  BSDF                        *thisBsdf;
  PHONG_BRDF                  *phong;
  VECTOR                      reflDir;
  COLOR                       tmp;
  double                      probDiffuse,probNonDiffuse,probTot;
  double                      tmpCos,pdf1,pdf2;
  int                         ns;

  // Sample BRDF only.
  if (cosTheta<0.0)
    return 0.0;

  // Easy access
  thisBsdf = hin.patch->surface->material->bsdf;
  phong    = (PHONG_BRDF *) thisBsdf->data;
  ns       = (int)phong->Ns;

  // Determine probabilities...
  tmp = BsdfReflectance(thisBsdf, /*&(hin.patch->midpoint)*/ NULL, NULL /*TODO*/, DIFFUSE_COMPONENT);
  probDiffuse = COLORSUMABSCOMPONENTS(tmp);
  tmp = BsdfReflectance(thisBsdf, /*&(hin.patch->midpoint),*/ NULL, NULL /*TODO*/,d
			ALL_COMPONENTS & (~DIFFUSE_COMPONENT));
  probNonDiffuse = COLORSUMABSCOMPONENTS(tmp);
  probTot = probDiffuse + probNonDiffuse;

  // Probability diffuse
  pdf1 = cosTheta * M_1_PI;

  // Probability specular
  reflDir  = IdealReflectedDirection(&rin.dir,&hin.normal);
  tmpCos   = VECTORDOTPRODUCT(reflDir,rout.dir);
  pdf2 = ( (ns + 1.0) * pow(tmpCos,ns) * M_1_2PI );

  // SetProbability
  return (pdf1*probDiffuse + pdf2*probNonDiffuse) / probTot;
}

