/*
 * IJKPlasma
 *
 * by Isaac Kuo
 *
 */



public class IJKPlasma {

 public final static long GOLD=2654435761L;

 private static long hashBAD(int a, int b, int c) {

  // Hash algorithms based on Robert Jenkins's
  // and Thomas Wang's hash functions found at
  // http://www.concentric.net/~Ttwang/tech/inthash.htm
  // Google is my friend!

  // Apply Knuth's golden ration hash to a,b
  a=(int)(a*GOLD);
  b=(int)(b*GOLD);

/*
  // Apply Thomas Wang's 32 bit mix on a
  a += ~(a << 15);
  a ^=  (a >>> 10);
  a +=  (a << 3);
  a ^=  (a >>> 6);
  a += ~(a << 11);
  a ^=  (a >>> 16);

  // Apply Robert Jenkin's 32 bit mix on b
  b += (b << 12);
  b ^= (b >> 22);
  b += (b << 4);
  b ^= (b >> 9);
  b += (b << 10);
  b ^= (b >> 2);
  b += (b << 7);
  b ^= (b >> 12);
 

  // Apply Thomas Wang's 64 bit mix on a,b
  long ab=((long)a)<<32+b;
  ab += ~(ab << 32);
  ab ^= (ab >>> 22);
  ab += ~(ab << 13);
  ab ^= (ab >>> 8);
  ab += (ab << 3);
  ab ^= (ab >>> 15);
  ab += ~(ab << 27);
  ab ^= (ab >>> 31);
  a=(int)(ab>>32);
  b=(int)ab;
 */

  // Apply Robert Jenkin's 96 bit mix
  a=a-b;  a=a-c;  a=a^(c>>13);
  b=b-c;  b=b-a;  b=b^(a<<8);
  c=c-a;  c=c-b;  c=c^(b>>13);
  a=a-b;  a=a-c;  a=a^(c>>12);
  b=b-c;  b=b-a;  b=b^(a<<16);
  c=c-a;  c=c-b;  c=c^(b>>5);
  a=a-b;  a=a-c;  a=a^(c>>3);
  b=b-c;  b=b-a;  b=b^(a<<10);
  c=c-a;  c=c-b;  c=c^(b>>15);


  return c^a^b;

/*
  int val=817253432;
  val=(int)(((val^c)*1751923737L)>>11);
  val=(int)(((val^b)*2892348231L)>>9);
  val=(int)(((val^a)*3982157643L)>>7);
  val=(int)(((val^b)*1925384479L)>>5);
  val=(int)(((val^c)*2876524395L)>>3);
  val=(int)(((val^a)*3864712107L)>>2);
  return val;
 */
 }

 private static long hash(int a, int b, int c) {
  return (int)Math.round(Math.random()*95213443212345621L);
 }

 public static void noisePos(int[][] z,int stepMax,int bumpMax,int seed) {
  //It is assumed that z has dimensions that are a power of 2,
  //and stepMax is a power of 2
  //the z values at coordinates which are multiples of stepMax
  //are the only values which will be modified--random noise is
  //entered in them with only positive values.
  noise(z,stepMax,bumpMax,seed);

  int xMax=z.length; int xMask=xMax-1;
  int yMax=z[0].length; int yMask=yMax-1;
  for(int x=0; x<xMax; x+=stepMax)
   for(int y=0; y<yMax; y+=stepMax)
    if(z[x][y]<0)z[x][y]=-z[x][y];
 } //end of noise

 public static void noise(int[][] z,int stepMax,int bumpMax,int seed) {
  //It is assumed that z has dimensions that are a power of 2,
  //and stepMax is a power of 2
  //the z values at coordinates which are multiples of stepMax
  //are the only values which will be modified--random noise is
  //entered in them.
  int xMax=z.length; int xMask=xMax-1;
  int yMax=z[0].length; int yMask=yMax-1;
  for(int x=0; x<xMax; x+=stepMax)
   for(int y=0; y<yMax; y+=stepMax)
    z[x][y]=(int)(( bumpMax*hash(x,y,seed) )>>31);
 }

 public static void plasma(int[][] z,int stepMax,int bumpMax,int seed) {
  //It is assumed that z has dimensions that are a power of 2,
  //and stepMax is a power of 2
  //the z heights at coordinates which are multiples of stepMax
  //are assumed to already be defined and will not be modified.
  int xMax=z.length; int xMask=xMax-1;
  int yMax=z[0].length; int yMask=yMax-1;

  int bump=bumpMax;

  // loop on stepsize d, from big to small
  for(int d=stepMax>>1;d>0;d=d>>1) {

   // first interpolate and bump the "centers"
   for(int x=0;x<xMax;x+=(d<<1))
    for(int y=0;y<yMax;y+=(d<<1))
     z[x+d][y+d]=(z[x][y]+z[(x+d+d)&xMask][y]
         +z[x][(y+d+d)&yMask]+z[(x+d+d)&xMask][(y+d+d)&yMask]
         +(int)(( bump*hash(x,y,seed) )>>29))>>2;
   bump=(bump*181)>>8;

   // next interpolate and bump the "edges"
   for(int x=0;x<xMax;x+=(d<<1))
    for(int y=0;y<yMax;y+=(d<<1)) {
     z[x+d][y]=(z[x][y]+z[(x+d)&xMask][(y+d)&yMask]
         +z[(x+d+d)&xMask][y]+z[(x+d)&xMask][(y-d)&yMask]
         +(int)(( bump*hash(x,y,seed) )>>29))>>2;
     z[x][y+d]=(z[x][y]+z[(x+d)&xMask][(y+d)&yMask]
         +z[x][(y+d+d)&yMask]+z[(x-d)&xMask][(y+d)&yMask]
         +(int)(( bump*hash(x,y,seed) )>>29))>>2;
    }
   bump=(bump*181)>>8;
  }
 } //end of plasma

} // end of class IJKPlasma
