//----------------------------------------------------------------------------
// William Baxter III's Ray Tracer
//
//     Project for Comp 238, Raster Graphics
//     University of North Carolina at Chapel Hill
//     
// $Id:$
//----------------------------------------------------------------------------

#include "wb3rt.hpp"
#include "ray3f.hpp"
#include "wb3Scene.hpp"

wb3RayTracer::wb3RayTracer(int w, int h)
  : m_image(w, h)
{
  m_iXRes = w;
  m_iYRes = h;
  m_iDepth = 10;
  m_pScene = 0;
  m_iSamples = 1;
  SetOutputFile("output.png");
}

wb3RayTracer::~wb3RayTracer()
{
}


inline float CLAMP(float f)
{
  // clamp between [0,1]
  if (f>1.0f) return 1.0f;
  if (f<0.0f) return 0.0f;
  return f;
}

void wb3RayTracer::Trace()
{
  Camera *cam = m_pScene->GetCamera();
  int nsamp = GetNumSamples();
  float *xoff = new float [nsamp*nsamp];
  float *yoff = new float [nsamp*nsamp];
  float step = 1.0f/float(nsamp);
  // Initialize antialias offsets
  int i=0;
  for (int passy = 0; passy<nsamp; passy++)
  {
    for (int passx = 0; passx<nsamp; passx++)
    {
      yoff[i] = -0.5f + step/2.0f + step*float(passy);
      xoff[i] = -0.5f + step/2.0f + step*float(passx);
      i++;
    }
  }

  cerr << "Begin trace " << m_iXRes << "x" << m_iYRes << "  " 
    << nsamp*nsamp << "x oversampling" << endl;
  for (int py = 0; py < m_iYRes; py++)
  {
    for (int px = 0; px < m_iYRes; px++)
    {
      Vec3f accum(Vec3f::ZERO);
      for (int pass = 0; pass<nsamp*nsamp; pass++)
      {
        Ray3f r;
        cam->GetPixelRay(float(px)+xoff[pass], float(py)+yoff[pass],
                         m_iXRes, m_iYRes, &r.m_p, &r.m_v);
        r.Normalize();
        Vec3f attenuation(1.0f,1.0f,1.0f);
        Vec3f color(Vec3f::ZERO);
        m_pScene->Shade(m_pScene, m_pScene, 0, r, Vec3f::ZERO, 
                        color, attenuation, m_iDepth);
        color *= step*step;
        accum += color;
      }
      m_image.SetForeground(CLAMP(accum.x), CLAMP(accum.y), CLAMP(accum.z));
      m_image.SetPixel(px, py);
    }
    if (((py+1)&0xF) == 0)
      cerr << "Row " << py+1 << "/" << m_iYRes << endl;
  }

  delete [] xoff; delete [] yoff;
}

