diff --git a/panda/src/mathutil/perlinNoise.I b/panda/src/mathutil/perlinNoise.I index 1efce2085f..f0c364dae3 100644 --- a/panda/src/mathutil/perlinNoise.I +++ b/panda/src/mathutil/perlinNoise.I @@ -25,7 +25,8 @@ //////////////////////////////////////////////////////////////////// INLINE double PerlinNoise:: fade(double t) { - return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); + // return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); + return (3.0 - 2.0 * t) * t * t; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/mathutil/perlinNoise.cxx b/panda/src/mathutil/perlinNoise.cxx index 6224dac21a..80bcdb168e 100644 --- a/panda/src/mathutil/perlinNoise.cxx +++ b/panda/src/mathutil/perlinNoise.cxx @@ -33,9 +33,21 @@ bool PerlinNoise::_got_first_seed = false; PerlinNoise:: PerlinNoise(int table_size, unsigned long seed) : _table_size(table_size), + _table_size_mask(table_size - 1), _mersenne(seed != 0 ? seed : get_next_seed()) { - // The _index table is just a randomly shuffled index. + // It is necessary for _table_size to be a power of 2. +#ifndef NDEBUG + if (_table_size != 0) { + bool table_size_power_2 = ((_table_size ^ _table_size_mask) == (_table_size + _table_size_mask)); + nassertd(table_size_power_2) { + _table_size = 0; + _table_size_mask = 0; + } + } +#endif // NDEBUG + + // The _index table is just a randomly shuffled index // table. _index.reserve(_table_size * 2); int i; @@ -56,3 +68,32 @@ PerlinNoise(int table_size, unsigned long seed) : _index.push_back(_index[i]); } } + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise::Copy Constructor +// Access: Protected +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +PerlinNoise:: +PerlinNoise(const PerlinNoise ©) : + _table_size(copy._table_size), + _table_size_mask(copy._table_size_mask), + _mersenne(copy._mersenne), + _index(copy._index) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise::Copy Assignment Operator +// Access: Protected +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +void PerlinNoise:: +operator = (const PerlinNoise ©) { + _table_size = copy._table_size; + _table_size_mask = copy._table_size_mask; + _mersenne = copy._mersenne; + _index = copy._index; +} diff --git a/panda/src/mathutil/perlinNoise.h b/panda/src/mathutil/perlinNoise.h index 71e88bc96c..5e8e8ae4d4 100644 --- a/panda/src/mathutil/perlinNoise.h +++ b/panda/src/mathutil/perlinNoise.h @@ -34,6 +34,8 @@ class EXPCL_PANDA PerlinNoise { protected: PerlinNoise(int table_size, unsigned long seed); + PerlinNoise(const PerlinNoise ©); + void operator = (const PerlinNoise ©); INLINE static double fade(double t); INLINE static double lerp(double t, double a, double b); @@ -49,6 +51,7 @@ PUBLISHED: protected: int _table_size; + int _table_size_mask; Mersenne _mersenne; static Mersenne _next_seed; diff --git a/panda/src/mathutil/perlinNoise2.I b/panda/src/mathutil/perlinNoise2.I index 6b1c5b9e53..f9ad2b2e85 100644 --- a/panda/src/mathutil/perlinNoise2.I +++ b/panda/src/mathutil/perlinNoise2.I @@ -17,6 +17,49 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::Default Constructor +// Access: Published +// Description: The default constructor makes an invalid PerlinNoise2 +// object. You must at least pass in a scale of each +// dimension. +// +// This constructor exists only so you can create a +// temporary placeholder PerlinNoise2 object, and later +// fill it in with the assignment operator. +//////////////////////////////////////////////////////////////////// +INLINE PerlinNoise2:: +PerlinNoise2() : + PerlinNoise(0, 1) +{ + _input_xform.fill(0.0f); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::Copy Constructor +// Access: Published +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +INLINE PerlinNoise2:: +PerlinNoise2(const PerlinNoise2 ©) : + PerlinNoise(copy), + _input_xform(copy._input_xform) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::Copy Assignment Operator +// Access: Published +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +INLINE void PerlinNoise2:: +operator = (const PerlinNoise2 ©) { + PerlinNoise::operator = (copy); + _input_xform = copy._input_xform; +} + //////////////////////////////////////////////////////////////////// // Function: PerlinNoise2::noise // Access: Published @@ -37,6 +80,36 @@ noise(const LVecBase2f &value) { return (float)noise(value[0], value[1]); } +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::operator () +// Access: Published +// Description: Returns the noise function of the two inputs. +//////////////////////////////////////////////////////////////////// +INLINE double PerlinNoise2:: +operator ()(double x, double y) { + return noise(x, y); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::noise +// Access: Published +// Description: Returns the noise function of the two inputs. +//////////////////////////////////////////////////////////////////// +INLINE float PerlinNoise2:: +operator ()(const LVecBase2f &value) { + return noise(value); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise2::noise +// Access: Published +// Description: Returns the noise function of the two inputs. +//////////////////////////////////////////////////////////////////// +INLINE double PerlinNoise2:: +operator ()(const LVecBase2d &value) { + return noise(value); +} + //////////////////////////////////////////////////////////////////// // Function: PerlinNoise2::grad // Access: Private, Static @@ -46,8 +119,22 @@ noise(const LVecBase2f &value) { //////////////////////////////////////////////////////////////////// INLINE double PerlinNoise2:: grad(int hash, double x, double y) { - // Convert lo 3 bits of hash code into 8 gradient directions. + // Convert low 3 bits of hash code into 8 gradient directions. + switch (hash & 7) { + // Four corners. + case 0: return x + y; + case 1: return x - y; + case 2: return -x + y; + case 3: return -x - y; - int h = hash & 7; - return _grad_table[h].dot(LVector2d(x, y)); + // Four edges. Here we scale by 1.707 to make all the vectors equal + // length, and to make their lengths consistent with PerlinNoise3. + case 4: return 1.707 * x; + case 5: return 1.707 * y; + case 6: return -1.707 * x; + case 7: return -1.707 * y; + } + + nassertr(false, 0); + return 0; } diff --git a/panda/src/mathutil/perlinNoise2.cxx b/panda/src/mathutil/perlinNoise2.cxx index d9ae6691e0..44414001cc 100644 --- a/panda/src/mathutil/perlinNoise2.cxx +++ b/panda/src/mathutil/perlinNoise2.cxx @@ -19,21 +19,6 @@ #include "perlinNoise2.h" #include "cmath.h" -LVector2d PerlinNoise2::_grad_table[8] = { - // Four corners. - LVector2d(1, 1), - LVector2d(1, -1), - LVector2d(-1, 1), - LVector2d(-1, -1), - - // Four edges. Here we scale by 1.707 to make all the vectors equal - // length, and to make their lengths consistent with PerlinNoise3. - LVector2d(1.707, 0), - LVector2d(0, 1.707), - LVector2d(-1.707, 0), - LVector2d(0, -1.707), -}; - //////////////////////////////////////////////////////////////////// // Function: PerlinNoise2::Constructor // Access: Published @@ -77,22 +62,25 @@ noise(const LVecBase2d &value) { double y = vec._v.v._1; // Find unit square that contains point. - int X = cmod((int)cfloor(x), _table_size); - int Y = cmod((int)cfloor(y), _table_size); + double xf = cfloor(x); + double yf = cfloor(y); + + int X = ((int)xf) & _table_size_mask; + int Y = ((int)yf) & _table_size_mask; // Find relative x,y of point in square. - x -= cfloor(x); - y -= cfloor(y); + x -= xf; + y -= yf; // Compute fade curves for each of x,y. double u = fade(x); double v = fade(y); - // Hash coordinates of the 4 square corners . . . + // Hash coordinates of the 4 square corners (A, B, A + 1, and B + 1) int A = _index[X] + Y; int B = _index[X + 1] + Y; - // . . . and add blended results from 8 corners of cube. + // and add blended results from 4 corners of square. double result = lerp(v, lerp(u, grad(_index[A], x, y), grad(_index[B], x - 1, y)), diff --git a/panda/src/mathutil/perlinNoise2.h b/panda/src/mathutil/perlinNoise2.h index 4b89274710..427f4ef495 100644 --- a/panda/src/mathutil/perlinNoise2.h +++ b/panda/src/mathutil/perlinNoise2.h @@ -31,21 +31,26 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA PerlinNoise2 : public PerlinNoise { PUBLISHED: + INLINE PerlinNoise2(); PerlinNoise2(double sx, double sy, int table_size = 256, unsigned long seed = 0); + INLINE PerlinNoise2(const PerlinNoise2 ©); + INLINE void operator = (const PerlinNoise2 ©); INLINE double noise(double x, double y); INLINE float noise(const LVecBase2f &value); double noise(const LVecBase2d &value); + + INLINE double operator ()(double x, double y); + INLINE float operator ()(const LVecBase2f &value); + INLINE double operator ()(const LVecBase2d &value); private: INLINE static double grad(int hash, double x, double y); private: LMatrix3d _input_xform; - - static LVector2d _grad_table[8]; }; #include "perlinNoise2.I" diff --git a/panda/src/mathutil/perlinNoise3.I b/panda/src/mathutil/perlinNoise3.I index 364006c3d2..36f6f71139 100644 --- a/panda/src/mathutil/perlinNoise3.I +++ b/panda/src/mathutil/perlinNoise3.I @@ -17,6 +17,49 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::Default Constructor +// Access: Published +// Description: The default constructor makes an invalid PerlinNoise3 +// object. You must at least pass in a scale of each +// dimension. +// +// This constructor exists only so you can create a +// temporary placeholder PerlinNoise3 object, and later +// fill it in with the assignment operator. +//////////////////////////////////////////////////////////////////// +INLINE PerlinNoise3:: +PerlinNoise3() : + PerlinNoise(0, 1) +{ + _input_xform.fill(0.0f); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::Copy Constructor +// Access: Published +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +INLINE PerlinNoise3:: +PerlinNoise3(const PerlinNoise3 ©) : + PerlinNoise(copy), + _input_xform(copy._input_xform) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::Copy Assignment Operator +// Access: Published +// Description: Makes an exact copy of the existing PerlinNoise +// object, including its random seed. +//////////////////////////////////////////////////////////////////// +INLINE void PerlinNoise3:: +operator = (const PerlinNoise3 ©) { + PerlinNoise::operator = (copy); + _input_xform = copy._input_xform; +} + //////////////////////////////////////////////////////////////////// // Function: PerlinNoise3::noise // Access: Published @@ -37,6 +80,36 @@ noise(const LVecBase3f &value) { return (float)noise(value[0], value[1], value[2]); } +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::operator () +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double PerlinNoise3:: +operator ()(double x, double y, double z) { + return noise(x, y, z); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE float PerlinNoise3:: +operator ()(const LVecBase3f &value) { + return noise(value); +} + +//////////////////////////////////////////////////////////////////// +// Function: PerlinNoise3::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double PerlinNoise3:: +operator ()(const LVecBase3d &value) { + return noise(value); +} + //////////////////////////////////////////////////////////////////// // Function: PerlinNoise3::grad // Access: Private, Static @@ -46,17 +119,38 @@ noise(const LVecBase3f &value) { //////////////////////////////////////////////////////////////////// INLINE double PerlinNoise3:: grad(int hash, double x, double y, double z) { - // Convert lo 4 bits of hash code into 12 gradient directions. - - int h = hash & 15; - return _grad_table[h].dot(LVector3d(x, y, z)); - + // Convert low 4 bits of hash code into 12 gradient directions. /* - This is Perlin's reference code, but the table lookup above is - slightly faster (no jump instructions) and produces exactly the - same results. + This is Perlin's reference code, but the switch statement below is + slightly faster and produces exactly the same results. + int h = hash & 15; double u = (h < 8) ? x : y; double v = (h < 4) ? y : ((h == 12 || h == 14) ? x : z); return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); */ + + switch (hash & 15) { + case 0: return x + y; + case 1: return -x + y; + case 2: return x - y; + case 3: return -x - y; + + case 4: return x + z; + case 5: return -x + z; + case 6: return x - z; + case 7: return -x - z; + + case 8: return y + z; + case 9: return -y + z; + case 10: return y - z; + case 11: return -y - z; + + case 12: return x + y; + case 13: return -y + z; + case 14: return -x + y; + case 15: return -y - z; + } + + nassertr(false, 0); + return 0; } diff --git a/panda/src/mathutil/perlinNoise3.cxx b/panda/src/mathutil/perlinNoise3.cxx index 940757d24f..b1847ecaf7 100644 --- a/panda/src/mathutil/perlinNoise3.cxx +++ b/panda/src/mathutil/perlinNoise3.cxx @@ -19,28 +19,6 @@ #include "perlinNoise3.h" #include "cmath.h" -LVector3d PerlinNoise3::_grad_table[16] = { - LVector3d(1, 1, 0), - LVector3d(-1, 1, 0), - LVector3d(1, -1, 0), - LVector3d(-1, -1, 0), - - LVector3d(1, 0, 1), - LVector3d(-1, 0, 1), - LVector3d(1, 0, -1), - LVector3d(-1, 0, -1), - - LVector3d(0, 1, 1), - LVector3d(0, -1, 1), - LVector3d(0, 1, -1), - LVector3d(0, -1, -1), - - LVector3d(1, 1, 0), - LVector3d(0, -1, 1), - LVector3d(-1, 1, 0), - LVector3d(0, -1, -1), -}; - //////////////////////////////////////////////////////////////////// // Function: PerlinNoise3::Constructor // Access: Published @@ -90,21 +68,26 @@ noise(const LVecBase3d &value) { double z = vec._v.v._2; // Find unit cube that contains point. - int X = cmod((int)cfloor(x), _table_size); - int Y = cmod((int)cfloor(y), _table_size); - int Z = cmod((int)cfloor(z), _table_size); + double xf = cfloor(x); + double yf = cfloor(y); + double zf = cfloor(z); + + int X = ((int)xf) & _table_size_mask; + int Y = ((int)yf) & _table_size_mask; + int Z = ((int)zf) & _table_size_mask; // Find relative x,y,z of point in cube. - x -= cfloor(x); - y -= cfloor(y); - z -= cfloor(z); + x -= xf; + y -= yf; + z -= zf; // Compute fade curves for each of x,y,z. double u = fade(x); double v = fade(y); double w = fade(z); - // Hash coordinates of the 8 cube corners . . . + // Hash coordinates of the 8 cube corners. The 8 corners correspond + // to AA, BA, AB, BB, AA + 1, BA + 1, AB + 1, and BB + 1. int A = _index[X] + Y; int AA = _index[A] + Z; int AB = _index[A + 1] + Z; @@ -112,7 +95,7 @@ noise(const LVecBase3d &value) { int BA = _index[B] + Z; int BB = _index[B + 1] + Z; - // . . . and add blended results from 8 corners of cube. + // and add blended results from 8 corners of cube. double result = lerp(w, lerp(v, lerp(u, grad(_index[AA], x, y, z), grad(_index[BA], x - 1, y, z)), diff --git a/panda/src/mathutil/perlinNoise3.h b/panda/src/mathutil/perlinNoise3.h index 1c65f563b4..a8d4b82bcb 100644 --- a/panda/src/mathutil/perlinNoise3.h +++ b/panda/src/mathutil/perlinNoise3.h @@ -31,21 +31,26 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA PerlinNoise3 : public PerlinNoise { PUBLISHED: + INLINE PerlinNoise3(); PerlinNoise3(double sx, double sy, double sz, int table_size = 256, unsigned long seed = 0); + INLINE PerlinNoise3(const PerlinNoise3 ©); + INLINE void operator = (const PerlinNoise3 ©); INLINE double noise(double x, double y, double z); INLINE float noise(const LVecBase3f &value); double noise(const LVecBase3d &value); + + INLINE double operator ()(double x, double y, double z); + INLINE float operator ()(const LVecBase3f &value); + INLINE double operator ()(const LVecBase3d &value); private: INLINE static double grad(int hash, double x, double y, double z); private: LMatrix4d _input_xform; - - static LVector3d _grad_table[16]; }; #include "perlinNoise3.I" diff --git a/panda/src/mathutil/stackedPerlinNoise2.I b/panda/src/mathutil/stackedPerlinNoise2.I index 51ce142937..f7d0798ff0 100644 --- a/panda/src/mathutil/stackedPerlinNoise2.I +++ b/panda/src/mathutil/stackedPerlinNoise2.I @@ -17,6 +17,17 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::Default Constructor +// Access: Published +// Description: Creates a StackedPerlinNoise2 object with no levels. +// You should call add_level() to add each level by +// hand. +//////////////////////////////////////////////////////////////////// +INLINE StackedPerlinNoise2:: +StackedPerlinNoise2() { +} + //////////////////////////////////////////////////////////////////// // Function: StackedPerlinNoise2::noise // Access: Published @@ -36,3 +47,33 @@ INLINE float StackedPerlinNoise2:: noise(const LVecBase2f &value) { return (float)noise(value[0], value[1]); } + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::operator () +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double StackedPerlinNoise2:: +operator ()(double x, double y) { + return noise(x, y); +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE float StackedPerlinNoise2:: +operator ()(const LVecBase2f &value) { + return noise(value); +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double StackedPerlinNoise2:: +operator ()(const LVecBase2d &value) { + return noise(value); +} diff --git a/panda/src/mathutil/stackedPerlinNoise2.cxx b/panda/src/mathutil/stackedPerlinNoise2.cxx index 2ab05c8094..5ae3a17b50 100644 --- a/panda/src/mathutil/stackedPerlinNoise2.cxx +++ b/panda/src/mathutil/stackedPerlinNoise2.cxx @@ -31,19 +31,70 @@ StackedPerlinNoise2:: StackedPerlinNoise2(double sx, double sy, int num_levels, double scale_factor, double amp_scale, - int table_size, unsigned long seed) : - _amp_scale(amp_scale) -{ + int table_size, unsigned long seed) { _noises.reserve(num_levels); + double amp = 1.0; for (int i = 0; i < num_levels; ++i) { PerlinNoise2 noise(sx, sy, table_size, seed); - _noises.push_back(noise); + add_level(noise, amp); + seed = noise.get_seed(); + amp *= amp_scale; sx /= scale_factor; sy /= scale_factor; } } +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::Copy Constructor +// Access: Published +// Description: Creates an exact duplicate of the existing +// StackedPerlinNoise2 object, including the random +// seed. +//////////////////////////////////////////////////////////////////// +StackedPerlinNoise2:: +StackedPerlinNoise2(const StackedPerlinNoise2 ©) : + _noises(copy._noises) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::Copy Assignment Operator +// Access: Published +// Description: Creates an exact duplicate of the existing +// StackedPerlinNoise2 object, including the random +// seed. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise2:: +operator = (const StackedPerlinNoise2 ©) { + _noises = copy._noises; +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::add_level +// Access: Published +// Description: Adds an arbitrary PerlinNoise2 object, and an +// associated amplitude, to the stack. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise2:: +add_level(const PerlinNoise2 &level, double amp) { + _noises.push_back(Noise()); + Noise &n = _noises.back(); + n._noise = level; + n._amp = amp; +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise2::clear +// Access: Published +// Description: Removes all levels from the stack. You must call +// add_level() again to restore them. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise2:: +clear() { + _noises.clear(); +} + //////////////////////////////////////////////////////////////////// // Function: StackedPerlinNoise2::noise // Access: Published @@ -51,13 +102,11 @@ StackedPerlinNoise2(double sx, double sy, int num_levels, //////////////////////////////////////////////////////////////////// double StackedPerlinNoise2:: noise(const LVecBase2d &value) { - double result = 0.0f; - double amp = 1.0f; + double result = 0.0; Noises::iterator ni; for (ni = _noises.begin(); ni != _noises.end(); ++ni) { - result += (*ni).noise(value) * amp; - amp *= _amp_scale; + result += (*ni)._noise(value) * (*ni)._amp; } return result; diff --git a/panda/src/mathutil/stackedPerlinNoise2.h b/panda/src/mathutil/stackedPerlinNoise2.h index 976764225e..0e18330931 100644 --- a/panda/src/mathutil/stackedPerlinNoise2.h +++ b/panda/src/mathutil/stackedPerlinNoise2.h @@ -31,18 +31,32 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA StackedPerlinNoise2 { PUBLISHED: - StackedPerlinNoise2(double sx, double sy, int num_levels = 3, + INLINE StackedPerlinNoise2(); + StackedPerlinNoise2(double sx, double sy, int num_levels = 2, double scale_factor = 4.0f, double amp_scale = 0.5f, int table_size = 256, unsigned long seed = 0); + StackedPerlinNoise2(const StackedPerlinNoise2 ©); + void operator = (const StackedPerlinNoise2 ©); + + void add_level(const PerlinNoise2 &level, double amp = 1.0); + void clear(); INLINE double noise(double x, double y); INLINE float noise(const LVecBase2f &value); double noise(const LVecBase2d &value); -private: - double _amp_scale; + INLINE double operator ()(double x, double y); + INLINE float operator ()(const LVecBase2f &value); + INLINE double operator ()(const LVecBase2d &value); - typedef pvector Noises; +private: + class Noise { + public: + PerlinNoise2 _noise; + double _amp; + }; + + typedef pvector Noises; Noises _noises; }; diff --git a/panda/src/mathutil/stackedPerlinNoise3.I b/panda/src/mathutil/stackedPerlinNoise3.I index 106d84d347..f38e0b25d0 100644 --- a/panda/src/mathutil/stackedPerlinNoise3.I +++ b/panda/src/mathutil/stackedPerlinNoise3.I @@ -17,6 +17,17 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::Default Constructor +// Access: Published +// Description: Creates a StackedPerlinNoise3 object with no levels. +// You should call add_level() to add each level by +// hand. +//////////////////////////////////////////////////////////////////// +INLINE StackedPerlinNoise3:: +StackedPerlinNoise3() { +} + //////////////////////////////////////////////////////////////////// // Function: StackedPerlinNoise3::noise // Access: Published @@ -36,3 +47,33 @@ INLINE float StackedPerlinNoise3:: noise(const LVecBase3f &value) { return (float)noise(value[0], value[1], value[2]); } + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::operator () +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double StackedPerlinNoise3:: +operator ()(double x, double y, double z) { + return noise(x, y, z); +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE float StackedPerlinNoise3:: +operator ()(const LVecBase3f &value) { + return noise(value); +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::noise +// Access: Published +// Description: Returns the noise function of the three inputs. +//////////////////////////////////////////////////////////////////// +INLINE double StackedPerlinNoise3:: +operator ()(const LVecBase3d &value) { + return noise(value); +} diff --git a/panda/src/mathutil/stackedPerlinNoise3.cxx b/panda/src/mathutil/stackedPerlinNoise3.cxx index 999e964cd3..abe397fc30 100644 --- a/panda/src/mathutil/stackedPerlinNoise3.cxx +++ b/panda/src/mathutil/stackedPerlinNoise3.cxx @@ -31,20 +31,71 @@ StackedPerlinNoise3:: StackedPerlinNoise3(double sx, double sy, double sz, int num_levels, double scale_factor, double amp_scale, - int table_size, unsigned long seed) : - _amp_scale(amp_scale) -{ + int table_size, unsigned long seed) { _noises.reserve(num_levels); + double amp = 1.0; for (int i = 0; i < num_levels; ++i) { PerlinNoise3 noise(sx, sy, sz, table_size, seed); - _noises.push_back(noise); + add_level(noise, amp); + seed = noise.get_seed(); + amp *= amp_scale; sx /= scale_factor; sy /= scale_factor; sz /= scale_factor; } } +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::Copy Constructor +// Access: Published +// Description: Creates an exact duplicate of the existing +// StackedPerlinNoise3 object, including the random +// seed. +//////////////////////////////////////////////////////////////////// +StackedPerlinNoise3:: +StackedPerlinNoise3(const StackedPerlinNoise3 ©) : + _noises(copy._noises) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::Copy Assignment Operator +// Access: Published +// Description: Creates an exact duplicate of the existing +// StackedPerlinNoise3 object, including the random +// seed. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise3:: +operator = (const StackedPerlinNoise3 ©) { + _noises = copy._noises; +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::add_level +// Access: Published +// Description: Adds an arbitrary PerlinNoise3 object, and an +// associated amplitude, to the stack. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise3:: +add_level(const PerlinNoise3 &level, double amp) { + _noises.push_back(Noise()); + Noise &n = _noises.back(); + n._noise = level; + n._amp = amp; +} + +//////////////////////////////////////////////////////////////////// +// Function: StackedPerlinNoise3::clear +// Access: Published +// Description: Removes all levels from the stack. You must call +// add_level() again to restore them. +//////////////////////////////////////////////////////////////////// +void StackedPerlinNoise3:: +clear() { + _noises.clear(); +} + //////////////////////////////////////////////////////////////////// // Function: StackedPerlinNoise3::noise // Access: Published @@ -52,13 +103,11 @@ StackedPerlinNoise3(double sx, double sy, double sz, int num_levels, //////////////////////////////////////////////////////////////////// double StackedPerlinNoise3:: noise(const LVecBase3d &value) { - double result = 0.0f; - double amp = 1.0f; + double result = 0.0; Noises::iterator ni; for (ni = _noises.begin(); ni != _noises.end(); ++ni) { - result += (*ni).noise(value) * amp; - amp *= _amp_scale; + result += (*ni)._noise(value) * (*ni)._amp; } return result; diff --git a/panda/src/mathutil/stackedPerlinNoise3.h b/panda/src/mathutil/stackedPerlinNoise3.h index d7eb1b4b9a..582e8e783f 100644 --- a/panda/src/mathutil/stackedPerlinNoise3.h +++ b/panda/src/mathutil/stackedPerlinNoise3.h @@ -31,18 +31,32 @@ //////////////////////////////////////////////////////////////////// class EXPCL_PANDA StackedPerlinNoise3 { PUBLISHED: + INLINE StackedPerlinNoise3(); StackedPerlinNoise3(double sx, double sy, double sz, int num_levels = 3, double scale_factor = 4.0f, double amp_scale = 0.5f, int table_size = 256, unsigned long seed = 0); + StackedPerlinNoise3(const StackedPerlinNoise3 ©); + void operator = (const StackedPerlinNoise3 ©); + + void add_level(const PerlinNoise3 &level, double amp = 1.0); + void clear(); INLINE double noise(double x, double y, double z); INLINE float noise(const LVecBase3f &value); double noise(const LVecBase3d &value); -private: - double _amp_scale; + INLINE double operator ()(double x, double y, double z); + INLINE float operator ()(const LVecBase3f &value); + INLINE double operator ()(const LVecBase3d &value); - typedef pvector Noises; +private: + class Noise { + public: + PerlinNoise3 _noise; + double _amp; + }; + + typedef pvector Noises; Noises _noises; };