Arch Game Engine  0.2
PerlinNoise.cpp
1 //Found here: http://stackoverflow.com/questions/4753055/perlin-noise-generation-for-terrain
2 
3 #include "PerlinNoise.h"
4 
5 PerlinNoise::PerlinNoise()
6 {
7  persistence = 0;
8  frequency = 0;
9  amplitude = 0;
10  octaves = 0;
11  randomseed = 0;
12 }
13 
14 PerlinNoise::PerlinNoise(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
15 {
16  persistence = _persistence;
17  frequency = _frequency;
18  amplitude = _amplitude;
19  octaves = _octaves;
20  randomseed = 2 + _randomseed * _randomseed;
21 }
22 
23 void PerlinNoise::Set(double _persistence, double _frequency, double _amplitude, int _octaves, int _randomseed)
24 {
25  persistence = _persistence;
26  frequency = _frequency;
27  amplitude = _amplitude;
28  octaves = _octaves;
29  randomseed = 2 + _randomseed * _randomseed;
30 }
31 
32 double PerlinNoise::GetHeight(double x, double y) const
33 {
34  return amplitude * Total(x, y);
35 }
36 
37 double PerlinNoise::Total(double i, double j) const
38 {
39  //properties of one octave (changing each loop)
40  double t = 0.0f;
41  double _amplitude = 1;
42  double freq = frequency;
43 
44  for(int k = 0; k < octaves; k++)
45  {
46  t += GetValue(j * freq + randomseed, i * freq + randomseed) * _amplitude;
47  _amplitude *= persistence;
48  freq *= 2;
49  }
50 
51  return t;
52 }
53 
54 double PerlinNoise::GetValue(double x, double y) const
55 {
56  int Xint = (int)x;
57  int Yint = (int)y;
58  double Xfrac = x - Xint;
59  double Yfrac = y - Yint;
60 
61  //noise values
62  double n01 = Noise(Xint-1, Yint-1);
63  double n02 = Noise(Xint+1, Yint-1);
64  double n03 = Noise(Xint-1, Yint+1);
65  double n04 = Noise(Xint+1, Yint+1);
66  double n05 = Noise(Xint-1, Yint);
67  double n06 = Noise(Xint+1, Yint);
68  double n07 = Noise(Xint, Yint-1);
69  double n08 = Noise(Xint, Yint+1);
70  double n09 = Noise(Xint, Yint);
71 
72  double n12 = Noise(Xint+2, Yint-1);
73  double n14 = Noise(Xint+2, Yint+1);
74  double n16 = Noise(Xint+2, Yint);
75 
76  double n23 = Noise(Xint-1, Yint+2);
77  double n24 = Noise(Xint+1, Yint+2);
78  double n28 = Noise(Xint, Yint+2);
79 
80  double n34 = Noise(Xint+2, Yint+2);
81 
82  //find the noise values of the four corners
83  double x0y0 = 0.0625*(n01+n02+n03+n04) + 0.125*(n05+n06+n07+n08) + 0.25*(n09);
84  double x1y0 = 0.0625*(n07+n12+n08+n14) + 0.125*(n09+n16+n02+n04) + 0.25*(n06);
85  double x0y1 = 0.0625*(n05+n06+n23+n24) + 0.125*(n03+n04+n09+n28) + 0.25*(n08);
86  double x1y1 = 0.0625*(n09+n16+n28+n34) + 0.125*(n08+n14+n06+n24) + 0.25*(n04);
87 
88  //interpolate between those values according to the x and y fractions
89  double v1 = Interpolate(x0y0, x1y0, Xfrac); //interpolate in x direction (y)
90  double v2 = Interpolate(x0y1, x1y1, Xfrac); //interpolate in x direction (y+1)
91  double fin = Interpolate(v1, v2, Yfrac); //interpolate in y direction
92 
93  return fin;
94 }
95 
96 double PerlinNoise::Interpolate(double x, double y, double a) const
97 {
98  double negA = 1.0 - a;
99  double negASqr = negA * negA;
100  double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA);
101  double aSqr = a * a;
102  double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a);
103 
104  return x * fac1 + y * fac2; //add the weighted factors
105 }
106 
107 double PerlinNoise::Noise(int x, int y) const
108 {
109  int n = x + y * 57;
110  n = (n << 13) ^ n;
111  int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff;
112  return 1.0 - double(t) * 0.931322574615478515625e-9;
113 }