Browse Source

optimizations, a few more interfaces

David Rose 20 years ago
parent
commit
8cef27663e

+ 2 - 1
panda/src/mathutil/perlinNoise.I

@@ -25,7 +25,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double PerlinNoise::
 INLINE double PerlinNoise::
 fade(double t) { 
 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;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 42 - 1
panda/src/mathutil/perlinNoise.cxx

@@ -33,9 +33,21 @@ bool PerlinNoise::_got_first_seed = false;
 PerlinNoise::
 PerlinNoise::
 PerlinNoise(int table_size, unsigned long seed) :
 PerlinNoise(int table_size, unsigned long seed) :
   _table_size(table_size),
   _table_size(table_size),
+  _table_size_mask(table_size - 1),
   _mersenne(seed != 0 ? seed : get_next_seed())
   _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.
   // table.
   _index.reserve(_table_size * 2);
   _index.reserve(_table_size * 2);
   int i;
   int i;
@@ -56,3 +68,32 @@ PerlinNoise(int table_size, unsigned long seed) :
     _index.push_back(_index[i]);
     _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 &copy) :
+  _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 &copy) {
+  _table_size = copy._table_size;
+  _table_size_mask = copy._table_size_mask;
+  _mersenne = copy._mersenne;
+  _index = copy._index;
+}

+ 3 - 0
panda/src/mathutil/perlinNoise.h

@@ -34,6 +34,8 @@
 class EXPCL_PANDA PerlinNoise {
 class EXPCL_PANDA PerlinNoise {
 protected:
 protected:
   PerlinNoise(int table_size, unsigned long seed);
   PerlinNoise(int table_size, unsigned long seed);
+  PerlinNoise(const PerlinNoise &copy);
+  void operator = (const PerlinNoise &copy);
 
 
   INLINE static double fade(double t);
   INLINE static double fade(double t);
   INLINE static double lerp(double t, double a, double b);
   INLINE static double lerp(double t, double a, double b);
@@ -49,6 +51,7 @@ PUBLISHED:
 
 
 protected:
 protected:
   int _table_size;
   int _table_size;
+  int _table_size_mask;
 
 
   Mersenne _mersenne;
   Mersenne _mersenne;
   static Mersenne _next_seed;
   static Mersenne _next_seed;

+ 90 - 3
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 &copy) :
+  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 &copy) {
+  PerlinNoise::operator = (copy);
+  _input_xform = copy._input_xform;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PerlinNoise2::noise
 //     Function: PerlinNoise2::noise
 //       Access: Published
 //       Access: Published
@@ -37,6 +80,36 @@ noise(const LVecBase2f &value) {
   return (float)noise(value[0], value[1]);
   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
 //     Function: PerlinNoise2::grad
 //       Access: Private, Static
 //       Access: Private, Static
@@ -46,8 +119,22 @@ noise(const LVecBase2f &value) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double PerlinNoise2::
 INLINE double PerlinNoise2::
 grad(int hash, double x, double y) {
 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;
+
+    // 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;
+  }
 
 
-  int h = hash & 7;
-  return _grad_table[h].dot(LVector2d(x, y));
+  nassertr(false, 0);
+  return 0;
 }
 }

+ 9 - 21
panda/src/mathutil/perlinNoise2.cxx

@@ -19,21 +19,6 @@
 #include "perlinNoise2.h"
 #include "perlinNoise2.h"
 #include "cmath.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
 //     Function: PerlinNoise2::Constructor
 //       Access: Published
 //       Access: Published
