1 // noisegen.cpp
2 //
3 // Copyright (C) 2003, 2004 Jason Bevins
4 //
5 // This library is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or (at
8 // your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
13 // License (COPYING.txt) for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 //
19 // The developer's email is jlbezigvins@gmzigail.com (for great email, take
20 // off every 'zig'.)
21 //
22 
23 #include "noisegen.h"
24 #include "interp.h"
25 #include "vectortable.h"
26 
27 using namespace noise;
28 
29 // Specifies the version of the coherent-noise functions to use.
30 // - Set to 2 to use the current version.
31 // - Set to 1 to use the flawed version from the original version of libnoise.
32 // If your application requires coherent-noise values that were generated by
33 // an earlier version of libnoise, change this constant to the appropriate
34 // value and recompile libnoise.
35 #define NOISE_VERSION 2
36 
37 // These constants control certain parameters that all coherent-noise
38 // functions require.
39 #if (NOISE_VERSION == 1)
40 // Constants used by the original version of libnoise.
41 // Because X_NOISE_GEN is not relatively prime to the other values, and
42 // Z_NOISE_GEN is close to 256 (the number of random gradient vectors),
43 // patterns show up in high-frequency coherent noise.
44 const int X_NOISE_GEN = 1;
45 const int Y_NOISE_GEN = 31337;
46 const int Z_NOISE_GEN = 263;
47 const int SEED_NOISE_GEN = 1013;
48 const int SHIFT_NOISE_GEN = 13;
49 #else
50 // Constants used by the current version of libnoise.
51 const int X_NOISE_GEN = 1619;
52 const int Y_NOISE_GEN = 31337;
53 const int Z_NOISE_GEN = 6971;
54 const int SEED_NOISE_GEN = 1013;
55 const int SHIFT_NOISE_GEN = 8;
56 #endif
57 
GradientCoherentNoise3D(double x,double y,double z,int seed,NoiseQuality noiseQuality)58 double noise::GradientCoherentNoise3D (double x, double y, double z, int seed,
59   NoiseQuality noiseQuality)
60 {
61   // Create a unit-length cube aligned along an integer boundary.  This cube
62   // surrounds the input point.
63   int x0 = (x > 0.0? (int)x: (int)x - 1);
64   int x1 = x0 + 1;
65   int y0 = (y > 0.0? (int)y: (int)y - 1);
66   int y1 = y0 + 1;
67   int z0 = (z > 0.0? (int)z: (int)z - 1);
68   int z1 = z0 + 1;
69 
70   // Map the difference between the coordinates of the input value and the
71   // coordinates of the cube's outer-lower-left vertex onto an S-curve.
72   double xs = 0, ys = 0, zs = 0;
73   switch (noiseQuality) {
74     case QUALITY_FAST:
75       xs = (x - (double)x0);
76       ys = (y - (double)y0);
77       zs = (z - (double)z0);
78       break;
79     case QUALITY_STD:
80       xs = SCurve3 (x - (double)x0);
81       ys = SCurve3 (y - (double)y0);
82       zs = SCurve3 (z - (double)z0);
83       break;
84     case QUALITY_BEST:
85       xs = SCurve5 (x - (double)x0);
86       ys = SCurve5 (y - (double)y0);
87       zs = SCurve5 (z - (double)z0);
88       break;
89   }
90 
91   // Now calculate the noise values at each vertex of the cube.  To generate
92   // the coherent-noise value at the input point, interpolate these eight
93   // noise values using the S-curve value as the interpolant (trilinear
94   // interpolation.)
95   double n0, n1, ix0, ix1, iy0, iy1;
96   n0   = GradientNoise3D (x, y, z, x0, y0, z0, seed);
97   n1   = GradientNoise3D (x, y, z, x1, y0, z0, seed);
98   ix0  = LinearInterp (n0, n1, xs);
99   n0   = GradientNoise3D (x, y, z, x0, y1, z0, seed);
100   n1   = GradientNoise3D (x, y, z, x1, y1, z0, seed);
101   ix1  = LinearInterp (n0, n1, xs);
102   iy0  = LinearInterp (ix0, ix1, ys);
103   n0   = GradientNoise3D (x, y, z, x0, y0, z1, seed);
104   n1   = GradientNoise3D (x, y, z, x1, y0, z1, seed);
105   ix0  = LinearInterp (n0, n1, xs);
106   n0   = GradientNoise3D (x, y, z, x0, y1, z1, seed);
107   n1   = GradientNoise3D (x, y, z, x1, y1, z1, seed);
108   ix1  = LinearInterp (n0, n1, xs);
109   iy1  = LinearInterp (ix0, ix1, ys);
110 
111   return LinearInterp (iy0, iy1, zs);
112 }
113 
GradientNoise3D(double fx,double fy,double fz,int ix,int iy,int iz,int seed)114 double noise::GradientNoise3D (double fx, double fy, double fz, int ix,
115   int iy, int iz, int seed)
116 {
117   // Randomly generate a gradient vector given the integer coordinates of the
118   // input value.  This implementation generates a random number and uses it
119   // as an index into a normalized-vector lookup table.
120   int vectorIndex = (
121       X_NOISE_GEN    * ix
122     + Y_NOISE_GEN    * iy
123     + Z_NOISE_GEN    * iz
124     + SEED_NOISE_GEN * seed)
125     & 0xffffffff;
126   vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN);
127   vectorIndex &= 0xff;
128 
129   double xvGradient = g_randomVectors[(vectorIndex << 2)    ];
130   double yvGradient = g_randomVectors[(vectorIndex << 2) + 1];
131   double zvGradient = g_randomVectors[(vectorIndex << 2) + 2];
132 
133   // Set up us another vector equal to the distance between the two vectors
134   // passed to this function.
135   double xvPoint = (fx - (double)ix);
136   double yvPoint = (fy - (double)iy);
137   double zvPoint = (fz - (double)iz);
138 
139   // Now compute the dot product of the gradient vector with the distance
140   // vector.  The resulting value is gradient noise.  Apply a scaling value
141   // so that this noise value ranges from -1.0 to 1.0.
142   return ((xvGradient * xvPoint)
143     + (yvGradient * yvPoint)
144     + (zvGradient * zvPoint)) * 2.12;
145 }
146 
IntValueNoise3D(int x,int y,int z,int seed)147 int noise::IntValueNoise3D (int x, int y, int z, int seed)
148 {
149   // All constants are primes and must remain prime in order for this noise
150   // function to work correctly.
151   int n = (
152       X_NOISE_GEN    * x
153     + Y_NOISE_GEN    * y
154     + Z_NOISE_GEN    * z
155     + SEED_NOISE_GEN * seed)
156     & 0x7fffffff;
157   n = (n >> 13) ^ n;
158   return (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
159 }
160 
ValueCoherentNoise3D(double x,double y,double z,int seed,NoiseQuality noiseQuality)161 double noise::ValueCoherentNoise3D (double x, double y, double z, int seed,
162   NoiseQuality noiseQuality)
163 {
164   // Create a unit-length cube aligned along an integer boundary.  This cube
165   // surrounds the input point.
166   int x0 = (x > 0.0? (int)x: (int)x - 1);
167   int x1 = x0 + 1;
168   int y0 = (y > 0.0? (int)y: (int)y - 1);
169   int y1 = y0 + 1;
170   int z0 = (z > 0.0? (int)z: (int)z - 1);
171   int z1 = z0 + 1;
172 
173   // Map the difference between the coordinates of the input value and the
174   // coordinates of the cube's outer-lower-left vertex onto an S-curve.
175   double xs = 0, ys = 0, zs = 0;
176   switch (noiseQuality) {
177     case QUALITY_FAST:
178       xs = (x - (double)x0);
179       ys = (y - (double)y0);
180       zs = (z - (double)z0);
181       break;
182     case QUALITY_STD:
183       xs = SCurve3 (x - (double)x0);
184       ys = SCurve3 (y - (double)y0);
185       zs = SCurve3 (z - (double)z0);
186       break;
187     case QUALITY_BEST:
188       xs = SCurve5 (x - (double)x0);
189       ys = SCurve5 (y - (double)y0);
190       zs = SCurve5 (z - (double)z0);
191       break;
192   }
193 
194   // Now calculate the noise values at each vertex of the cube.  To generate
195   // the coherent-noise value at the input point, interpolate these eight
196   // noise values using the S-curve value as the interpolant (trilinear
197   // interpolation.)
198   double n0, n1, ix0, ix1, iy0, iy1;
199   n0   = ValueNoise3D (x0, y0, z0, seed);
200   n1   = ValueNoise3D (x1, y0, z0, seed);
201   ix0  = LinearInterp (n0, n1, xs);
202   n0   = ValueNoise3D (x0, y1, z0, seed);
203   n1   = ValueNoise3D (x1, y1, z0, seed);
204   ix1  = LinearInterp (n0, n1, xs);
205   iy0  = LinearInterp (ix0, ix1, ys);
206   n0   = ValueNoise3D (x0, y0, z1, seed);
207   n1   = ValueNoise3D (x1, y0, z1, seed);
208   ix0  = LinearInterp (n0, n1, xs);
209   n0   = ValueNoise3D (x0, y1, z1, seed);
210   n1   = ValueNoise3D (x1, y1, z1, seed);
211   ix1  = LinearInterp (n0, n1, xs);
212   iy1  = LinearInterp (ix0, ix1, ys);
213   return LinearInterp (iy0, iy1, zs);
214 }
215 
ValueNoise3D(int x,int y,int z,int seed)216 double noise::ValueNoise3D (int x, int y, int z, int seed)
217 {
218   return 1.0 - ((double)IntValueNoise3D (x, y, z, seed) / 1073741824.0);
219 }
220 
221