PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/MonoStrategy/MonoStrategy/GameMap/Utilities/PerlinNoise.cs

#
C# | 358 lines | 271 code | 64 blank | 23 comment | 15 complexity | c475f633edeb554f3d44524d42bf1de4 MD5 | raw file
  1. /*
  2. * This file is part of MonoStrategy.
  3. *
  4. * Copyright (C) 2010-2011 Christoph Husse
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * Authors:
  20. * # Christoph Husse
  21. *
  22. * Also checkout our homepage: http://monostrategy.codeplex.com/
  23. */
  24. using System;
  25. using System.Collections.Generic;
  26. using System.Linq;
  27. using System.Text;
  28. namespace MonoStrategy
  29. {
  30. internal class PerlinNoise
  31. {
  32. internal void FillNoiseArray2D(
  33. int inOctaves,
  34. double inFrequency,
  35. double inAmplitude,
  36. int inSeed,
  37. int inWidth,
  38. int inHeight,
  39. double[] outArray)
  40. {
  41. PerlinNoise noise = new PerlinNoise(inOctaves, inFrequency, inAmplitude, inSeed);
  42. double[] vec = new double[2];
  43. for (int y = 0, offset = 0; y < inHeight; y++)
  44. {
  45. for (int x = 0; x < inWidth; x++)
  46. {
  47. vec[0] = x;
  48. vec[1] = y;
  49. outArray[offset++] = noise.Perlin_noise_2D(vec);
  50. }
  51. }
  52. }
  53. internal void FillNoiseArray3D(
  54. int inOctaves,
  55. double inFrequency,
  56. double inAmplitude,
  57. int inSeed,
  58. int inWidth,
  59. int inHeight,
  60. int inDepth,
  61. double[] outArray)
  62. {
  63. PerlinNoise noise = new PerlinNoise(inOctaves, inFrequency, inAmplitude, inSeed);
  64. double[] vec = new double[3];
  65. for (int z = 0; z < inDepth; z++)
  66. {
  67. for (int y = 0, offset = 0; y < inHeight; y++)
  68. {
  69. for (int x = 0; x < inWidth; x++)
  70. {
  71. vec[0] = x;
  72. vec[1] = y;
  73. vec[2] = z;
  74. outArray[offset++] = noise.Perlin_noise_3D(vec);
  75. }
  76. }
  77. }
  78. }
  79. private const int SAMPLE_SIZE = 1024;
  80. private const int B = SAMPLE_SIZE;
  81. private const int BM = (SAMPLE_SIZE - 1);
  82. private const int N = 0x1000;
  83. private const int NP = 12;
  84. private const int NM = 0xfff;
  85. private int mOctaves;
  86. private double mFrequency;
  87. private double mAmplitude;
  88. private int mSeed;
  89. private CrossRandom mRngCtx;
  90. private int[] p = new int[SAMPLE_SIZE + SAMPLE_SIZE + 2];
  91. private double[][] g3 = new double[SAMPLE_SIZE + SAMPLE_SIZE + 2][];
  92. private double[][] g2 = new double[SAMPLE_SIZE + SAMPLE_SIZE + 2][];
  93. private double[] g1 = new double[SAMPLE_SIZE + SAMPLE_SIZE + 2];
  94. private static double s_curve(double t) { return (t * t * (3.0f - 2.0f * t)); }
  95. private static double lerp(double t, double a, double b) { return (a + t * (b - a)); }
  96. double Noise1(double arg)
  97. {
  98. int bx0, bx1;
  99. double rx0, rx1, sx, t, u, v;
  100. double[] vec = new double[1];
  101. vec[0] = arg;
  102. t = vec[0] + N;
  103. bx0 = ((int)t) & BM;
  104. bx1 = (bx0 + 1) & BM;
  105. rx0 = t - (int)t;
  106. rx1 = rx0 - 1.0f;
  107. sx = s_curve(rx0);
  108. u = rx0 * g1[p[bx0]];
  109. v = rx1 * g1[p[bx1]];
  110. return lerp(sx, u, v);
  111. }
  112. double Noise2(double[] vec)
  113. {
  114. int bx0, bx1, by0, by1, b00, b10, b01, b11;
  115. double rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
  116. double[] q;
  117. int i, j;
  118. t = vec[0] + N;
  119. bx0 = ((int)t) & BM;
  120. bx1 = (bx0 + 1) & BM;
  121. rx0 = t - (int)t;
  122. rx1 = rx0 - 1.0f;
  123. t = vec[1] + N;
  124. by0 = ((int)t) & BM;
  125. by1 = (by0 + 1) & BM;
  126. ry0 = t - (int)t;
  127. ry1 = ry0 - 1.0f;
  128. i = p[bx0];
  129. j = p[bx1];
  130. b00 = p[i + by0];
  131. b10 = p[j + by0];
  132. b01 = p[i + by1];
  133. b11 = p[j + by1];
  134. sx = s_curve(rx0);
  135. sy = s_curve(ry0);
  136. q = g2[b00];
  137. u = (rx0 * q[0] + ry0 * q[1]);
  138. q = g2[b10];
  139. v = (rx1 * q[0] + ry0 * q[1]);
  140. a = lerp(sx, u, v);
  141. q = g2[b01];
  142. u = (rx0 * q[0] + ry1 * q[1]);
  143. q = g2[b11];
  144. v = (rx1 * q[0] + ry1 * q[1]);
  145. b = lerp(sx, u, v);
  146. return lerp(sy, a, b);
  147. }
  148. double Noise3(double[] vec)
  149. {
  150. int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
  151. double rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
  152. double[] q;
  153. int i, j;
  154. t = vec[0] + N;
  155. bx0 = ((int)t) & BM;
  156. bx1 = (bx0 + 1) & BM;
  157. rx0 = t - (int)t;
  158. rx1 = rx0 - 1.0f;
  159. t = vec[1] + N;
  160. by0 = ((int)t) & BM;
  161. by1 = (by0 + 1) & BM;
  162. ry0 = t - (int)t;
  163. ry1 = ry0 - 1.0f;
  164. t = vec[2] + N;
  165. bz0 = ((int)t) & BM;
  166. bz1 = (bz0 + 1) & BM;
  167. rz0 = t - (int)t;
  168. rz1 = rz0 - 1.0f;
  169. i = p[bx0];
  170. j = p[bx1];
  171. b00 = p[i + by0];
  172. b10 = p[j + by0];
  173. b01 = p[i + by1];
  174. b11 = p[j + by1];
  175. t = s_curve(rx0);
  176. sy = s_curve(ry0);
  177. sz = s_curve(rz0);
  178. q = g3[b00 + bz0]; u = (rx0 * q[0] + ry0 * q[1] + rz0 * q[2]);
  179. q = g3[b10 + bz0]; v = (rx1 * q[0] + ry0 * q[1] + rz0 * q[2]);
  180. a = lerp(t, u, v);
  181. q = g3[b01 + bz0]; u = (rx0 * q[0] + ry1 * q[1] + rz0 * q[2]);
  182. q = g3[b11 + bz0]; v = (rx1 * q[0] + ry1 * q[1] + rz0 * q[2]);
  183. b = lerp(t, u, v);
  184. c = lerp(sy, a, b);
  185. q = g3[b00 + bz1]; u = (rx0 * q[0] + ry0 * q[1] + rz1 * q[2]);
  186. q = g3[b10 + bz1]; v = (rx1 * q[0] + ry0 * q[1] + rz1 * q[2]);
  187. a = lerp(t, u, v);
  188. q = g3[b01 + bz1]; u = (rx0 * q[0] + ry1 * q[1] + rz1 * q[2]);
  189. q = g3[b11 + bz1]; v = (rx1 * q[0] + ry1 * q[1] + rz1 * q[2]);
  190. b = lerp(t, u, v);
  191. d = lerp(sy, a, b);
  192. return lerp(sz, c, d);
  193. }
  194. void Normalize2(double[] v)
  195. {
  196. double s;
  197. s = (double)Math.Sqrt(v[0] * v[0] + v[1] * v[1]);
  198. s = 1.0f / s;
  199. v[0] = v[0] * s;
  200. v[1] = v[1] * s;
  201. }
  202. void Normalize3(double[] v)
  203. {
  204. double s;
  205. s = (double)Math.Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  206. s = 1.0f / s;
  207. v[0] = v[0] * s;
  208. v[1] = v[1] * s;
  209. v[2] = v[2] * s;
  210. }
  211. internal PerlinNoise(int octaves, double freq, double amp, int seed)
  212. {
  213. int i, j, k;
  214. mOctaves = octaves;
  215. mFrequency = freq;
  216. mAmplitude = amp;
  217. mSeed = seed;
  218. mRngCtx = new CrossRandom(mSeed);
  219. for (i = 0; i < g3.Length; i++)
  220. {
  221. g3[i] = new double[3];
  222. g2[i] = new double[2];
  223. }
  224. for (i = 0; i < B; i++)
  225. {
  226. p[i] = i;
  227. g1[i] = (double)((mRngCtx.Next() % (B + B)) - B) / B;
  228. for (j = 0; j < 2; j++)
  229. g2[i][j] = (double)((mRngCtx.Next() % (B + B)) - B) / B;
  230. Normalize2(g2[i]);
  231. for (j = 0; j < 3; j++)
  232. g3[i][j] = (double)((mRngCtx.Next() % (B + B)) - B) / B;
  233. Normalize3(g3[i]);
  234. }
  235. while (--i > 0)
  236. {
  237. k = p[i];
  238. p[i] = p[j = mRngCtx.Next() % B];
  239. p[j] = k;
  240. }
  241. for (i = 0; i < B + 2; i++)
  242. {
  243. p[B + i] = p[i];
  244. g1[B + i] = g1[i];
  245. for (j = 0; j < 2; j++)
  246. g2[B + i][j] = g2[i][j];
  247. for (j = 0; j < 3; j++)
  248. g3[B + i][j] = g3[i][j];
  249. }
  250. }
  251. internal double Perlin_noise_3D(double[] vec)
  252. {
  253. int terms = mOctaves;
  254. double freq = mFrequency;
  255. double result = 0.0f;
  256. double amp = mAmplitude;
  257. vec[0] *= mFrequency;
  258. vec[1] *= mFrequency;
  259. vec[2] *= mFrequency;
  260. for (int i = 0; i < terms; i++)
  261. {
  262. result += Noise3(vec) * amp;
  263. vec[0] *= 2.0f;
  264. vec[1] *= 2.0f;
  265. vec[2] *= 2.0f;
  266. amp *= 0.5f;
  267. }
  268. return result;
  269. }
  270. internal double Perlin_noise_2D(double x, double y)
  271. {
  272. double[] vec = new double[2];
  273. vec[0] = x; vec[1] = y;
  274. return Perlin_noise_2D(vec);
  275. }
  276. internal double Perlin_noise_2D(double[] vec)
  277. {
  278. int terms = mOctaves;
  279. double freq = mFrequency;
  280. double result = 0.0f;
  281. double amp = mAmplitude;
  282. vec[0] *= mFrequency;
  283. vec[1] *= mFrequency;
  284. for (int i = 0; i < terms; i++)
  285. {
  286. result += Noise2(vec) * amp;
  287. vec[0] *= 2.0f;
  288. vec[1] *= 2.0f;
  289. amp *= 0.5f;
  290. }
  291. return result;
  292. }
  293. }
  294. }