ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/noise.C
Revision: 1.2
Committed: Fri Apr 22 02:03:10 2011 UTC (13 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +199 -7 lines
Log Message:
move gridmap to arch, refactor cf.pm a bit

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 *
6 * Deliantra is free software: you can redistribute it and/or modify it under
7 * the terms of the Affero GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * 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 General Public License for more details.
15 *
16 * You should have received a copy of the Affero GNU General Public License
17 * and the GNU General Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 * The authors can be reached via e-mail to <support@deliantra.net>
21 */
22
23 #include "noise.h"
24
25 /////////////////////////////////////////////////////////////////////////////
26
27 noise2d::noise2d (uint32_t seed)
28 {
29 seedable_rand_gen rng (seed);
30
31 for (int i = 0; i < 256; ++i)
32 {
33 for (int j = 0; j < 2; ++j)
34 rvec [i][j] = rng () - 0.5f;
35
36 // normalise
37 float mag = 1.f / sqrtf (rvec [i][0] * rvec [i][0] + rvec [i][1] * rvec [i][1]);
38
39 rvec [i][0] *= mag;
40 rvec [i][1] *= mag;
41 }
42
43 rvmap [0].seed (rng);
44 rvmap [1].seed (rng);
45 }
46
47 float
48 noise2d::noise (float x, float y)
49 {
50 int ix = floorf (x); float fx = x - ix;
51 int iy = floorf (y); float fy = y - iy;
52
53 float v = 0;
54
55 for (int j = -1; j <= 2; ++j)
56 for (int i = -1; i <= 2; ++i)
57 {
58 float Ax = fx - i;
59 float Ay = fy - j;
60
61 float d = Ax * Ax + Ay * Ay;
62
63 if (d < 4)
64 {
65 int h = rvmap [0](ix + i) ^ rvmap [1](iy + j);
66 float *G = rvec [h & 0xff];
67
68 float t1 = 1 - d / 4;
69 float t2 = t1 * t1;
70 float t4 = t2 * t2;
71
72 float p = (4 * t1 - 3) * t4;
73 v += (Ax * G[0] + Ay * G[1]) * p;
74 }
75 }
76
77 return clamp (v * 2, -.9999999f, .9999999f);
78 }
79
80 #if 0||ABSTRACTION_PENALTY_IS_GONE
81 float
82 noise2d::noise (float x, float y)
83 {
84 vec2d X = vec2d (x, y);
85 gen_vec<2,int> I = floor (X);
86 vec2d F = X - I;
87
88 float v = 0;
89
90 for (int j = -1; j <= 2; ++j)
91 for (int i = -1; i <= 2; ++i)
92 {
93 vec2d A = F - vec2d (i, j);
94
95 float d = A * A;
96
97 if (d < 4)
98 {
99 int h = rvmap [0](I[0] + i) ^ rvmap [1](I[1] + j);
100 float *G = rvec [h & 0xff];
101
102 float t1 = 1 - d / 4;
103 float t2 = t1 * t1;
104 float t4 = t2 * t2;
105
106 float p = (4 * t1 - 3) * t4;
107 v += A * vec2d (G[0], G[1]) * p;
108 }
109 }
110
111 return clamp (v * 2, -.9999999f, .9999999f);
112 }
113 #endif
114
115 /////////////////////////////////////////////////////////////////////////////
116
117 noise3d::noise3d (uint32_t seed)
118 {
119 seedable_rand_gen rng (seed);
120
121 for (int i = 0; i < 256; ++i)
122 {
123 for (int j = 0; j < 3; ++j)
124 rvec [i][j] = rng () - 0.5f;
125
126 // normalise
127 float mag = 1.f / sqrtf (rvec [i][0] * rvec [i][0]
128 + rvec [i][1] * rvec [i][1]
129 + rvec [i][2] * rvec [i][2]);
130
131 rvec [i][0] *= mag;
132 rvec [i][1] *= mag;
133 rvec [i][2] *= mag;
134 }
135
136 rvmap [0].seed (rng);
137 rvmap [1].seed (rng);
138 rvmap [2].seed (rng);
139 }
140
141 float
142 noise3d::noise (float x, float y, float z)
143 {
144 int ix = floorf (x); float fx = x - ix;
145 int iy = floorf (y); float fy = y - iy;
146 int iz = floorf (z); float fz = z - iz;
147
148 float v = 0;
149
150 for (int j = -1; j <= 2; ++j)
151 for (int i = -1; i <= 2; ++i)
152 for (int k = -1; k <= 2; ++k)
153 {
154 float Ax = fx - i;
155 float Ay = fy - j;
156 float Az = fz - k;
157
158 float d = Ax * Ax + Ay * Ay + Az * Az;
159
160 if (d < 4)
161 {
162 int h = rvmap [0](ix + i) ^ rvmap [1](iy + j) ^ rvmap [2](iz + k);
163 float *G = rvec [h & 0xff];
164
165 float t1 = 1 - d / 4;
166 float t2 = t1 * t1;
167 float t4 = t2 * t2;
168
169 // (4t⁵ - 3t⁴)
170 float p = (4 * t1 - 3) * t4;
171 v += (Ax * G[0] + Ay * G[1] + Az * G[2]) * p;
172 }
173 }
174
175 return clamp (v * 2, -.9999999f, .9999999f);
176 }
177
178 float
179 noise3d::noise (float x, float y, float z, float nx, float ny, float nz)
180 {
181 int ix = floorf (x); float fx = x - ix;
182 int iy = floorf (y); float fy = y - iy;
183 int iz = floorf (z); float fz = z - iz;
184
185 float v = 0;
186
187 for (int j = -1; j <= 2; ++j)
188 for (int i = -1; i <= 2; ++i)
189 for (int k = -1; k <= 2; ++k)
190 {
191 float Dx = fx - i;
192 float Dy = fy - j;
193 float Dz = fz - k;
194
195 float e = Dx * nx + Dy * ny + Dz * nz;
196
197 float o = 1 - abs (e);
198
199 if (o > 0)
200 {
201 float Ax = Dx - e * nx;
202 float Ay = Dy - e * ny;
203 float Az = Dz - e * nz;
204
205 float d = Ax * Ax + Ay * Ay + Az * Az;
206
207 if (d < 4)
208 {
209 int h = rvmap [0](ix + i) ^ rvmap [1](iy + j) ^ rvmap [2](iz + k);
210 float *G = rvec [h & 0xff];
211
212 float t1 = 1 - d / 4;
213 float t2 = t1 * t1;
214 float t4 = t2 * t2;
215
216 float o2 = o * o;
217
218 // (4t⁵ - 3t⁴) * (3o³ - 2o²)
219 float p = (4 * t1 - 3) * t4 * (3 * o2 - 2 * o2 * o);
220 v += (Ax * G[0] + Ay * G[1] + Az * G[2]) * p;
221 }
222 }
223 }
224
225 return clamp (v * 2, -.9999999f, .9999999f);
226 }
227
228 frac_gen::frac_gen (float hurst_expo, float lacunarity)
229 : h (hurst_expo), lac (lacunarity), noise2d (0)
230 {
231 float exsum = 0;
232
233 for (int i = 0; i < MAX_OCTAVES; ++i)
234 {
235 ex [i] = powf (lac, -h * i);
236 exsum += ex [i];
237 fbm_mul [i] = 0.5f / (exsum * 0.75f); // .75f is a heuristic
238 rot [i].set (0.4488f * i);
239 }
240 }
241
242 float
243 frac_gen::fBm (float x, float y, int octaves)
244 {
245 float v = 0.f;
246
247 for (int i = 0; i < octaves; ++i)
248 {
249 rot [i](x, y);
250
251 v += noise (x + i, y) * ex [i];
252
253 x *= lac;
254 y *= lac;
255 }
256
257 return clamp (v * fbm_mul [octaves - 1] + 0.5f, 0.f, .9999999f);
258 }
259
260 float
261 frac_gen::turbulence (float x, float y, int octaves)
262 {
263 float v = 0.f;
264
265 for (int i = 0; i < octaves; ++i)
266 {
267 rot [i](x, y);
268
269 v += fabsf (noise (x + i, y)) * ex [i];
270
271 x *= lac;
272 y *= lac;
273 }
274
275 return clamp (v * fbm_mul [octaves - 1] * 2.f, 0.f, .9999999f);
276 }
277
278 float
279 frac_gen::multifractal (float x, float y, int octaves, float offset)
280 {
281 float v = 1.f;
282
283 for (int i = 0; i < octaves; ++i)
284 {
285 rot [i](x, y);
286
287 v *= noise (x, y) * ex [i] + offset;
288
289 x *= lac;
290 y *= lac;
291 }
292
293 return clamp (v * 0.5f, 0.f, .9999999f);
294 }
295
296 float
297 frac_gen::heterofractal (float x, float y, int octaves, float offset)
298 {
299 float v = noise (x, y) + offset;
300 int i;
301
302 for (i = 1; i < octaves; ++i)
303 {
304 rot [i](x, y);
305
306 x *= lac;
307 y *= lac;
308
309 v += v * (noise (x, y) * ex [i] + offset);
310 }
311
312 return v / powf (2., octaves);
313 }
314
315 float
316 frac_gen::hybridfractal (float x, float y, int octaves, float offset, float gain)
317 {
318 float v = (noise (x, y) + offset) * ex [0];
319 float weight = v;
320 int i;
321
322 for (i = 1; i < octaves; ++i)
323 {
324 rot [i](x, y);
325
326 x *= lac;
327 y *= lac;
328
329 min_it (weight, 1.f);
330
331 float sig = (noise (x, y) + offset) * ex [i];
332 v += weight * sig;
333 weight *= gain * sig;
334 }
335
336 return clamp (v * 0.5f + 0.5f, 0.f, .9999999f);
337 }
338
339 // http://www.gamasutra.com/view/feature/3098/a_realtime_procedural_universe_.php?page=2
340 float
341 frac_gen::terrain (float x, float y, int octaves)
342 {
343 float v = 0.f;
344
345 for (int i = 0; i < octaves; ++i)
346 {
347 rot[i] (x, y);
348
349 v += noise (x + i, y) * ex [i];
350
351 x *= lac;
352 y *= lac;
353 }
354
355 v *= fbm_mul [octaves - 1];
356
357 return v <= 0.f ? - powf (-v, 0.7f) : powf (v, 1. + noise (x, y) * v);
358 }
359
360 float
361 frac_gen::terrain2 (float x, float y, int octaves)
362 {
363 float a = fBm (x, y, octaves);
364 float b = ridgedmultifractal (x, y, octaves, 1, 8);
365 float fade = fBm (x + 10.3, y + 10.3, octaves);
366
367 const float width = 0.05f;
368
369 if (fade > 0.5f + width)
370 return a;
371 else if (fade < 0.5f - width)
372 return b;
373
374 fade = (fade - 0.5f + width) / (width * 2);
375
376 // sigmoidal curve
377 fade = fade * fade * 2 * (1.5f - fade);
378
379 return a * fade + b * (1 - fade);
380 }
381
382 float
383 frac_gen::ridgedmultifractal (float x, float y, int octaves, float offset, float gain)
384 {
385 float sig = offset - fabsf (noise (x, y));
386 sig *= sig;
387 float v = sig;
388
389 for (int i = 1; i < octaves; ++i)
390 {
391 rot [i](x, y);
392
393 x *= lac;
394 y *= lac;
395
396 float w = clamp (sig * gain, 0.f, 1.f);
397
398 sig = offset - fabsf (noise (x, y));
399 sig *= sig;
400 sig *= w;
401
402 v += sig * ex [i];
403 }
404
405 return clamp (v * 0.25f, 0.f, .9999999f);
406 }
407
408 #if 0
409 void hack()
410 {
411 frac_gen gen (0.5, 2);
412 noise3d n(0);
413
414 #if 0
415 int N = 1024;
416
417 printf ("P6 %d %d 255\n", N, N);
418 // pmake&&server/deliantra-server >x&&convert -depth 8 -size 512xx512 gray:x x.ppm&& cv x.ppm
419 for (int y = 0; y < N; ++y)
420 {
421 if (!(y&63))fprintf (stderr, "y %d\n", y);//D
422 for (int x = 0; x < N; ++x)
423 {
424 putc (128 + 128 * n.noise (x * 0.04 + 0.2, y * 0.04 + 0.2), stdout);
425 putc (128 + 128 * n.noise (x * 0.04 + 0.2, y * 0.08 + 0.2), stdout);
426 putc (128 + 128 * n.noise (x * 0.08 + 0.2, y * 0.04 + 0.2), stdout);
427 //putc (256 * gen.terrain2 (x * 0.004, y * 0.004, 8), stdout);
428 //putc (256 * gen.fBm (x * 0.001, y * 0.001, 3), stdout);
429 //putc (256 * gen.turbulence (x * 0.004 - 1, y * 0.004 - 1, 8), stdout);
430 //putc (256 * gen.heterofractal (x * 0.008, y * 0.008, 8, -1.1, 2.0), stdout);
431 //putc (256 * gen.ridgedmultifractal (x * 0.001, y * 0.001, 32, 1.001, 32), stdout);
432 }
433 }
434 #else
435 int N = 128;
436
437 //printf ("P6 %d %d 255\n", N, N);
438 // pmake&&server/deliantra-server >x&&convert -depth 8 -size 512xx512 gray:x x.ppm&& cv x.ppm
439 for (int z = 0; z < N; ++z)
440 {
441 if (!(z&4))fprintf (stderr, "z %d\n", z);//D
442 for (int y = 0; y < N; ++y)
443 for (int x = 0; x < N; ++x)
444 {
445 float v = n.noise (x * 0.06 + 0.2, y * 0.06 + 0.2, z * 0.06 + 0.2) * 0.5 + 0.5;
446
447 if (z < 64)
448 v = v * (z * z) / (64 * 64);
449
450 if (v <= 0.1)
451 continue;
452
453 float r[4];
454 int i[4];
455
456 r[0] = x;
457 r[1] = y;
458 r[2] = z;
459 r[3] = v;
460
461 memcpy (i, r, 16);
462
463 i[0] = htonl (i[0]);
464 i[1] = htonl (i[1]);
465 i[2] = htonl (i[2]);
466 i[3] = htonl (i[3]);
467
468 fwrite (i, 4*4, 1, stdout);
469 }
470 }
471 #endif
472
473 exit (0);
474 }
475 #endif