package march;

/*
  三矩形の集合で表した物体
*/

import java.awt.*;
import java.lang.*;
import java.util.*;
import java.awt.image.*;

public class TriangleStrip{
 Vector vertex_list;  // List of Vertex
 Vector edge_list;    // List of Edge
 Vector surface_list; // List of Triangle
    
 public TriangleStrip(){
   vertex_list  = new Vector();
   edge_list    = new Vector();
   surface_list = new Vector();
 }

 public TriangleStrip(Vector vertex_list,
		      Vector edge_list,
		      Vector surface_list){
   this.vertex_list  = vertex_list;
   this.edge_list    = edge_list;
   this.surface_list = surface_list;
 }

 public TriangleStrip(Vector vertex_list,
                      Vector surface_list){
     this.vertex_list  = vertex_list;
     this.surface_list = surface_list;
     
     this.edge_list = new Vector();
     for(int i = 0; i < surface_list.size(); i++){
         Triangle t = (Triangle)surface_list.elementAt(i);
         edge_list.add(t.e1);
         edge_list.add(t.e2);
         edge_list.add(t.e3);
     }
 }
 
 public void translate(float tx, float ty, float tz){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.translate(tx, ty ,tz);
   }
 }

 public Rotation getRot(){
   Vertex v = (Vertex)vertex_list.elementAt(0);
   return new Rotation(v.rot_x, v.rot_y, v.rot_z);
 }

 public void returnToInit(){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.returnToInit();
   }
 }

 public void xAxisRotate(float r){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.xAxisRotate(r);
   }
 }

 public void yAxisRotate(float r){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.yAxisRotate(r);
   }
 }

 public void zAxisRotate(float r){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.zAxisRotate(r);
   }
 }
  
 /* 視点を (0,0,prp) prp > vp において xy平面に平行な平面(z = vp)
     に透視投影したときの座標を計算してセットする  
     何かをする前にはこれをしなくてはならない                 */
 public void calcPerspectiveProjection(float vp, float prp){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.calcPerspectiveProjection(vp,prp);
   }
 }

 public void calcPerspectiveProjection(Vec fp, float R,
                                       float sin_the, float cos_the,
                                       float sin_phi, float cos_phi){
     Vertex v;
     for(int i = 0; i < vertex_list.size(); i++){
         v = (Vertex)vertex_list.elementAt(i);
         v.calcPerspectiveProjection(fp, R, sin_the, cos_the, 
                                     sin_phi, cos_phi);
     }
 }

 public void calcPerspectiveProjection(Vec fp, float R,
                                       float the, float phi){
     float st = (float)Math.sin(the);
     float ct = (float)Math.cos(the);
     float sp = (float)Math.sin(phi);
     float cp = (float)Math.cos(phi);
     calcPerspectiveProjection(fp, R, st,ct,sp,cp);
 }

 public void calcParallelProjection(float vp){
   Vertex v;
   for(int i = 0; i < vertex_list.size(); i++){
     v = (Vertex)vertex_list.elementAt(i);
     v.calcParallelProjection(vp);
   }
 }

 public void drawWireFrame(Graphics g, 
                           Vec fp, float R, float the, float phi){
   int edge_num = edge_list.size();
   Edge e;
   int  x1,y1,x2,y2;

   calcPerspectiveProjection(fp, R, the, phi);

   for(int i = 0; i < edge_num; i++){
     e = (Edge)edge_list.elementAt(i);
     if( e.v1.visible && e.v2.visible ){
       x1 = (int)e.v1.px;
       y1 = (int)e.v1.py;
       x2 = (int)e.v2.px;
       y2 = (int)e.v2.py;
       g.drawLine(x1,-y1,x2,-y2);
     }
   }
 }

 public void setAllColor(Color c){
   int surface_num = surface_list.size();
   Triangle t;
   for(int i = 0; i < surface_num; i++){
     t = (Triangle)surface_list.elementAt(i);
     t.setBaseColor(c.getRGB());
   }
 }

 /* 光線は全ての面に同じ角度で当たっているとする */
 /* minz: どれほど遠くまで見るか */
 public MemoryImageSource drawZBuffer(Graphics g, float minz, int back_color, 
				      int wind_minx,  int wind_miny,
				      int wind_maxx,  int wind_maxy,
				      int Ia, int Il, Vec L,
				      Vec fp, float R, float the, float phi){
   calcPerspectiveProjection(fp, R, the, phi);
   System.out.println(wind_minx +","+ wind_miny +"," + wind_maxx +"," + wind_maxy);
   int wind_width  = wind_maxx - wind_minx + 1;
   int wind_height = wind_maxy - wind_miny + 1;

  
   float[][] depth_buffer = new float[wind_width][wind_height];
   int[]    color_buffer = new int[wind_width * wind_height];

   for(int i = 0; i < wind_width; i++){
     for(int j = 0; j < wind_height; j++){
       depth_buffer[i][j] = minz;
       color_buffer[i + j*wind_width] = back_color;
     }
   }

   int surface_num = surface_list.size();

   Triangle              t;
   ZBufferScanInfo      si;

   int      surface_miny;
   int      surface_height;
   float[] startz_array;
   int[]    startx_array;
   int[]    endx_array;
   float   AdC;        // A/C
   float   depth;
   int      startx;
   int      endx;
   int      xwid;

   for(int i = 0; i < surface_num; i++){
     t = (Triangle)surface_list.elementAt(i);
     
     if( t.in(wind_minx, wind_miny, wind_maxx, wind_maxy) ){
       t.calcABCD();
       t.calcColor(Ia, Il, L);
       t.calcPABCD();
       si = t.makeZBufferScanInfo();
       surface_miny    = si.miny;
       surface_height  = si.height;
       if( surface_height != 0 ){
	 startz_array    = si.startz_array;
	 startx_array    = si.startx_array;
	 endx_array      = si.endx_array;
	 AdC             = t.pA / t.pC;
	 
	 int by = surface_miny - wind_miny;
	
	 for(int k = 0; k < surface_height; k++){
	   depth    = startz_array[k];
	   startx   = startx_array[k];
	   endx     = endx_array[k];
	   xwid     = endx - startx + 1;
	  
	   int bx = startx - wind_minx;
	   for(int l = 0; l < xwid; l++){
	     if(bx >= 0 && bx < wind_width 
		&& by >= 0 && by < wind_height
		&& depth > depth_buffer[bx][by]){
	       depth_buffer[bx][by] = depth;
	       color_buffer[bx+(wind_height - by - 1)*wind_width] = t.color;
	     }
	     depth -= AdC;
	     bx++;
	   }
	   by++;
	 }
       }
     }
   }
  
 
   int px = wind_minx;
   int py = wind_miny;
   MemoryImageSource mis = new MemoryImageSource(wind_width,wind_height,
						 color_buffer,0,wind_width);
   return mis;
 }
   


}

