1 /* Copyright (C) 2009 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
19 * 2D and 3D seamless Perlin noise
22 // Based on http://www.cs.cmu.edu/~mzucker/code/perlin-noise-math-faq.html
23 // and http://mrl.nyu.edu/~perlin/paper445.pdf.
24 // Not optimized for speed yet.
26 #include "precompiled.h"
29 #include <boost/random/mersenne_twister.hpp>
33 /// Random number generator (Boost Mersenne Twister)
36 /// Utility function for random numbers
38 return ((float)rng()) / 4294967296.0f
;
41 /// Utility function used in both noises as an ease curve
42 float easeCurve(float t
)
44 return t
*t
*t
*(t
*(t
*6-15)+10);
48 Noise2D::Noise2D(int f
)
51 grads
= new CVector2D
*[freq
];
52 for(int i
=0; i
<freq
; i
++)
54 grads
[i
] = new CVector2D
[freq
];
55 for(int j
=0; j
<freq
; j
++)
57 float a
= randFloat() * 2 * (float)M_PI
;
58 grads
[i
][j
] = CVector2D(cos(a
), sin(a
));
65 for(int i
=0; i
<freq
; i
++)
72 float Noise2D::operator()(float x
, float y
)
77 int ix
= (int)floor(x
);
78 int iy
= (int)floor(y
);
83 ix
%= freq
; if(ix
<0) ix
+= freq
;
84 iy
%= freq
; if(iy
<0) iy
+= freq
;
86 int ix1
= (ix
+1) % freq
;
87 int iy1
= (iy
+1) % freq
;
89 float s
= grads
[ix
][iy
].Dot(CVector2D(fx
, fy
));
90 float t
= grads
[ix1
][iy
].Dot(CVector2D(fx
-1, fy
));
91 float u
= grads
[ix
][iy1
].Dot(CVector2D(fx
, fy
-1));
92 float v
= grads
[ix1
][iy1
].Dot(CVector2D(fx
-1, fy
-1));
94 float ex
= easeCurve(fx
);
95 float ey
= easeCurve(fy
);
96 float a
= s
+ ex
*(t
-s
);
97 float b
= u
+ ex
*(v
-u
);
98 return (a
+ ey
*(b
-a
)) * .5 + .5;
101 Noise3D::Noise3D(int f
, int v
) : freq(f
), vfreq(v
)
103 grads
= new CVector3D
**[freq
];
104 for(int i
=0; i
<freq
; i
++)
106 grads
[i
] = new CVector3D
*[freq
];
107 for(int j
=0; j
<freq
; j
++)
109 grads
[i
][j
] = new CVector3D
[vfreq
];
110 for(int k
=0; k
<vfreq
; k
++)
114 vec
= CVector3D(2*randFloat()-1, 2*randFloat()-1, 2*randFloat()-1);
116 while(vec
.LengthSquared() > 1 || vec
.LengthSquared() < 0.1);
118 grads
[i
][j
][k
] = CVector3D(vec
.X
, vec
.Y
, vec
.Z
);
126 for(int i
=0; i
<freq
; i
++)
128 for(int j
=0; j
<freq
; j
++)
130 delete[] grads
[i
][j
];
137 float Noise3D::operator()(float x
, float y
, float z
)
143 int ix
= (int)floor(x
);
144 int iy
= (int)floor(y
);
145 int iz
= (int)floor(z
);
151 ix
%= freq
; if(ix
<0) ix
+= freq
;
152 iy
%= freq
; if(iy
<0) iy
+= freq
;
153 iz
%= vfreq
; if(iz
<0) iz
+= vfreq
;
155 int ix1
= (ix
+1) % freq
;
156 int iy1
= (iy
+1) % freq
;
157 int iz1
= (iz
+1) % vfreq
;
159 float s0
= grads
[ix
][iy
][iz
].Dot(CVector3D(fx
, fy
, fz
));
160 float t0
= grads
[ix1
][iy
][iz
].Dot(CVector3D(fx
-1, fy
, fz
));
161 float u0
= grads
[ix
][iy1
][iz
].Dot(CVector3D(fx
, fy
-1, fz
));
162 float v0
= grads
[ix1
][iy1
][iz
].Dot(CVector3D(fx
-1, fy
-1, fz
));
164 float s1
= grads
[ix
][iy
][iz1
].Dot(CVector3D(fx
, fy
, fz
-1));
165 float t1
= grads
[ix1
][iy
][iz1
].Dot(CVector3D(fx
-1, fy
, fz
-1));
166 float u1
= grads
[ix
][iy1
][iz1
].Dot(CVector3D(fx
, fy
-1, fz
-1));
167 float v1
= grads
[ix1
][iy1
][iz1
].Dot(CVector3D(fx
-1, fy
-1, fz
-1));
169 float ex
= easeCurve(fx
);
170 float ey
= easeCurve(fy
);
171 float ez
= easeCurve(fz
);
173 float a0
= s0
+ ex
*(t0
-s0
);
174 float b0
= u0
+ ex
*(v0
-u0
);
175 float c0
= a0
+ ey
*(b0
-a0
);
177 float a1
= s1
+ ex
*(t1
-s1
);
178 float b1
= u1
+ ex
*(v1
-u1
);
179 float c1
= a1
+ ey
*(b1
-a1
);
181 return (c0
+ ez
*(c1
-c0
)) * .5 + .5;