import Raster;
import Drawable;
import Vertex2D;
import Triangle;
           
public class GradTriangle extends Triangle implements Drawable {
	boolean allSame;
                
    public GradTriangle(Vertex2D v0, Vertex2D v1, Vertex2D v2) {
    	v = new Vertex2D[3];
        v[0] = v0;
        v[1] = v1;
        v[2] = v2;
                   
        /*
        	check if all vertices are the same color
        */
        allSame = (v0.argb == v1.argb) && (v0.argb == v2.argb);
        if (allSame) {
        	color = v0.argb;
        } 
        else {
        	color = 0;
        }
    }
    
    
    public void Draw(Raster raster)
    {
    	int v0c = Triangle.v[0].argb;	//assigning vertex colors
		int v1c = Triangle.v[1].argb;
		int v2c = Triangle.v[2].argb;
   
   		float v0x = Triangle.v[0].x;
		float v1x = Triangle.v[1].x;
		float v2x = Triangle.v[2].x;
		float v0y = Triangle.v[0].y;
		float v1y = Triangle.v[1].y;
		float v2y = Triangle.v[2].y;

		float Mins[] = new float[2];
		float Mids[] = new float[2];
		float Maxs[] = new float[2];
		

		int v0a = (v0c & 0xff000000) >> 24;
		int v1a = (v1c & 0xff000000) >> 24;
		int v2a = (v2c & 0xff000000) >> 24;
		int v0r = (v0c & 0xff0000) >> 16;
		int v1r = (v1c & 0xff0000) >> 16;
		int v2r = (v2c & 0xff0000) >> 16;
		int v0g = (v0c & 0xff00) >> 8;
		int v1g = (v1c & 0xff00) >> 8;
		int v2g = (v2c & 0xff00) >> 8;
		int v0b = v0c & 0xff;
		int v1b = v1c & 0xff;
		int v2b = v2c & 0xff;
    	
    	
    	//b stands for base
		float b = super.span(v0x, v1x, v2x, Mins, Mids, Maxs, 0);
		//h is the height
		float h = span(v0y, v1y, v2y, Mins, Mids, Maxs, 1);
   		float a = b*h/(float)2;
		
		float factor = (1/(2*a));
		float qa1 = v1y - v2y;
		float qa2 = v2y - v0y;
		float qa3 = v0y - v1y;
		float qb1 = v2x - v1x;
		float qb2 = v0x - v2x;
		float qb3 = v1x - v0x;
		float qc1 = (v1x*v2y) - (v2x*v1y);
		float qc2 = (v2x*v0y) - (v0x*v2y);
		float qc3 = (v0x*v1y) - (v1x*v0y);
				
		float Aa = factor*(v0a*qa1 + v1a*qa2 + v2a*qa3);
		float Ba = factor*(v0a*qb1 + v1a*qb2 + v2a*qb3);
		float Ca = factor*(v0a*qc1 + v1a*qc2 + v2a*qc3);

		float Ar = factor*(v0r*qa1 + v1r*qa2 + v2r*qa3);
		float Br = factor*(v0r*qb1 + v1r*qb2 + v2r*qb3);
		float Cr = factor*(v0r*qc1 + v1r*qc2 + v2r*qc3);

		float Ag = factor*(v0g*qa1 + v1g*qa2 + v2g*qa3);
		float Bg = factor*(v0g*qb1 + v1g*qb2 + v2g*qb3);
		float Cg = factor*(v0g*qc1 + v1g*qc2 + v2g*qc3);

		float Ab = factor*(v0b*qa1 + v1b*qa2 + v2b*qa3);
		float Bb = factor*(v0b*qb1 + v1b*qb2 + v2b*qb3);
		float Cb = factor*(v0b*qc1 + v1b*qc2 + v2b*qc3);

		//all scenarios have the following variables
		
		float yStartPt = Maxs[1];	//where we begin at the top
		float xStartPt;
		float yEndPt = Mins[1]; 	//where we end at the bottom
		float xEndPt; 		
		///////////////////////////////////////////////
		//if the y-coords of two vertices equal the max y-coord... 
		
		/*
		this is the case:
		-------------
		\           /
		 \         /
		  \       /
		   \     /
 		    \   /
 		     \ /
 		      |
 		*/
		
		
		if (((yStartPt == v0y) && (yStartPt == v1y)) ||
		    ((yStartPt == v0y) && (yStartPt == v2y)) ||
		    ((yStartPt == v1y) && (yStartPt == v2y)))
		{
			float yStartPt2 = Maxs[1];	//here are more variables to keep
			float xStartPt2;			//track of the other top vertex
			
			if (v0y == yStartPt)		//assigning x-coords...
			{
				xStartPt = v0x;
				if (v1y == yStartPt)
				{
					xStartPt2 = v1x;
				}
				else
				{
					xStartPt2 = v2x;
				}
			}		
			else
			{
				xStartPt = v1x;
				xStartPt2 = v2x;
			}
			if (xStartPt > xStartPt2)	//make sure that xStartPt is to the
			{							//left of xStartPt2
				float temp;
				temp = xStartPt2;
				xStartPt2 = xStartPt;
				xStartPt = temp;
			}
			if (yEndPt == v0y)			//assign more x-coords
			{
				xEndPt = v0x;
			}
			else
			{
				if (yEndPt == v1y)
				{
					xEndPt = v1x;
				}
				else
				{
					xEndPt = v2x;
				}
			}
			//slope from bottom to left top
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from bottom to right top	 
			float n = (yStartPt2 - yEndPt)/(xStartPt2 - xEndPt);
			
			//the amounts we should subtract from our x-coords every time we increase
			//y by 1
			float dxm = 1/m;
			float dxn = 1/n;
			
			//go from top to bottom -- SuperCede refused to let me use ceil and floor
			//so I settled for my own close (but not perfect) approximations of them	
			for (int j = (int)(yStartPt + .5); j <= (int)(yEndPt - .5); j++)
			{
				//each time we increase y by 1, we change x accordingly
				xStartPt -= dxm;
				xStartPt2 -= dxn;

				//go from left to right incrementally
				//with each following row, xStartPt and xStartPt2 become closer
				for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
				{
					//draw a pixel 
					raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
				}
			}
		}
		/////////////////////////////////////////////////
		//if the y-coords of 2 vertices are equal to the min y-coord...
		/*
		of this form:
		
		        /\
			   /__\	
				
		*/
		 
		if (((yEndPt == v0y) && (yEndPt == v1y)) ||
		    ((yEndPt == v0y) && (yEndPt == v2y)) ||
		    ((yEndPt == v1y) && (yEndPt == v2y)))
		{	
			float xStartPt2;
			float xEndPt2;
			float yEndPt2 = yEndPt;
			
			if (v0y == yEndPt)
			{
				xEndPt = v0x;
				if (v1y == yEndPt)
				{
					xEndPt2 = v1x;
				}
				else
				{
					xEndPt2 = v2x;
				}
			}		
			else
			{
				xEndPt = v1x;
				xEndPt2 = v2x;
			}
							
			if (xEndPt > xEndPt2)
			{
				float temp;
				temp = xEndPt2;
				xEndPt2 = xEndPt;
				xEndPt = temp;
			}
			if (v0y > v1y)
			{
				yStartPt = v0y;
				xStartPt2 = xStartPt = v0x;
			}
			else
			{
				if (v1y > v2y)
				{
					yStartPt = v1y;
					xStartPt2 = xStartPt = v1x;
				}
				else
				{
					yStartPt = v2y;
					xStartPt2 = xStartPt = v2x;
				}
			}
			//slope from left bottom to top
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from right bottom to top
			float n = (yStartPt - yEndPt2)/(xStartPt - xEndPt2);
			
			float dxm = 1/m;
			float dxn = 1/n;
						
			for (int j = (int)(yStartPt + .5); j <= (int)(yEndPt - .5); j--)
			{
				xStartPt -= dxm;
				xStartPt2 -= dxn;
				
				//on the first iteration, xStartPt = xStartPt2, afterwards, 
				//they grow farther apart 
				for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
				{
					raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
				}
			}

		}
	//////////////////////////////////////////////////////////
		//if all y's are distinct...	
		if (!(v0y == v1y || v1y == v2y || v2y == v0y))
		{
			float yBreakPt = Mids[1];	//yBreakPt is the middle y-coord
			float xBreakPt;
			float xStartPt2;
			boolean toLeft;				//if the bp is to the left, this is true
			if (yStartPt == v0y)
			{
				xStartPt2 = xStartPt = v0x;
			}
			if (yStartPt == v1y)
			{
				xStartPt2 = xStartPt = v1x;
			}
			else
			{
				xStartPt2 = xStartPt = v2x;
			}		

			if (v0y == yBreakPt)
			{
				xBreakPt = v0x;
			}
			if (v1y == yBreakPt)
			{
				xBreakPt = v1x;
			}
			else
			{
				xBreakPt = v2x;
			}
			if (yEndPt == v0y)
			{
				xEndPt = v0x;
			}
			if (yEndPt == v1y)
			{
				xEndPt = v1x;
			}
			else
			{
				xEndPt = v2x;
			}
			//slope from the bottom to the top...			
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from the bottom to the breakpoint...
			float n = (yBreakPt - yEndPt)/(xBreakPt - xEndPt);
	
			//if the slope from bottom to top is less than the slope from the bottom
			//to breakpoint, then the breakpoint is a left one
			if (m < n)
			{
				toLeft = true;
			}
			else 
			{
				toLeft = false;
			}
			
			float dxm = 1/m;
			float dxn = 1/n;
			
			//the code that follows is a little tricky
			//depending on which side the breakpoint is on, we fill in pixels
			//from top to bottom, following the top two edges until we hit the 
			//breakpoint at which point we switch the appropriate edge out and 
			//put the new low one in
			if (toLeft)
			{
				//slope from breakpoint to top
				float o = (yStartPt - yBreakPt)/(xStartPt - xBreakPt);
				float dxo = 1/o;
			 
				for (int j = (int)(yStartPt + .5); j > (int)(yBreakPt - .5); j--)
				{
					xStartPt -= dxo;
					xStartPt2 -= dxm;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
					}
				}
				for (int j = (int)(yBreakPt + .5); j >= (int)(yEndPt - .5); j--)
				{
					xStartPt -= dxn;
					xStartPt2 -= dxm;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 -.5); i++)
					{
						raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
					}
				}
			}
			else
			{
				float o = (yStartPt - yBreakPt)/(xStartPt - xBreakPt);
				float dxo = 1/o;
			 
				for (int j = (int)(yStartPt + .5); j > (int)(yBreakPt - .5); j--)
				{
					xStartPt -= dxm;
					xStartPt2 -= dxo;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
					}
				}
				for (int j = (int)(yBreakPt + .5); j >= (int)(yEndPt - .5); j--)
				{
					xStartPt -= dxm;
					xStartPt2 -= dxn;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(makeColor(Aa, Ba, Ca, Ar, Br, Cr,
						                          Ag, Bg, Cg, Ab, Bb, Cb, i, j), i, j);
					}
				}
			}
		}
	}
	
	public int makeColor(float Aa1, float Ba1, float Ca1, 
						float Ar1, float Br1, float Cr1,
						float Ag1, float Bg1, float Cg1,
						float Ab1, float Bb1, float Cb1,
						int x, int y)
	{ 
		int alpha = (int)(Aa1*x + Ba1*y + Ca1);
		int red = (int)(Ar1*x + Br1*y + Cr1);
		int green = (int)(Ag1*x + Bg1*y + Cg1);
		int blue = (int)(Ab1*x + Bb1*y + Cb1);
		int myColor = ((alpha & 0xff000000) >> 24) | 
						((red & 0xff0000) >> 16) | 
						((green & 0xff00) >> 8) | 
						blue & 0xff;
		return myColor;
	}
}	
		

