//
import java.util.*;
import java.awt.*;
import Geometry.*;

public class SimpleRayTracer extends PixApplet
{
	Vector shapes = new Vector();

	public void init() 
	{
		super.init();
		shapes.addElement(new Sphere( .07,.06,-2,.07));
		shapes.addElement(new Sphere(-.07,.06,-2,.07));
		shapes.addElement(new Sphere(0,0,-2.02,.1));
	}

	public double dot(double[] v, double[] u)
	{
		return v[0]*u[0]+v[1]*u[1]+v[2]*u[2];
	}
	
	public void normalize(double[] v)
	{
		double norm = Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
		v[0] /= norm;
		v[1] /= norm;
		v[2] /= norm;
	}
	
	double viewpoint[] = {0,0,0};             // VIEW POINT
	private double light[] = {1,1,1};	
	private double shiny = 30;
	private double ambCoeff=0.4;
	private double difCoeff=0.6;
	private double spcCoeff=0.7;

	private double light2[] = {-1,-1,1};	
	private double shiny2 = 30;
	private double ambCoeff2=0.4;
	private double difCoeff2=0.6;
	private double spcCoeff2=0.7;

	//private double ambCoeff=0.3;
	//private double difCoeff=0.4;
	
	
	//Computes the Phong illumination equation for a single directional light
	public double[] illuminate(double p[], double light[], double[] viewpoint, 
			double[] normal, double[] material, 
			double dif, double spc, double shiny)
	{
		double rgb[] = new double[3];
		double reflect[] = new double[3];
		double view[] = new double[3];

		// DO SHADING AT POINT - MODULATE WITH TEXTURE
		double dotNL = dot(normal,light);      
		for(int i=0; i<3; i++)
		{
			reflect[i] = 2*normal[i]*dotNL - light[i]; 
			view[i] = p[i] - viewpoint[i];
		}
		normalize(reflect);
		normalize(view); 

		double dotRV = dot(reflect,view);
		double dotRVtoN = dotRV>0 ? 0 : Math.pow(dotRV, shiny);

		//Math.pow(dot(reflect,view), shiny);
		for(int i=0; i<3; i++)
		{

			//K_amb*M_amb*L_amb + K_dif*M_dif*L_dif*(L_dir dot Norml) + K_spc*M_spc*L_spc*(
			rgb[i] = clamp(	dif*material[i]*dotNL +
					spc*dotRVtoN, 0, 1);
		}
		
		return rgb;
	}

	public void setPix(int frame) 
	{
		System.out.println("setPix Versio 2");
		double focal_length = 3.5;        // FOCAL LENGTH OF "LENS"
		//double v[] = {0,0,0};             // VIEW POINT
		
		double w[] = {0,0,-focal_length}; // RAY DIRECTION
		//double w[] = {0,0,-focal_length}; // RAY DIRECTION
		
		double t[] = new double[2];       // PLACE TO STORE ROOTS
		double p[] = {0,0,0};             // SURFACE POINT
		double n[] = {0,0,0};             // SURFACE NORMAL
		double center[] = {0,0,-2.02};	  // CENTER OF VIEW

		double w2[] = new double[3];
		for(int i=0; i<3; i++)
			w2[i] = center[i] - viewpoint[i];	
		normalize(w2);
		for(int j=0; j<3; j++)
			w2[j] *= focal_length;

		w = w2;


		double rgb1[] = new double[3];
		double rgb2[] = new double[3];
		double rgb[] = new double[3];

		normalize(light);

		// LOOP THROUGH PIXELS OF IMAGE
		for (int row = 0 ; row < H ; row++)
		for (int col = 0 ; col < W ; col++) 
		{
			// CONSTRUCT RAY DIRECTION VECTOR
			w[0] =  col / (double)W - 0.5;
			w[1] = -row / (double)W + 0.5 * H / W;

			// LOOP THROUGH ALL SHAPES
			Shape nearest_s = null;
			double nearest_t = 1000000;
			for (int i = 0 ; i < shapes.size() ; i++) 
			{
				Shape s = (Shape)shapes.elementAt(i);
				if (s.traceRay(viewpoint,w,t)>0 && t[0]>0 && t[0]0 ? 0 : Math.pow(dotRV, shiny);
		
				//Math.pow(dot(reflect,view), shiny);
				for(int i=0; i<3; i++)
				{
					
					//K_amb*M_amb*L_amb + K_dif*M_dif*L_dif*(L_dir dot Norml) + K_spc*M_spc*L_spc*(
					rgb[i] = clamp(ambCoeff*color[i] + 
							   difCoeff*color[i]*dotNL +
							   spcCoeff*dotRVtoN, 0, 1);
				}
				*/

				rgb1 = illuminate(p, light, viewpoint, n, color, difCoeff, spcCoeff, shiny);
				rgb2 = illuminate(p, light2, viewpoint, n, color, difCoeff2, spcCoeff2, shiny2);
				for(int i=0; i<3; i++)
					rgb[i] = clamp(ambCoeff*color[i] + rgb1[i] + rgb2[i], 0, 1);

				pix[xy2i(col, row)] = pack(d2i(rgb[0]),d2i(rgb[1]),d2i(rgb[2]));			
			}
			else
			{
				if(!showShadow)
				{
					pix[xy2i(col, row)] = pack(200, 200, 255);
				}
				else
				{
					double zTarget = -3;

					//Find the parameter for which this ray would hit the target
					double uTarget = (zTarget - viewpoint[2]) / w[2];
					
					//Find the point on the back plane
					double backPoint[] = { viewpoint[0] + uTarget*w[0], viewpoint[1] + uTarget*w[1], zTarget};

					//Find the ray to the light
					double rayToLight[] = {light[0]-backPoint[0], light[1]-backPoint[1], light[2]-backPoint[2]};

					//System.out.println(backPoint[0] + " " + backPoint[1] + " " + backPoint[2]);

					// LOOP THROUGH ALL SHAPES
					nearest_s = null;
					nearest_t = 1000000;
					for (int i = 0 ; i < shapes.size() ; i++) 
					{
						Shape s = (Shape)shapes.elementAt(i);
						if (s.traceRay(backPoint,rayToLight,t)>0 && t[0]>0 && t[0] max )
			return max;
		else 
			return x;
	}

	private final int d2i(double d)
	{
		return (int)(255*clamp(d,0,1));
	}

}