From 174281ce204c0fa7ad3a10df5816ef8931e3ae8d Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 1 Jul 2015 23:32:27 +1000 Subject: [PATCH] n/rand: add general keyed random facility --- Makefile.am | 2 ++ noise/basis/perlin.hpp | 1 - noise/basis/perlin.ipp | 31 ++++------------------ noise/basis/value.hpp | 2 -- noise/basis/value.ipp | 31 ++++------------------ noise/basis/worley.ipp | 1 - noise/midpoint.cpp | 43 +++++++++++------------------- noise/rand.hpp | 33 +++++++++++++++++++++++ noise/rand.ipp | 60 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 120 insertions(+), 84 deletions(-) create mode 100644 noise/rand.hpp create mode 100644 noise/rand.ipp diff --git a/Makefile.am b/Makefile.am index 26dcf0c4..57382779 100644 --- a/Makefile.am +++ b/Makefile.am @@ -172,6 +172,8 @@ UTIL_FILES = \ noise/lut.hpp \ noise/midpoint.cpp \ noise/midpoint.hpp \ + noise/rand.hpp \ + noise/rand.ipp \ noise/turbulence.hpp \ noise/turbulence.ipp \ pascal.cpp \ diff --git a/noise/basis/perlin.hpp b/noise/basis/perlin.hpp index 2732570e..00f50c16 100644 --- a/noise/basis/perlin.hpp +++ b/noise/basis/perlin.hpp @@ -35,7 +35,6 @@ namespace util { namespace noise { namespace basis { seed_t seed (seed_t); private: - vector<2,T> gradient (point<2,intmax_t>) const; seed_t m_seed; }; } } } diff --git a/noise/basis/perlin.ipp b/noise/basis/perlin.ipp index 70fae7db..821d528b 100644 --- a/noise/basis/perlin.ipp +++ b/noise/basis/perlin.ipp @@ -19,7 +19,7 @@ #endif #define __UTIL_NOISE_BASIS_PERLIN_IPP -#include "../../hash/murmur/murmur2.hpp" +#include "../rand.hpp" namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// @@ -78,10 +78,10 @@ namespace util { namespace noise { namespace basis { auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 }; // generate the corner gradients - auto g0 = gradient (p0); - auto g1 = gradient (p1); - auto g2 = gradient (p2); - auto g3 = gradient (p3); + auto g0 = noise::rand<2,T> (m_seed, p0); + auto g1 = noise::rand<2,T> (m_seed, p1); + auto g2 = noise::rand<2,T> (m_seed, p2); + auto g3 = noise::rand<2,T> (m_seed, p3); // compute the dot products T v0 = dot (g0, p - p0); @@ -96,25 +96,4 @@ namespace util { namespace noise { namespace basis { return L_; } - - /////////////////////////////////////////////////////////////////////////// - template L> - vector<2,T> - perlin::gradient (point<2,intmax_t> p) const - { - using util::hash::murmur2::mix; - - auto u = mix (m_seed, mix (uint64_t (p.x), uint64_t (p.y))); - auto v = mix (u, m_seed); - - auto r = util::vector<2,T> { - (u & 0xffff) / T{0xffff}, - (v & 0xffff) / T{0xffff} - } * 2 - 1; - - CHECK_GE (r, T{-1}); - CHECK_LE (r, T{ 1}); - - return r; - } } } } diff --git a/noise/basis/value.hpp b/noise/basis/value.hpp index 0ae31b85..b43fb06c 100644 --- a/noise/basis/value.hpp +++ b/noise/basis/value.hpp @@ -35,8 +35,6 @@ namespace util { namespace noise { namespace basis { seed_t seed (seed_t); private: - T generate (point<2,intmax_t>) const; - seed_t m_seed; }; } } } diff --git a/noise/basis/value.ipp b/noise/basis/value.ipp index 00fa27e4..8f867c7f 100644 --- a/noise/basis/value.ipp +++ b/noise/basis/value.ipp @@ -19,7 +19,7 @@ #endif #define __UTIL_NOISE_BASIS_VALIE_IPP -#include "../../hash/murmur/murmur2.hpp" +#include "../rand.hpp" namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// @@ -75,10 +75,10 @@ namespace util { namespace noise { namespace basis { auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 }; // Generate the four corner values - T g0 = generate (p0); - T g1 = generate (p1); - T g2 = generate (p2); - T g3 = generate (p3); + T g0 = noise::rand (m_seed, p0); + T g1 = noise::rand (m_seed, p1); + T g2 = noise::rand (m_seed, p2); + T g3 = noise::rand (m_seed, p3); // Interpolate on one dimension, then the other. auto l0 = L (g0, g1, p_rem.x); @@ -87,25 +87,4 @@ namespace util { namespace noise { namespace basis { return l_; } - - - /////////////////////////////////////////////////////////////////////////// - // Generate a type from [-UNIT..UNIT] - template L> - T - value::generate (point<2,intmax_t> p) const - { - using util::hash::murmur2::mix; - - T v = mix ( - m_seed, - mix ( - uint64_t (p.y), - uint64_t (p.x) - ) - ) & 0xffff; - - v = v / T{0xffff} * 2 - 1; - return v; - } } } } diff --git a/noise/basis/worley.ipp b/noise/basis/worley.ipp index c73cc28e..451082af 100644 --- a/noise/basis/worley.ipp +++ b/noise/basis/worley.ipp @@ -21,7 +21,6 @@ #include "../../debug.hpp" -#include "../../hash/murmur/murmur2.hpp" namespace util { namespace noise { namespace basis { diff --git a/noise/midpoint.cpp b/noise/midpoint.cpp index c6e59318..64ccf54a 100644 --- a/noise/midpoint.cpp +++ b/noise/midpoint.cpp @@ -18,25 +18,7 @@ #include "region.hpp" #include "point.hpp" -#include "hash/murmur/murmur2.hpp" - -/////////////////////////////////////////////////////////////////////////////// -template -static T -gen (uint64_t seed, util::point2u p) -{ - using util::hash::murmur2::mix; - - uint64_t v = mix ( - seed, - mix ( - p.y, - p.x - ) - ) & 0xffff; - - return v / T{0xffff} * 2 - 1; -} +#include "rand.hpp" /////////////////////////////////////////////////////////////////////////////// @@ -78,7 +60,7 @@ fill (util::image::buffer &img, // do the centre { const auto avg = (v0 + v1 + v2 + v3) / 4; - const auto val = avg + scale * gen (seed, target.centre ()); + const auto val = avg + scale * util::noise::rand (seed, target.centre ()); const auto pos = target.p + target.e / 2; img[pos] = val; @@ -91,10 +73,10 @@ fill (util::image::buffer &img, const auto p32 = target.p + util::vector2u{w/2, h-1}; const auto p20 = target.p + util::vector2u{0, h/2}; - const auto v01 = (v0 + v1) / 2 + sides * scale * gen (seed, p01); - const auto v13 = (v1 + v3) / 2 + sides * scale * gen (seed, p13); - const auto v32 = (v3 + v2) / 2 + sides * scale * gen (seed, p32); - const auto v20 = (v2 + v0) / 2 + sides * scale * gen (seed, p20); + const auto v01 = (v0 + v1) / 2 + sides * scale * util::noise::rand (seed, p01); + const auto v13 = (v1 + v3) / 2 + sides * scale * util::noise::rand (seed, p13); + const auto v32 = (v3 + v2) / 2 + sides * scale * util::noise::rand (seed, p32); + const auto v20 = (v2 + v0) / 2 + sides * scale * util::noise::rand (seed, p20); img[p01] = v01; img[p13] = v13; @@ -119,10 +101,15 @@ template void util::noise::midpoint (image::buffer &img, uint64_t seed, float persistence, float sides) { - img[{0, 0}] = gen (seed, { 0, 0 }); - img[{0, img.w-1}] = gen (seed, { 0, img.w-1 }); - img[{img.h-1, 0}] = gen (seed, { img.h-1, 0 }); - img[{img.h-1, img.w-1}] = gen (seed, { img.h-1, img.w-1 }); + static const util::point2u CORNERS[] = { + { 0, 0 }, + { 0, img.w - 1 }, + { img.h - 1, 0 }, + { img.h - 1, img.w - 1 } + }; + + for (auto i: CORNERS) + img[i] = util::noise::rand (seed, i); fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides); } diff --git a/noise/rand.hpp b/noise/rand.hpp new file mode 100644 index 00000000..105ca1bd --- /dev/null +++ b/noise/rand.hpp @@ -0,0 +1,33 @@ +/* + * 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 2015 Danny Robson + */ + +#ifndef __UTIL_NOISE_RAND_HPP +#define __UTIL_NOISE_RAND_HPP + +namespace util { namespace noise { + /// generate a uniform random floating point in the range [-1, 1] from a seed and vector + template + T + rand (uint64_t seed, V value); + + template + vector + rand (uint64_t seed, V value); +} } + +#include "rand.ipp" + +#endif diff --git a/noise/rand.ipp b/noise/rand.ipp new file mode 100644 index 00000000..f8d932d8 --- /dev/null +++ b/noise/rand.ipp @@ -0,0 +1,60 @@ +/* + * 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 2015 Danny Robson + */ + + +#ifdef __UTIL_NOISE_RAND_IPP +#error +#endif +#define __UTIL_NOISE_RAND_IPP + +#include "../hash/murmur/murmur2.hpp" + + +namespace util { namespace noise { + template + T + rand (uint64_t seed, V value) + { + uint64_t accum = seed; + for (auto i: value) + accum = hash::murmur2::mix (accum, i); + + T out = (accum & 0xFFFF) / T{0xFFFF}; + + out *= 2; + out -= 1; + + return out; + } + + + template + vector + rand (uint64_t seed, V value) + { + uint64_t accum = seed; + for (auto i: value) + accum = hash::murmur2::mix (accum, i); + + vector out; + for (auto &i: out) { + i = (accum & 0xFFFF) / T{0xFFFF}; + accum = hash::murmur2::mix (accum, seed); + } + + return out * 2 - 1; + } +} }