
public class rayTraceApplet extends PixApplet {

    // All this verbiage is responsible for calculating the vertices of a
    // centered icosahedron
    //int hackstop = 26;
    //int hackstart = 0;


    private plane[] planes = new plane[46];

    private plane[] cubeplanes = new plane[6];
    private plane[] octplanes = new plane[8];
    private plane[] icoplanes = new plane[20];
    private plane[] dodplanes = new plane[12];

    private double[] ambientColor = {0.2,0.1,0.2};
    private double[][] lights = {
	{3.0,3.0,-5.0},
	{-7.0,-3.0,-15.0}
    };
    private double[][] lightColors = {
	{1.0,1.0,1.0},
	{1.0,1.0,1.0}
    };
    private double[][] diffuseColors = {
	{1.0,0.2,0.0}, //red sphere
	{0.0,0.6,1.0}, //blue sphere
	{1.0,1.0,0.0}, //yellow plane
	{1.0,1.0,1.0}  // gray plane
    };
    private double[][] specularColors = {
	{1.0,0.2,0.0},  //red sphere
	{1.0,1.0,0.2},  //blue sphere
	{1.0,0.2,1.0},  //yellow plane
	{0.2,1.0,1.0}   //gray plane 
    };
    private double[] eyeDirection = {0.0,0.0,0.0};

    private double[] rgb = {0.0,0.0,0.0};
    
    private double[] v = {0.0,0.0,0.0};
    private double[] w = {0.0,0.0,0.0};
    
    private sphere[] spheres = new sphere[3];
    private double[][] c = {
	{-1.0,0.75,-15.0},
	{1.25,1.0,-15.0}
	,{.5,.5,-15.0}
    };
    private double[] r = {0.3,0.5,0.9,0.75};
    private double[][] sphereColors = {
	{1.0,0.2,0.0},
	{.2,.95,.2},
	{.3,.4,.5}
    };

    //    int numplanes = 6; // cube to start

    //    private plane[] planes = new plane[numplanes];
    private plane floor = null;
    
    
    private double focalLength = 3.0;
    private double epsilon = 0.01;
    
