X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fnoise.cpp;h=255d3faee001c5770f0c864434fb738bc5998720;hb=2b3490db1f0e99a427e34135770f8e5afcf275ce;hp=443c405cec8030a88a1b0b2175b26b3761356e09;hpb=aab7c83d0229c2c7aa3b60de3ca1b1a4eb326b55;p=dragonfireclient.git diff --git a/src/noise.cpp b/src/noise.cpp index 443c405ce..255d3faee 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -23,10 +23,10 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include "noise.h" #include -#include // memset +#include // memset #include "debug.h" #include "util/numeric.h" #include "util/string.h" @@ -47,8 +47,8 @@ typedef float (*Interp3dFxn)( float x, float y, float z); float cos_lookup[16] = { - 1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238, - 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238 + 1.0f, 0.9238f, 0.7071f, 0.3826f, .0f, -0.3826f, -0.7071f, -0.9238f, + 1.0f, -0.9238f, -0.7071f, -0.3826f, .0f, 0.3826f, 0.7071f, 0.9238f }; FlagDesc flagdesc_noiseparams[] = { @@ -90,23 +90,35 @@ u32 PcgRandom::next() u32 PcgRandom::range(u32 bound) { + // If the bound is 0, we cover the whole RNG's range + if (bound == 0) + return next(); + /* - If the bound is not a multiple of the RNG's range, it may cause bias, - e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2. - Using rand() % 3, the number 0 would be twice as likely to appear. - With a very large RNG range, the effect becomes less prevalent but - still present. This can be solved by modifying the range of the RNG - to become a multiple of bound by dropping values above the a threshhold. - In our example, threshhold == 4 - 3 = 1 % 3 == 1, so reject 0, thus - making the range 3 with no bias. - - This loop looks dangerous, but will always terminate due to the - RNG's property of uniformity. + This is an optimization of the expression: + 0x100000000ull % bound + since 64-bit modulo operations typically much slower than 32. */ - u32 threshhold = -bound % bound; + u32 threshold = -bound % bound; u32 r; - while ((r = next()) < threshhold) + /* + If the bound is not a multiple of the RNG's range, it may cause bias, + e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2. + Using rand() % 3, the number 0 would be twice as likely to appear. + With a very large RNG range, the effect becomes less prevalent but + still present. + + This can be solved by modifying the range of the RNG to become a + multiple of bound by dropping values above the a threshold. + + In our example, threshold == 4 % 3 == 1, so reject values < 1 + (that is, 0), thus making the range == 3 with no bias. + + This loop may look dangerous, but will always terminate due to the + RNG's property of uniformity. + */ + while ((r = next()) < threshold) ; return r % bound; @@ -118,7 +130,9 @@ s32 PcgRandom::range(s32 min, s32 max) if (max < min) throw PrngException("Invalid range (max < min)"); - u32 bound = max - min + 1; + // We have to cast to s64 because otherwise this could overflow, + // and signed overflow is undefined behavior. + u32 bound = (s64)max - (s64)min + 1; return range(bound) + min; } @@ -153,23 +167,23 @@ s32 PcgRandom::randNormalDist(s32 min, s32 max, int num_trials) /////////////////////////////////////////////////////////////////////////////// -float noise2d(int x, int y, int seed) +float noise2d(int x, int y, s32 seed) { - int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + unsigned int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_SEED * seed) & 0x7fffffff; n = (n >> 13) ^ n; n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; - return 1.f - (float)n / 0x40000000; + return 1.f - (float)(int)n / 0x40000000; } -float noise3d(int x, int y, int z, int seed) +float noise3d(int x, int y, int z, s32 seed) { - int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z + unsigned int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z + NOISE_MAGIC_SEED * seed) & 0x7fffffff; n = (n >> 13) ^ n; n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; - return 1.f - (float)n / 0x40000000; + return 1.f - (float)(int)n / 0x40000000; } @@ -232,7 +246,7 @@ float triLinearInterpolationNoEase( return linearInterpolation(u, v, z); } -float noise2d_gradient(float x, float y, int seed, bool eased) +float noise2d_gradient(float x, float y, s32 seed, bool eased) { // Calculate the integer coordinates int x0 = myfloor(x); @@ -248,12 +262,12 @@ float noise2d_gradient(float x, float y, int seed, bool eased) // Interpolate if (eased) return biLinearInterpolation(v00, v10, v01, v11, xl, yl); - else - return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl); + + return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl); } -float noise3d_gradient(float x, float y, float z, int seed, bool eased) +float noise3d_gradient(float x, float y, float z, s32 seed, bool eased) { // Calculate the integer coordinates int x0 = myfloor(x); @@ -278,16 +292,16 @@ float noise3d_gradient(float x, float y, float z, int seed, bool eased) v000, v100, v010, v110, v001, v101, v011, v111, xl, yl, zl); - } else { - return triLinearInterpolationNoEase( - v000, v100, v010, v110, - v001, v101, v011, v111, - xl, yl, zl); } + + return triLinearInterpolationNoEase( + v000, v100, v010, v110, + v001, v101, v011, v111, + xl, yl, zl); } -float noise2d_perlin(float x, float y, int seed, +float noise2d_perlin(float x, float y, s32 seed, int octaves, float persistence, bool eased) { float a = 0; @@ -303,14 +317,14 @@ float noise2d_perlin(float x, float y, int seed, } -float noise2d_perlin_abs(float x, float y, int seed, +float noise2d_perlin_abs(float x, float y, s32 seed, int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; for (int i = 0; i < octaves; i++) { - a += g * fabs(noise2d_gradient(x * f, y * f, seed + i, eased)); + a += g * std::fabs(noise2d_gradient(x * f, y * f, seed + i, eased)); f *= 2.0; g *= persistence; } @@ -318,7 +332,7 @@ float noise2d_perlin_abs(float x, float y, int seed, } -float noise3d_perlin(float x, float y, float z, int seed, +float noise3d_perlin(float x, float y, float z, s32 seed, int octaves, float persistence, bool eased) { float a = 0; @@ -333,14 +347,14 @@ float noise3d_perlin(float x, float y, float z, int seed, } -float noise3d_perlin_abs(float x, float y, float z, int seed, +float noise3d_perlin_abs(float x, float y, float z, s32 seed, int octaves, float persistence, bool eased) { float a = 0; float f = 1.0; float g = 1.0; for (int i = 0; i < octaves; i++) { - a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i, eased)); + a += g * std::fabs(noise3d_gradient(x * f, y * f, z * f, seed + i, eased)); f *= 2.0; g *= persistence; } @@ -350,7 +364,7 @@ float noise3d_perlin_abs(float x, float y, float z, int seed, float contour(float v) { - v = fabs(v); + v = std::fabs(v); if (v >= 1.0) return 0.0; return (1.0 - v); @@ -360,7 +374,7 @@ float contour(float v) ///////////////////////// [ New noise ] //////////////////////////// -float NoisePerlin2D(NoiseParams *np, float x, float y, int seed) +float NoisePerlin2D(NoiseParams *np, float x, float y, s32 seed) { float a = 0; float f = 1.0; @@ -375,7 +389,7 @@ float NoisePerlin2D(NoiseParams *np, float x, float y, int seed) np->flags & (NOISE_FLAG_DEFAULTS | NOISE_FLAG_EASED)); if (np->flags & NOISE_FLAG_ABSVALUE) - noiseval = fabs(noiseval); + noiseval = std::fabs(noiseval); a += g * noiseval; f *= np->lacunarity; @@ -386,7 +400,7 @@ float NoisePerlin2D(NoiseParams *np, float x, float y, int seed) } -float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed) +float NoisePerlin3D(NoiseParams *np, float x, float y, float z, s32 seed) { float a = 0; float f = 1.0; @@ -402,7 +416,7 @@ float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed) np->flags & NOISE_FLAG_EASED); if (np->flags & NOISE_FLAG_ABSVALUE) - noiseval = fabs(noiseval); + noiseval = std::fabs(noiseval); a += g * noiseval; f *= np->lacunarity; @@ -413,7 +427,7 @@ float NoisePerlin3D(NoiseParams *np, float x, float y, float z, int seed) } -Noise::Noise(NoiseParams *np_, int seed, u32 sx, u32 sy, u32 sz) +Noise::Noise(NoiseParams *np_, s32 seed, u32 sx, u32 sy, u32 sz) { memcpy(&np, np_, sizeof(np)); this->seed = seed; @@ -421,10 +435,6 @@ Noise::Noise(NoiseParams *np_, int seed, u32 sx, u32 sy, u32 sz) this->sy = sy; this->sz = sz; - this->persist_buf = NULL; - this->gradient_buf = NULL; - this->result = NULL; - allocBuffers(); } @@ -512,9 +522,9 @@ void Noise::resizeNoiseBuf(bool is3d) // + 2 for the two initial endpoints // + 1 for potentially crossing a boundary due to offset - size_t nlx = (size_t)ceil(num_noise_points_x) + 3; - size_t nly = (size_t)ceil(num_noise_points_y) + 3; - size_t nlz = is3d ? (size_t)ceil(num_noise_points_z) + 3 : 1; + size_t nlx = (size_t)std::ceil(num_noise_points_x) + 3; + size_t nly = (size_t)std::ceil(num_noise_points_y) + 3; + size_t nlz = is3d ? (size_t)std::ceil(num_noise_points_z) + 3 : 1; delete[] noise_buf; try { @@ -540,7 +550,7 @@ void Noise::resizeNoiseBuf(bool is3d) void Noise::gradientMap2D( float x, float y, float step_x, float step_y, - int seed) + s32 seed) { float v00, v01, v10, v11, u, v, orig_u; u32 index, i, j, noisex, noisey; @@ -551,8 +561,8 @@ void Noise::gradientMap2D( Interp2dFxn interpolate = eased ? biLinearInterpolation : biLinearInterpolationNoEase; - x0 = floor(x); - y0 = floor(y); + x0 = std::floor(x); + y0 = std::floor(y); u = x - (float)x0; v = y - (float)y0; orig_u = u; @@ -604,7 +614,7 @@ void Noise::gradientMap2D( void Noise::gradientMap3D( float x, float y, float z, float step_x, float step_y, float step_z, - int seed) + s32 seed) { float v000, v010, v100, v110; float v001, v011, v101, v111; @@ -616,9 +626,9 @@ void Noise::gradientMap3D( Interp3dFxn interpolate = (np.flags & NOISE_FLAG_EASED) ? triLinearInterpolation : triLinearInterpolationNoEase; - x0 = floor(x); - y0 = floor(y); - z0 = floor(z); + x0 = std::floor(x); + y0 = std::floor(y); + z0 = std::floor(z); u = x - (float)x0; v = y - (float)y0; w = z - (float)z0; @@ -720,7 +730,7 @@ float *Noise::perlinMap2D(float x, float y, float *persistence_map) g *= np.persist; } - if (fabs(np.offset - 0.f) > 0.00001 || fabs(np.scale - 1.f) > 0.00001) { + if (std::fabs(np.offset - 0.f) > 0.00001 || std::fabs(np.scale - 1.f) > 0.00001) { for (size_t i = 0; i != bufsize; i++) result[i] = result[i] * np.scale + np.offset; } @@ -758,7 +768,7 @@ float *Noise::perlinMap3D(float x, float y, float z, float *persistence_map) g *= np.persist; } - if (fabs(np.offset - 0.f) > 0.00001 || fabs(np.scale - 1.f) > 0.00001) { + if (std::fabs(np.offset - 0.f) > 0.00001 || std::fabs(np.scale - 1.f) > 0.00001) { for (size_t i = 0; i != bufsize; i++) result[i] = result[i] * np.scale + np.offset; } @@ -768,19 +778,19 @@ float *Noise::perlinMap3D(float x, float y, float z, float *persistence_map) void Noise::updateResults(float g, float *gmap, - float *persistence_map, size_t bufsize) + const float *persistence_map, size_t bufsize) { // This looks very ugly, but it is 50-70% faster than having // conditional statements inside the loop if (np.flags & NOISE_FLAG_ABSVALUE) { if (persistence_map) { for (size_t i = 0; i != bufsize; i++) { - result[i] += gmap[i] * fabs(gradient_buf[i]); + result[i] += gmap[i] * std::fabs(gradient_buf[i]); gmap[i] *= persistence_map[i]; } } else { for (size_t i = 0; i != bufsize; i++) - result[i] += g * fabs(gradient_buf[i]); + result[i] += g * std::fabs(gradient_buf[i]); } } else { if (persistence_map) {