// PerlinNoise.C  - Perlin Noise functions -  public source
//
//
//  Use hash-table lockup method of Perlin, combined with recursive method of
//  Ward, but written down as an iteration
//
//
// 27/11/00 Pieter.Peers@cs.kuleuven.ac.be
//

#include "PerlinNoise.H"
#include <math.h>

#include <stdio.h>

namespace xrml {

#define lerp(t, a, b)   (a + t * (b - a))


// noise expects coord to be for each component between 0 and 1
float PerlinNoise::noise(float *coord)
{
  int i, m, j, k, i1, i2;
  float value;
  int bits = 1<<dimension;
  
  // set up int Boundaries and Real-part of the pixel 
  i1 = 0;  // 2*i
  for(i = 0; i < dimension; i++)
    {
      value = coord[i] * ctrlPoints;
      b[i1 + 0] = (int)(value);
      b[i1 + 1] = b[i1] + 1;
      r[i1 + 0] = value - b[i1];
      r[i1 + 1] = r[i1] - 1;
      s[i] = r[i1] * r[i1] * (3. - 2. * r[i1]); // t^2 * (3 - 2t)

      i1 += 2;
    }

  // calcuate indices of each point in G-table (resolve hash)
  // recursive hashing using b values
  m = 1;
  i1 = 0;  // 2*i
  index[MaxDim*0 + 0] = 0;

  for(i = 0; i < dimension; i++)
    {
      i2 = m - 1;   // j/2 - 1
      m <<= 1;

      for(j = m; j > 0; j-=2)
	{
	  index[j - 1] = Perm[ index[i2] + b[i1 + 1] ];
	  index[j - 2] = Perm[ index[i2] + b[i1 + 0] ];
	  i2--;
	}

      i1 += 2;
    }

  // calc random values of each corner in dimension-cube
  for(j = 0; j < bits; j++)
    {
      interp[j] = 0;

      i1 = 0;   // i*2
      for(i = 0; i < dimension; i++)
	{
	  k = ((j & (1 << (dimension - i - 1))) != 0);
	  interp[j] += r[i1 + k] * G[ctrlPoints*i + index[j] ];
	  i1 += 2;
	}
    }

  m = bits;

  // interpolate
  for(i = 0; i < dimension; i++)
    {
      m >>= 1;

      for(j = 0; j < m; j++)
	interp[j] = lerp(s[i], interp[j], interp[j + m]);
    }

  // return
  value = interp[0];

  return value;
}


float PerlinNoise::turbulence(float *coord, float octaves, float persistence)
{
  float total = 0; 
  float frequency = 1;
  float amplitude = 1;
  float p[2];

  p[0] = coord[0];
  p[1] = coord[1]; 

  for (float i = 0; i < octaves; i++) 
    { 
      p[0] = (p[0] * frequency) - floor(p[0] * frequency); 
      p[1] = (p[1] * frequency) - floor(p[1] * frequency); 

      total += fabs(noise(p)) * amplitude; 

      frequency *= 2;
      amplitude *= persistence;
    } 
  
   // clipping 
  if (total > 1) total  = 1; 
  return(total); 
}


void PerlinNoise::Dnoise(float *coord, float *d, float pixelsize)
{
  // calc d for every dimension
  // and return this array.
  // ASSUME: that *d is a large enough array

  // calc d as if we are working on a virtual texturemap with size (1/pixelsize)
  float *a = new float[dimension];
  float *b = new float[dimension];
  float A, B;

  for(int i = 0; i < dimension; i++)
    {
      // calc interpolation coord coord
      for(int j = 0; j < dimension; j++)
	if(i == j)  {
	  a[j] = coord[j];
	  b[j] = coord[j] + pixelsize;
	}
	else {
	  a[j] = coord[j];
	  b[j] = coord[j];
	}

      // calc interpolated d
      A = noise(a);
      B = noise(b);

      d[i] = (B - A);
    }

  delete[] a;
  delete[] b;
}
  
}  // namespace xrml
