import vrml.*;
import vrml.field.*;
import vrml.node.*;
import java.lang.*;

public class Fractal extends Script{

  // Declare attributes
     private int i = 0;
     private int j = 0;
     private int cpt = 0;
     private int XMax = 80;
     private int YMax = 64;

  // Declare fields

  // Declare eventOut
  private MFColor colorpoint;
  private MFFloat tabpoint;

  // Set up fields and eventOut
  public void initialize() {
    colorpoint = (MFColor) getEventOut("colorpoint");
    tabpoint = (MFFloat) getEventOut("tabpoint");
    for(i=0,cpt=0;i<YMax;i++) {
	   for(j=0;j<XMax;j++,cpt++) {
	      colorpoint.addValue((float)0.6, (float)0.5, (float)0.1);
	      tabpoint.addValue((float)0.0);
	   }
	}
    System.out.println("Fractal: initialize() ");
  }

  public SFColor GetColor(float Hauteur)
  {
    if (Hauteur > 13.0)
    {
      return new SFColor((float)1.0, (float)1.0, (float)1.0);
    }
    if(Hauteur > 11.0)
    {
      return new SFColor((float)0.5, (float)0.5, (float)0.5);
    }

    if(Hauteur > 5.0)
    {
      return new SFColor((float)0.3, (float)0.8,(float) 0.0);
    }

    if(Hauteur > 1.0)
    {
      return new SFColor((float)0.0, (float)0.5, (float)0.0);
    }

    if(Hauteur > 0.0)
    {
      return new SFColor((float)0.9, (float)0.8, (float)0.5);
    }

    if(Hauteur > -3.0)
    {
      return new SFColor((float)0.3, (float)0.3, (float)1.0);
    }

    return new SFColor((float)0.0, (float)0.0, (float)0.9);
  }
  
  public void MNTRecursif(int x, int y, int Larg, int Haut, float Tab[], float Coin[])
  {
    int MidleX = 0;
    int MidleY = 0;
    int cptH = 0;
    int cptB = 0;
    int cptG = 0;
    int cptD = 0;
    int cptM = 0;
    float tmp0 = 0;
    float tmp1 = 0;
    float tmp2 = 0;
    float tmp3 = 0;
    int DistX1 = 0;
    int DistX2 = 0;
    int DistY1 = 0;
    int DistY2 = 0;
    float DistX_norm = 0;
    float DistY_norm = 0;

    if((Larg > 2) || (Haut > 2))
    {

      MidleX = x + Larg/2;
      MidleY = y + Haut/2;

      DistX1 = MidleX-x+1; DistX2 = Larg+x-MidleX;
      DistY1 = MidleY-y+1; DistY2 = Haut+y-MidleY;

      tmp0 = Coin[0]; tmp1 = Coin[1]; tmp2 = Coin[2]; tmp3 = Coin[3];
      DistX_norm = Larg/XMax;
      DistY_norm = Haut/YMax;

      // Haut
      cptH = y*XMax + MidleX;
      Tab[cptH] = (float)((tmp0+tmp1)/2.0*(1-DistX_norm) + 
                            (Math.random()-0.4)*30.0*(DistX_norm));

      // Bas 
      cptB = (y+Haut-1)*XMax + MidleX;
      Tab[cptB] = (float)((tmp2+tmp3)/2.0*(1-DistX_norm) + 
                            (Math.random()-0.4)*30.0*(DistX_norm));
      // Gauche
      cptG = MidleY*XMax + x;
      Tab[cptG] = (float)((tmp0+tmp2)/2.0*(1-DistY_norm) + 
                            (Math.random()-0.4)*30.0*(DistY_norm));
      // Droite
      cptD = MidleY*XMax + x + (Larg-1);
      Tab[cptD] = (float)((tmp1+tmp3)/2.0*(1-DistY_norm) + 
                            (Math.random()-0.4)*30.0*(DistY_norm));
      // Milieu
      cptM = MidleY*XMax + MidleX;
      Tab[cptM] = (float)((DistX1*Tab[cptH]+DistX2*Tab[cptB] +
                           DistY1*Tab[cptG]+DistY2*Tab[cptB])/(Larg+Haut+2) + 
                            (Math.random()-0.4)*(Larg/2));

      // Appel recursif

      Coin[0]=tmp0; Coin[1]=Tab[cptH]; Coin[2]=Tab[cptG]; Coin[3]=Tab[cptM];
      MNTRecursif(x, y, DistX1, DistY1, Tab, Coin);

      Coin[0]=Tab[cptH]; Coin[1]=tmp1; Coin[2]=Tab[cptM]; Coin[3]=Tab[cptD];
      MNTRecursif(MidleX, y, DistX2, DistY1, Tab, Coin);

      Coin[0]=Tab[cptG]; Coin[1]=Tab[cptM]; Coin[2]=tmp2; Coin[3]=Tab[cptB];
      MNTRecursif(x, MidleY, DistX1, DistY2, Tab, Coin);

      Coin[0]=Tab[cptM]; Coin[1]=Tab[cptD]; Coin[2]=Tab[cptB]; Coin[3]=tmp3;
      MNTRecursif(MidleX, MidleY, DistX2, DistY2, Tab, Coin);
    }
  }

  // Handle events
  public void processEvent(Event event) {

    float TabHaut[] = new float[XMax*YMax];
    float TabLiss[] = new float[XMax*YMax];
    float Coin[] = new float[4];

    int Lig = 0;

    if (event.getName().equals("start")) {
      if ((((ConstSFBool)event.getValue()).getValue()) == true) {

        System.out.println("Generation en cours.");

        Coin[0] = TabHaut[0] = (float)((Math.random()-0.2) * 20.0);
        Coin[1] = TabHaut[XMax-1] = (float)((Math.random()-0.2) * 20.0);
        Coin[2] = TabHaut[XMax*(YMax-1)] = (float)((Math.random()-0.2) * 20.0);
        Coin[3] = TabHaut[XMax*YMax -1] = (float)((Math.random()-0.2) * 20.0);

        MNTRecursif(0, 0, XMax, YMax, TabHaut, Coin);

        // Lissage

        for(i=1, cpt=1; i<YMax-1; i++, cpt+=2)
        {
          for(j=1; j<XMax-1; j++, cpt++)
          {
            Lig = i *XMax;
            TabLiss[Lig+j] = (float)( 0.1*TabHaut[Lig-XMax-1+j] +
                                      0.1*TabHaut[Lig-XMax+j] +
                                      0.1*TabHaut[Lig-XMax+1+j] +
                                      0.1*TabHaut[Lig-1+j] +
                                      0.2*TabHaut[Lig+j] +
                                      0.1*TabHaut[Lig+1+j] +
                                      0.1*TabHaut[Lig+XMax-1+j] +
                                      0.1*TabHaut[Lig+XMax+j] +
                                      0.1*TabHaut[Lig+XMax+1+j]);
            //if(TabLiss[Lig+j]<0) TabLiss[Lig+j] = 0;
            colorpoint.set1Value(cpt, GetColor(TabLiss[Lig+j]));
          }
        }
        tabpoint.setValue(XMax*YMax, TabLiss);

        System.out.println("Generation terminee.");
   
      }
    }
  }

}




