Line data Source code
1 : /*
2 : * Minetest
3 : * Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
4 : * Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without modification, are
8 : * permitted provided that the following conditions are met:
9 : * 1. Redistributions of source code must retain the above copyright notice, this list of
10 : * conditions and the following disclaimer.
11 : * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 : * of conditions and the following disclaimer in the documentation and/or other materials
13 : * provided with the distribution.
14 : *
15 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 : * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
18 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 : * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22 : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 : */
25 :
26 : #include <math.h>
27 : #include "noise.h"
28 : #include <iostream>
29 : #include <string.h> // memset
30 : #include "debug.h"
31 : #include "util/numeric.h"
32 : #include "util/string.h"
33 : #include "exceptions.h"
34 :
35 : #define NOISE_MAGIC_X 1619
36 : #define NOISE_MAGIC_Y 31337
37 : #define NOISE_MAGIC_Z 52591
38 : #define NOISE_MAGIC_SEED 1013
39 :
40 : typedef float (*Interp2dFxn)(
41 : float v00, float v10, float v01, float v11,
42 : float x, float y);
43 :
44 : typedef float (*Interp3dFxn)(
45 : float v000, float v100, float v010, float v110,
46 : float v001, float v101, float v011, float v111,
47 : float x, float y, float z);
48 :
49 : float cos_lookup[16] = {
50 : 1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238,
51 : 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238
52 : };
53 :
54 : FlagDesc flagdesc_noiseparams[] = {
55 : {"defaults", NOISE_FLAG_DEFAULTS},
56 : {"eased", NOISE_FLAG_EASED},
57 : {"absvalue", NOISE_FLAG_ABSVALUE},
58 : {"pointbuffer", NOISE_FLAG_POINTBUFFER},
59 : {"simplex", NOISE_FLAG_SIMPLEX},
60 : {NULL, 0}
61 : };
62 :
63 : ///////////////////////////////////////////////////////////////////////////////
64 :
65 1 : PcgRandom::PcgRandom(u64 state, u64 seq)
66 : {
67 1 : seed(state, seq);
68 1 : }
69 :
70 2 : void PcgRandom::seed(u64 state, u64 seq)
71 : {
72 2 : m_state = 0U;
73 2 : m_inc = (seq << 1u) | 1u;
74 2 : next();
75 2 : m_state += state;
76 2 : next();
77 2 : }
78 :
79 :
80 73933 : u32 PcgRandom::next()
81 : {
82 73933 : u64 oldstate = m_state;
83 73933 : m_state = oldstate * 6364136223846793005ULL + m_inc;
84 :
85 73933 : u32 xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
86 73933 : u32 rot = oldstate >> 59u;
87 73933 : return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
88 : }
89 :
90 :
91 73862 : u32 PcgRandom::range(u32 bound)
92 : {
93 : /*
94 : If the bound is not a multiple of the RNG's range, it may cause bias,
95 : e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2.
96 : Using rand() % 3, the number 0 would be twice as likely to appear.
97 : With a very large RNG range, the effect becomes less prevalent but
98 : still present. This can be solved by modifying the range of the RNG
99 : to become a multiple of bound by dropping values above the a threshhold.
100 : In our example, threshhold == 4 - 3 = 1 % 3 == 1, so reject 0, thus
101 : making the range 3 with no bias.
102 :
103 : This loop looks dangerous, but will always terminate due to the
104 : RNG's property of uniformity.
105 : */
106 73862 : u32 threshhold = -bound % bound;
107 : u32 r;
108 :
109 73862 : while ((r = next()) < threshhold)
110 : ;
111 :
112 73862 : return r % bound;
113 : }
114 :
115 :
116 73862 : s32 PcgRandom::range(s32 min, s32 max)
117 : {
118 73862 : if (max < min)
119 0 : throw PrngException("Invalid range (max < min)");
120 :
121 73862 : u32 bound = max - min + 1;
122 73862 : return range(bound) + min;
123 : }
124 :
125 :
126 0 : void PcgRandom::bytes(void *out, size_t len)
127 : {
128 0 : u8 *outb = (u8 *)out;
129 0 : int bytes_left = 0;
130 : u32 r;
131 :
132 0 : while (len--) {
133 0 : if (bytes_left == 0) {
134 0 : bytes_left = sizeof(u32);
135 0 : r = next();
136 : }
137 :
138 0 : *outb = r & 0xFF;
139 0 : outb++;
140 0 : bytes_left--;
141 0 : r >>= 8;
142 : }
143 0 : }
144 :
145 :
146 0 : s32 PcgRandom::randNormalDist(s32 min, s32 max, int num_trials)
147 : {
148 0 : s32 accum = 0;
149 0 : for (int i = 0; i != num_trials; i++)
150 0 : accum += range(min, max);
151 0 : return myround((float)accum / num_trials);
152 : }
153 :
154 : ///////////////////////////////////////////////////////////////////////////////
155 :
156 9199872 : float noise2d(int x, int y, int seed)
157 : {
158 9199872 : int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
159 9199872 : + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
160 9199872 : n = (n >> 13) ^ n;
161 9199872 : n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
162 9199872 : return 1.f - (float)n / 0x40000000;
163 : }
164 :
165 :
166 1463 : float noise3d(int x, int y, int z, int seed)
167 : {
168 1463 : int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
169 1463 : + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
170 1463 : n = (n >> 13) ^ n;
171 1463 : n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
172 1463 : return 1.f - (float)n / 0x40000000;
173 : }
174 :
175 :
176 : inline float dotProduct(float vx, float vy, float wx, float wy)
177 : {
178 : return vx * wx + vy * wy;
179 : }
180 :
181 :
182 6899904 : inline float linearInterpolation(float v0, float v1, float t)
183 : {
184 6899904 : return v0 + (v1 - v0) * t;
185 : }
186 :
187 :
188 2299968 : inline float biLinearInterpolation(
189 : float v00, float v10,
190 : float v01, float v11,
191 : float x, float y)
192 : {
193 2299968 : float tx = easeCurve(x);
194 2299968 : float ty = easeCurve(y);
195 : #if 0
196 : return (
197 : v00 * (1 - tx) * (1 - ty) +
198 : v10 * tx * (1 - ty) +
199 : v01 * (1 - tx) * ty +
200 : v11 * tx * ty
201 : );
202 : #endif
203 2299968 : float u = linearInterpolation(v00, v10, tx);
204 2299968 : float v = linearInterpolation(v01, v11, tx);
205 2299968 : return linearInterpolation(u, v, ty);
206 : }
207 :
208 :
209 0 : inline float biLinearInterpolationNoEase(
210 : float v00, float v10,
211 : float v01, float v11,
212 : float x, float y)
213 : {
214 0 : float u = linearInterpolation(v00, v10, x);
215 0 : float v = linearInterpolation(v01, v11, x);
216 0 : return linearInterpolation(u, v, y);
217 : }
218 :
219 :
220 0 : float triLinearInterpolation(
221 : float v000, float v100, float v010, float v110,
222 : float v001, float v101, float v011, float v111,
223 : float x, float y, float z)
224 : {
225 0 : float tx = easeCurve(x);
226 0 : float ty = easeCurve(y);
227 0 : float tz = easeCurve(z);
228 : #if 0
229 : return (
230 : v000 * (1 - tx) * (1 - ty) * (1 - tz) +
231 : v100 * tx * (1 - ty) * (1 - tz) +
232 : v010 * (1 - tx) * ty * (1 - tz) +
233 : v110 * tx * ty * (1 - tz) +
234 : v001 * (1 - tx) * (1 - ty) * tz +
235 : v101 * tx * (1 - ty) * tz +
236 : v011 * (1 - tx) * ty * tz +
237 : v111 * tx * ty * tz
238 : );
239 : #endif
240 0 : float u = biLinearInterpolationNoEase(v000, v100, v010, v110, tx, ty);
241 0 : float v = biLinearInterpolationNoEase(v001, v101, v011, v111, tx, ty);
242 0 : return linearInterpolation(u, v, tz);
243 : }
244 :
245 0 : float triLinearInterpolationNoEase(
246 : float v000, float v100, float v010, float v110,
247 : float v001, float v101, float v011, float v111,
248 : float x, float y, float z)
249 : {
250 0 : float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y);
251 0 : float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y);
252 0 : return linearInterpolation(u, v, z);
253 : }
254 :
255 :
256 : #if 0
257 : float noise2d_gradient(float x, float y, int seed)
258 : {
259 : // Calculate the integer coordinates
260 : int x0 = (x > 0.0 ? (int)x : (int)x - 1);
261 : int y0 = (y > 0.0 ? (int)y : (int)y - 1);
262 : // Calculate the remaining part of the coordinates
263 : float xl = x - (float)x0;
264 : float yl = y - (float)y0;
265 : // Calculate random cosine lookup table indices for the integer corners.
266 : // They are looked up as unit vector gradients from the lookup table.
267 : int n00 = (int)((noise2d(x0, y0, seed)+1)*8);
268 : int n10 = (int)((noise2d(x0+1, y0, seed)+1)*8);
269 : int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8);
270 : int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8);
271 : // Make a dot product for the gradients and the positions, to get the values
272 : float s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
273 : float u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
274 : float v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
275 : float w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
276 : // Interpolate between the values
277 : return biLinearInterpolation(s,u,v,w,xl,yl);
278 : }
279 : #endif
280 :
281 :
282 2299968 : float noise2d_gradient(float x, float y, int seed, bool eased)
283 : {
284 : // Calculate the integer coordinates
285 2299968 : int x0 = myfloor(x);
286 2299968 : int y0 = myfloor(y);
287 : // Calculate the remaining part of the coordinates
288 2299968 : float xl = x - (float)x0;
289 2299968 : float yl = y - (float)y0;
290 : // Get values for corners of square
291 2299968 : float v00 = noise2d(x0, y0, seed);
292 2299968 : float v10 = noise2d(x0+1, y0, seed);
293 2299968 : float v01 = noise2d(x0, y0+1, seed);
294 2299968 : float v11 = noise2d(x0+1, y0+1, seed);
295 : // Interpolate
296 2299968 : if (eased)
297 2299968 : return biLinearInterpolation(v00, v10, v01, v11, xl, yl);
298 : else
299 0 : return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl);
300 : }
301 :
302 :
303 0 : float noise3d_gradient(float x, float y, float z, int seed, bool eased)
304 : {
305 : // Calculate the integer coordinates
306 0 : int x0 = myfloor(x);
307 0 : int y0 = myfloor(y);
308 0 : int z0 = myfloor(z);
309 : // Calculate the remaining part of the coordinates
310 0 : float xl = x - (float)x0;
311 0 : float yl = y - (float)y0;
312 0 : float zl = z - (float)z0;
313 : // Get values for corners of cube
314 0 : float v000 = noise3d(x0, y0, z0, seed);
315 0 : float v100 = noise3d(x0 + 1, y0, z0, seed);
316 0 : float v010 = noise3d(x0, y0 + 1, z0, seed);
317 0 : float v110 = noise3d(x0 + 1, y0 + 1, z0, seed);
318 0 : float v001 = noise3d(x0, y0, z0 + 1, seed);
319 0 : float v101 = noise3d(x0 + 1, y0, z0 + 1, seed);
320 0 : float v011 = noise3d(x0, y0 + 1, z0 + 1, seed);
321 0 : float v111 = noise3d(x0 + 1, y0 + 1, z0 + 1, seed);
322 : // Interpolate
323 0 : if (eased) {
324 : return triLinearInterpolation(
325 : v000, v100, v010, v110,
326 : v001, v101, v011, v111,
327 0 : xl, yl, zl);
328 : } else {
329 : return triLinearInterpolationNoEase(
330 : v000, v100, v010, v110,
331 : v001, v101, v011, v111,
332 0 : xl, yl, zl);
333 : }
334 : }
335 :
336 :
337 766656 : float noise2d_perlin(float x, float y, int seed,
338 : int octaves, float persistence, bool eased)
339 : {
340 766656 : float a = 0;
341 766656 : float f = 1.0;
342 766656 : float g = 1.0;
343 3066624 : for (int i = 0; i < octaves; i++)
344 : {
345 2299968 : a += g * noise2d_gradient(x * f, y * f, seed + i, eased);
346 2299968 : f *= 2.0;
347 2299968 : g *= persistence;
348 : }
349 766656 : return a;
350 : }
351 :
352 :
353 0 : float noise2d_perlin_abs(float x, float y, int seed,
354 : int octaves, float persistence, bool eased)
355 : {
356 0 : float a = 0;
357 0 : float f = 1.0;
358 0 : float g = 1.0;
359 0 : for (int i = 0; i < octaves; i++) {
360 0 : a += g * fabs(noise2d_gradient(x * f, y * f, seed + i, eased));
361 0 : f *= 2.0;
362 0 : g *= persistence;
363 : }
364 0 : return a;
365 : }
366 :
367 :
368 0 : float noise3d_perlin(float x, float y, float z, int seed,
369 : int octaves, float persistence, bool eased)
370 : {
371 0 : float a = 0;
372 0 : float f = 1.0;
373 0 : float g = 1.0;
374 0 : for (int i = 0; i < octaves; i++) {
375 0 : a += g * noise3d_gradient(x * f, y * f, z * f, seed + i, eased);
376 0 : f *= 2.0;
377 0 : g *= persistence;
378 : }
379 0 : return a;
380 : }
381 :
382 :
383 0 : float noise3d_perlin_abs(float x, float y, float z, int seed,
384 : int octaves, float persistence, bool eased)
385 : {
386 0 : float a = 0;
387 0 : float f = 1.0;
388 0 : float g = 1.0;
389 0 : for (int i = 0; i < octaves; i++) {
390 0 : a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i, eased));
391 0 : f *= 2.0;
392 0 : g *= persistence;
393 : }
394 0 : return a;
395 : }
396 :
397 :
398 0 : float contour(float v)
399 : {
400 0 : v = fabs(v);
401 0 : if (v >= 1.0)
402 0 : return 0.0;
403 0 : return (1.0 - v);
404 : }
405 :
406 :
407 : ///////////////////////// [ New noise ] ////////////////////////////
408 :
409 :
410 0 : float NoisePerlin2D(NoiseParams *np, float x, float y, int seed)
411 : {
412 0 : float a = 0;
413 0 : float f = 1.0;
414 0 : float g = 1.0;
415 :
416 0 : x /= np->spread.X;
417 0 : y /= np->spread.Y;
418 0 : seed += np->seed;
419 :
420 0 : for (size_t i = 0; i < np->octaves; i++) {
421 0 : float noiseval = noise2d_gradient(x * f, y * f, seed + i,
422 0 : np->flags & (NOISE_FLAG_DEFAULTS | NOISE_FLAG_EASED));
423 :
424 0 : if (np->flags & NOISE_FLAG_ABSVALUE)
425 0 : noiseval = fabs(noiseval);
426 :
427 0 : a += g * noiseval;
428 0 : f *= np->lacunarity;
429 0 : g *= np->persist;
430 : }
431 :
432 0 : return np->offset + a * np->scale;
433 : }
434 :
435 :
436 0 : float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed)
437 : {
438 0 : float a = 0;
439 0 : float f = 1.0;
440 0 : float g = 1.0;
441 :
442 0 : x /= np->spread.X;
443 0 : y /= np->spread.Y;
444 0 : z /= np->spread.Z;
445 0 : seed += np->seed;
446 :
447 0 : for (size_t i = 0; i < np->octaves; i++) {
448 0 : float noiseval = noise3d_gradient(x * f, y * f, z * f, seed + i,
449 0 : np->flags & NOISE_FLAG_EASED);
450 :
451 0 : if (np->flags & NOISE_FLAG_ABSVALUE)
452 0 : noiseval = fabs(noiseval);
453 :
454 0 : a += g * noiseval;
455 0 : f *= np->lacunarity;
456 0 : g *= np->persist;
457 : }
458 :
459 0 : return np->offset + a * np->scale;
460 : }
461 :
462 :
463 0 : Noise::Noise(NoiseParams *np_, int seed, u32 sx, u32 sy, u32 sz)
464 : {
465 0 : memcpy(&np, np_, sizeof(np));
466 0 : this->seed = seed;
467 0 : this->sx = sx;
468 0 : this->sy = sy;
469 0 : this->sz = sz;
470 :
471 0 : this->persist_buf = NULL;
472 0 : this->gradient_buf = NULL;
473 0 : this->result = NULL;
474 :
475 0 : allocBuffers();
476 0 : }
477 :
478 :
479 0 : Noise::~Noise()
480 : {
481 0 : delete[] gradient_buf;
482 0 : delete[] persist_buf;
483 0 : delete[] noise_buf;
484 0 : delete[] result;
485 0 : }
486 :
487 :
488 0 : void Noise::allocBuffers()
489 : {
490 0 : if (sx < 1)
491 0 : sx = 1;
492 0 : if (sy < 1)
493 0 : sy = 1;
494 0 : if (sz < 1)
495 0 : sz = 1;
496 :
497 0 : this->noise_buf = NULL;
498 0 : resizeNoiseBuf(sz > 1);
499 :
500 0 : delete[] gradient_buf;
501 0 : delete[] persist_buf;
502 0 : delete[] result;
503 :
504 : try {
505 0 : size_t bufsize = sx * sy * sz;
506 0 : this->persist_buf = NULL;
507 0 : this->gradient_buf = new float[bufsize];
508 0 : this->result = new float[bufsize];
509 0 : } catch (std::bad_alloc &e) {
510 0 : throw InvalidNoiseParamsException();
511 : }
512 0 : }
513 :
514 :
515 0 : void Noise::setSize(u32 sx, u32 sy, u32 sz)
516 : {
517 0 : this->sx = sx;
518 0 : this->sy = sy;
519 0 : this->sz = sz;
520 :
521 0 : allocBuffers();
522 0 : }
523 :
524 :
525 0 : void Noise::setSpreadFactor(v3f spread)
526 : {
527 0 : this->np.spread = spread;
528 :
529 0 : resizeNoiseBuf(sz > 1);
530 0 : }
531 :
532 :
533 0 : void Noise::setOctaves(int octaves)
534 : {
535 0 : this->np.octaves = octaves;
536 :
537 0 : resizeNoiseBuf(sz > 1);
538 0 : }
539 :
540 :
541 0 : void Noise::resizeNoiseBuf(bool is3d)
542 : {
543 : //maximum possible spread value factor
544 0 : float ofactor = (np.lacunarity > 1.0) ?
545 0 : pow(np.lacunarity, np.octaves - 1) :
546 0 : np.lacunarity;
547 :
548 : // noise lattice point count
549 : // (int)(sz * spread * ofactor) is # of lattice points crossed due to length
550 0 : float num_noise_points_x = sx * ofactor / np.spread.X;
551 0 : float num_noise_points_y = sy * ofactor / np.spread.Y;
552 0 : float num_noise_points_z = sz * ofactor / np.spread.Z;
553 :
554 : // protect against obviously invalid parameters
555 0 : if (num_noise_points_x > 1000000000.f ||
556 0 : num_noise_points_y > 1000000000.f ||
557 : num_noise_points_z > 1000000000.f)
558 0 : throw InvalidNoiseParamsException();
559 :
560 : // + 2 for the two initial endpoints
561 : // + 1 for potentially crossing a boundary due to offset
562 0 : size_t nlx = (size_t)ceil(num_noise_points_x) + 3;
563 0 : size_t nly = (size_t)ceil(num_noise_points_y) + 3;
564 0 : size_t nlz = is3d ? (size_t)ceil(num_noise_points_z) + 3 : 1;
565 :
566 0 : delete[] noise_buf;
567 : try {
568 0 : noise_buf = new float[nlx * nly * nlz];
569 0 : } catch (std::bad_alloc &e) {
570 0 : throw InvalidNoiseParamsException();
571 : }
572 0 : }
573 :
574 :
575 : /*
576 : * NB: This algorithm is not optimal in terms of space complexity. The entire
577 : * integer lattice of noise points could be done as 2 lines instead, and for 3D,
578 : * 2 lines + 2 planes.
579 : * However, this would require the noise calls to be interposed with the
580 : * interpolation loops, which may trash the icache, leading to lower overall
581 : * performance.
582 : * Another optimization that could save half as many noise calls is to carry over
583 : * values from the previous noise lattice as midpoints in the new lattice for the
584 : * next octave.
585 : */
586 : #define idx(x, y) ((y) * nlx + (x))
587 0 : void Noise::gradientMap2D(
588 : float x, float y,
589 : float step_x, float step_y,
590 : int seed)
591 : {
592 : float v00, v01, v10, v11, u, v, orig_u;
593 : u32 index, i, j, noisex, noisey;
594 : u32 nlx, nly;
595 : s32 x0, y0;
596 :
597 0 : bool eased = np.flags & (NOISE_FLAG_DEFAULTS | NOISE_FLAG_EASED);
598 : Interp2dFxn interpolate = eased ?
599 0 : biLinearInterpolation : biLinearInterpolationNoEase;
600 :
601 0 : x0 = floor(x);
602 0 : y0 = floor(y);
603 0 : u = x - (float)x0;
604 0 : v = y - (float)y0;
605 0 : orig_u = u;
606 :
607 : //calculate noise point lattice
608 0 : nlx = (u32)(u + sx * step_x) + 2;
609 0 : nly = (u32)(v + sy * step_y) + 2;
610 0 : index = 0;
611 0 : for (j = 0; j != nly; j++)
612 0 : for (i = 0; i != nlx; i++)
613 0 : noise_buf[index++] = noise2d(x0 + i, y0 + j, seed);
614 :
615 : //calculate interpolations
616 0 : index = 0;
617 0 : noisey = 0;
618 0 : for (j = 0; j != sy; j++) {
619 0 : v00 = noise_buf[idx(0, noisey)];
620 0 : v10 = noise_buf[idx(1, noisey)];
621 0 : v01 = noise_buf[idx(0, noisey + 1)];
622 0 : v11 = noise_buf[idx(1, noisey + 1)];
623 :
624 0 : u = orig_u;
625 0 : noisex = 0;
626 0 : for (i = 0; i != sx; i++) {
627 0 : gradient_buf[index++] = interpolate(v00, v10, v01, v11, u, v);
628 :
629 0 : u += step_x;
630 0 : if (u >= 1.0) {
631 0 : u -= 1.0;
632 0 : noisex++;
633 0 : v00 = v10;
634 0 : v01 = v11;
635 0 : v10 = noise_buf[idx(noisex + 1, noisey)];
636 0 : v11 = noise_buf[idx(noisex + 1, noisey + 1)];
637 : }
638 : }
639 :
640 0 : v += step_y;
641 0 : if (v >= 1.0) {
642 0 : v -= 1.0;
643 0 : noisey++;
644 : }
645 : }
646 0 : }
647 : #undef idx
648 :
649 :
650 : #define idx(x, y, z) ((z) * nly * nlx + (y) * nlx + (x))
651 0 : void Noise::gradientMap3D(
652 : float x, float y, float z,
653 : float step_x, float step_y, float step_z,
654 : int seed)
655 : {
656 : float v000, v010, v100, v110;
657 : float v001, v011, v101, v111;
658 : float u, v, w, orig_u, orig_v;
659 : u32 index, i, j, k, noisex, noisey, noisez;
660 : u32 nlx, nly, nlz;
661 : s32 x0, y0, z0;
662 :
663 0 : Interp3dFxn interpolate = (np.flags & NOISE_FLAG_EASED) ?
664 0 : triLinearInterpolation : triLinearInterpolationNoEase;
665 :
666 0 : x0 = floor(x);
667 0 : y0 = floor(y);
668 0 : z0 = floor(z);
669 0 : u = x - (float)x0;
670 0 : v = y - (float)y0;
671 0 : w = z - (float)z0;
672 0 : orig_u = u;
673 0 : orig_v = v;
674 :
675 : //calculate noise point lattice
676 0 : nlx = (u32)(u + sx * step_x) + 2;
677 0 : nly = (u32)(v + sy * step_y) + 2;
678 0 : nlz = (u32)(w + sz * step_z) + 2;
679 0 : index = 0;
680 0 : for (k = 0; k != nlz; k++)
681 0 : for (j = 0; j != nly; j++)
682 0 : for (i = 0; i != nlx; i++)
683 0 : noise_buf[index++] = noise3d(x0 + i, y0 + j, z0 + k, seed);
684 :
685 : //calculate interpolations
686 0 : index = 0;
687 0 : noisey = 0;
688 0 : noisez = 0;
689 0 : for (k = 0; k != sz; k++) {
690 0 : v = orig_v;
691 0 : noisey = 0;
692 0 : for (j = 0; j != sy; j++) {
693 0 : v000 = noise_buf[idx(0, noisey, noisez)];
694 0 : v100 = noise_buf[idx(1, noisey, noisez)];
695 0 : v010 = noise_buf[idx(0, noisey + 1, noisez)];
696 0 : v110 = noise_buf[idx(1, noisey + 1, noisez)];
697 0 : v001 = noise_buf[idx(0, noisey, noisez + 1)];
698 0 : v101 = noise_buf[idx(1, noisey, noisez + 1)];
699 0 : v011 = noise_buf[idx(0, noisey + 1, noisez + 1)];
700 0 : v111 = noise_buf[idx(1, noisey + 1, noisez + 1)];
701 :
702 0 : u = orig_u;
703 0 : noisex = 0;
704 0 : for (i = 0; i != sx; i++) {
705 0 : gradient_buf[index++] = interpolate(
706 : v000, v100, v010, v110,
707 : v001, v101, v011, v111,
708 0 : u, v, w);
709 :
710 0 : u += step_x;
711 0 : if (u >= 1.0) {
712 0 : u -= 1.0;
713 0 : noisex++;
714 0 : v000 = v100;
715 0 : v010 = v110;
716 0 : v100 = noise_buf[idx(noisex + 1, noisey, noisez)];
717 0 : v110 = noise_buf[idx(noisex + 1, noisey + 1, noisez)];
718 0 : v001 = v101;
719 0 : v011 = v111;
720 0 : v101 = noise_buf[idx(noisex + 1, noisey, noisez + 1)];
721 0 : v111 = noise_buf[idx(noisex + 1, noisey + 1, noisez + 1)];
722 : }
723 : }
724 :
725 0 : v += step_y;
726 0 : if (v >= 1.0) {
727 0 : v -= 1.0;
728 0 : noisey++;
729 : }
730 : }
731 :
732 0 : w += step_z;
733 0 : if (w >= 1.0) {
734 0 : w -= 1.0;
735 0 : noisez++;
736 : }
737 : }
738 0 : }
739 : #undef idx
740 :
741 :
742 0 : float *Noise::perlinMap2D(float x, float y, float *persistence_map)
743 : {
744 0 : float f = 1.0, g = 1.0;
745 0 : size_t bufsize = sx * sy;
746 :
747 0 : x /= np.spread.X;
748 0 : y /= np.spread.Y;
749 :
750 0 : memset(result, 0, sizeof(float) * bufsize);
751 :
752 0 : if (persistence_map) {
753 0 : if (!persist_buf)
754 0 : persist_buf = new float[bufsize];
755 0 : for (size_t i = 0; i != bufsize; i++)
756 0 : persist_buf[i] = 1.0;
757 : }
758 :
759 0 : for (size_t oct = 0; oct < np.octaves; oct++) {
760 0 : gradientMap2D(x * f, y * f,
761 0 : f / np.spread.X, f / np.spread.Y,
762 0 : seed + np.seed + oct);
763 :
764 0 : updateResults(g, persist_buf, persistence_map, bufsize);
765 :
766 0 : f *= np.lacunarity;
767 0 : g *= np.persist;
768 : }
769 :
770 0 : if (fabs(np.offset - 0.f) > 0.00001 || fabs(np.scale - 1.f) > 0.00001) {
771 0 : for (size_t i = 0; i != bufsize; i++)
772 0 : result[i] = result[i] * np.scale + np.offset;
773 : }
774 :
775 0 : return result;
776 : }
777 :
778 :
779 0 : float *Noise::perlinMap3D(float x, float y, float z, float *persistence_map)
780 : {
781 0 : float f = 1.0, g = 1.0;
782 0 : size_t bufsize = sx * sy * sz;
783 :
784 0 : x /= np.spread.X;
785 0 : y /= np.spread.Y;
786 0 : z /= np.spread.Z;
787 :
788 0 : memset(result, 0, sizeof(float) * bufsize);
789 :
790 0 : if (persistence_map) {
791 0 : if (!persist_buf)
792 0 : persist_buf = new float[bufsize];
793 0 : for (size_t i = 0; i != bufsize; i++)
794 0 : persist_buf[i] = 1.0;
795 : }
796 :
797 0 : for (size_t oct = 0; oct < np.octaves; oct++) {
798 0 : gradientMap3D(x * f, y * f, z * f,
799 0 : f / np.spread.X, f / np.spread.Y, f / np.spread.Z,
800 0 : seed + np.seed + oct);
801 :
802 0 : updateResults(g, persist_buf, persistence_map, bufsize);
803 :
804 0 : f *= np.lacunarity;
805 0 : g *= np.persist;
806 : }
807 :
808 0 : if (fabs(np.offset - 0.f) > 0.00001 || fabs(np.scale - 1.f) > 0.00001) {
809 0 : for (size_t i = 0; i != bufsize; i++)
810 0 : result[i] = result[i] * np.scale + np.offset;
811 : }
812 :
813 0 : return result;
814 : }
815 :
816 :
817 0 : void Noise::updateResults(float g, float *gmap,
818 : float *persistence_map, size_t bufsize)
819 : {
820 : // This looks very ugly, but it is 50-70% faster than having
821 : // conditional statements inside the loop
822 0 : if (np.flags & NOISE_FLAG_ABSVALUE) {
823 0 : if (persistence_map) {
824 0 : for (size_t i = 0; i != bufsize; i++) {
825 0 : result[i] += gmap[i] * fabs(gradient_buf[i]);
826 0 : gmap[i] *= persistence_map[i];
827 : }
828 : } else {
829 0 : for (size_t i = 0; i != bufsize; i++)
830 0 : result[i] += g * fabs(gradient_buf[i]);
831 : }
832 : } else {
833 0 : if (persistence_map) {
834 0 : for (size_t i = 0; i != bufsize; i++) {
835 0 : result[i] += gmap[i] * gradient_buf[i];
836 0 : gmap[i] *= persistence_map[i];
837 : }
838 : } else {
839 0 : for (size_t i = 0; i != bufsize; i++)
840 0 : result[i] += g * gradient_buf[i];
841 : }
842 : }
843 3 : }
|