import java.awt.Color;

public class FilledTriDrawer extends TriangleDrawer {

  public FilledTriDrawer(Vertex2D v0, Vertex2D v1, Vertex2D v2) {
    super(v0, v1, v2);
  }
  
  public void draw(Raster r) {
    Vertex2D topV, midV, botV;

    if (v0.y > v1.y &&
	v0.y > v2.y) {
      botV = v0;
      if (v1.y > v2.y) {
	midV = v1;
	topV = v2;
      } else {
	midV = v2;
	topV = v1;
      }
    } else if (v1.y > v2.y) {
      botV = v1;
      if (v0.y > v2.y) {
	midV = v0;
	topV = v2;
      } else {
	midV = v2;
	topV = v0;
      }
    } else {
      botV = v2;
      if (v0.y > v1.y) {
	midV = v0;
	topV = v1;
      } else {
	midV = v1;
	topV = v0;
      }
    }
      
    double xMin, xMax;
    int rgb = interpolate(topV.argb, midV.argb, botV.argb);

    double invSlopeLeft, invSlopeRight;
    boolean midPointOnLeft;
    
    // find inverse slope for incremental edge walking
    if (getPoint(topV, botV, midV.y) > midV.x) {
      invSlopeLeft = getInverseSlope(topV, midV);
      invSlopeRight = getInverseSlope(topV, botV);
      midPointOnLeft = true;
    } else {
      invSlopeLeft = getInverseSlope(topV, botV);
      invSlopeRight = getInverseSlope(topV, midV);
      midPointOnLeft = false;
    }

    // draw top half
    xMin = xMax = topV.x;        
    
    for (double y = Math.ceil(topV.y); y < Math.ceil(midV.y); y++ ) {
      for (double x = Math.ceil(xMin); x <= Math.ceil(xMax); x++ ) {
	r.setPixel( rgb, (int) x, (int) y);	
      }      
      xMin += invSlopeLeft;
      xMax += invSlopeRight;
    }

    // draw bottom half
    if (midPointOnLeft) {
      xMin = midV.x;
      // xMax = getPoint(topV, botV, midV.y);
      invSlopeLeft = getInverseSlope(midV, botV);
    } else {
      // xMin = getPoint(topV, botV, midV.y);
      xMax = midV.x;
      invSlopeRight = getInverseSlope(midV, botV);
    }    
    for (double y = Math.ceil(midV.y); y < Math.ceil(botV.y); y++ ) {
      for (double x =  Math.ceil(xMin); x <= Math.ceil(xMax); x++ ) {
	r.setPixel( rgb, (int) x,  (int) y);
      }
      xMin += invSlopeLeft;
      xMax += invSlopeRight;
    }
    
  }
    
  private double getPoint(Vertex2D p0, Vertex2D p1, double y) {
    double x;
    if (p1.x == p0.x) {
      x = p0.x;
    } else if (p1.y == p0.y) {
      x = p1.x;
    } else {
      double m = (p1.y - p0.y) / (p1.x - p0.x);
      double b = p1.y - m*p1.x;
      x =  ((y - b) / m);
    }
    return x;
  }

  private int interpolate( int c1, int c2, int c3) {
    int alpha = (int)(( ((c1 >> 24)&255) +
			((c2 >> 24)&255) +
			((c3 >> 24)&255) ) /3f) << 24;
    int red = (int)(( ((c1 >> 16)&255) +
		      ((c2 >> 16)&255) +
		      ((c3 >> 16)&255) ) /3f) << 16;
    int green = (int)(( ((c1 >> 8)&255) +
			((c2 >> 8)&255) +
			((c3 >> 8)&255) ) /3f) << 8;
    int blue = (int)(( (c1 & 255) +
		       (c2 & 255) +
		       (c3 & 255) )/3f);
    int rgb = alpha + red + green + blue;
    
    
    // System.out.println(Integer.toHexString(rgb));

    return rgb;
  }    

  
  private double getInverseSlope(Vertex2D p0, Vertex2D p1) {
    return (p1.x - p0.x)/(p1.y - p0.y);
  }


}
