n/rand: add general keyed random facility

This commit is contained in:
Danny Robson 2015-07-01 23:32:27 +10:00
parent 6b712e2f57
commit 174281ce20
9 changed files with 120 additions and 84 deletions

View File

@ -172,6 +172,8 @@ UTIL_FILES = \
noise/lut.hpp \ noise/lut.hpp \
noise/midpoint.cpp \ noise/midpoint.cpp \
noise/midpoint.hpp \ noise/midpoint.hpp \
noise/rand.hpp \
noise/rand.ipp \
noise/turbulence.hpp \ noise/turbulence.hpp \
noise/turbulence.ipp \ noise/turbulence.ipp \
pascal.cpp \ pascal.cpp \

View File

@ -35,7 +35,6 @@ namespace util { namespace noise { namespace basis {
seed_t seed (seed_t); seed_t seed (seed_t);
private: private:
vector<2,T> gradient (point<2,intmax_t>) const;
seed_t m_seed; seed_t m_seed;
}; };
} } } } } }

View File

@ -19,7 +19,7 @@
#endif #endif
#define __UTIL_NOISE_BASIS_PERLIN_IPP #define __UTIL_NOISE_BASIS_PERLIN_IPP
#include "../../hash/murmur/murmur2.hpp" #include "../rand.hpp"
namespace util { namespace noise { namespace basis { 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 }; auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 };
// generate the corner gradients // generate the corner gradients
auto g0 = gradient (p0); auto g0 = noise::rand<2,T> (m_seed, p0);
auto g1 = gradient (p1); auto g1 = noise::rand<2,T> (m_seed, p1);
auto g2 = gradient (p2); auto g2 = noise::rand<2,T> (m_seed, p2);
auto g3 = gradient (p3); auto g3 = noise::rand<2,T> (m_seed, p3);
// compute the dot products // compute the dot products
T v0 = dot (g0, p - p0); T v0 = dot (g0, p - p0);
@ -96,25 +96,4 @@ namespace util { namespace noise { namespace basis {
return L_; return L_;
} }
///////////////////////////////////////////////////////////////////////////
template <typename T, lerp_t<T> L>
vector<2,T>
perlin<T,L>::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;
}
} } } } } }

View File

@ -35,8 +35,6 @@ namespace util { namespace noise { namespace basis {
seed_t seed (seed_t); seed_t seed (seed_t);
private: private:
T generate (point<2,intmax_t>) const;
seed_t m_seed; seed_t m_seed;
}; };
} } } } } }

View File

@ -19,7 +19,7 @@
#endif #endif
#define __UTIL_NOISE_BASIS_VALIE_IPP #define __UTIL_NOISE_BASIS_VALIE_IPP
#include "../../hash/murmur/murmur2.hpp" #include "../rand.hpp"
namespace util { namespace noise { namespace basis { 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 }; auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 };
// Generate the four corner values // Generate the four corner values
T g0 = generate (p0); T g0 = noise::rand<float> (m_seed, p0);
T g1 = generate (p1); T g1 = noise::rand<float> (m_seed, p1);
T g2 = generate (p2); T g2 = noise::rand<float> (m_seed, p2);
T g3 = generate (p3); T g3 = noise::rand<float> (m_seed, p3);
// Interpolate on one dimension, then the other. // Interpolate on one dimension, then the other.
auto l0 = L (g0, g1, p_rem.x); auto l0 = L (g0, g1, p_rem.x);
@ -87,25 +87,4 @@ namespace util { namespace noise { namespace basis {
return l_; return l_;
} }
///////////////////////////////////////////////////////////////////////////
// Generate a type from [-UNIT..UNIT]
template <typename T, lerp_t<T> L>
T
value<T,L>::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;
}
} } } } } }

View File

