import java.awt.Event;
import zBuffer;

public class Erde extends StereoImage
{
  int Size=200,Smoothness=5;
  float Waterheight=0.2f,Variance=0.2f;
  float Variscale;
  int xres=2,yres=1;
  RGB Colortable[];
  NodeItem Nodelist[],Destlist[];
  XYZ Triangle[];

public void init()
  {
    int i;
    String param=getParameter("Size");
    Size=(param==null)?Size:Integer.parseInt(param);
    param=getParameter("Smoothness");
    Smoothness=(param==null)?Smoothness:Integer.parseInt(param);
    param=getParameter("Waterheight");
    Waterheight=(param==null)?Waterheight:Float.valueOf(param).floatValue();
    param=getParameter("Variance");
    Variance=(param==null)?Variance:Float.valueOf(param).floatValue();
    Variscale=Variance;
    Resize(Size,Size);
    RotateX(1f);
    Nodelist=new NodeItem[2];
    Triangle=new XYZ[3];
    Colortable=new RGB[100];
    for (i=0;i<25;i++) {
      Colortable[i]=new RGB(0f,0f,(float)i/50f);
      Colortable[i+25]=new RGB(0f,(float)i/50f,(float)i/50f+0.5f);
      Colortable[i+50]=new RGB((float)i/25f,1f-(float)i/25f,0f);
      Colortable[i+75]=new RGB(1f,(float)i/25f,(float)i/25f);
    };
    Nodelist[0]=new NodeItem(0f,0f,Waterheight,Waterheight);
    Nodelist[1]=new NodeItem(0.5f,0f,Waterheight,Waterheight);
    for (i=0;i<Smoothness;i++) MakeItSmoother();
    DrawScene();
    repaint();
  }

public void MakeItSmoother()
  {
    int x0,y0,x1,y1;
    float p1,p2,p1p,p2p,h;
    Destlist=new NodeItem[xres*yres*4];
    for (x0=0;x0<xres;x0++) {
      x1=(x0+1)%xres;
      for (y0=0;y0<yres;y0++) {
        y1=(y0+1)%yres;
        Destlist[(y0*2)*(xres*2)+(x0*2)]=Nodelist[y0*xres+x0];
        p1p=(float)(x0*2+1)/(float)(xres*2);
        p2=(float)y0/(float)yres;
        h=(Nodelist[y0*xres+x0].h+Nodelist[y0*xres+x1].h)/2+Random();
        Destlist[(y0*2)*(xres*2)+(x0*2+1)]=new NodeItem(p1p,p2,h,Waterheight);
        p1=(float)x0/(float)xres;
        p2p=(float)(y0*2+1)/(float)(yres*2);
        h=(Nodelist[y0*xres+x0].h+Nodelist[y1*xres+x0].h)/2+Random();
        Destlist[(y0*2+1)*(xres*2)+(x0*2)]=new NodeItem(p1,p2p,h,Waterheight);
        h=(Nodelist[y0*xres+x1].h+Nodelist[y1*xres+x0].h)/2+Random();
        Destlist[(y0*2+1)*(xres*2)+(x0*2+1)]=new NodeItem(p1p,p2p,h,Waterheight);
      };
    };
    Nodelist=Destlist;
    xres*=2;
    yres*=2;
    Variance*=0.7f;
  }

public float Random()
  {
    float r;
    r=(float)(Math.random()-0.5)*Variance;
    return(r);
  }

public int GetColorIndex(float h)
  {
    float hrel,idx;
    hrel=(h-Waterheight)/Variscale;
    idx=hrel*70f+50f;
    idx=(idx>99)?99:idx;
    idx=(idx<0)?0:idx;
    return((int)idx);
  }

public void DrawScene()
  {
    int x0,y0,x1,y1,i;
    float h;
    RGB Mycolor;
    Clear();
    for (x0=0;x0<xres;x0++) {
      x1=(x0+1)%xres;
      for (y0=0;y0<yres;y0++) {
        y1=(y0+1)%yres;
        h=(Nodelist[y0*xres+x0].h+Nodelist[y0*xres+x1].h+Nodelist[y1*xres+x0].h)/3;
        i=GetColorIndex(h);
        Mycolor=Colortable[i];
        Triangle[0]=Nodelist[y0*xres+x0].pt;
        Triangle[1]=Nodelist[y0*xres+x1].pt;
        Triangle[2]=Nodelist[y1*xres+x0].pt;
        Polygon(Triangle,3,Mycolor);
        Triangle[0]=Nodelist[y1*xres+x1].pt;
        h=(Nodelist[y1*xres+x1].h+Nodelist[y0*xres+x1].h+Nodelist[y1*xres+x0].h)/3;
        i=GetColorIndex(h);
        Mycolor=Colortable[i];
        Polygon(Triangle,3,Mycolor);
      };
    };
    SetBackground(Colortable[10]);
  }

public boolean handleEvent(Event e)
  {
    if ((e.id==Event.MOUSE_DOWN)&&(yres<Size)) {
      MakeItSmoother();
      DrawScene();
      repaint();
    };
    return true;
  }
}

class NodeItem
{
  float p1,p2,h;
  XYZ pt;

  public NodeItem(float p1,float p2,float h,float wh)
  {
    double a1,a2,x,y,z,ha;
    this.p1=p1;
    this.p2=p2;
    this.h=h;
    a1=2*Math.PI*p1;
    a2=2*Math.PI*p2;
    ha=((h>wh)?h:wh)*Math.sin(a2);
    x=(0.5+ha)*Math.sin(a1);
    y=(0.5+ha)*Math.cos(a1);
    z=((h>wh)?h:wh)*Math.cos(a2);
    this.pt=new XYZ((float)x,(float)y,(float)z);
  }
}
