X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnoise.cpp;h=35057146da9c919c7bb8d90f64451bc51dd0431c;hb=206f0764225de4eeb3b2cef119e22df8005e5d60;hp=3874848ad3836672138caa24cc36d6268fd6f3eb;hpb=96898c179458174f858bab6363636ef231b49865;p=oweals%2Fminetest.git diff --git a/src/noise.cpp b/src/noise.cpp index 3874848ad..35057146d 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -1,6 +1,7 @@ /* -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -20,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "noise.h" #include +#include // memset #include "debug.h" #include "util/numeric.h" @@ -270,47 +272,27 @@ float contour(float v) Noise::Noise(NoiseParams *np, int seed, int sx, int sy) { - int nlx, nly; - float ofactor; - - //maximum possible spread value factor - ofactor = (float)(1 << (np->octaves - 1)); - - //noise lattice point count - //(int)(sz * spread * ofactor) is # of lattice points crossed due to length - // + 2 for the two initial endpoints - // + 1 for potentially crossing a boundary due to offset - nlx = (int)(sx * ofactor / np->spread.X) + 3; - nly = (int)(sy * ofactor / np->spread.Y) + 3; - - this->np = np; - this->seed = seed; - this->sx = sx; - this->sy = sy; - this->sz = 1; - this->noisebuf = new float[nlx * nly]; - this->buf = new float[sx * sy]; - this->result = new float[sx * sy]; + init(np, seed, sx, sy, 1); } Noise::Noise(NoiseParams *np, int seed, int sx, int sy, int sz) { - int nlx, nly, nlz; - float ofactor; + init(np, seed, sx, sy, sz); +} - ofactor = (float)(1 << (np->octaves - 1)); - nlx = (int)(sx * ofactor / np->spread.X) + 3; - nly = (int)(sy * ofactor / np->spread.Y) + 3; - nlz = (int)(sz * ofactor / np->spread.Z) + 3; +void Noise::init(NoiseParams *np, int seed, int sx, int sy, int sz) { this->np = np; this->seed = seed; this->sx = sx; this->sy = sy; this->sz = sz; - this->noisebuf = new float[nlx * nly * nlz]; - this->buf = new float[sx * sy * sz]; - this->result = new float[sx * sy * sz]; + + this->noisebuf = NULL; + resizeNoiseBuf(sz > 1); + + this->buf = new float[sx * sy * sz]; + this->result = new float[sx * sy * sz]; } @@ -321,6 +303,61 @@ Noise::~Noise() { } +void Noise::setSize(int sx, int sy) { + setSize(sx, sy, 1); +} + + +void Noise::setSize(int sx, int sy, int sz) { + this->sx = sx; + this->sy = sy; + this->sz = sz; + + this->noisebuf = NULL; + resizeNoiseBuf(sz > 1); + + delete[] buf; + delete[] result; + this->buf = new float[sx * sy * sz]; + this->result = new float[sx * sy * sz]; +} + + +void Noise::setSpreadFactor(v3f spread) { + this->np->spread = spread; + + resizeNoiseBuf(sz > 1); +} + + +void Noise::setOctaves(int octaves) { + this->np->octaves = octaves; + + resizeNoiseBuf(sz > 1); +} + + +void Noise::resizeNoiseBuf(bool is3d) { + int nlx, nly, nlz; + float ofactor; + + //maximum possible spread value factor + ofactor = (float)(1 << (np->octaves - 1)); + + //noise lattice point count + //(int)(sz * spread * ofactor) is # of lattice points crossed due to length + // + 2 for the two initial endpoints + // + 1 for potentially crossing a boundary due to offset + nlx = (int)(sx * ofactor / np->spread.X) + 3; + nly = (int)(sy * ofactor / np->spread.Y) + 3; + nlz = is3d ? (int)(sz * ofactor / np->spread.Z) + 3 : 1; + + if (noisebuf) + delete[] noisebuf; + noisebuf = new float[nlx * nly * nlz]; +} + + /* * NB: This algorithm is not optimal in terms of space complexity. The entire * integer lattice of noise points could be done as 2 lines instead, and for 3D, @@ -332,6 +369,7 @@ Noise::~Noise() { * values from the previous noise lattice as midpoints in the new lattice for the * next octave. */ +#define idx(x, y) ((y) * nlx + (x)) void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed) { float v00, v01, v10, v11, u, v, orig_u; int index, i, j, x0, y0, noisex, noisey; @@ -344,7 +382,6 @@ void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed orig_u = u; //calculate noise point lattice - nlx = (int)(u + sx * step_x) + 2; nly = (int)(v + sy * step_y) + 2; index = 0; @@ -353,25 +390,26 @@ void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed noisebuf[index++] = noise2d(x0 + i, y0 + j, seed); //calculate interpolations + index = 0; noisey = 0; for (j = 0; j != sy; j++) { - v00 = noisebuf[noisey * nlx]; - v10 = noisebuf[noisey * nlx + 1]; - v01 = noisebuf[(noisey + 1) * nlx]; - v11 = noisebuf[(noisey + 1) * nlx + 1]; + v00 = noisebuf[idx(0, noisey)]; + v10 = noisebuf[idx(1, noisey)]; + v01 = noisebuf[idx(0, noisey + 1)]; + v11 = noisebuf[idx(1, noisey + 1)]; u = orig_u; noisex = 0; for (i = 0; i != sx; i++) { - buf[j * sx + i] = biLinearInterpolation(v00, v10, v01, v11, u, v); + buf[index++] = biLinearInterpolation(v00, v10, v01, v11, u, v); u += step_x; if (u >= 1.0) { u -= 1.0; noisex++; v00 = v10; v01 = v11; - v10 = noisebuf[noisey * nlx + noisex + 1]; - v11 = noisebuf[(noisey + 1) * nlx + noisex + 1]; + v10 = noisebuf[idx(noisex + 1, noisey)]; + v11 = noisebuf[idx(noisex + 1, noisey + 1)]; } } @@ -382,14 +420,16 @@ void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed } } } +#undef idx +#define idx(x, y, z) ((z) * nly * nlx + (y) * nlx + (x)) void Noise::gradientMap3D(float x, float y, float z, float step_x, float step_y, float step_z, int seed) { float v000, v010, v100, v110; float v001, v011, v101, v111; - float u, v, w, orig_u, orig_w; + float u, v, w, orig_u, orig_v; int index, i, j, k, x0, y0, z0, noisex, noisey, noisez; int nlx, nly, nlz; @@ -400,49 +440,39 @@ void Noise::gradientMap3D(float x, float y, float z, v = y - (float)y0; w = z - (float)z0; orig_u = u; - orig_w = w; + orig_v = v; //calculate noise point lattice nlx = (int)(u + sx * step_x) + 2; nly = (int)(v + sy * step_y) + 2; - nlz = (int)(v + sy * step_z) + 2; + nlz = (int)(w + sz * step_z) + 2; index = 0; for (k = 0; k != nlz; k++) for (j = 0; j != nly; j++) for (i = 0; i != nlx; i++) noisebuf[index++] = noise3d(x0 + i, y0 + j, z0 + k, seed); -#define index(x, y, z) ((z) * nly * nlx + (y) * nlx + (x)) - //calculate interpolations + index = 0; noisey = 0; noisez = 0; for (k = 0; k != sz; k++) { - v000 = noisebuf[index(0, noisey, noisez)]; - v100 = noisebuf[index(1, noisey, noisez)]; - v010 = noisebuf[index(0, noisey + 1, noisez)]; - v110 = noisebuf[index(1, noisey + 1, noisez)]; - v001 = noisebuf[index(0, noisey, noisez + 1)]; - v101 = noisebuf[index(1, noisey, noisez + 1)]; - v011 = noisebuf[index(0, noisey + 1, noisez + 1)]; - v111 = noisebuf[index(1, noisey + 1, noisez + 1)]; - - w = orig_w; + v = orig_v; noisey = 0; for (j = 0; j != sy; j++) { - v000 = noisebuf[index(0, noisey, noisez)]; - v100 = noisebuf[index(1, noisey, noisez)]; - v010 = noisebuf[index(0, noisey + 1, noisez)]; - v110 = noisebuf[index(1, noisey + 1, noisez)]; - v001 = noisebuf[index(0, noisey, noisez + 1)]; - v101 = noisebuf[index(1, noisey, noisez + 1)]; - v011 = noisebuf[index(0, noisey + 1, noisez + 1)]; - v111 = noisebuf[index(1, noisey + 1, noisez + 1)]; + v000 = noisebuf[idx(0, noisey, noisez)]; + v100 = noisebuf[idx(1, noisey, noisez)]; + v010 = noisebuf[idx(0, noisey + 1, noisez)]; + v110 = noisebuf[idx(1, noisey + 1, noisez)]; + v001 = noisebuf[idx(0, noisey, noisez + 1)]; + v101 = noisebuf[idx(1, noisey, noisez + 1)]; + v011 = noisebuf[idx(0, noisey + 1, noisez + 1)]; + v111 = noisebuf[idx(1, noisey + 1, noisez + 1)]; u = orig_u; noisex = 0; for (i = 0; i != sx; i++) { - buf[j * sx + i] = triLinearInterpolation( + buf[index++] = triLinearInterpolation( v000, v100, v010, v110, v001, v101, v011, v111, u, v, w); @@ -452,12 +482,12 @@ void Noise::gradientMap3D(float x, float y, float z, noisex++; v000 = v100; v010 = v110; - v100 = noisebuf[index(noisex + 1, noisey, noisez)]; - v110 = noisebuf[index(noisex + 1, noisey + 1, noisez)]; + v100 = noisebuf[idx(noisex + 1, noisey, noisez)]; + v110 = noisebuf[idx(noisex + 1, noisey + 1, noisez)]; v001 = v101; v011 = v111; - v101 = noisebuf[index(noisex + 1, noisey, noisez + 1)]; - v111 = noisebuf[index(noisex + 1, noisey + 1, noisez + 1)]; + v101 = noisebuf[idx(noisex + 1, noisey, noisez + 1)]; + v111 = noisebuf[idx(noisex + 1, noisey + 1, noisez + 1)]; } } @@ -475,10 +505,11 @@ void Noise::gradientMap3D(float x, float y, float z, } } } +#undef idx float *Noise::perlinMap2D(float x, float y) { - float a = 0.0, f = 1.0, g = 1.0; + float f = 1.0, g = 1.0; int i, j, index, oct; x /= np->spread.X; @@ -507,8 +538,43 @@ float *Noise::perlinMap2D(float x, float y) { } +float *Noise::perlinMap2DModulated(float x, float y, float *persist_map) { + float f = 1.0; + int i, j, index, oct; + + x /= np->spread.X; + y /= np->spread.Y; + + memset(result, 0, sizeof(float) * sx * sy); + + float *g = new float[sx * sy]; + for (index = 0; index != sx * sy; index++) + g[index] = 1.0; + + for (oct = 0; oct < np->octaves; oct++) { + gradientMap2D(x * f, y * f, + f / np->spread.X, f / np->spread.Y, + seed + np->seed + oct); + + index = 0; + for (j = 0; j != sy; j++) { + for (i = 0; i != sx; i++) { + result[index] += g[index] * buf[index]; + g[index] *= persist_map[index]; + index++; + } + } + + f *= 2.0; + } + + delete[] g; + return result; +} + + float *Noise::perlinMap3D(float x, float y, float z) { - float a = 0.0, f = 1.0, g = 1.0; + float f = 1.0, g = 1.0; int i, j, k, index, oct; x /= np->spread.X;