#include "common.hpp" #include namespace procgen { void prng_t::seed(uint32_t seed) { state = seed; next(); next(); } uint32_t prng_t::next(void) { // glibc's LCG parameters (with m = 2^32 - 1). state *= 1103515245; state += 12345; return state; } float prng_t::next_float(void) { return (float)next() / 4294967295.0f; } void prng_t::unit_vec(float out[2]) { float t; t = next_float() * 2.0f * M_PI; out[0] = cos(t); out[1] = sin(t); } v2f_t prng_t::unit_vec2(void) { float t; t = next_float() * 2.0f * M_PI; return {cos(t), sin(t)}; } void perlin_noise_t::generate(prng_t *prng, size_t size_) { if (table) delete[] table; size = size_; table = new float[size * size][2]; for (size_t y = 0; y < size; y++) for (size_t x = 0; x < size; x++) prng->unit_vec(table[y * size + x]); } float perlin_noise_t::table_dot(size_t nx, size_t ny, float dx, float dy) { return table[ny * size + nx][0] * dx + table[ny * size + nx][1] * dy; } static float smooth_step(float x) { return 3 * x * x - 2 * x * x * x; } float perlin_noise_t::get(v2f_t x, float scale) { size_t nx, ny, nx1, ny1; float s, t, a, b, c, d; x /= scale; nx = (ssize_t)floor(x[0]) & (size - 1); ny = (ssize_t)floor(x[1]) & (size - 1); nx1 = (nx == size - 1 ? 0 : nx + 1); ny1 = (ny == size - 1 ? 0 : ny + 1); s = smooth_step(x[0] - floor(x[0])); t = smooth_step(x[1] - floor(x[1])); a = table_dot(nx, ny, -s, -t); b = table_dot(nx1, ny, -s + 1.0f, -t); c = table_dot(nx, ny1, -s, -t + 1.0f); d = table_dot(nx1, ny1, -s + 1.0f, -t + 1.0f); return bilerp(a, b, c, d, s, t); } perlin_noise_t::~perlin_noise_t() { delete[] table; } } // namespace procgen