#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");
}