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


CombineBRDFSamplingStrategy::CombineBRDFSamplingStrategy(int n)
{
  // Save n
  nm = n;

  // Alloc space for particle bouncer and probability array
  pb = new SamplingStrategy* [nm];
  p = new float[nm];
}


CombineBRDFSamplingStrategy::~CombineBRDFSamplingStrategy()
{
  int i;

  // Delete contents of particle bouncer array.
  for (i=0;i<nm;i++)
    {
      if (pb[i] != NULL)
	delete pb[i];
    }

  // Delete the array itself.
  delete pb;

  // Delete probability array.
  delete p;
}


void CombineBRDFSamplingStrategy::setSamplingStrategy(int i,float np,SamplingStrategy *npb)
{
  pb[i] = npb;
  p[i] = np;
}


void CombineBRDFSamplingStrategy::Update()
{
  int i;

  for (i=0;i<nm;i++)
    pb[i]->Update();
}


double CombineBRDFSamplingStrategy::BounceRay(RAY &rin,HITREC &hin,RAY &rout,HITREC &hout)
{
  double cosTheta;
  double res;
  float  rn;
  int    m,i;

  // Choose a method according to probability array.
  rn = drand48();
  m = 0;
  while (m < nm)
    {
      if (rn <= p[m])
	break;
      rn -= p[m];
      m++;
    }

  // Set default result
  res = 0.0;

  // A method is choosen
  if (m < nm)
    {
      // First select the ray using the choosen method.
      res = p[m] * pb[m]->BounceRay(rin,hin,rout,hout);
      
      // Sometimes a method fails to choose a ray.
      if (res==0.0)
	return 0.0;

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

      // Combine using Eric Veach article...
      for (i=0;i<nm;i++)
	{
	  if (i != m)
	    res += p[i] * pb[i]->EvalRay(rin,hin,rout,hout,cosTheta);
	}
    }

  return res;
}


double CombineBRDFSamplingStrategy::EvalRay(RAY &rin,HITREC &hin,RAY &rout,HITREC &hout,const double cosTheta)
{ 
  double res;
  int    i;

  // Check we are on the good side
  if (cosTheta<0.0)
    return 0.0;

  // Initialise res.
  res = 0.0;

  // Combine using Eric Veach article...
  for (i=0;i<nm;i++)
    res += p[i] * pb[i]->EvalRay(rin,hin,rout,hout,cosTheta);

  return res;
}





