ultimatepp/uppdev/CtrlLibTest/PerlinNoise.cpp
cxl 2e4b276e07 Merge continued
git-svn-id: svn://ultimatepp.org/upp/trunk@10263 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-10-04 08:34:39 +00:00

166 lines
No EOL
4.1 KiB
C++

#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
*/