/* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * * Copyright (©) 2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * * Deliantra is free software: you can redistribute it and/or modify it under * the terms of the Affero GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public License * and the GNU General Public License along with this program. If not, see * . * * The authors can be reached via e-mail to */ #include "noise.h" noise_gen::noise_gen (uint32_t seed) { seedable_rand_gen rng (seed); for (int i = 0; i < 256; ++i) { for (int j = 0; j < 2; ++j) rvec [i][j] = rng () - 0.5f; // normalise float mag = 1.f / sqrtf (rvec [i][0] * rvec [i][0] + rvec [i][1] * rvec [i][1]); rvec [i][0] *= mag; rvec [i][1] *= mag; } rvmap [0].seed (rng); rvmap [1].seed (rng); } float noise_gen::noise (float x, float y) { int ix = floorf (x); float fx = x - ix; int iy = floorf (y); float fy = y - iy; float v = 0; for (int j = -1; j <= 2; ++j) for (int i = -1; i <= 2; ++i) { float Ax = fx - i; float Ay = fy - j; float d = Ax * Ax + Ay * Ay; if (d < 4) { int h = rvmap [0](ix + i) ^ rvmap [1](iy + j); float *G = rvec [h & 0xff]; float t1 = 1 - d / 4; float t2 = t1 * t1; float t4 = t2 * t2; float p = (4 * t1 - 3) * t4; v += (Ax * G[0] + Ay * G[1]) * p; } } return clamp (v * 2, -.9999999f, .9999999f); } frac_gen::frac_gen (float hurst_expo, float lacunarity) : h (hurst_expo), lac (lacunarity), noise_gen (0) { float exsum = 0; for (int i = 0; i < MAX_OCTAVES; ++i) { ex [i] = powf (lac, -h * i); exsum += ex [i]; fbm_mul [i] = 0.5f / (exsum * 0.75f); // .75f is a heuristic rot [i].set (0.4488f * i); } } float frac_gen::fBm (float x, float y, int octaves) { float v = 0.f; for (int i = 0; i < octaves; ++i) { rot [i](x, y); v += noise (x + i, y) * ex [i]; x *= lac; y *= lac; } return clamp (v * fbm_mul [octaves - 1] + 0.5f, 0.f, .9999999f); } float frac_gen::turbulence (float x, float y, int octaves) { float v = 0.f; for (int i = 0; i < octaves; ++i) { rot [i](x, y); v += fabsf (noise (x + i, y)) * ex [i]; x *= lac; y *= lac; } return clamp (v * fbm_mul [octaves - 1] * 2.f, 0.f, .9999999f); } float frac_gen::multifractal (float x, float y, int octaves, float offset) { float v = 1.f; for (int i = 0; i < octaves; ++i) { rot [i](x, y); v *= noise (x, y) * ex [i] + offset; x *= lac; y *= lac; } return clamp (v * 0.5f, 0.f, .9999999f); } float frac_gen::heterofractal (float x, float y, int octaves, float offset) { float v = noise (x, y) + offset; int i; for (i = 1; i < octaves; ++i) { rot [i](x, y); x *= lac; y *= lac; v += v * (noise (x, y) * ex [i] + offset); } return v / powf (2., octaves); } float frac_gen::hybridfractal (float x, float y, int octaves, float offset, float gain) { float v = (noise (x, y) + offset) * ex [0]; float weight = v; int i; for (i = 1; i < octaves; ++i) { rot [i](x, y); x *= lac; y *= lac; min_it (weight, 1.f); float sig = (noise (x, y) + offset) * ex [i]; v += weight * sig; weight *= gain * sig; } return clamp (v * 0.5f + 0.5f, 0.f, .9999999f); } // http://www.gamasutra.com/view/feature/3098/a_realtime_procedural_universe_.php?page=2 float frac_gen::terrain (float x, float y, int octaves) { float v = 0.f; for (int i = 0; i < octaves; ++i) { rot[i] (x, y); v += noise (x + i, y) * ex [i]; x *= lac; y *= lac; } v *= fbm_mul [octaves - 1]; return v <= 0.f ? - powf (-v, 0.7f) : powf (v, 1. + noise (x, y) * v); } float frac_gen::terrain2 (float x, float y, int octaves) { float a = fBm (x, y, octaves); float b = ridgedmultifractal (x, y, octaves, 1, 8); float fade = fBm (x + 10.3, y + 10.3, octaves); const float width = 0.05f; if (fade > 0.5f + width) return a; else if (fade < 0.5f - width) return b; fade = (fade - 0.5f + width) / (width * 2); // sigmoidal curve fade = fade * fade * 2 * (1.5f - fade); return a * fade + b * (1 - fade); } float frac_gen::ridgedmultifractal (float x, float y, int octaves, float offset, float gain) { float sig = offset - fabsf (noise (x, y)); sig *= sig; float v = sig; for (int i = 1; i < octaves; ++i) { rot [i](x, y); x *= lac; y *= lac; float w = clamp (sig * gain, 0.f, 1.f); sig = offset - fabsf (noise (x, y)); sig *= sig; sig *= w; v += sig * ex [i]; } return clamp (v * 0.25f, 0.f, .9999999f); } #if 0 void hack() { frac_gen gen (0.5, 2); int N = 1024; printf ("P5 %d %d 255\n", N, N); // pmake&&server/deliantra-server >x&&convert -depth 8 -size 512xx512 gray:x x.ppm&& cv x.ppm for (int y = 0; y < N; ++y) { if (!(y&63))fprintf (stderr, "y %d\n", y);//D for (int x = 0; x < N; ++x) { //putc (128 + 128 * gen.noise (x * 0.04, y * 0.04), stdout); putc (256 * gen.terrain2 (x * 0.004, y * 0.004, 8), stdout); //putc (256 * gen.fBm (x * 0.001, y * 0.001, 3), stdout); //putc (256 * gen.turbulence (x * 0.004 - 1, y * 0.004 - 1, 8), stdout); //putc (256 * gen.heterofractal (x * 0.008, y * 0.008, 8, -1.1, 2.0), stdout); //putc (256 * gen.ridgedmultifractal (x * 0.001, y * 0.001, 32, 1.001, 32), stdout); } } exit (0); } #endif