@ -21,7 +21,6 @@
#include "../../debug.hpp" #include "../../debug.hpp"
#include "../../hash/murmur/murmur2.hpp"
namespace util { namespace noise { namespace basis { namespace util { namespace noise { namespace basis {

View File

@ -18,25 +18,7 @@
#include "region.hpp" #include "region.hpp"
#include "point.hpp" #include "point.hpp"
#include "hash/murmur/murmur2.hpp" #include "rand.hpp"
///////////////////////////////////////////////////////////////////////////////
template <typename T>
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;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -78,7 +60,7 @@ fill (util::image::buffer<T> &img,
// do the centre // do the centre
{ {
const auto avg = (v0 + v1 + v2 + v3) / 4; const auto avg = (v0 + v1 + v2 + v3) / 4;
const auto val = avg + scale * gen<T> (seed, target.centre ()); const auto val = avg + scale * util::noise::rand<T> (seed, target.centre ());
const auto pos = target.p + target.e / 2; const auto pos = target.p + target.e / 2;
img[pos] = val; img[pos] = val;
@ -91,10 +73,10 @@ fill (util::image::buffer<T> &img,
const auto p32 = target.p + util::vector2u{w/2, h-1}; const auto p32 = target.p + util::vector2u{w/2, h-1};
const auto p20 = target.p + util::vector2u{0, h/2}; const auto p20 = target.p + util::vector2u{0, h/2};
const auto v01 = (v0 + v1) / 2 + sides * scale * gen<T> (seed, p01); const auto v01 = (v0 + v1) / 2 + sides * scale * util::noise::rand<T> (seed, p01);
const auto v13 = (v1 + v3) / 2 + sides * scale * gen<T> (seed, p13); const auto v13 = (v1 + v3) / 2 + sides * scale * util::noise::rand<T> (seed, p13);
const auto v32 = (v3 + v2) / 2 + sides * scale * gen<T> (seed, p32); const auto v32 = (v3 + v2) / 2 + sides * scale * util::noise::rand<T> (seed, p32);
const auto v20 = (v2 + v0) / 2 + sides * scale * gen<T> (seed, p20); const auto v20 = (v2 + v0) / 2 + sides * scale * util::noise::rand<T> (seed, p20);
img[p01] = v01; img[p01] = v01;
img[p13] = v13; img[p13] = v13;
@ -119,10 +101,15 @@ template <typename T>
void void
util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence, float sides) util::noise::midpoint (image::buffer<T> &img, uint64_t seed, float persistence, float sides)
{ {
img[{0, 0}] = gen<T> (seed, { 0, 0 }); static const util::point2u CORNERS[] = {
img[{0, img.w-1}] = gen<T> (seed, { 0, img.w-1 }); { 0, 0 },
img[{img.h-1, 0}] = gen<T> (seed, { img.h-1, 0 }); { 0, img.w - 1 },
img[{img.h-1, img.w-1}] = gen<T> (seed, { img.h-1, img.w-1 }); { img.h - 1, 0 },
{ img.h - 1, img.w - 1 }
};
for (auto i: CORNERS)
img[i] = util::noise::rand<T> (seed, i);
fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides); fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides);
} }

33
noise/rand.hpp Normal file
View File

@ -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 <danny@nerdcruft.net>
*/
#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 <typename T, typename V>
T
rand (uint64_t seed, V value);
template <size_t N, typename T, typename V>
vector<N,T>
rand (uint64_t seed, V value);
} }
#include "rand.ipp"
#endif

60
noise/rand.ipp Normal file
View File

@ -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 <danny@nerdcruft.net>
*/
#ifdef __UTIL_NOISE_RAND_IPP
#error
#endif
#define __UTIL_NOISE_RAND_IPP
#include "../hash/murmur/murmur2.hpp"
namespace util { namespace noise {
template <typename T, typename V>
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 <size_t N, typename T, typename V>
vector<N,T>
rand (uint64_t seed, V value)
{
uint64_t accum = seed;
for (auto i: value)
accum = hash::murmur2::mix (accum, i);
vector<N,T> out;
for (auto &i: out) {
i = (accum & 0xFFFF) / T{0xFFFF};
accum = hash::murmur2::mix (accum, seed);
}
return out * 2 - 1;
}
} }