@@ -77,22 +62,25 @@ noise(const LVecBase2d &value) {
   double y = vec._v.v._1;
   double y = vec._v.v._1;
 
 
   // Find unit square that contains point.
   // 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.
   // 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.
   // Compute fade curves for each of x,y.
   double u = fade(x);
   double u = fade(x);
   double v = fade(y);
   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 A = _index[X] + Y;
   int B = _index[X + 1] + 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 =
   double result =
     lerp(v, lerp(u, grad(_index[A], x, y), 
     lerp(v, lerp(u, grad(_index[A], x, y), 
                  grad(_index[B], x - 1, y)), 
                  grad(_index[B], x - 1, y)), 

+ 7 - 2
panda/src/mathutil/perlinNoise2.h

@@ -31,21 +31,26 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA PerlinNoise2 : public PerlinNoise {
 class EXPCL_PANDA PerlinNoise2 : public PerlinNoise {
 PUBLISHED:
 PUBLISHED:
+  INLINE PerlinNoise2();
   PerlinNoise2(double sx, double sy,
   PerlinNoise2(double sx, double sy,
 	       int table_size = 256,
 	       int table_size = 256,
 	       unsigned long seed = 0);
 	       unsigned long seed = 0);
+  INLINE PerlinNoise2(const PerlinNoise2 &copy);
+  INLINE void operator = (const PerlinNoise2 &copy);
 
 
   INLINE double noise(double x, double y);
   INLINE double noise(double x, double y);
   INLINE float noise(const LVecBase2f &value);
   INLINE float noise(const LVecBase2f &value);
   double noise(const LVecBase2d &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:
 private:
   INLINE static double grad(int hash, double x, double y);
   INLINE static double grad(int hash, double x, double y);
 
 
 private:
 private:
   LMatrix3d _input_xform;
   LMatrix3d _input_xform;
-
-  static LVector2d _grad_table[8];
 };
 };
 
 
 #include "perlinNoise2.I"
 #include "perlinNoise2.I"

+ 102 - 8
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 &copy) :
+  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 &copy) {
+  PerlinNoise::operator = (copy);
+  _input_xform = copy._input_xform;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PerlinNoise3::noise
 //     Function: PerlinNoise3::noise
 //       Access: Published
 //       Access: Published
@@ -37,6 +80,36 @@ noise(const LVecBase3f &value) {
   return (float)noise(value[0], value[1], value[2]);
   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
 //     Function: PerlinNoise3::grad
 //       Access: Private, Static
 //       Access: Private, Static
@@ -46,17 +119,38 @@ noise(const LVecBase3f &value) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double PerlinNoise3::
 INLINE double PerlinNoise3::
 grad(int hash, double x, double y, double z) {
 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 u = (h < 8) ? x : y;
   double v = (h < 4) ? y : ((h == 12 || h == 14) ? x : z);
   double v = (h < 4) ? y : ((h == 12 || h == 14) ? x : z);
   return ((h & 1) ? -u : u) + ((h & 2) ? -v : v);
   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;
 }
 }

+ 13 - 30
panda/src/mathutil/perlinNoise3.cxx

@@ -19,28 +19,6 @@
 #include "perlinNoise3.h"
 #include "perlinNoise3.h"
 #include "cmath.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
 //     Function: PerlinNoise3::Constructor
 //       Access: Published
 //       Access: Published
@@ -90,21 +68,26 @@ noise(const LVecBase3d &value) {
   double z = vec._v.v._2;
   double z = vec._v.v._2;
 
 
   // Find unit cube that contains point.
   // 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.
   // 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.
   // Compute fade curves for each of x,y,z.
   double u = fade(x);
   double u = fade(x);
   double v = fade(y);
   double v = fade(y);
   double w = fade(z);
   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 A = _index[X] + Y;
   int AA = _index[A] + Z;
   int AA = _index[A] + Z;
   int AB = _index[A + 1] + Z;
   int AB = _index[A + 1] + Z;
@@ -112,7 +95,7 @@ noise(const LVecBase3d &value) {
   int BA = _index[B] + Z;
   int BA = _index[B] + Z;
   int BB = _index[B + 1] + 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 =
   double result =
     lerp(w, lerp(v, lerp(u, grad(_index[AA], x, y, z), 
     lerp(w, lerp(v, lerp(u, grad(_index[AA], x, y, z), 
                          grad(_index[BA], x - 1, y, z)), 
                          grad(_index[BA], x - 1, y, z)), 

+ 7 - 2
panda/src/mathutil/perlinNoise3.h

@@ -31,21 +31,26 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA PerlinNoise3 : public PerlinNoise {
 class EXPCL_PANDA PerlinNoise3 : public PerlinNoise {
 PUBLISHED:
 PUBLISHED:
+  INLINE PerlinNoise3();
   PerlinNoise3(double sx, double sy, double sz,
   PerlinNoise3(double sx, double sy, double sz,
 	       int table_size = 256,
 	       int table_size = 256,
 	       unsigned long seed = 0);
 	       unsigned long seed = 0);
+  INLINE PerlinNoise3(const PerlinNoise3 &copy);
+  INLINE void operator = (const PerlinNoise3 &copy);
 
 
   INLINE double noise(double x, double y, double z);
   INLINE double noise(double x, double y, double z);
   INLINE float noise(const LVecBase3f &value);
   INLINE float noise(const LVecBase3f &value);
   double noise(const LVecBase3d &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:
 private:
   INLINE static double grad(int hash, double x, double y, double z);
   INLINE static double grad(int hash, double x, double y, double z);
 
 
 private:
 private:
   LMatrix4d _input_xform;
   LMatrix4d _input_xform;
-
-  static LVector3d _grad_table[16];
 };
 };
 
 
 #include "perlinNoise3.I"
 #include "perlinNoise3.I"

+ 41 - 0
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
 //     Function: StackedPerlinNoise2::noise
 //       Access: Published
 //       Access: Published
@@ -36,3 +47,33 @@ INLINE float StackedPerlinNoise2::
 noise(const LVecBase2f &value) {
 noise(const LVecBase2f &value) {
   return (float)noise(value[0], value[1]);
   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);
+}

+ 57 - 8
panda/src/mathutil/stackedPerlinNoise2.cxx

@@ -31,19 +31,70 @@
 StackedPerlinNoise2::
 StackedPerlinNoise2::
 StackedPerlinNoise2(double sx, double sy, int num_levels,
 StackedPerlinNoise2(double sx, double sy, int num_levels,
                     double scale_factor, double amp_scale,
                     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);
   _noises.reserve(num_levels);
+  double amp = 1.0;
   for (int i = 0; i < num_levels; ++i) {
   for (int i = 0; i < num_levels; ++i) {
     PerlinNoise2 noise(sx, sy, table_size, seed);
     PerlinNoise2 noise(sx, sy, table_size, seed);
-    _noises.push_back(noise);
+    add_level(noise, amp);
+
     seed = noise.get_seed();
     seed = noise.get_seed();
+    amp *= amp_scale;
     sx /= scale_factor;
     sx /= scale_factor;
     sy /= 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 &copy) :
+  _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 &copy) {
+  _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
 //     Function: StackedPerlinNoise2::noise
 //       Access: Published
 //       Access: Published
@@ -51,13 +102,11 @@ StackedPerlinNoise2(double sx, double sy, int num_levels,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 double StackedPerlinNoise2::
 double StackedPerlinNoise2::
 noise(const LVecBase2d &value) {
 noise(const LVecBase2d &value) {
-  double result = 0.0f;
-  double amp = 1.0f;
+  double result = 0.0;
 
 
   Noises::iterator ni;
   Noises::iterator ni;
   for (ni = _noises.begin(); ni != _noises.end(); ++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;
   return result;

+ 17 - 3
panda/src/mathutil/stackedPerlinNoise2.h

@@ -31,18 +31,32 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA StackedPerlinNoise2 {
 class EXPCL_PANDA StackedPerlinNoise2 {
 PUBLISHED:
 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,
                       double scale_factor = 4.0f, double amp_scale = 0.5f,
                       int table_size = 256, unsigned long seed = 0);
                       int table_size = 256, unsigned long seed = 0);
+  StackedPerlinNoise2(const StackedPerlinNoise2 &copy);
+  void operator = (const StackedPerlinNoise2 &copy);
+
+  void add_level(const PerlinNoise2 &level, double amp = 1.0);
+  void clear();
 
 
   INLINE double noise(double x, double y);
   INLINE double noise(double x, double y);
   INLINE float noise(const LVecBase2f &value);
   INLINE float noise(const LVecBase2f &value);
   double noise(const LVecBase2d &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:
 private:
-  double _amp_scale;
+  class Noise {
+  public:
+    PerlinNoise2 _noise;
+    double _amp;
+  };
 
 
-  typedef pvector<PerlinNoise2> Noises;
+  typedef pvector<Noise> Noises;
   Noises _noises;
   Noises _noises;
 };
 };
 
 

+ 41 - 0
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
 //     Function: StackedPerlinNoise3::noise
 //       Access: Published
 //       Access: Published
@@ -36,3 +47,33 @@ INLINE float StackedPerlinNoise3::
 noise(const LVecBase3f &value) {
 noise(const LVecBase3f &value) {
   return (float)noise(value[0], value[1], value[2]);
   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);
+}

+ 57 - 8
panda/src/mathutil/stackedPerlinNoise3.cxx

@@ -31,20 +31,71 @@
 StackedPerlinNoise3::
 StackedPerlinNoise3::
 StackedPerlinNoise3(double sx, double sy, double sz, int num_levels,
 StackedPerlinNoise3(double sx, double sy, double sz, int num_levels,
                     double scale_factor, double amp_scale,
                     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);
   _noises.reserve(num_levels);
+  double amp = 1.0;
   for (int i = 0; i < num_levels; ++i) {
   for (int i = 0; i < num_levels; ++i) {
     PerlinNoise3 noise(sx, sy, sz, table_size, seed);
     PerlinNoise3 noise(sx, sy, sz, table_size, seed);
-    _noises.push_back(noise);
+    add_level(noise, amp);
+
     seed = noise.get_seed();
     seed = noise.get_seed();
+    amp *= amp_scale;
     sx /= scale_factor;
     sx /= scale_factor;
     sy /= scale_factor;
     sy /= scale_factor;
     sz /= 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 &copy) :
+  _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 &copy) {
+  _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
 //     Function: StackedPerlinNoise3::noise
 //       Access: Published
 //       Access: Published
@@ -52,13 +103,11 @@ StackedPerlinNoise3(double sx, double sy, double sz, int num_levels,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 double StackedPerlinNoise3::
 double StackedPerlinNoise3::
 noise(const LVecBase3d &value) {
 noise(const LVecBase3d &value) {
-  double result = 0.0f;
-  double amp = 1.0f;
+  double result = 0.0;
 
 
   Noises::iterator ni;
   Noises::iterator ni;
   for (ni = _noises.begin(); ni != _noises.end(); ++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;
   return result;

+ 16 - 2
panda/src/mathutil/stackedPerlinNoise3.h

@@ -31,18 +31,32 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA StackedPerlinNoise3 {
 class EXPCL_PANDA StackedPerlinNoise3 {
 PUBLISHED:
 PUBLISHED:
+  INLINE StackedPerlinNoise3();
   StackedPerlinNoise3(double sx, double sy, double sz, int num_levels = 3,
   StackedPerlinNoise3(double sx, double sy, double sz, int num_levels = 3,
                       double scale_factor = 4.0f, double amp_scale = 0.5f,
                       double scale_factor = 4.0f, double amp_scale = 0.5f,
                       int table_size = 256, unsigned long seed = 0);
                       int table_size = 256, unsigned long seed = 0);
+  StackedPerlinNoise3(const StackedPerlinNoise3 &copy);
+  void operator = (const StackedPerlinNoise3 &copy);
+
+  void add_level(const PerlinNoise3 &level, double amp = 1.0);
+  void clear();
 
 
   INLINE double noise(double x, double y, double z);
   INLINE double noise(double x, double y, double z);
   INLINE float noise(const LVecBase3f &value);
   INLINE float noise(const LVecBase3f &value);
   double noise(const LVecBase3d &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:
 private:
-  double _amp_scale;
+  class Noise {
+  public:
+    PerlinNoise3 _noise;
+    double _amp;
+  };
 
 
-  typedef pvector<PerlinNoise3> Noises;
+  typedef pvector<Noise> Noises;
   Noises _noises;
   Noises _noises;
 };
 };