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
));
226 double contour(double v
)
234 double noise3d_param(const NoiseParams
¶m
, double x
, double y
, double z
)
236 double s
= param
.pos_scale
;
241 if(param
.type
== NOISE_PERLIN
)
243 return param
.noise_scale
*noise3d_perlin(x
,y
,z
, param
.seed
,
247 else if(param
.type
== NOISE_PERLIN_ABS
)
249 return param
.noise_scale
*noise3d_perlin_abs(x
,y
,z
, param
.seed
,
253 else if(param
.type
== NOISE_PERLIN_CONTOUR
)
255 return contour(param
.noise_scale
*noise3d_perlin(x
,y
,z
,
256 param
.seed
, param
.octaves
,
259 else if(param
.type
== NOISE_PERLIN_CONTOUR_FLIP_YZ
)
261 return contour(param
.noise_scale
*noise3d_perlin(x
,z
,y
,
262 param
.seed
, param
.octaves
,
272 NoiseBuffer::NoiseBuffer():
277 NoiseBuffer::~NoiseBuffer()
282 void NoiseBuffer::clear()
292 void NoiseBuffer::create(const NoiseParams
¶m
,
293 double first_x
, double first_y
, double first_z
,
294 double last_x
, double last_y
, double last_z
,
295 double samplelength_x
, double samplelength_y
, double samplelength_z
)
299 m_start_x
= first_x
- samplelength_x
;
300 m_start_y
= first_y
- samplelength_y
;
301 m_start_z
= first_z
- samplelength_z
;
302 m_samplelength_x
= samplelength_x
;
303 m_samplelength_y
= samplelength_y
;
304 m_samplelength_z
= samplelength_z
;
306 m_size_x
= (last_x
- m_start_x
)/samplelength_x
+ 2;
307 m_size_y
= (last_y
- m_start_y
)/samplelength_y
+ 2;
308 m_size_z
= (last_z
- m_start_z
)/samplelength_z
+ 2;
310 m_data
= new double[m_size_x
*m_size_y
*m_size_z
];
312 for(int x
=0; x
<m_size_x
; x
++)
313 for(int y
=0; y
<m_size_y
; y
++)
314 for(int z
=0; z
<m_size_z
; z
++)
316 double xd
= (m_start_x
+ (double)x
*m_samplelength_x
);
317 double yd
= (m_start_y
+ (double)y
*m_samplelength_y
);
318 double zd
= (m_start_z
+ (double)z
*m_samplelength_z
);
319 double a
= noise3d_param(param
, xd
,yd
,zd
);
324 void NoiseBuffer::multiply(const NoiseParams
¶m
)
326 assert(m_data
!= NULL
);
328 for(int x
=0; x
<m_size_x
; x
++)
329 for(int y
=0; y
<m_size_y
; y
++)
330 for(int z
=0; z
<m_size_z
; z
++)
332 double xd
= (m_start_x
+ (double)x
*m_samplelength_x
);
333 double yd
= (m_start_y
+ (double)y
*m_samplelength_y
);
334 double zd
= (m_start_z
+ (double)z
*m_samplelength_z
);
335 double a
= noise3d_param(param
, xd
,yd
,zd
);
336 intMultiply(x
,y
,z
, a
);
341 void NoiseBuffer::create(int seed
, int octaves
, double persistence
,
343 double first_x
, double first_y
, double first_z
,
344 double last_x
, double last_y
, double last_z
,
345 double samplelength_x
, double samplelength_y
, double samplelength_z
)
348 param
.type
= abs
? NOISE_PERLIN_ABS
: NOISE_PERLIN
;
350 param
.octaves
= octaves
;
351 param
.persistence
= persistence
;
353 create(param
, first_x
, first_y
, first_z
,
354 last_x
, last_y
, last_z
,
355 samplelength_x
, samplelength_y
, samplelength_z
);
358 void NoiseBuffer::intSet(int x
, int y
, int z
, double d
)
360 int i
= m_size_x
*m_size_y
*z
+ m_size_x
*y
+ x
;
362 assert(i
< m_size_x
*m_size_y
*m_size_z
);
366 void NoiseBuffer::intMultiply(int x
, int y
, int z
, double d
)
368 int i
= m_size_x
*m_size_y
*z
+ m_size_x
*y
+ x
;
370 assert(i
< m_size_x
*m_size_y
*m_size_z
);
371 m_data
[i
] = m_data
[i
] * d
;
374 double NoiseBuffer::intGet(int x
, int y
, int z
)
376 int i
= m_size_x
*m_size_y
*z
+ m_size_x
*y
+ x
;
378 assert(i
< m_size_x
*m_size_y
*m_size_z
);
382 double NoiseBuffer::get(double x
, double y
, double z
)
387 x
/= m_samplelength_x
;
388 y
/= m_samplelength_y
;
389 z
/= m_samplelength_z
;
390 // Calculate the integer coordinates
391 int x0
= (x
> 0.0 ? (int)x
: (int)x
- 1);
392 int y0
= (y
> 0.0 ? (int)y
: (int)y
- 1);
393 int z0
= (z
> 0.0 ? (int)z
: (int)z
- 1);
394 // Calculate the remaining part of the coordinates
395 double xl
= x
- (double)x0
;
396 double yl
= y
- (double)y0
;
397 double zl
= z
- (double)z0
;
398 // Get values for corners of cube
399 double v000
= intGet(x0
, y0
, z0
);
400 double v100
= intGet(x0
+1, y0
, z0
);
401 double v010
= intGet(x0
, y0
+1, z0
);
402 double v110
= intGet(x0
+1, y0
+1, z0
);
403 double v001
= intGet(x0
, y0
, z0
+1);
404 double v101
= intGet(x0
+1, y0
, z0
+1);
405 double v011
= intGet(x0
, y0
+1, z0
+1);
406 double v111
= intGet(x0
+1, y0
+1, z0
+1);
408 return triLinearInterpolation(v000
,v100
,v010
,v110
,v001
,v101
,v011
,v111
,xl
,yl
,zl
);