/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2012-2015 Danny Robson */ #include "worley.hpp" #include "../../hash/murmur/murmur2.hpp" using util::noise::basis::worley; /////////////////////////////////////////////////////////////////////////////// template 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::point<2,T> { (u & 0xffff) / T{0xffff}, (v & 0xffff) / T{0xffff} }; CHECK_LIMIT (r, T{0}, T{1}); return r; } /////////////////////////////////////////////////////////////////////////////// template worley::worley (seed_t _seed): seed (_seed) { ; } //----------------------------------------------------------------------------- template worley::worley (): worley (time (nullptr)) { ; } //----------------------------------------------------------------------------- template util::range worley::bounds (void) const { return { 0.0, 1.5 }; } //----------------------------------------------------------------------------- template T 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).template as (); // 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; // 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_LIMIT (pos.x, T{0}, T{1}); CHECK_LIMIT (pos.y, T{0}, T{1}); *cursor = distance2 (pos + off, p_rem); cursor++; } } // 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]; } /////////////////////////////////////////////////////////////////////////////// #include "../lerp.hpp" namespace util { namespace noise { namespace basis { template struct worley; template struct worley; } } }