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