/* PerlinNoise.C  - PerlinNoise functions - private source */

#include "PerlinNoise.H"
#include "xrml.H"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

namespace xrml {

PerlinNoise::PerlinNoise(int dim, int cPoints)
{
  if (dim > MaxDim) Error(NULL, "PerlinNoise::PerlinNoise maximum dimension is %d", sizeof(int));
 if (dim <= 0) Error(NULL, "PerlinNoise::PerlinNoise minimum dimension is 1");
  
  int i, j, h, d;
  double norm;
  dimension = dim;
  ctrlPoints = cPoints;
  Perm = new int[ctrlPoints + ctrlPoints];
  G = new double[ctrlPoints * dim];

  // init data
  for(i = 0; i < ctrlPoints; i++)
    {
    Perm[i] = i;

    // generate and normalize over the dimension
    norm = 0;
    for(d = 0; d < dim; d++)
      {
      G[ctrlPoints*d + i] = (2 * drand48() - 1);
      norm += G[ctrlPoints*d + i] * G[ctrlPoints*d + i];
      }

    norm = sqrt(norm);
    /* norm < EPSILON is almost impossible */
    for(d = 0; d < dim; d++)
      G[ctrlPoints*d + i] /= norm;
    
    }

  for(i = 0; i < ctrlPoints; i++)
    {
      h = Perm[i];
      Perm[i] = Perm[j = ( lrand48() % (ctrlPoints - 1) ) ];
      Perm[j] = h;
    }

  for(i = 0; i < ctrlPoints; i++)
      Perm[ctrlPoints + i] = Perm[i];

  // allocate memory for tables used in evaluation
  int bits = 1<<dimension;
  b = new int[dimension<<1];
  r = new float[dimension<<1];
  s = new float[dimension];
  index = new int[bits];
  interp = new double[bits];    

  // display msg
  //  printf("Creating PerlinNoise generator with dimension %d and %d ctrlPoints\n", dim, cPoints);
}


PerlinNoise::PerlinNoise(const PerlinNoise& src)
{
  dimension = src.dimension;
  ctrlPoints = src.ctrlPoints;

  Perm = new int[ctrlPoints + ctrlPoints];
  G = new double[ctrlPoints*dimension];

  memcpy(Perm, src.Perm, (ctrlPoints + ctrlPoints) * sizeof(int));
  memcpy(G, src.G, ctrlPoints * sizeof(double) * dimension);

  // allocate memory for tables used in evaluation
  int bits = 1<<dimension;
  b = new int[dimension<<1];
  r = new float[dimension<<1];
  s = new float[dimension];
  index = new int[bits];
  interp = new double[bits];    

  // display msg
  //  printf("Cloning PerlinNoise generator with dimension %d and %d ctrlPoints\n", src.dimension, src.ctrlPoints);
}

PerlinNoise& PerlinNoise::operator=(const PerlinNoise& src)
{
  if (this != &src)
    {
      if (Perm) delete[] Perm;
      if (G) delete[] G;
      if (b) delete[] b;
      if (r) delete[] r;
      if (s) delete[] s;
      if (index) delete[] index;
      if (interp) delete[] interp;

      dimension = src.dimension;
      ctrlPoints = src.ctrlPoints;

      Perm = new int[ctrlPoints + ctrlPoints];
      G = new double[ctrlPoints*dimension];
  
      memcpy(Perm, src.Perm, (ctrlPoints + ctrlPoints) * sizeof(int));
      memcpy(G, src.G, ctrlPoints * sizeof(double) * dimension);

      // allocate memory for tables used in evaluation
      int bits = 1<<dimension;
      b = new int[dimension<<1];
      r = new float[dimension<<1];
      s = new float[dimension];
      index = new int[bits];
      interp = new double[bits];    
    }

  // display msg
  //  printf("Copying PerlinNoise generator with dimension %d and %d ctrlPoints\n", src.dimension, src.ctrlPoints);

  return *this;
}

PerlinNoise::~PerlinNoise()
{
  if (Perm) delete[] Perm;
  if (G) delete[] G;
  if (b) delete[] b;
  if (r) delete[] r;
  if (s) delete[] s;
  if (index) delete[] index;
  if (interp) delete[] interp;
}

}  // namespace xrml
