/*
	ZSimplexNoiseMap.cpp
	Author : Chris Ertel

	Purpose :	Implementation of 2D, 3D, and 4D simplex noise maps.

	Changelog
	2/20/11 - Creation (crertel)
*/

#include <ZUtil/ZSimplexNoise.hpp>
#include <ZUtil/ZSimplexNoiseMap.hpp>
#include <string.h>
#include <math.h>

bool ZSimplexNoiseMap2D::Generate(int _seed)
{
	 int buffsize;
	int currOctave;
	float b_coeff;
	float a_coeff;
	float u,v;
	int xstride;

	noiseGen.reseed(_seed);

	/* allocate buffer */
	if (this->values != NULL)
	{
		delete [] this->values;
		this->values = NULL;
	}

	buffsize = this->numberSamplesInX * this->numberSamplesInY;
	this->values = znew float[buffsize];
	if (this->values == NULL)
		return false;

	memset(this->values, 0, buffsize * sizeof(float));

	/* fill in the noise */
	/* for good reference, consult http://local.wasp.uwa.edu.au/~pbourke/texture_colour/perlin/ */
	for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
	{
		b_coeff = pow(this->lacunarity, currOctave);
		a_coeff = pow(this->persistence, currOctave);

		for (int i = 0; i < this->numberSamplesInX; i++)
		{
			u = ((float) i)/((float) this->numberSamplesInX);
			xstride = i * this->numberSamplesInY;
			for (int j = 0; j < this->numberSamplesInY; j++)
			{
				v = ((float) j)/((float) this->numberSamplesInY);
				this->values[ xstride + j ] += ((float) this->noiseGen.noise2(b_coeff * u, b_coeff * v))/a_coeff;
			}
		}
	}

	return true;
}

void ZSimplexNoiseMap2D::Cleanup()
{
	delete [] this->values;
	this->values = NULL;
}

float ZSimplexNoiseMap2D::getValue(int _x, int _y)
{
	float ret;
	int xstride = _x * this->numberSamplesInY;
	ret = this->values[ xstride + _y];
	return ret;
}

bool ZSimplexNoiseMap3D::Generate(int _seed)
{
	 int buffsize;
	int currOctave;
	float b_coeff;
	float a_coeff;
	float u,v,w;
	int xstride, ystride;

	noiseGen.reseed(_seed);

	/* allocate buffer */
	if (this->values != NULL)
	{
		delete [] this->values;
		this->values = NULL;
	}

	buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ;
	this->values = znew float[buffsize];
	if (this->values == NULL)
		return false;

	memset(this->values, 0, buffsize * sizeof(float));

	/* fill in the noise */
	for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
	{
		b_coeff = pow(this->lacunarity, currOctave);
		a_coeff = pow(this->persistence, currOctave);

		for (int i = 0; i < this->numberSamplesInX; i++)
		{
			u = ((float) i)/((float) this->numberSamplesInX);
			xstride = i * this->numberSamplesInY * this->numberSamplesInZ;

			for (int j = 0; j < this->numberSamplesInY; j++)
			{
				v = ((float) j)/((float) this->numberSamplesInY);
				
				ystride = j * this->numberSamplesInZ ;
				for (int k = 0; k < this->numberSamplesInZ; k++)
				{
					w = ((float) k)/((float) this->numberSamplesInZ);
					this->values[xstride+ystride+k] += ((float) this->noiseGen.noise3(b_coeff * u, b_coeff * v, b_coeff * w))/a_coeff;
				}
			}
		}
	}

	return true;
}

void ZSimplexNoiseMap3D::Cleanup()
{
	delete [] this->values;
	this->values = NULL;
}

float ZSimplexNoiseMap3D::getValue(int _x, int _y, int _z)
{
	float ret;
	int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ;
	int ystride = _y * this->numberSamplesInZ;
	ret = this->values[ xstride + ystride + _z];
	return ret;
}

bool ZSimplexNoiseMap4D::Generate(int _seed)
{
	int buffsize;
	int currOctave;
	float b_coeff;
	float a_coeff;
	float u,v,w,r;
	int xstride, ystride, zstride;

	noiseGen.reseed(_seed);

	/* allocate buffer */
	if (this->values != NULL)
	{
		delete [] this->values;
		this->values = NULL;
	}

	buffsize = this->numberSamplesInX * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;
	this->values = znew float[buffsize];
	if (this->values == NULL)
		return false;

	/* fill in the noise */
	for (currOctave = 0; currOctave < this->numberofoctaves; currOctave++)
	{
		b_coeff = pow(this->lacunarity, currOctave);
		a_coeff = pow(this->persistence, currOctave);

		for (int i = 0; i < this->numberSamplesInX; i++)
		{
			u = ((float) i)/((float) this->numberSamplesInX);
			xstride = i * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;

			for (int j = 0; j < this->numberSamplesInY; j++)
			{
				v = ((float) j)/((float) this->numberSamplesInY);
				ystride = j * this->numberSamplesInZ * this->numberSamplesInW;

				for (int k = 0; k < this->numberSamplesInZ; k++)
				{
					w = ((float) k)/((float) this->numberSamplesInZ);
					zstride = k * this->numberSamplesInW;

					for (int l = 0; l < this->numberSamplesInW; l++)
					{
						r = ((float) l)/((float) this->numberSamplesInW);
						this->values[xstride+ystride+zstride+l] += ((float) this->noiseGen.noise4(b_coeff * u, b_coeff * v, b_coeff * w, b_coeff*r))/a_coeff;
					}
				}
			}
		}
	}

	return true;
}

void ZSimplexNoiseMap4D::Cleanup()
{
	delete [] this->values;
	this->values = NULL;
}

float ZSimplexNoiseMap4D::getValue(int _x, int _y, int _z, int _w)
{
	float ret;
	int xstride = _x * this->numberSamplesInY * this->numberSamplesInZ * this->numberSamplesInW;
	int ystride = _y * this->numberSamplesInZ * this->numberSamplesInW;
	int zstride = _z * this->numberSamplesInW;
	ret = this->values[ xstride + ystride + zstride + _w];
	return ret;
}