    public void setPix(int frame) { // SET PIXELS FOR THIS ANIMATION FRAME
	// (THIS OVERRIDES A METHOD IN PIXAPPLET CLASS)
	v[0] = 0.0;
	v[1] = 0.0; // CAMERA EYEPOINT IS AT THE ORIGIN
	v[2] = 0.0;


	//////////////////////////////////
	// Geometric DATA

    double margin = 0;//0.25;
    double margin2 = 0;//0.25;
    double SS  = 0.75;//1
    double t1  = 2 * Math.PI / 5;
    double t2  = Math.PI / 10;
    double t4  = Math.PI / 5 ;
    double t3  = -3 * Math.PI / 10;
    double RR  = (SS/2) / Math.sin(t4);
    double HH  = Math.cos(t4) * RR;
    double Cx  = RR * Math.cos(t2);
    double Cy  = RR * Math.sin(t2);
    double H1 = Math.sqrt(SS*SS - RR*RR);
    double H2 = Math.sqrt((HH+RR) * (HH + RR) - (HH*HH));
    double Z2 = (H2 - H1) / 2;
    double Z1 = Z2 + H1;
    
    double zpushcube = 0;//20;
    double zpushico = 0.75;
    double zpushoct = 0;//14;
    double cubesize = 0.2;
    double octsize = 0.3;

    double cube1[] = {-cubesize,-cubesize,-cubesize-zpushcube, 1};
    double cube2[] = {-cubesize, cubesize,-cubesize-zpushcube, 1};
    double cube3[] = {-cubesize, cubesize, cubesize-zpushcube, 1};
    double cube4[] = {-cubesize,-cubesize, cubesize-zpushcube, 1};
    double cube5[] = { cubesize,-cubesize,-cubesize-zpushcube, 1};
    double cube6[] = { cubesize, cubesize,-cubesize-zpushcube, 1};
    double cube7[] = { cubesize, cubesize, cubesize-zpushcube, 1};
    double cube8[] = { cubesize,-cubesize, cubesize-zpushcube, 1};

    double oct1[] = {octsize-margin2,  0-margin2,        0-zpushoct,        1};
    double oct2[] = {0-margin2,        octsize-margin2,  0-zpushoct,        1};
    double oct3[] = {0-margin2,        0-margin2,        octsize-zpushoct,  1};
    double oct4[] = {-octsize-margin2, 0-margin2,        0-zpushoct,        1};
    double oct5[] = {0-margin2,        -octsize-margin2, 0-zpushoct,        1};
    double oct6[] = {0-margin2,        0-margin2,        -octsize-zpushoct, 1};

    double aa[] = {   0-margin,   0-margin,    Z1-zpushico, 1};
    double bb[] = {   0-margin,   RR-margin,   Z2-zpushico, 1};
    double cc[] = {  Cx-margin,   Cy-margin,   Z2-zpushico, 1};
    double dd[] = { SS/2-margin,  -HH-margin,  Z2-zpushico, 1};
    double ee[] = {-SS/2-margin,  -HH-margin,  Z2-zpushico, 1};
    double ff[] = { -Cx-margin,   Cy-margin,   Z2-zpushico, 1};
    double gg[] = {   0-margin,   -RR-margin, -Z2-zpushico, 1};
    double hh[] = { -Cx-margin,   -Cy-margin, -Z2-zpushico, 1};
    double ii[] = {-SS/2-margin,  HH-margin,  -Z2-zpushico, 1};
    double jj[] = { SS/2-margin,  HH-margin,  -Z2-zpushico, 1};
    double kk[] = {  Cx-margin,   -Cy-margin, -Z2-zpushico, 1};
    double ll[] = {   0-margin,   0-margin,   -Z1-zpushico, 1};
    //garbage
    double phi = (1 + Math.sqrt(5))/2;
    double alpha = 2 - phi;
    double beta = 1/phi;
    double dodpush = 12.0;

    double dodpt1[]={alpha,0,1-dodpush,1};
    double dodpt2[]={-alpha,0,1-dodpush,1};
    double dodpt3[]={-beta,beta,beta-dodpush,1};
    double dodpt4[]={0,1,alpha-dodpush,1};
    double dodpt5[]={beta,beta,beta-dodpush,1};
    double dodpt6[]={beta,-beta,beta-dodpush,1};
    double dodpt7[]={0,-1,alpha-dodpush,1};
    double dodpt8[]={-beta,-beta,beta-dodpush,1};
    double dodpt9[]={alpha,0,-1-dodpush,1};
    double dodpt10[]={-alpha,0,-1-dodpush,1};
    double dodpt11[]={-beta,-beta,-beta-dodpush,1};
    double dodpt12[]={0,-1,-alpha-dodpush,1};
    double dodpt13[]={beta,-beta,-beta-dodpush,1};
    double dodpt14[]={beta,beta,-beta-dodpush,1};
    double dodpt15[]={0,1,-alpha-dodpush,1};
    double dodpt16[]={-beta,beta-dodpush,-beta};
    double dodpt17[]={1,alpha,0-dodpush,1};
    double dodpt18[]={-1,alpha,0-dodpush,1};
    double dodpt19[]={-1,-alpha,0-dodpush,1};
    double dodpt20[]={1,-alpha,0-dodpush,1};


    double dodface1[][]=
	{dodpt1,dodpt2,dodpt3,dodpt4,dodpt5};
    double dodface2[][]=
	{dodpt2,dodpt1,dodpt6,dodpt7,dodpt8};
    double dodface3[][]=
	{dodpt9,dodpt10,dodpt11,dodpt12,dodpt13};
    double dodface4[][]=
	{dodpt10,dodpt9,dodpt14,dodpt15,dodpt16};
    double dodface5[][]=
	{dodpt15,dodpt4,dodpt5,dodpt17,dodpt14};
    double dodface6[][]=
	{dodpt4,dodpt15,dodpt16,dodpt18,dodpt3};
    double dodface7[][]=
	{dodpt12,dodpt7,dodpt8,dodpt19,dodpt11};
    double dodface8[][]=
	{dodpt7,dodpt12,dodpt13,dodpt20,dodpt6};
    double dodface9[][]=
	{dodpt17,dodpt20,dodpt6,dodpt1,dodpt5};
    double dodface10[][]=
	{dodpt20,dodpt17,dodpt14,dodpt9,dodpt13};
    double dodface11[][]=
	{dodpt18,dodpt19,dodpt11,dodpt10,dodpt16};
    double dodface12[][]=
	{dodpt19,dodpt18,dodpt3,dodpt2,dodpt8};
	//garbageend

    double cubepoints[][] = {cube1,cube2,cube3,cube4,cube5,cube6,cube7,cube8};
    double octpoints[][] = {oct1,oct2,oct3,oct4,oct5,oct6};
    double icopoints[][] = {aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,ll};
    //garbage
    double dodpoints[][] = {dodpt1,dodpt2,dodpt3,dodpt4,dodpt5,
			    dodpt6,dodpt7,dodpt8,dodpt9,dodpt10,
			    dodpt11,dodpt12,dodpt13,dodpt14,dodpt15,
			    dodpt16,dodpt17,dodpt18,dodpt19,dodpt20};
			    //garbageend
    Matrix3D M = new Matrix3D();
    M.Identity();
    M.xRotate(Math.PI/4);
    M.yRotate(Math.PI/4);
    M.zRotate(Math.PI/4);
    //    M.translate(-.5,-.5,-.5);

    M.printout();

    double zpcube = 7.5;
    double zpico =  7.5;
    double zpoct =  7.5;

    for (int i=0;i<cubepoints.length;i++){
	  double[] temp = new double[4];
	  temp[3] = 1.0;
	  M.transform(cubepoints[i],temp);
	  temp[2] = temp[2] - zpcube;
	  cubepoints[i] = temp;
    //System.out.println("ABRAHAM SAID HERE I AM");

    };

    for (int i=0;i<octpoints.length;i++){
	  double[] temp = new double[4];
	  temp[3] = 1.0;
	  M.transform(octpoints[i],temp);
	  temp[2] = temp[2] - zpoct;
	  octpoints[i] = temp;
    };

    for (int i=0;i<icopoints.length;i++){
	  double[] temp = new double[4];
	  temp[3] = 1.0;
	  M.transform(icopoints[i],temp);
	  temp[2] = temp[2] - zpico;
	  icopoints[i] = temp;
    };
    //garbage
    for (int i=0;i<dodpoints.length;i++){
	  double[] temp = new double[4];
	  temp[3] = 1.0;
	  M.transform(dodpoints[i],temp);
	  temp[2] = temp[2] - zpico;
	  dodpoints[i] = temp;
	  //System.out.println("the dodecahedron point i[0]: " + i + " is : " + dodpoints[i][0]);
	  //System.out.println("the dodecahedron point i[1]: " + i + " is : " + dodpoints[i][1]);
	  //System.out.println("the dodecahedron point i[2]: " + i + " is : " + dodpoints[i][2]);
	  //System.out.println("the dodecahedron point i[3]: " + i + " is : " + dodpoints[i][3]);
    };
    //garbageend
    double octfaces[][][] = {
	{octpoints[1],octpoints[2],octpoints[0]},
	{octpoints[1],octpoints[3],octpoints[2]},
	{octpoints[1],octpoints[5],octpoints[3]},
	{octpoints[1],octpoints[0],octpoints[5]},
	{octpoints[4],octpoints[0],octpoints[2]},
	{octpoints[4],octpoints[2],octpoints[3]},
	{octpoints[4],octpoints[3],octpoints[5]},
	{octpoints[4],octpoints[5],octpoints[0]}
    };

    double cubefaces[][][] = {
	{cubepoints[3], cubepoints[2], cubepoints[1], cubepoints[0]},
	{cubepoints[4], cubepoints[5], cubepoints[6], cubepoints[7]},
	{cubepoints[1], cubepoints[2], cubepoints[6], cubepoints[5]},
	{cubepoints[7], cubepoints[3], cubepoints[0], cubepoints[4]},
	{cubepoints[7], cubepoints[6], cubepoints[2], cubepoints[3]},
	{cubepoints[1], cubepoints[5], cubepoints[4], cubepoints[0]}
    };
    //garbage
    double dodfaces[][][] = {
	dodface1,dodface2,dodface3,dodface4,dodface5,dodface6,
	dodface7,dodface8,dodface9,dodface10,dodface11,dodface12
    };
    //garbageend    
    double icofaces[][][] = {
	{icopoints[2],icopoints[1],icopoints[0]},
	{icopoints[3],icopoints[2],icopoints[0]},
	{icopoints[4],icopoints[3],icopoints[0]},
	{icopoints[5],icopoints[4],icopoints[0]},
	{icopoints[1],icopoints[5],icopoints[0]},
	{icopoints[1],icopoints[2],icopoints[9]},
	{icopoints[9],icopoints[2],icopoints[10]},
	{icopoints[10],icopoints[2],icopoints[3]},
	{icopoints[10],icopoints[3],icopoints[6]},
	{icopoints[6],icopoints[4],icopoints[7]},
	{icopoints[7],icopoints[4],icopoints[5]},
	{icopoints[5],icopoints[8],icopoints[7]},
	{icopoints[5],icopoints[1],icopoints[8]},
	{icopoints[8],icopoints[1],icopoints[9]},
	{icopoints[9],icopoints[1],icopoints[2]},
	{icopoints[11],icopoints[9],icopoints[10]},
	{icopoints[11],icopoints[10],icopoints[6]},
	{icopoints[11],icopoints[6],icopoints[7]},
	{icopoints[11],icopoints[7],icopoints[8]},
	{icopoints[11],icopoints[8],icopoints[9]}
    };



	//////////////////////////////////



	// this is to fill planes from icofaces
	
	for (int i = 0; i < 20; i++)
	    {
		double thisu[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisu[j] = icofaces[i][1][j] - icofaces[i][0][j];
		    };
		double thisv[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisv[j] = icofaces[i][2][j] - icofaces[i][1][j];
		    };
		double g[] = new double[4];
		g[0] = thisu[1]*thisv[2] - thisu[2]*thisv[1];
		g[1] = thisu[2]*thisv[0] - thisu[0]*thisv[2];
		g[2] = thisu[0]*thisv[1] - thisu[1]*thisv[0];
		g[3] = - (g[0]*icofaces[i][1][0] + g[1]*icofaces[i][1][1] + g[2]*icofaces[i][1][2]);
		//		//System.out.println("the D for icoplane" + i + "is : " + g[3]);
		//		//System.out.println("components " + icofaces[i][1][0] +" "
		//		                 + icofaces[i][1][1] +" "
		//		                 + icofaces[i][1][2]);
		icoplanes[i] = new plane("plane "+i,
					 g[0],g[1],g[2],g[3],diffuseColors[2]);
		icoplanes[i].setDiffuseColor(diffuseColors[2]);
		icoplanes[i].setSpecularColor(specularColors[2]);
	    };

	// this is to fill planes from cubefaces

	for (int i = 0; i < 6; i++)
	    {
		double thisu[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisu[j] = cubefaces[i][1][j] - cubefaces[i][0][j];
		    };
		//System.out.println("for face " + i + " the u is (" +
		//6		   thisu[0] + ", " +
		//6		   thisu[1] + ", " +
		//6		   thisu[2] + ")");
		double thisv[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisv[j] = cubefaces[i][2][j] - cubefaces[i][1][j];
		    };
		//System.out.println("for face " + i + " the v is (" +
		//6		   thisv[0] + ", " +
		//6		   thisv[1] + ", " +
		//6		   thisv[2] + ")");
		double g[] = new double[4];
		g[0] = thisu[1]*thisv[2] - thisu[2]*thisv[1];
		g[1] = thisu[2]*thisv[0] - thisu[0]*thisv[2];
		g[2] = thisu[0]*thisv[1] - thisu[1]*thisv[0];
		g[3] = - (g[0]*cubefaces[i][1][0] + g[1]*cubefaces[i][1][1] + g[2]*cubefaces[i][1][2]);
		//System.out.println("the A for CUBEplane " + i + " is : " + g[0]);
		//System.out.println("the B for CUBEplane " + i + " is : " + g[1]);
		//System.out.println("the C for CUBEplane " + i + " is : " + g[2]);
		//System.out.println("the D for CUBEplane " + i + " is : " + g[3]);
		//System.out.println("components " + cubefaces[i][1][0] +" "
		//6		                 + cubefaces[i][1][1] +" "
		//6		                 + cubefaces[i][1][2]);
		cubeplanes[i] = new plane("cube "+i,
					 g[0],g[1],g[2],g[3],diffuseColors[2]);
		cubeplanes[i].setDiffuseColor(diffuseColors[2]);
		cubeplanes[i].setSpecularColor(specularColors[2]);
	    };

	// this is to fill planes from icofaces

	for (int i = 0; i < 8; i++)
	    {
		double thisu[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisu[j] = octfaces[i][1][j] - octfaces[i][0][j];
		    };
		//System.out.println("for face " + i + " the u is (" +
		//6		   thisu[0] + ", " +
		//6		   thisu[1] + ", " +
		//6		   thisu[2] + ")");
		double thisv[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisv[j] = octfaces[i][2][j] - octfaces[i][1][j];
		    };
		//System.out.println("for face " + i + " the v is (" +
		//6		   thisv[0] + ", " +
		//6		   thisv[1] + ", " +
		//6		   thisv[2] + ")");
		double g[] = new double[4];
		g[0] = thisu[1]*thisv[2] - thisu[2]*thisv[1];
		g[1] = thisu[2]*thisv[0] - thisu[0]*thisv[2];
		g[2] = thisu[0]*thisv[1] - thisu[1]*thisv[0];
		g[3] = - (g[0]*octfaces[i][1][0] + g[1]*octfaces[i][1][1] + g[2]*octfaces[i][1][2]);
		//System.out.println("the A for OCTplane " + i + " is : " + g[0]);
		//System.out.println("the B for OCTplane " + i + " is : " + g[1]);
		//System.out.println("the C for OCTplane " + i + " is : " + g[2]);
		//System.out.println("the D for OCTplane " + i + " is : " + g[3]);
		//System.out.println("components " + octfaces[i][1][0] +" "
		//6		                 + octfaces[i][1][1] +" "
		//6		                 + octfaces[i][1][2]);
		octplanes[i] = new plane("oct "+i,
					 g[0],g[1],g[2],g[3],diffuseColors[2]);
		octplanes[i].setDiffuseColor(diffuseColors[2]);
		octplanes[i].setSpecularColor(specularColors[2]);
	    };


	// this is to fill planes from dodfaces
	//garbage
	for (int i = 0; i < 12; i++)
	    {
		double thisu[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisu[j] = dodfaces[i][1][j] - dodfaces[i][0][j];
		    };
		//System.out.println("for face " + i + " the u is (" +
		//6		   thisu[0] + ", " +
		//6		   thisu[1] + ", " +
		//6		   thisu[2] + ")");
		double thisv[] = new double[3];
		for (int j = 0; j < 3; j++)
		    {
			thisv[j] = dodfaces[i][2][j] - dodfaces[i][1][j];
		    };
		//System.out.println("for face " + i + " the v is (" +
		//6		   thisv[0] + ", " +
		//6		   thisv[1] + ", " +
		//6		   thisv[2] + ")");
		double g[] = new double[4];
		g[0] = thisu[1]*thisv[2] - thisu[2]*thisv[1];
		g[1] = thisu[2]*thisv[0] - thisu[0]*thisv[2];
		g[2] = thisu[0]*thisv[1] - thisu[1]*thisv[0];
		g[3] = - (g[0]*dodfaces[i][1][0] + g[1]*dodfaces[i][1][1] + g[2]*dodfaces[i][1][2]);
		//System.out.println("the A for DODplane " + i + " is : " + g[0]);
		//System.out.println("the B for DODplane " + i + " is : " + g[1]);
		//System.out.println("the C for DODplane " + i + " is : " + g[2]);
		//System.out.println("the D for DODplane " + i + " is : " + g[3]);
		//System.out.println("components " + dodfaces[i][1][0] +" "
		//6		                 + dodfaces[i][1][1] +" "
		//6		                 + dodfaces[i][1][2]);
		dodplanes[i] = new plane("dod "+i,
					 g[0],g[1],g[2],g[3],diffuseColors[2]);
		dodplanes[i].setDiffuseColor(diffuseColors[2]);
		dodplanes[i].setSpecularColor(specularColors[2]);
	    };
	//garbageend

	//System.out.println("here I am 001");

	spheres[0] = new sphere("sphere0",c[0],r[0],sphereColors[0]);
	spheres[0].setSphereDiffuseColor(diffuseColors[0]);
	spheres[0].setSphereSpecularColor(specularColors[0]);
	spheres[1] = new sphere("sphere1",c[1],r[1],sphereColors[1]);
	spheres[1].setSphereDiffuseColor(diffuseColors[1]);
	spheres[1].setSphereSpecularColor(specularColors[1]);
	spheres[2] = new sphere("sphere2",c[2],r[1],sphereColors[2]);
	spheres[2].setSphereDiffuseColor(diffuseColors[1]);
	spheres[2].setSphereSpecularColor(specularColors[1]);


	//System.out.println("here I am 002");
	double epsilon = 0.0;

	for (int i = 0; i < 6; i++) {
	    planes[i] = new plane("plane " + i,
				  cubeplanes[i].getA(),cubeplanes[i].getB(),cubeplanes[i].getC(),cubeplanes[i].getD(),
				  diffuseColors[2]);
	    planes[i].setDiffuseColor(diffuseColors[0]);
	    planes[i].setSpecularColor(specularColors[0]);
	};

	for (int i = 0; i < 20; i++) {
	    planes[i+6] = new plane("plane " + i,
				  icoplanes[i].getA(),icoplanes[i].getB(),icoplanes[i].getC(),icoplanes[i].getD(),
				  diffuseColors[2]);
	    planes[i+6].setDiffuseColor(diffuseColors[0]);
	    planes[i+6].setSpecularColor(specularColors[0]);
	};

	for (int i = 0; i < 8; i++) {
	    planes[i+26] = new plane("plane " + i,
				  octplanes[i].getA(),octplanes[i].getB(),octplanes[i].getC(),octplanes[i].getD(),
				  diffuseColors[2]);
	    planes[i+26].setDiffuseColor(diffuseColors[0]);
	    planes[i+26].setSpecularColor(specularColors[0]);
	};
	//garbage
	for (int i = 0; i < 12; i++) {
	    planes[i+34] = new plane("plane " + i,
				  dodplanes[i].getA(),dodplanes[i].getB(),dodplanes[i].getC(),dodplanes[i].getD(),
				  diffuseColors[2]);
	    planes[i+34].setDiffuseColor(diffuseColors[0]);
	    planes[i+34].setSpecularColor(specularColors[0]);
	};
	//garbageend

	floor = new plane("floor",
			  0.0,1.25,0.0,1.0,
			  diffuseColors[3]);
	floor.setDiffuseColor(diffuseColors[3]);
	floor.setSpecularColor(specularColors[3]);


      	for (int i=0; i<planes.length;i++){
	    //System.out.println("the plane numbers for plane " + i + "are ");
	    //System.out.println("a: " + planes[i].getA());
	    //System.out.println("b: " + planes[i].getB());
	    //System.out.println("c: " + planes[i].getC());
	    //System.out.println("d: " + planes[i].getD());
	}




	int n = 0;
	for (int j = 0 ; j < H ; j++)   // loop rows
	    for (int i = 0 ; i < W ; i++) { // loop cols
		w[0] = (double)(i - W/2) / W;     // ray direction at pixel
		w[1] = (double)(H/2 - j) / W;     //
		w[2] = -focalLength;              // img plane@ z= -focalLength
		rayTrace(v,w,0);              // raytrace the pixel
		////System.out.println(rgb[0]+","+rgb[1]+","+rgb[2]);
		pix[n++] = pack(Math.max(0,Math.min(255,(int)(255 * rgb[0]))),
				Math.max(0,Math.min(255,(int)(255 * rgb[1]))),
				Math.max(0,Math.min(255,(int)(255 * rgb[2]))));
		////System.out.println("in the loop at row"+j+" and col "+i);
	    }
    };

