/*
-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
#include <math.h>
#include "noise.h"
#include <iostream>
+#include <string.h> // memset
#include "debug.h"
#include "util/numeric.h"
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];
}
}
+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,
* 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;
orig_u = u;
//calculate noise point lattice
-
nlx = (int)(u + sx * step_x) + 2;
nly = (int)(v + sy * step_y) + 2;
index = 0;
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)];
}
}
}
}
}
+#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;
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);
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)];
}
}
}
}
}
+#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;
}
+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;
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++;
+ }
+ }
+ }
+}