| |
| |
| #include "trandom.h" |
| |
| #include "perlinnoise.h" |
| |
| |
| |
| |
| |
| 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(); |
| |
| Noise[k + TimeSize * j + TimeSize * Size * i] = tmp; |
| } |
| } |
| } |
| |
| |
| } |
| |
| int PerlinNoise::Size = 60; |
| int PerlinNoise::TimeSize = 20; |
| int PerlinNoise::Offset = 1000000; |
| double PerlinNoise::Pixel_size = |
| 0.01; |
| |
| |
| 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"); |
| } |
| |