3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <string.h> // memset
26 #include "util/numeric.h"
28 #define NOISE_MAGIC_X 1619
29 #define NOISE_MAGIC_Y 31337
30 #define NOISE_MAGIC_Z 52591
31 #define NOISE_MAGIC_SEED 1013
33 typedef float (*Interp3dFxn)(
34 float v000, float v100, float v010, float v110,
35 float v001, float v101, float v011, float v111,
36 float x, float y, float z);
38 float cos_lookup[16] = {
39 1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238,
40 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238
44 ///////////////////////////////////////////////////////////////////////////////
47 //noise poly: p(n) = 60493n^3 + 19990303n + 137612589
48 float noise2d(int x, int y, int seed)
50 int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
51 + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
53 n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
54 return 1.f - (float)n / 0x40000000;
58 float noise3d(int x, int y, int z, int seed)
60 int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
61 + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
63 n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
64 return 1.f - (float)n / 0x40000000;
68 float dotProduct(float vx, float vy, float wx, float wy)
70 return vx * wx + vy * wy;
74 inline float linearInterpolation(float v0, float v1, float t)
76 return v0 + (v1 - v0) * t;
80 float biLinearInterpolation(
85 float tx = easeCurve(x);
86 float ty = easeCurve(y);
87 float u = linearInterpolation(v00, v10, tx);
88 float v = linearInterpolation(v01, v11, tx);
89 return linearInterpolation(u, v, ty);
93 float biLinearInterpolationNoEase(
94 float x0y0, float x1y0,
95 float x0y1, float x1y1,
98 float u = linearInterpolation(x0y0, x1y0, x);
99 float v = linearInterpolation(x0y1, x1y1, x);
100 return linearInterpolation(u, v, y);
104 float triLinearInterpolation(
105 float v000, float v100, float v010, float v110,
106 float v001, float v101, float v011, float v111,
107 float x, float y, float z)
109 float u = biLinearInterpolation(v000, v100, v010, v110, x, y);
110 float v = biLinearInterpolation(v001, v101, v011, v111, x, y);
111 return linearInterpolation(u, v, z);
115 float triLinearInterpolationNoEase(
116 float v000, float v100, float v010, float v110,
117 float v001, float v101, float v011, float v111,
118 float x, float y, float z)
120 float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y);
121 float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y);
122 return linearInterpolation(u, v, z);
127 float triLinearInterpolation(
128 float v000, float v100, float v010, float v110,
129 float v001, float v101, float v011, float v111,
130 float x, float y, float z)
132 float tx = easeCurve(x);
133 float ty = easeCurve(y);
134 float tz = easeCurve(z);
137 v000 * (1 - tx) * (1 - ty) * (1 - tz) +
138 v100 * tx * (1 - ty) * (1 - tz) +
139 v010 * (1 - tx) * ty * (1 - tz) +
140 v110 * tx * ty * (1 - tz) +
141 v001 * (1 - tx) * (1 - ty) * tz +
142 v101 * tx * (1 - ty) * tz +
143 v011 * (1 - tx) * ty * tz +
148 float triLinearInterpolationNoEase(
149 float v000, float v100, float v010, float v110,
150 float v001, float v101, float v011, float v111,
151 float x, float y, float z)
157 v000 * (1 - tx) * (1 - ty) * (1 - tz) +
158 v100 * tx * (1 - ty) * (1 - tz) +
159 v010 * (1 - tx) * ty * (1 - tz) +
160 v110 * tx * ty * (1 - tz) +
161 v001 * (1 - tx) * (1 - ty) * tz +
162 v101 * tx * (1 - ty) * tz +
163 v011 * (1 - tx) * ty * tz +
170 float noise2d_gradient(float x, float y, int seed)
172 // Calculate the integer coordinates
173 int x0 = (x > 0.0 ? (int)x : (int)x - 1);
174 int y0 = (y > 0.0 ? (int)y : (int)y - 1);
175 // Calculate the remaining part of the coordinates
176 float xl = x - (float)x0;
177 float yl = y - (float)y0;
178 // Calculate random cosine lookup table indices for the integer corners.
179 // They are looked up as unit vector gradients from the lookup table.
180 int n00 = (int)((noise2d(x0, y0, seed)+1)*8);
181 int n10 = (int)((noise2d(x0+1, y0, seed)+1)*8);
182 int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8);
183 int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8);
184 // Make a dot product for the gradients and the positions, to get the values
185 float s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
186 float u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
187 float v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
188 float w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
189 // Interpolate between the values
190 return biLinearInterpolation(s,u,v,w,xl,yl);
195 float noise2d_gradient(float x, float y, int seed)
197 // Calculate the integer coordinates
200 // Calculate the remaining part of the coordinates
201 float xl = x - (float)x0;
202 float yl = y - (float)y0;
203 // Get values for corners of square
204 float v00 = noise2d(x0, y0, seed);
205 float v10 = noise2d(x0+1, y0, seed);
206 float v01 = noise2d(x0, y0+1, seed);
207 float v11 = noise2d(x0+1, y0+1, seed);
209 return biLinearInterpolation(v00, v10, v01, v11, xl, yl);
213 float noise3d_gradient(float x, float y, float z, int seed)
215 // Calculate the integer coordinates
219 // Calculate the remaining part of the coordinates
220 float xl = x - (float)x0;
221 float yl = y - (float)y0;
222 float zl = z - (float)z0;
223 // Get values for corners of cube
224 float v000 = noise3d(x0, y0, z0, seed);
225 float v100 = noise3d(x0 + 1, y0, z0, seed);
226 float v010 = noise3d(x0, y0 + 1, z0, seed);
227 float v110 = noise3d(x0 + 1, y0 + 1, z0, seed);
228 float v001 = noise3d(x0, y0, z0 + 1, seed);
229 float v101 = noise3d(x0 + 1, y0, z0 + 1, seed);
230 float v011 = noise3d(x0, y0 + 1, z0 + 1, seed);
231 float v111 = noise3d(x0 + 1, y0 + 1, z0 + 1, seed);
233 return triLinearInterpolationNoEase(
234 v000, v100, v010, v110,
235 v001, v101, v011, v111,
240 float noise2d_perlin(float x, float y, int seed,
241 int octaves, float persistence)
246 for (int i = 0; i < octaves; i++)
248 a += g * noise2d_gradient(x * f, y * f, seed + i);
256 float noise2d_perlin_abs(float x, float y, int seed,
257 int octaves, float persistence)
262 for (int i = 0; i < octaves; i++)
264 a += g * fabs(noise2d_gradient(x * f, y * f, seed + i));
272 float noise3d_perlin(float x, float y, float z, int seed,
273 int octaves, float persistence)
278 for (int i = 0; i < octaves; i++)
280 a += g * noise3d_gradient(x * f, y * f, z * f, seed + i);
288 float noise3d_perlin_abs(float x, float y, float z, int seed,
289 int octaves, float persistence)
294 for (int i = 0; i < octaves; i++)
296 a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i));
305 float contour(float v)
314 ///////////////////////// [ New perlin stuff ] ////////////////////////////
317 Noise::Noise(NoiseParams *np, int seed, int sx, int sy, int sz)
325 this->noisebuf = NULL;
326 resizeNoiseBuf(sz > 1);
328 this->buf = new float[sx * sy * sz];
329 this->result = new float[sx * sy * sz];
341 void Noise::setSize(int sx, int sy, int sz)
347 this->noisebuf = NULL;
348 resizeNoiseBuf(sz > 1);
352 this->buf = new float[sx * sy * sz];
353 this->result = new float[sx * sy * sz];
357 void Noise::setSpreadFactor(v3f spread)
359 this->np->spread = spread;
361 resizeNoiseBuf(sz > 1);
365 void Noise::setOctaves(int octaves)
367 this->np->octaves = octaves;
369 resizeNoiseBuf(sz > 1);
373 void Noise::resizeNoiseBuf(bool is3d)
378 //maximum possible spread value factor
379 ofactor = (float)(1 << (np->octaves - 1));
381 //noise lattice point count
382 //(int)(sz * spread * ofactor) is # of lattice points crossed due to length
383 // + 2 for the two initial endpoints
384 // + 1 for potentially crossing a boundary due to offset
385 nlx = (int)(sx * ofactor / np->spread.X) + 3;
386 nly = (int)(sy * ofactor / np->spread.Y) + 3;
387 nlz = is3d ? (int)(sz * ofactor / np->spread.Z) + 3 : 1;
391 noisebuf = new float[nlx * nly * nlz];
396 * NB: This algorithm is not optimal in terms of space complexity. The entire
397 * integer lattice of noise points could be done as 2 lines instead, and for 3D,
398 * 2 lines + 2 planes.
399 * However, this would require the noise calls to be interposed with the
400 * interpolation loops, which may trash the icache, leading to lower overall
402 * Another optimization that could save half as many noise calls is to carry over
403 * values from the previous noise lattice as midpoints in the new lattice for the
406 #define idx(x, y) ((y) * nlx + (x))
407 void Noise::gradientMap2D(
409 float step_x, float step_y,
412 float v00, v01, v10, v11, u, v, orig_u;
413 int index, i, j, x0, y0, noisex, noisey;
422 //calculate noise point lattice
423 nlx = (int)(u + sx * step_x) + 2;
424 nly = (int)(v + sy * step_y) + 2;
426 for (j = 0; j != nly; j++)
427 for (i = 0; i != nlx; i++)
428 noisebuf[index++] = noise2d(x0 + i, y0 + j, seed);
430 //calculate interpolations
433 for (j = 0; j != sy; j++) {
434 v00 = noisebuf[idx(0, noisey)];
435 v10 = noisebuf[idx(1, noisey)];
436 v01 = noisebuf[idx(0, noisey + 1)];
437 v11 = noisebuf[idx(1, noisey + 1)];
441 for (i = 0; i != sx; i++) {
442 buf[index++] = biLinearInterpolation(v00, v10, v01, v11, u, v);
449 v10 = noisebuf[idx(noisex + 1, noisey)];
450 v11 = noisebuf[idx(noisex + 1, noisey + 1)];
464 #define idx(x, y, z) ((z) * nly * nlx + (y) * nlx + (x))
465 void Noise::gradientMap3D(
466 float x, float y, float z,
467 float step_x, float step_y, float step_z,
468 int seed, bool eased)
470 float v000, v010, v100, v110;
471 float v001, v011, v101, v111;
472 float u, v, w, orig_u, orig_v;
473 int index, i, j, k, x0, y0, z0, noisex, noisey, noisez;
476 Interp3dFxn interpolate = eased ?
477 triLinearInterpolation : triLinearInterpolationNoEase;
488 //calculate noise point lattice
489 nlx = (int)(u + sx * step_x) + 2;
490 nly = (int)(v + sy * step_y) + 2;
491 nlz = (int)(w + sz * step_z) + 2;
493 for (k = 0; k != nlz; k++)
494 for (j = 0; j != nly; j++)
495 for (i = 0; i != nlx; i++)
496 noisebuf[index++] = noise3d(x0 + i, y0 + j, z0 + k, seed);
498 //calculate interpolations
502 for (k = 0; k != sz; k++) {
505 for (j = 0; j != sy; j++) {
506 v000 = noisebuf[idx(0, noisey, noisez)];
507 v100 = noisebuf[idx(1, noisey, noisez)];
508 v010 = noisebuf[idx(0, noisey + 1, noisez)];
509 v110 = noisebuf[idx(1, noisey + 1, noisez)];
510 v001 = noisebuf[idx(0, noisey, noisez + 1)];
511 v101 = noisebuf[idx(1, noisey, noisez + 1)];
512 v011 = noisebuf[idx(0, noisey + 1, noisez + 1)];
513 v111 = noisebuf[idx(1, noisey + 1, noisez + 1)];
517 for (i = 0; i != sx; i++) {
518 buf[index++] = interpolate(
519 v000, v100, v010, v110,
520 v001, v101, v011, v111,
529 v100 = noisebuf[idx(noisex + 1, noisey, noisez)];
530 v110 = noisebuf[idx(noisex + 1, noisey + 1, noisez)];
533 v101 = noisebuf[idx(noisex + 1, noisey, noisez + 1)];
534 v111 = noisebuf[idx(noisex + 1, noisey + 1, noisez + 1)];
555 float *Noise::perlinMap2D(float x, float y)
557 float f = 1.0, g = 1.0;
558 size_t bufsize = sx * sy;
563 memset(result, 0, sizeof(float) * bufsize);
565 for (int oct = 0; oct < np->octaves; oct++) {
566 gradientMap2D(x * f, y * f,
567 f / np->spread.X, f / np->spread.Y,
568 seed + np->seed + oct);
570 for (size_t i = 0; i != bufsize; i++)
571 result[i] += g * buf[i];
581 float *Noise::perlinMap2DModulated(float x, float y, float *persist_map)
584 size_t bufsize = sx * sy;
589 memset(result, 0, sizeof(float) * bufsize);
591 float *g = new float[bufsize];
592 for (size_t i = 0; i != bufsize; i++)
595 for (int oct = 0; oct < np->octaves; oct++) {
596 gradientMap2D(x * f, y * f,
597 f / np->spread.X, f / np->spread.Y,
598 seed + np->seed + oct);
600 for (size_t i = 0; i != bufsize; i++) {
601 result[i] += g[i] * buf[i];
602 g[i] *= persist_map[i];
613 float *Noise::perlinMap3D(float x, float y, float z, bool eased)
615 float f = 1.0, g = 1.0;
616 size_t bufsize = sx * sy * sz;
622 memset(result, 0, sizeof(float) * bufsize);
624 for (int oct = 0; oct < np->octaves; oct++) {
625 gradientMap3D(x * f, y * f, z * f,
626 f / np->spread.X, f / np->spread.Y, f / np->spread.Z,
627 seed + np->seed + oct, eased);
629 for (size_t i = 0; i != bufsize; i++)
630 result[i] += g * buf[i];
640 void Noise::transformNoiseMap()
644 for (int z = 0; z != sz; z++)
645 for (int y = 0; y != sy; y++)
646 for (int x = 0; x != sx; x++) {
647 result[i] = result[i] * np->scale + np->offset;