Blob Blame Raw


#include "trandom.h"
//#include "tfxparam.h"
#include "perlinnoise.h"

//using std::cout;
//using std::endl;
//-------------------------------------------------------------------

double PerlinNoise::LinearNoise(double x, double y, double t)
{

	int ix, iy, it, ix1, iy1, it1;
	double dx, dy, dt, val1, val2, val3, val4, val5, val6;

	ix = (int)x;
	iy = (int)y;
	it = (int)t;

	dx = x - ix;
	dy = y - iy;
	dt = t - it;

	ix = ix % Size;
	iy = iy % Size;
	it = it % TimeSize;

	ix1 = (ix + 1) % Size;
	iy1 = (iy + 1) % Size;
	it1 = (it + 1) % TimeSize;

	val1 = Noise[it + TimeSize * iy + TimeSize * Size * ix] +
		   dx * (Noise[it + TimeSize * iy + TimeSize * Size * ix1] -
				 Noise[it + TimeSize * iy + TimeSize * Size * ix]);
	val2 = Noise[it + TimeSize * iy1 + TimeSize * Size * ix] +
		   dx * (Noise[it + TimeSize * iy1 + TimeSize * Size * ix1] -
				 Noise[it + TimeSize * iy1 + TimeSize * Size * ix]);
	val3 = Noise[it1 + TimeSize * iy + TimeSize * Size * ix] +
		   dx * (Noise[it1 + TimeSize * iy + TimeSize * Size * ix1] -
				 Noise[it1 + TimeSize * iy + TimeSize * Size * ix]);
	val4 = Noise[it1 + TimeSize * iy1 + TimeSize * Size * ix] +
		   dx * (Noise[it1 + TimeSize * iy1 + TimeSize * Size * ix1] -
				 Noise[it1 + TimeSize * iy1 + TimeSize * Size * ix]);

	val5 = (val1 + dy * (val2 - val1));
	val6 = (val3 + dy * (val4 - val3));

	return (val5 + dt * (val6 - val5));
}

double PerlinNoise::Turbolence(double u, double v, double k, double grain)
{

	u += Offset;
	v += Offset;
	Pixel_size = 0.05;
	double t = 0.0, scale = 1.0, tscale = 0;

	u /= grain;
	v /= grain;
	k /= 10;
	while (scale > Pixel_size) {
		tscale += scale;
		t += LinearNoise(u / scale, v / scale, k / scale) * scale;
		scale /= 2.0;
	}
	return t / tscale;
}

double PerlinNoise::Turbolence(double u, double v, double k, double grain, double min, double max)
{

	u += Offset;
	v += Offset;
	Pixel_size = 0.05;
	double t = 0.0, scale = 1.0, tscale = 0;

	u /= grain;
	v /= grain;
	k /= 10;
	while (scale > Pixel_size) {
		tscale += scale;
		t += LinearNoise(u / scale, v / scale, k / scale) * scale;
		scale /= 2.0;
	}
	t = t / tscale;
	if (t < min)
		t = 0;
	else {
		if (t > max)
			t = 1;
		else
			t = (t - min) / ((max - min));
	}
	return t;
}

double PerlinNoise::Marble(double u, double v, double k, double grain)
{

	u += Offset;
	v += Offset;
	Pixel_size = 0.05;
	double t = 0.0, scale = 1.0, tscale = 0;

	u /= grain;
	v /= grain;
	k /= 10;
	while (scale > Pixel_size) {
		tscale += scale;
		t += LinearNoise(u / scale, v / scale, k / scale) * scale;
		scale /= 2.0;
	}
	t = 10 * t;
	return (t - (int)t);
}

double PerlinNoise::Marble(double u, double v, double k, double grain, double min, double max)
{

	u += Offset;
	v += Offset;
	Pixel_size = 0.05;
	double t = 0.0, scale = 1.0, tscale = 0;

	u /= grain;
	v /= grain;
	k /= 10;
	while (scale > Pixel_size) {
		tscale += scale;
		t += LinearNoise(u / scale, v / scale, k / scale) * scale;
		scale /= 2.0;
	}
	t = 10 * t;
	t = (t - (int)t);
	if (t < min)
		t = 0;
	else {
		if (t > max)
			t = 1;
		else
			t = (t - min) / ((max - min));
	}
	return t;
}

PerlinNoise::PerlinNoise()
	: Noise(new float[Size * Size * TimeSize])
{
	TRandom random(1);
	for (int i = 0; i < Size; i++) {
		for (int j = 0; j < Size; j++) {
			for (int k = 0; k < TimeSize; k++) {
				float tmp = random.getFloat();
				//cout << "tmp = " << tmp << "HM = "<< HowMany<< endl;
				Noise[k + TimeSize * j + TimeSize * Size * i] = tmp;
			}
		}
	}

	//cout << "HowMany = " << HowMany <<endl;
}

int PerlinNoise::Size = 60;
int PerlinNoise::TimeSize = 20;
int PerlinNoise::Offset = 1000000;
double PerlinNoise::Pixel_size = 0.01; //il pixel size va animato da 1 (escluso)
									   //a 0.1 (consigliato) fino ad un min di 0.001

namespace
{
template <typename PIXEL>
void doCloudsT(const TRasterPT<PIXEL> &ras, const TSpectrumT<PIXEL> &spectrum,
			   TPointD &tilepos, double evolution, double size, double min, double max, int type, double scale)
{
	int j;
	TAffine aff = TScale(1 / scale);
	PerlinNoise Noise;
	ras->lock();
	if (type == PNOISE_CLOUDS) {
		for (j = 0; j < ras->getLy(); j++) {
			TPointD pos = tilepos;
			pos.y += j;
			PIXEL *pix = ras->pixels(j);
			PIXEL *endPix = pix + ras->getLx();
			while (pix < endPix) {
				TPointD posAff = aff * pos;
				double pnoise = Noise.Turbolence(posAff.x, posAff.y, evolution, size, min, max);
				pos.x += 1.0;
				*pix++ = spectrum.getPremultipliedValue(pnoise);
			}
		}
	} else {
		for (j = 0; j < ras->getLy(); j++) {
			TPointD pos = tilepos;
			pos.y += j;
			PIXEL *pix = ras->pixels(j);
			PIXEL *endPix = pix + ras->getLx();
			while (pix < endPix) {
				TPointD posAff = aff * pos;
				double pnoise = Noise.Marble(posAff.x, posAff.y, evolution, size, min, max);
				pos.x += 1.0;
				*pix++ = spectrum.getPremultipliedValue(pnoise);
			}
		}
	}
	ras->unlock();
}
}

void doClouds(
	const TRasterP &ras,
	const TSpectrumParamP colors,
	TPointD pos,
	double evolution,
	double size,
	double min,
	double max,
	int type,
	double scale,
	double frame)
{

	if ((TRaster32P)ras)
		doCloudsT<TPixel32>(
			ras,
			colors->getValue(frame),
			pos, evolution, size, min, max, type, scale);
	else if ((TRaster64P)ras)
		doCloudsT<TPixel64>(
			ras,
			colors->getValue64(frame),
			pos, evolution, size, min, max, type, scale);
	else
		throw TException("CloudsFx: unsupported Pixel Type");
}