//----------------------------------------------------------------------------
// William Baxter III's Ray Tracer
//
//     Project for Comp 238, Raster Graphics
//     University of North Carolina at Chapel Hill
//     
// $Id:$
//----------------------------------------------------------------------------

#include <ostream.h>
#include <vec3f.hpp>
#include <camera.hpp>
#include "wb3Sphere.hpp"
#include "wb3Triangle.hpp"
#include "wb3CastingShader.hpp"
#include "wb3TracingShader.hpp"
#include "wb3Material.hpp"
#include "wb3Light.hpp"
#include "wb3rt.hpp"
#include "wb3ArtifactSet.hpp"

static wb3Scene *makeScene()
{
  //----- MAKE SHADER ----------
  //wb3Shader *shader = new wb3CastingShader;
  wb3Shader *shader = new wb3TracingShader;

  //----- MAKE MATERIALS ---------
  Vec3f Ka(0.0f, 0.0f, 0.0f);
  Vec3f Kd(0.0f, 0.0f, 0.0f);
  Vec3f Ks(0.2f, 0.2f, 0.2f);
  Vec3f Kr(0.1f, 0.1f, 0.1f);
  Vec3f Kt(0.8f, 0.8f, 0.8f);
  wb3Material *glass = 
    new wb3Material(Ka, Kd, Ks, Kr, Kt);
  glass->SetIndex(1.33f);
  glass->SetSpecularity(100);
/*
  Ka.Set(0.2f, 0.2f, 0.2f);
  Kd.Set(0.5f, 0.5f, 0.6f);
  Ks.Set(0.1f, 0.1f, 0.1f);
*/
  Ka.Set(0.1f, 0.1f, 0.1f);
  Kd.Set(0.1f, 0.1f, 0.1f);
  Ks.Set(0.9f, 0.9f, 0.9f);
  Kr.Set(0.9f, 0.9f, 0.9f);
  Kt.Set(0.0f, 0.0f, 0.0f);
  wb3Material *chrome =
    new wb3Material(Ka, Kd, Ks, Kr, Kt);
  chrome->SetSpecularity(100);

  Ka.Set(0.2f, 0.2f, 0.2f);
  Kd.Set(0.4f, 0.6f, 0.4f);
  Ks.Set(0.4f, 0.4f, 0.4f);
  Kr.Set(0.1f, 0.1f, 0.1f);
  Kt.Set(0.0f, 0.0f, 0.0f);
  wb3Material *diffusegreen =
    new wb3Material(Ka, Kd, Ks, Kr, Kt);
  diffusegreen->SetSpecularity(50);

  Ka.Set(0.2f, 0.2f, 0.2f);
  Kd.Set(0.05f, 0.2f, 0.6f);
  Ks.Set(0.2f, 0.2f, 0.2f);
  Kr.Set(0.0f, 0.0f, 0.0f);
  Kt.Set(0.0f, 0.0f, 0.0f);
  wb3Material *diffuseblue =
    new wb3Material(Ka, Kd, Ks, Kr, Kt);
  diffuseblue->SetSpecularity(50);

#if 1
  //----- MAKE SPHERES ----------
  Vec3f C(0,1,8);
  wb3Sphere *S1 = new wb3Sphere(C, 2.0f);
  S1->SetShader(shader);
  S1->SetMaterial(glass);

  C.Set(3.1f,1,8);
  wb3Sphere *S2 = new wb3Sphere(C, 1.0f);
  S2->SetShader(shader);
  S2->SetMaterial(chrome);

  C.Set(-3.1f,1,6);
  wb3Sphere *S3 = new wb3Sphere(C, 1.0f);
  S3->SetShader(shader);
  S3->SetMaterial(chrome);

  C.Set(-1.3f,-0.9f,3.5f);
  wb3Sphere *S4 = new wb3Sphere(C, 1.0f);
  S4->SetShader(shader);
  S4->SetMaterial(chrome);
#endif

#if 1
  //----- MAKE TRIANGLES ----------
//  Vec3f p1(1.5f,-3.0f,15.0f);
//  Vec3f p2(5.0f,-4.0f,6.0f);
//  Vec3f p3(-5.0f,-4.0f,2.0f);

//  Vec3f p1(0.0f,3.0f,10.0f);
//  Vec3f p2(3.0f,-3.0f,10.0f);
//  Vec3f p3(-3.0f,-3.0f,10.0f);

  Vec3f p1(0.0f,12.0f,30.0f);
  Vec3f p2(3.0f,9.0f,35.0f);
  Vec3f p3(-3.0f,9.0f,35.0f);

  Vec3f p4(6.0f,6.0f,35.0f);
  Vec3f p5(0.0f,6.0f,33.0f);
  Vec3f p6(-6.0f,6.0f,35.0f);

  Vec3f p7(9.0f,3.0f,30.0f);
  Vec3f p8(3.0f,3.0f,35.0f);
  Vec3f p9(-3.0f,3.0f,35.0f);
  Vec3f p10(-9.0f,3.0f,30.0f);

  wb3Triangle *T1 = new wb3Triangle(p1,p2,p3);
  T1->SetShader(shader);
  T1->SetMaterial(diffuseblue);
  wb3Triangle *T2 = new wb3Triangle(p2,p4,p5);
  T2->SetShader(shader);
  T2->SetMaterial(diffuseblue);
  wb3Triangle *T3 = new wb3Triangle(p3,p5,p6);
  T3->SetShader(shader);
  T3->SetMaterial(diffuseblue);
  wb3Triangle *T4 = new wb3Triangle(p4,p7,p8);
  T4->SetShader(shader);
  T4->SetMaterial(diffuseblue);
  wb3Triangle *T5 = new wb3Triangle(p5,p8,p9);
  T5->SetShader(shader);
  T5->SetMaterial(diffuseblue);
  wb3Triangle *T6 = new wb3Triangle(p6,p9,p10);
  T6->SetShader(shader);
  T6->SetMaterial(diffuseblue);

#endif

#if 1
  //----- MAKE GROUNDPLANE ----------
  Vec3f pP(0.0f,-2.0f,0.0f);
  Vec3f pN(0.0f,1.0f,0.0f);
  wb3Plane *P1 = new wb3Plane(pN,pP);
  P1->SetShader(shader);
  P1->SetMaterial(diffusegreen);
#endif

  // ------ MAKE OBJ HOLDER ---------
  wb3ArtifactSet *pGroup = new wb3ArtifactSet();
  pGroup->AddArtifact(T1);
  pGroup->AddArtifact(T2);
  pGroup->AddArtifact(T3);
  pGroup->AddArtifact(T4);
  pGroup->AddArtifact(T5);
  pGroup->AddArtifact(T6);
  pGroup->AddArtifact(P1);
  pGroup->AddArtifact(S1);
  pGroup->AddArtifact(S2);
  pGroup->AddArtifact(S3);
  pGroup->AddArtifact(S4);

  // ------ MAKE LIGHTS --------
  Vec3f Lcolor(1.0f, 1.0f, 1.0f);
  Vec3f Lpos(4.0f, 7.0f, 1.0f);
  wb3Light *L1 = new wb3Light(Lpos, Lcolor);
  Lcolor.Set(0.5f, 0, 0);
  Lpos.Set(-2.0f, -1.9f, 0.0f);
  wb3Light *L2 = new wb3Light(Lpos, Lcolor);
  // L2->SetAttenuationFactors(0.0f, 0.5f, 1.0f);

  //---- MAKE CAMERA ---------
  Camera *cam = new Camera;
//  Vec3f orig(0,0,-2);
//  Vec3f center(0,-1,5.0);
  Vec3f orig(-4,2,0);
  Vec3f center(0,0,8);
  Vec3f up(0,1,0);
  cam->LookAt(orig, center, up);
  cam->Perspective(60.0f, /*1280.0f/1024.0f*/ 384.0f/384.0f, 0.01f, 20.0f);

  // ------ MAKE SCENE ---------
  float bg[3] = {0.6f, 0.9f, 1.0f};
  wb3Scene *scene = new wb3Scene(pGroup, bg);
  scene->AddLight(L1);
//  scene->AddLight(L2);
  scene->SetCamera(cam);
  return scene;
}


int main(int argc, char* argv[])
{
  wb3Scene *scene = makeScene();

  // ---- RAY TRACER ----------
//  wb3RayTracer tracer(1280, 1024);
  wb3RayTracer tracer(512, 512);
  tracer.Trace(scene);
  tracer.WritePPM("ImageOut.ppm");

  delete scene;
  return 0;
}

