X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fnoise.h;h=854781731b9cc19920e963d5d71e0da167aaf600;hb=fb4815c660d6d9cfc9df76a3ba763095b9701925;hp=66be8db93d440cd0d781c58181474e9a8c5ba644;hpb=fb2bc956b18bd70a47bff00d5726d4754867856a;p=dragonfireclient.git diff --git a/src/noise.h b/src/noise.h index 66be8db93..854781731 100644 --- a/src/noise.h +++ b/src/noise.h @@ -23,52 +23,82 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef NOISE_HEADER -#define NOISE_HEADER +#pragma once -#include "debug.h" #include "irr_v3d.h" +#include "exceptions.h" #include "util/string.h" +#if defined(RANDOM_MIN) +#undef RANDOM_MIN +#endif +#if defined(RANDOM_MAX) +#undef RANDOM_MAX +#endif + extern FlagDesc flagdesc_noiseparams[]; -class PseudoRandom -{ +// Note: this class is not polymorphic so that its high level of +// optimizability may be preserved in the common use case +class PseudoRandom { public: - PseudoRandom(): m_next(0) - { - } - PseudoRandom(int seed): m_next(seed) + const static u32 RANDOM_RANGE = 32767; + + inline PseudoRandom(int seed=0): + m_next(seed) { } - void seed(int seed) + + inline void seed(int seed) { m_next = seed; } - // Returns 0...32767 - int next() + + inline int next() { m_next = m_next * 1103515245 + 12345; - return((unsigned)(m_next/65536) % 32768); + return (unsigned)(m_next / 65536) % (RANDOM_RANGE + 1); } - int range(int min, int max) + + inline int range(int min, int max) { - if(max-min > 32768/10) - { - //dstream<<"WARNING: PseudoRandom::range: max > 32767"< max) - { - assert(0); - return max; - } - return (next()%(max-min+1))+min; + if (max < min) + throw PrngException("Invalid range (max < min)"); + /* + Here, we ensure the range is not too large relative to RANDOM_MAX, + as otherwise the effects of bias would become noticable. Unlike + PcgRandom, we cannot modify this RNG's range as it would change the + output of this RNG for reverse compatibility. + */ + if ((u32)(max - min) > (RANDOM_RANGE + 1) / 10) + throw PrngException("Range too large"); + + return (next() % (max - min + 1)) + min; } + private: int m_next; }; +class PcgRandom { +public: + const static s32 RANDOM_MIN = -0x7fffffff - 1; + const static s32 RANDOM_MAX = 0x7fffffff; + const static u32 RANDOM_RANGE = 0xffffffff; + + PcgRandom(u64 state=0x853c49e6748fea9bULL, u64 seq=0xda3e39cb94b95bdbULL); + void seed(u64 state, u64 seq=0xda3e39cb94b95bdbULL); + u32 next(); + u32 range(u32 bound); + s32 range(s32 min, s32 max); + void bytes(void *out, size_t len); + s32 randNormalDist(s32 min, s32 max, int num_trials=6); + +private: + u64 m_state; + u64 m_inc; +}; + #define NOISE_FLAG_DEFAULTS 0x01 #define NOISE_FLAG_EASED 0x02 #define NOISE_FLAG_ABSVALUE 0x04 @@ -78,27 +108,18 @@ class PseudoRandom #define NOISE_FLAG_SIMPLEX 0x10 struct NoiseParams { - float offset; - float scale; - v3f spread; - s32 seed; - u16 octaves; - float persist; - float lacunarity; - u32 flags; - - NoiseParams() { - offset = 0.0f; - scale = 1.0f; - spread = v3f(250, 250, 250); - seed = 12345; - octaves = 3; - persist = 0.6f; - lacunarity = 2.0f; - flags = NOISE_FLAG_DEFAULTS; - } - - NoiseParams(float offset_, float scale_, v3f spread_, s32 seed_, + float offset = 0.0f; + float scale = 1.0f; + v3f spread = v3f(250, 250, 250); + s32 seed = 12345; + u16 octaves = 3; + float persist = 0.6f; + float lacunarity = 2.0f; + u32 flags = NOISE_FLAG_DEFAULTS; + + NoiseParams() = default; + + NoiseParams(float offset_, float scale_, const v3f &spread_, s32 seed_, u16 octaves_, float persist_, float lacunarity_, u32 flags_=NOISE_FLAG_DEFAULTS) { @@ -113,70 +134,103 @@ struct NoiseParams { } }; - -// Convenience macros for getting/setting NoiseParams in Settings as a string -// WARNING: Deprecated, use Settings::getNoiseParamsFromValue() instead -#define NOISEPARAMS_FMT_STR "f,f,v3,s32,u16,f" -//#define getNoiseParams(x, y) getStruct((x), NOISEPARAMS_FMT_STR, &(y), sizeof(y)) -//#define setNoiseParams(x, y) setStruct((x), NOISEPARAMS_FMT_STR, &(y)) - class Noise { public: NoiseParams np; - int seed; - int sx; - int sy; - int sz; - float *noise_buf; - float *gradient_buf; - float *persist_buf; - float *result; - - Noise(NoiseParams *np, int seed, int sx, int sy, int sz=1); + s32 seed; + u32 sx; + u32 sy; + u32 sz; + float *noise_buf = nullptr; + float *gradient_buf = nullptr; + float *persist_buf = nullptr; + float *result = nullptr; + + Noise(const NoiseParams *np, s32 seed, u32 sx, u32 sy, u32 sz=1); ~Noise(); - void setSize(int sx, int sy, int sz=1); + void setSize(u32 sx, u32 sy, u32 sz=1); void setSpreadFactor(v3f spread); void setOctaves(int octaves); void gradientMap2D( float x, float y, float step_x, float step_y, - int seed); + s32 seed); void gradientMap3D( float x, float y, float z, float step_x, float step_y, float step_z, - int seed); + s32 seed); float *perlinMap2D(float x, float y, float *persistence_map=NULL); float *perlinMap3D(float x, float y, float z, float *persistence_map=NULL); - void transformNoiseMap(); + inline float *perlinMap2D_PO(float x, float xoff, float y, float yoff, + float *persistence_map=NULL) + { + return perlinMap2D( + x + xoff * np.spread.X, + y + yoff * np.spread.Y, + persistence_map); + } + + inline float *perlinMap3D_PO(float x, float xoff, float y, float yoff, + float z, float zoff, float *persistence_map=NULL) + { + return perlinMap3D( + x + xoff * np.spread.X, + y + yoff * np.spread.Y, + z + zoff * np.spread.Z, + persistence_map); + } private: void allocBuffers(); void resizeNoiseBuf(bool is3d); - void updateResults(float g, float *gmap, float *persistence_map, size_t bufsize); + void updateResults(float g, float *gmap, const float *persistence_map, + size_t bufsize); }; +float NoisePerlin2D(const NoiseParams *np, float x, float y, s32 seed); +float NoisePerlin3D(const NoiseParams *np, float x, float y, float z, s32 seed); + +inline float NoisePerlin2D_PO(NoiseParams *np, float x, float xoff, + float y, float yoff, s32 seed) +{ + return NoisePerlin2D(np, + x + xoff * np->spread.X, + y + yoff * np->spread.Y, + seed); +} + +inline float NoisePerlin3D_PO(NoiseParams *np, float x, float xoff, + float y, float yoff, float z, float zoff, s32 seed) +{ + return NoisePerlin3D(np, + x + xoff * np->spread.X, + y + yoff * np->spread.Y, + z + zoff * np->spread.Z, + seed); +} + // Return value: -1 ... 1 -float noise2d(int x, int y, int seed); -float noise3d(int x, int y, int z, int seed); +float noise2d(int x, int y, s32 seed); +float noise3d(int x, int y, int z, s32 seed); -float noise2d_gradient(float x, float y, int seed, bool eased=true); -float noise3d_gradient(float x, float y, float z, int seed, bool eased=false); +float noise2d_gradient(float x, float y, s32 seed, bool eased=true); +float noise3d_gradient(float x, float y, float z, s32 seed, bool eased=false); -float noise2d_perlin(float x, float y, int seed, +float noise2d_perlin(float x, float y, s32 seed, int octaves, float persistence, bool eased=true); -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=true); -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=false); -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=false); inline float easeCurve(float t) @@ -185,39 +239,3 @@ inline float easeCurve(float t) } float contour(float v); - -#define NoisePerlin2D(np, x, y, s) \ - ((np)->offset + (np)->scale * noise2d_perlin( \ - (float)(x) / (np)->spread.X, \ - (float)(y) / (np)->spread.Y, \ - (s) + (np)->seed, (np)->octaves, (np)->persist)) - -#define NoisePerlin2DNoTxfm(np, x, y, s) \ - (noise2d_perlin( \ - (float)(x) / (np)->spread.X, \ - (float)(y) / (np)->spread.Y, \ - (s) + (np)->seed, (np)->octaves, (np)->persist)) - -#define NoisePerlin2DPosOffset(np, x, xoff, y, yoff, s) \ - ((np)->offset + (np)->scale * noise2d_perlin( \ - (float)(xoff) + (float)(x) / (np)->spread.X, \ - (float)(yoff) + (float)(y) / (np)->spread.Y, \ - (s) + (np)->seed, (np)->octaves, (np)->persist)) - -#define NoisePerlin2DNoTxfmPosOffset(np, x, xoff, y, yoff, s) \ - (noise2d_perlin( \ - (float)(xoff) + (float)(x) / (np)->spread.X, \ - (float)(yoff) + (float)(y) / (np)->spread.Y, \ - (s) + (np)->seed, (np)->octaves, (np)->persist)) - -#define NoisePerlin3D(np, x, y, z, s) ((np)->offset + (np)->scale * \ - noise3d_perlin((float)(x) / (np)->spread.X, (float)(y) / (np)->spread.Y, \ - (float)(z) / (np)->spread.Z, (s) + (np)->seed, (np)->octaves, (np)->persist)) - -#define NoisePerlin3DEased(np, x, y, z, s) ((np)->offset + (np)->scale * \ - noise3d_perlin((float)(x) / (np)->spread.X, (float)(y) / (np)->spread.Y, \ - (float)(z) / (np)->spread.Z, (s) + (np)->seed, (np)->octaves, \ - (np)->persist, true)) - -#endif -