diff --git a/noise/basis/worley.cpp b/noise/basis/worley.cpp index bf0ef8bc..ba80f9d3 100644 --- a/noise/basis/worley.cpp +++ b/noise/basis/worley.cpp @@ -23,92 +23,84 @@ using util::noise::basis::worley; /////////////////////////////////////////////////////////////////////////////// template -util::vector<2,T> -generate (util::point<2,T> p, uint64_t seed) +util::point<2,T> +generate (util::point<2,intmax_t> p, uint64_t seed) { using util::hash::murmur2::mix; auto u = mix (seed, mix (uint64_t (p.x), uint64_t (p.y))); auto v = mix (u, seed); - auto r = util::vector<2,T> { + auto r = util::point<2,T> { (u & 0xffff) / T{0xffff}, (v & 0xffff) / T{0xffff} - } * 2 - 1; - - CHECK_GE (r, T{-1}); - CHECK_LE (r, T{ 1}); + }; + CHECK_LIMIT (r, T{0}, T{1}); return r; } /////////////////////////////////////////////////////////////////////////////// -template -worley::worley (seed_t _seed): +template +worley::worley (seed_t _seed): seed (_seed) { ; } //----------------------------------------------------------------------------- -template -worley::worley (): - seed (time (nullptr)) +template +worley::worley (): + worley (time (nullptr)) { ; } //----------------------------------------------------------------------------- -template +template util::range -worley::bounds (void) const +worley::bounds (void) const { return { 0.0, 1.5 }; } //----------------------------------------------------------------------------- -template +template T -worley::operator() (util::point<2,T> p) const +worley::operator() (util::point<2,T> p) const { // extract integer and fractional parts. be careful to always round down // (particularly with negatives) and avoid rounding errors. auto p_int = p.template cast (); if (p.x < 0) p_int.x -= 1; if (p.y < 0) p_int.y -= 1; - auto p_rem = abs (p - p_int); + auto p_rem = abs (p - p_int).template as (); - // +---+---+---+ - // | 0 | 1 | 2 | - // +---+---+---+ - // | 3 | 4 | 5 | - // +---+-------+ - // | 6 | 7 | 8 | - // +---+---+---+ - - T distances[9] = { std::numeric_limits::quiet_NaN () }; + // setup an array of distances + static constexpr size_t RADIUS = 1; + static constexpr size_t COUNT = pow2 (RADIUS * 2 + 1); + T distances[COUNT] = { std::numeric_limits::quiet_NaN () }; T *cursor = distances; - for (signed y_off = -1; y_off <= 1 ; ++y_off) - for (signed x_off = -1; x_off <= 1; ++x_off) { - auto pos = vector<2,T> (T (x_off), T (y_off)); - auto off = generate (p_int + pos, this->seed); - off += T{1}; - off /= T{2}; + // record the distances to each candidate point + for (signed y_off = -signed(RADIUS); y_off <= signed(RADIUS) ; ++y_off) { + for (signed x_off = -signed(RADIUS); x_off <= signed(RADIUS); ++x_off) { + auto off = vector<2,intmax_t> {x_off, y_off}; + auto pos = generate (p_int + off, this->seed); - CHECK (off.x >= 0 && off.x <= 1); - CHECK (off.y >= 0 && off.y <= 1); + CHECK_LIMIT (pos.x, T{0}, T{1}); + CHECK_LIMIT (pos.y, T{0}, T{1}); - pos += off; *cursor = distance2 (pos + off, p_rem); cursor++; } } - std::sort (std::begin (distances), std::end (distances)); - CHECK_GE (distances[0], 0); - CHECK (bounds ().contains (distances[0])); - return distances[0]; + // find the f'th lowest value + static_assert (F < COUNT, "worley order must be less than search radius"); + std::partial_sort (distances, distances + F, distances + COUNT); + CHECK_GE (distances[F], 0); + return distances[F]; } diff --git a/noise/basis/worley.hpp b/noise/basis/worley.hpp index 6c472b8d..5b2455bf 100644 --- a/noise/basis/worley.hpp +++ b/noise/basis/worley.hpp @@ -23,7 +23,7 @@ #include "../../range.hpp" namespace util { namespace noise { namespace basis { - template + template struct worley { worley (seed_t); worley ();