#include "CtrlLibTest.h" void PerlinNoiseCache::Cache(int cx, int cy) { ASSERT(cx >= 1 && cy >= 1); Clear(); sz = Size(cx, cy); InitNoise(); int xycnt = cx *cy; cache.Alloc(xycnt); float *q = ~cache; for (int y = 0; y < sz.cy; y++) for (int x = 0; x < sz.cx; x++, q++) *q = PerlinNoise2D(x, y); DeinitNoise(); } Image PerlinNoiseCache::AsImage() const { ASSERT(~cache); ImageBuffer ib(sz.cx, sz.cy); RGBA *q = ~ib; RGBA *eoi = q + ib.GetLength(); const float *v = ~cache; while (q != eoi) { q->r = q->g = q->b = 128 + int(128 * (*v)); q->a = 255; q++; v++; } return ib; } float PerlinNoiseCache::Get(int x, int y, int z) const { int offset = z * 151; return Get(x+offset, y+offset); } float PerlinNoiseCache::Get(float x, float y, int z) const { int integer_X = int(x); float fractional_X = x - integer_X; int integer_Y = int(y); float fractional_Y = y - integer_Y; float v1 = Get(integer_X, integer_Y, z); float v2 = Get(integer_X + 1, integer_Y, z); float v3 = Get(integer_X, integer_Y + 1, z); float v4 = Get(integer_X + 1, integer_Y + 1, z); float i1 = CosineInterpolate(v1, v2, fractional_X); float i2 = CosineInterpolate(v3, v4, fractional_X); return CosineInterpolate(i1, i2, fractional_Y); } void PerlinNoiseCache::InitNoise() { int xycnt = sz.cx * sz.cy; noise.Alloc(xycnt); float *q = ~noise; for (int y = 0; y < sz.cy; y++) for (int x = 0; x < sz.cx; x++, q++) *q = ((rand() % 10000) - 5000) / 10000.0f; //*q = PerlinNoise::Noise(x, y); } inline int Abs(int v) { return (v < 0) ? -v : v; } float PerlinNoiseCache::Noise(int x, int y) const { ASSERT(~noise); return noise[Abs((x % sz.cx) + sz.cx * (y % sz.cy))]; } void PerlinNoiseCache::Clear() { cache.Clear(); noise.Clear(); sz = Null; } /* ** Original author: Hugo Elias ** http://freespace.virgin.net/hugo.elias/models/m_perlin.htm ** Modified and corrected by James Thomas */ float PerlinNoise::Noise(int x, int y) const { int n = x + y * 22283; n = (n<<13) ^ n; return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f); } float PerlinNoise::SmoothNoise1(int x, int y) const { float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16; float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8; float center = Noise(x, y) / 4; return corners + sides + center; } float PerlinNoise::CosineInterpolate(float a, float b, float x) const { float ft = x * 3.1415927f; float f = (1 - (float)cos(ft)) * 0.5f; return a*(1-f) + b*f; } float PerlinNoise::InterpolatedNoise1(float x, float y) const { int integer_X = int(x); float fractional_X = x - integer_X; int integer_Y = int(y); float fractional_Y = y - integer_Y; float v1 = SmoothNoise1(integer_X, integer_Y); float v2 = SmoothNoise1(integer_X + 1, integer_Y); float v3 = SmoothNoise1(integer_X, integer_Y + 1); float v4 = SmoothNoise1(integer_X + 1, integer_Y + 1); float i1 = CosineInterpolate(v1, v2, fractional_X); float i2 = CosineInterpolate(v3, v4, fractional_X); return CosineInterpolate(i1, i2, fractional_Y); } float PerlinNoise::PerlinNoise2D(int x, int y) const { float total = 0; float amplitude = 1.0f; float max = 0.0f; int frequency = 1; float fx = float(x); float fy = float(y); for (int i = 0; i < octaves; i++) { total = total + InterpolatedNoise1(fx / frequency, fy / frequency) * amplitude; max += amplitude; amplitude *= persistence; frequency <<= 1; } return total / max; } float PerlinNoise::PerlinNoise2D(float x, float y) const { float total = 0; float amplitude = 1.0f; float max = 0.0f; int frequency = 1; float fx = float(x); float fy = float(y); for (int i = 0; i < octaves; i++) { total = total + InterpolatedNoise1(fx / frequency, fy / frequency) * amplitude; max += amplitude; amplitude *= persistence; frequency <<= 1; } return total / max; } /* ** End of Hugo Elias code */