package march;

/*
   三角形
*/

import java.lang.*;
import java.awt.*;

public class Triangle{
  public Edge   e1,e2,e3;
  public Vertex v1,v2,v3;
  
  /* 平面の方程式のパラメタ */
  /* Ax + By + Cz + D = 0   */
  public float A, B, C, D;
  public float pA,pB,pC,pD;

  /* Diffuse-reflection coefficient      */
  /* [0,1] 実際の値は              */
  /* (255,255,255)の光が垂直に当たった時
     (255*kd_r,255*kd_g,255*kd_b)色に見える          */

  public float kd_r; // 赤に対する係数
  public float kd_g;
  public float kd_b;

  public int color;

  public Triangle(Edge e1,Edge e2, Edge e3,
		  Vertex v1,Vertex v2, Vertex v3){
    this.e1 = e1;
    this.e2 = e2;
    this.e3 = e3;
    this.v1 = v1;
    this.v2 = v2;
    this.v3 = v3;
  }

  public Triangle(Vertex v1, Vertex v2, Vertex v3){
      //System.err.println("make trinangle");
      this.v1 = v1;
      this.v2 = v2;
      this.v3 = v3;
      this.e1 = new Edge(v1,v2);
      this.e2 = new Edge(v2,v3);
      this.e3 = new Edge(v3,v1);
  }

  
  public void calcABCD(){
    float x1,x2,x3,y1,y2,y3,z1,z2,z3;
    x1 = v1.x; x2 = v2.x; x3 = v3.x;
    y1 = v1.y; y2 = v2.y; y3 = v3.y;
    z1 = v1.z; z2 = v2.z; z3 = v3.z;
    A = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2);
    B = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2);
    C = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2);
    D =  (- x1) * (y2*z3 - y3*z2) 
       + (- x2) * (y3*z1 - y1*z3) 
       + (- x3) * (y1*z2 - y2*z1);
  }

  public void calcPABCD(){
    float x1,x2,x3,y1,y2,y3,z1,z2,z3;
    x1 = v1.px; x2 = v2.px; x3 = v3.px;
    y1 = v1.py; y2 = v2.py; y3 = v3.py;
    z1 = v1.pz; z2 = v2.pz; z3 = v3.pz;
    pA = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2);
    pB = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2);
    pC = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2);
    pD =  (- x1) * (y2*z3 - y3*z2) 
       + (- x2) * (y3*z1 - y1*z3) 
       + (- x3) * (y1*z2 - y2*z1);
  }

  public void setBaseColor(int color){
    kd_r = ((float)((color & 0x00ff0000) >> 16))/255.0f;
    kd_g = ((float)((color & 0x0000ff00) >> 8))/255.0f;
    kd_b = ((float)(color & 0x000000ff))/255.0f;
  }



  /* 理想的な散乱面として計算 */
  /* 環境光    Ia = xxRRGGBB  */
  /* ライト光  Il = xxRRGGBB 
               方向 L = (x,y,z) && |L| = 1     */

  public void calcColor(int Ia, int Il, Vec L){
    float N_length = (float)Math.sqrt(A*A + B*B + C*C);
    float NL = (A*(-L.x) + B*(-L.y) + C*(-L.z))/N_length;
    if( NL < 0.0f ){
      NL = 0.0f;
    }
    int r = (int)( kd_r * ( (float)((Ia & 0x00ff0000)>>16) 
                          + (float)((Il & 0x00ff0000)>>16)*NL ));
    int g = (int)( kd_g * ( (float)((Ia & 0x0000ff00)>>8) 
                          + (float)((Il & 0x0000ff00)>>8)*NL )); 
    int b = (int)( kd_b * ( (float)(Ia & 0x000000ff) 
                          + (float)(Il & 0x000000ff)*NL ));
    
    if( r > 255 ){ r = 255;}
    if( g > 255 ){ g = 255;}
    if( b > 255 ){ b = 255;}
    color = 0xff000000 | (r << 16) | (g << 8) | b;
  }
  

  public boolean in(int wind_minx, int wind_miny, 
		    int wind_maxx, int wind_maxy){
    return (e1.v1.visible && e1.v2.visible &&
	    e2.v1.visible && e2.v2.visible &&
	    e3.v1.visible && e3.v2.visible &&
	    (   v1.in(wind_minx, wind_miny, wind_maxx, wind_maxy)
	     || v2.in(wind_minx, wind_miny, wind_maxx, wind_maxy)
	     || v3.in(wind_minx, wind_miny, wind_maxx, wind_maxy)
	     ));
  }

  public int getMinPy(){
    int miny = (int)v1.py;
    if( (int)v2.py < miny ){ miny = (int)v2.py; }
    if( (int)v3.py < miny ){ miny = (int)v3.py; }
    return miny;
  }

  public int getMaxPy(){
    int maxy = (int)v1.py;
    if( (int)v2.py > maxy ){ maxy = (int)v2.py; }
    if( (int)v3.py > maxy ){ maxy = (int)v3.py; }
    return maxy;
  }

  public int getMinPx(){
    int minx = (int)v1.px;
    if( (int)v2.px < minx ){ minx = (int)v2.px; }
    if( (int)v3.px < minx ){ minx = (int)v3.px; }
    return minx;
  }

  public int getMaxPx(){
    int maxx = (int)v1.px;
    if( (int)v2.px > maxx ){ maxx = (int)v2.px; }
    if( (int)v3.px > maxx ){ maxx = (int)v3.px; }
    return maxx;
  }
  
  public String toString(){
    String s = "v1 = " + v1.toString() + "\n";
    s += ("v2 = " + v2.toString() + "\n");
    s += ("v3 = " + v3.toString() + "\n");
    s += ("e1 = " + e1.toString() + "\n");
    s += ("e2 = " + e2.toString() + "\n");
    s += ("e3 = " + e2.toString() + "\n");
    return s;
  }

  public ZBufferScanInfo makeZBufferScanInfo(float vp, float prp){
    //System.out.println(this.toString());
    ZBufferScanInfo si;
    float[]    startz_array = null;
    int[]       startx_array = null;
    int[]       endx_array   = null;
    boolean[]   already      = null;
    int miny;
    int maxy;
    int height;
    
    
    miny = getMinPy();
    maxy = getMaxPy();
    height = maxy - miny + 1;
    
    startz_array = new float[height];
    startx_array = new int[height];
    endx_array   = new int[height];
    already      = new boolean[height];
    
    Edge[] edges = new Edge[3];
    Edge e;
    float m;
    Vertex upper;
    Vertex lower;
    int x,y;
    float depth;
    float dd;
    float dx;
    float float_x;

    if( ((int)v1.py == (int)v2.py) && ((int)v2.py == (int)v3.py) ){
      int minx = getMinPx();
      int maxx = getMaxPx();
      x = minx;
      y = (int)v1.py;
      depth = v1.pz;
      startx_array[0] = minx;
      endx_array[0]   = maxx;
      startz_array[0] = depth;
      return (new ZBufferScanInfo(miny,height,
				  startz_array,startx_array,endx_array)); 
    }

    
    for(int i = 0; i < height; i++){
      already[i] = false;
    }

    edges[0] = e1; edges[1] = e2;  edges[2] = e3; 
    for(int i = 0 ; i < 3; i++){
     
      e = edges[i];
      if( (int)e.v1.py == (int)e.v2.py ){ continue; }
      upper = e.getUpper();
      lower = e.getLower();

      float_x = upper.px;

      x = (int)upper.px;
      y = (int)upper.py;
     
      if( e.v1.px  == e.v2.px){
	dd = pB/pC ;
	dx = 0.0f;
      }
      else{
	m = e.getSlope();
	dd = (pA/m + pB)/pC ;
	dx = - 1.0f/m;
      }

      int km;
      depth = upper.pz;
      for(int k = (int)upper.py; k >= (int)lower.py ; k--){
	
	x = (int)float_x;
	km = k - miny;
	if(already[km]){
	  if( x < startx_array[km] ){
	    startx_array[km] = x;
	    startz_array[km] = depth;
	  }
	  else if(x > endx_array[km]){
	    endx_array[km] = x;
	  }
	}
	else{
	  startx_array[km]  = x;
	  endx_array[km]    = x;
	  startz_array[km] = depth;
	  already[km] = true;
	}

	float_x += dx;
	if( dx > 0 && (int)float_x > (int)lower.px ){
	  float_x = lower.px;
	}
	if( dx < 0 && (int)float_x < (int)lower.px ){
	  float_x = lower.px;
	}
	depth    += dd;
     
      }
    }

    si = new ZBufferScanInfo(miny,height,startz_array,
			     startx_array,
			     endx_array);
    return si;
  }
    
}




