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