    public void rayTrace(double[] v,double[] w,int numBounces) {
	sphere sph = null;
	plane pl = null;
	int sphereNum = -1;
	int planeNum = -1;
	int planeNum2 = -1;

	// cube
	//int hackstart = 0;
	//int hackstop = 6;

	// ico
	int hackstart = 6;
	int hackstop = 26;

System.out.println("this ought to be the only console output");

	// oct
	//int hackstart = 26;
	//int hackstop = 34;

	// dod
	//int hackstart = 34;
	//int hackstop = 46;

	// ALL
	//int hackstart = 0;
	//int hackstop = 46;

	double t = Double.POSITIVE_INFINITY;
	double tn = t;
	double[] S = {0.0, 0.0, 0.0};
	double[] n = {0.0, 0.0, 0.0};
	double[] R = {0.0, 0.0, 0.0};
	double wn = 0.0;
	double[] newV = {0.0, 0.0, 0.0};
	double[] newW = {0.0, 0.0, 0.0};
	double LiDotN = 0.0;
	double[] diffuseColor = {0.0, 0.0, 0.0};
	double[] specularColor = {0.0, 0.0, 0.0};
	double[] Hi = {0.0, 0.0, 0.0};
	double HiDotE = 0.0;
	double p = 16.0;
	double[] sum = {0.0, 0.0, 0.0};
	double[] eye = {0.0, 0.0, 0.0};
	double[] Li = {0.0, 0.0, 0.0};
	double[] e = {0.0, 0.0, 0.0};
	double RDotN = 0.0;
	sphereRayTracer srt = null;
	planeRayTracer prt = null;
	double distance = 0.0;
	double[] inTs = {0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0, 0.0,
			 0.0, 0.0, 0.0, 0.0,0.0,0.0};
	double[] outTs = {Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY};

	double[] inTs2 = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
	double[] outTs2 = {Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
			  Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY};

	double inT = 0.0;
	double outT = Double.POSITIVE_INFINITY;

	double inT2 = 0.0;
	double outT2 = Double.POSITIVE_INFINITY;
	boolean inCube = true;
	boolean inCube2 = true;

	for(int i=0;i<spheres.length;i++) {
	    srt = new sphereRayTracer(spheres[i],v,w);
	    tn = srt.getT();
	    if (tn < t) {
		t = tn;
		sphereNum = i;
	    }
	}

	////////////////////////
	////////////////////////

	//	for (int i = 0; i < planarobjects.length; i++) {

	for(int i=hackstart;i< hackstop;i++) {//planes.length;i++) {
	    //	    //System.out.println("in the planes loop, where i is "+i);
	    prt = new planeRayTracer(planes[i],v,w);
	    if (prt.getIn())
		inTs[i] = prt.getT();
	    else if (prt.getOut())
		outTs[i] = prt.getT();
	    ////System.out.println(i+": in:"+inTs[i]+" out:"+outTs[i]);
	    if ((prt.getDenominator() == 0.0) && (prt.getNumerator() < 0.0))
		inCube = false;
	}

	for(int i=hackstart;i<hackstop;i++) { //inTs.length;i++) {
	    //if ((inTs[i] != 0.0) && (inT < inTs[i])) {
	    if (inT < inTs[i]) {
		inT = inTs[i];
		planeNum = i;
	    }

	    if (outT > outTs[i]) {
		outT = outTs[i];
	    }
	}

	////System.out.println("inT: "+inT+" outT:"+outT);

	if ((inT < outT) && (inT < t) && inCube) {
	    t = inT;
	    sphereNum = -1;
	    ////System.out.println(planeNum);
	    ////System.out.println("inT: "+inT+" outT:"+outT);
	}
	else
	    planeNum = -1;

	////////////////////////
	////////////////////////
	/*
	hackstart = 0; hackstop = 6;

	for(int i=hackstart;i< hackstop;i++) {//planes.length;i++) {
	    //	    //System.out.println("in the planes loop, where i is "+i);
	    prt = new planeRayTracer(planes[i],v,w);
	    if (prt.getIn())
		inTs[i] = prt.getT();
	    else if (prt.getOut())
		outTs[i] = prt.getT();
	    ////System.out.println(i+": in:"+inTs[i]+" out:"+outTs[i]);
	    if ((prt.getDenominator() == 0.0) && (prt.getNumerator() < 0.0))
		inCube = false;
	}

	for(int i=hackstart;i<hackstop;i++) { //inTs.length;i++) {
	    //if ((inTs[i] != 0.0) && (inT < inTs[i])) {
	    if (inT < inTs[i]) {
		inT = inTs[i];
		planeNum = i;
	    }

	    if (outT > outTs[i]) {
		outT = outTs[i];
	    }
	}

	////System.out.println("inT: "+inT+" outT:"+outT);

	if ((inT < outT) && (inT < t) && inCube) {
	    t = inT;
	    sphereNum = -1;
	    ////System.out.println(planeNum);
	    ////System.out.println("inT: "+inT+" outT:"+outT);
	}
	else
	    planeNum = -1;
	*/
	////////////////////////
	////////////////////////



	prt = new planeRayTracer(floor,v,w);

	if ((prt.getT() > 0.0) && (prt.getT() < t)) {
	    t = prt.getT();
	    sphereNum = -1;
	    planeNum = -1;
	    pl = floor;
	}
	else 
	    pl = null;

	if ((sphereNum >= 0) && (sphereNum < spheres.length))
	    sph = spheres[sphereNum];
	else if ((planeNum >= hackstart) && (planeNum < hackstop)) //planes.length))
	    pl = planes[planeNum];
	else if (pl != null) {
	    sph = null;
	}
	else {
	    sph = null;
	    pl = null;
	}
	
	if ((sph == null) && (pl == null)) {
	    rgb[0] = 0.0;
	    rgb[1] = 0.0;
	    rgb[2] = 0.0;
	}
	else if (numBounces < 5) {
	    S[0] = v[0] + t*w[0];
	    S[1] = v[1] + t*w[1];
	    S[2] = v[2] + t*w[2];
	    if (sph != null) {
		n[0] = (S[0] - sph.getSphereCenter()[0])/sph.getSphereRadius();
		n[1] = (S[1] - sph.getSphereCenter()[1])/sph.getSphereRadius();
		n[2] = (S[2] - sph.getSphereCenter()[2])/sph.getSphereRadius();
	    }
	    else if (pl != null) {
		n[0] = pl.getA();
		n[1] = pl.getB();
		n[2] = pl.getC();
		distance = (double)Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
		n[0] = n[0]/distance;
		n[1] = n[1]/distance; 
		n[2] = n[2]/distance;
	    }
	    wn = w[0]*n[0] + w[1]*n[1] + w[2]*n[2];
	    R[0] = -2.0*wn*n[0] + w[0];
	    R[1] = -2.0*wn*n[1] + w[1];
	    R[2] = -2.0*wn*n[2] + w[2];
	    newV[0] = S[0] + epsilon*R[0];
	    newV[1] = S[1] + epsilon*R[1];
	    newV[2] = S[2] + epsilon*R[2];
	    newW[0] = R[0];
	    newW[1] = R[1];
	    newW[2] = R[2];
	    
	    numBounces++;

	    rayTrace(newV,newW,numBounces);

	    for(int i=0;i<lights.length;i++) {
		Li[0] = lights[i][0] - S[0];
		Li[1] = lights[i][1] - S[1];
		Li[2] = lights[i][2] - S[2];
		distance = (double)Math.sqrt(Li[0]*Li[0]+Li[1]*Li[1]+Li[2]*Li[2]);
		Li[0] = Li[0]/distance;
		Li[1] = Li[1]/distance;
		Li[2] = Li[2]/distance;
		
		LiDotN = Li[0]*n[0] + Li[1]*n[1] + Li[2]*n[2];

		if (sph != null) {
		    diffuseColor[0] = sph.getSphereDiffuseColor()[0]*(double)Math.max(0,LiDotN);
		    diffuseColor[1] = sph.getSphereDiffuseColor()[1]*(double)Math.max(0,LiDotN);
		    diffuseColor[2] = sph.getSphereDiffuseColor()[2]*(double)Math.max(0,LiDotN);
		}
		else if (pl != null) {
		    diffuseColor[0] = pl.getDiffuseColor()[0]*(double)Math.max(0,LiDotN);
		    diffuseColor[1] = pl.getDiffuseColor()[1]*(double)Math.max(0,LiDotN);
		    diffuseColor[2] = pl.getDiffuseColor()[2]*(double)Math.max(0,LiDotN);
		}

		Hi[0] = 2.0*LiDotN*n[0] - Li[0];
		Hi[1] = 2.0*LiDotN*n[1] - Li[1];
		Hi[2] = 2.0*LiDotN*n[2] - Li[2];
		distance = (double)Math.sqrt(Hi[0]*Hi[0]+Hi[1]*Hi[1]+Hi[2]*Hi[2]);
		Hi[0] = Hi[0]/distance;
		Hi[1] = Hi[1]/distance;
		Hi[2] = Hi[2]/distance;
		
		distance = (double)Math.sqrt(R[0]*R[0]+R[1]*R[1]+R[2]*R[2]);
		R[0] = R[0]/distance;
		R[1] = R[1]/distance;
		R[2] = R[2]/distance;
		RDotN = R[0]*n[0] + R[1]*n[1] + R[2]*n[2];
		e[0] = 2.0*RDotN*n[0] - R[0];
		e[1] = 2.0*RDotN*n[1] - R[1];
		e[2] = 2.0*RDotN*n[2] - R[2];
		distance = (double)Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]);
		e[0] = e[0]/distance;
		e[1] = e[1]/distance;
		e[2] = e[2]/distance;

		HiDotE = Hi[0]*e[0] + Hi[1]*e[1] + Hi[2]*e[2];

		if (sph != null) {
		    specularColor[0] = sph.getSphereSpecularColor()[0]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		    specularColor[1] = sph.getSphereSpecularColor()[1]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		    specularColor[2] = sph.getSphereSpecularColor()[2]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		}
		else if (pl != null) {
		    specularColor[0] = pl.getSpecularColor()[0]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		    specularColor[1] = pl.getSpecularColor()[1]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		    specularColor[2] = pl.getSpecularColor()[2]*(double)Math.pow((double)Math.max(0,HiDotE),p);
		}
		
		sum[0] = sum[0] + lightColors[i][0] * (diffuseColor[0] + specularColor[0]);
		sum[1] = sum[1] + lightColors[i][1] * (diffuseColor[1] + specularColor[1]);
		sum[2] = sum[2] + lightColors[i][2] * (diffuseColor[2] + specularColor[2]);
		}
	    
	    rgb[0] = 0.25*rgb[0] + 0.75*(ambientColor[0] + sum[0]);
	    rgb[1] = 0.25*rgb[1] + 0.75*(ambientColor[1] + sum[1]);
	    rgb[2] = 0.25*rgb[2] + 0.75*(ambientColor[2] + sum[2]);
	    }	
	}
}

