3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #define NOISE_MAGIC_X 1619
26 #define NOISE_MAGIC_Y 31337
27 #define NOISE_MAGIC_Z 52591
28 #define NOISE_MAGIC_SEED 1013
30 double cos_lookup[16] = {
31 1.0,0.9238,0.7071,0.3826,0,-0.3826,-0.7071,-0.9238,
32 1.0,-0.9238,-0.7071,-0.3826,0,0.3826,0.7071,0.9238
35 double dotProduct(double vx, double vy, double wx, double wy){
39 double easeCurve(double t){
40 return 6*pow(t,5)-15*pow(t,4)+10*pow(t,3);
43 double linearInterpolation(double x0, double x1, double t){
47 double biLinearInterpolation(double x0y0, double x1y0, double x0y1, double x1y1, double x, double y){
48 double tx = easeCurve(x);
49 double ty = easeCurve(y);
52 double u = linearInterpolation(x0y0,x1y0,tx);
53 double v = linearInterpolation(x0y1,x1y1,tx);
54 return linearInterpolation(u,v,ty);
57 double triLinearInterpolation(
58 double v000, double v100, double v010, double v110,
59 double v001, double v101, double v011, double v111,
60 double x, double y, double z)
62 /*double tx = easeCurve(x);
63 double ty = easeCurve(y);
64 double tz = easeCurve(z);*/
69 v000*(1-tx)*(1-ty)*(1-tz) +
70 v100*tx*(1-ty)*(1-tz) +
71 v010*(1-tx)*ty*(1-tz) +
73 v001*(1-tx)*(1-ty)*tz +
80 double noise2d(int x, int y, int seed)
82 int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
83 + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
85 n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
86 return 1.0 - (double)n/1073741824;
89 double noise3d(int x, int y, int z, int seed)
91 int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
92 + NOISE_MAGIC_SEED * seed) & 0x7fffffff;
94 n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
95 return 1.0 - (double)n/1073741824;
99 double noise2d_gradient(double x, double y, int seed)
101 // Calculate the integer coordinates
102 int x0 = (x > 0.0 ? (int)x : (int)x - 1);
103 int y0 = (y > 0.0 ? (int)y : (int)y - 1);
104 // Calculate the remaining part of the coordinates
105 double xl = x - (double)x0;
106 double yl = y - (double)y0;
107 // Calculate random cosine lookup table indices for the integer corners.
108 // They are looked up as unit vector gradients from the lookup table.
109 int n00 = (int)((noise2d(x0, y0, seed)+1)*8);
110 int n10 = (int)((noise2d(x0+1, y0, seed)+1)*8);
111 int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8);
112 int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8);
113 // Make a dot product for the gradients and the positions, to get the values
114 double s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
115 double u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
116 double v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
117 double w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
118 // Interpolate between the values
119 return biLinearInterpolation(s,u,v,w,xl,yl);
124 double noise2d_gradient(double x, double y, int seed)
126 // Calculate the integer coordinates
127 int x0 = (x > 0.0 ? (int)x : (int)x - 1);
128 int y0 = (y > 0.0 ? (int)y : (int)y - 1);
129 // Calculate the remaining part of the coordinates
130 double xl = x - (double)x0;
131 double yl = y - (double)y0;
132 // Get values for corners of cube
133 double v00 = noise2d(x0, y0, seed);
134 double v10 = noise2d(x0+1, y0, seed);
135 double v01 = noise2d(x0, y0+1, seed);
136 double v11 = noise2d(x0+1, y0+1, seed);
138 return biLinearInterpolation(v00,v10,v01,v11,xl,yl);
142 double noise3d_gradient(double x, double y, double z, int seed)
144 // Calculate the integer coordinates
145 int x0 = (x > 0.0 ? (int)x : (int)x - 1);
146 int y0 = (y > 0.0 ? (int)y : (int)y - 1);
147 int z0 = (z > 0.0 ? (int)z : (int)z - 1);
148 // Calculate the remaining part of the coordinates
149 double xl = x - (double)x0;
150 double yl = y - (double)y0;
151 double zl = z - (double)z0;
152 // Get values for corners of cube
153 double v000 = noise3d(x0, y0, z0, seed);
154 double v100 = noise3d(x0+1, y0, z0, seed);
155 double v010 = noise3d(x0, y0+1, z0, seed);
156 double v110 = noise3d(x0+1, y0+1, z0, seed);
157 double v001 = noise3d(x0, y0, z0+1, seed);
158 double v101 = noise3d(x0+1, y0, z0+1, seed);
159 double v011 = noise3d(x0, y0+1, z0+1, seed);
160 double v111 = noise3d(x0+1, y0+1, z0+1, seed);
162 return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
165 double noise2d_perlin(double x, double y, int seed,
166 int octaves, double persistence)
171 for(int i=0; i<octaves; i++)
173 a += g * noise2d_gradient(x*f, y*f, seed+i);
180 double noise2d_perlin_abs(double x, double y, int seed,
181 int octaves, double persistence)
186 for(int i=0; i<octaves; i++)
188 a += g * fabs(noise2d_gradient(x*f, y*f, seed+i));
195 double noise3d_perlin(double x, double y, double z, int seed,
196 int octaves, double persistence)
201 for(int i=0; i<octaves; i++)
203 a += g * noise3d_gradient(x*f, y*f, z*f, seed+i);
210 double noise3d_perlin_abs(double x, double y, double z, int seed,
211 int octaves, double persistence)
216 for(int i=0; i<octaves; i++)
218 a += g * fabs(noise3d_gradient(x*f, y*f, z*f, seed+i));
229 NoiseBuffer::NoiseBuffer():
234 NoiseBuffer::~NoiseBuffer()
239 void NoiseBuffer::clear()
249 void NoiseBuffer::create(int seed, int octaves, double persistence,
251 double first_x, double first_y, double first_z,
252 double last_x, double last_y, double last_z,
253 double samplelength_x, double samplelength_y, double samplelength_z)
257 m_start_x = first_x - samplelength_x;
258 m_start_y = first_y - samplelength_y;
259 m_start_z = first_z - samplelength_z;
260 m_samplelength_x = samplelength_x;
261 m_samplelength_y = samplelength_y;
262 m_samplelength_z = samplelength_z;
264 m_size_x = (last_x - m_start_x)/samplelength_x + 2;
265 m_size_y = (last_y - m_start_y)/samplelength_y + 2;
266 m_size_z = (last_z - m_start_z)/samplelength_z + 2;
268 /*dstream<<"m_size_x="<<m_size_x<<", m_size_y="<<m_size_y
269 <<", m_size_z="<<m_size_z<<std::endl;*/
271 m_data = new double[m_size_x*m_size_y*m_size_z];
273 for(int x=0; x<m_size_x; x++)
274 for(int y=0; y<m_size_y; y++)
275 for(int z=0; z<m_size_z; z++)
277 double xd = (m_start_x + (double)x*m_samplelength_x)/pos_scale;
278 double yd = (m_start_y + (double)y*m_samplelength_y)/pos_scale;
279 double zd = (m_start_z + (double)z*m_samplelength_z)/pos_scale;
280 intSet(x,y,z, noise3d_perlin(xd,yd,zd,seed,octaves,persistence));
284 void NoiseBuffer::intSet(int x, int y, int z, double d)
286 int i = m_size_x*m_size_y*z + m_size_x*y + x;
288 assert(i < m_size_x*m_size_y*m_size_z);
292 double NoiseBuffer::intGet(int x, int y, int z)
294 int i = m_size_x*m_size_y*z + m_size_x*y + x;
296 assert(i < m_size_x*m_size_y*m_size_z);
300 double NoiseBuffer::get(double x, double y, double z)
305 x /= m_samplelength_x;
306 y /= m_samplelength_y;
307 z /= m_samplelength_z;
308 // Calculate the integer coordinates
309 int x0 = (x > 0.0 ? (int)x : (int)x - 1);
310 int y0 = (y > 0.0 ? (int)y : (int)y - 1);
311 int z0 = (z > 0.0 ? (int)z : (int)z - 1);
312 // Calculate the remaining part of the coordinates
313 double xl = x - (double)x0;
314 double yl = y - (double)y0;
315 double zl = z - (double)z0;
316 // Get values for corners of cube
317 double v000 = intGet(x0, y0, z0);
318 double v100 = intGet(x0+1, y0, z0);
319 double v010 = intGet(x0, y0+1, z0);
320 double v110 = intGet(x0+1, y0+1, z0);
321 double v001 = intGet(x0, y0, z0+1);
322 double v101 = intGet(x0+1, y0, z0+1);
323 double v011 = intGet(x0, y0+1, z0+1);
324 double v111 = intGet(x0+1, y0+1, z0+1);
326 return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);