Remove FPS from being next to the version string
[oweals/minetest.git] / src / noise.cpp
index 5cb4be29a1d7ce862f800b33a9bed7366696d01c..35057146da9c919c7bb8d90f64451bc51dd0431c 100644 (file)
@@ -1,6 +1,7 @@
 /*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
 
 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 <math.h>
 #include "noise.h"
 #include <iostream>
+#include <string.h> // 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   = 0;
-       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;
@@ -538,3 +604,16 @@ float *Noise::perlinMap3D(float x, float y, float z) {
 
        return result;
 }
+
+
+void Noise::transformNoiseMap() {
+       int i = 0;
+       for (int z = 0; z != sz; z++) {
+               for (int y = 0; y != sy; y++) {
+                       for (int x = 0; x != sx; x++) {
+                               result[i] = result[i] * np->scale + np->offset;
+                               i++;
+                       }
+               }
+       }
+}