psemek/libs/pcg/source/perlin.cpp

50 lines
1.3 KiB
C++

#include <psemek/pcg/perlin.hpp>
#include <psemek/geom/interval.hpp>
#include <psemek/util/assert.hpp>
namespace psemek::pcg
{
perlin::perlin(gfx::basic_pixmap<geom::vector<float, 2>> grad_map)
: grad_map_(std::move(grad_map))
{}
static float step(float x0, float x1, float t)
{
return x0 * (1.f - t) + x1 * t;
}
static float smoothstep(float x0, float x1, float t)
{
float const s = t * t * (3.f - 2.f * t);
return step(x0, x1, s);
}
float perlin::operator()(float x, float y) const
{
assert(x >= 0.f);
assert(y >= 0.f);
assert(x <= 1.f);
assert(y <= 1.f);
x *= width();
y *= height();
int const ix = geom::clamp<int>(std::floor(x), {0, static_cast<int>(width()) - 1});
int const iy = geom::clamp<int>(std::floor(y), {0, static_cast<int>(height()) - 1});
float const tx = x - ix;
float const ty = y - iy;
float const d00 = tx * grad_map_(ix, iy)[0] + ty * grad_map_(ix, iy)[1];
float const d10 = (tx-1.f) * grad_map_(ix+1, iy)[0] + ty * grad_map_(ix+1, iy)[1];
float const d01 = tx * grad_map_(ix, iy+1)[0] + (ty-1.f) * grad_map_(ix, iy+1)[1];
float const d11 = (tx-1.f) * grad_map_(ix+1, iy+1)[0] + (ty-1.f) * grad_map_(ix+1, iy+1)[1];
return smoothstep(smoothstep(d00, d10, tx), smoothstep(d01, d11, tx), ty);
}
}