From e80e445645100e170ea3683a2815f4ea15cd519f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 6 Oct 2015 15:45:26 +1100 Subject: [PATCH] noise: support n-dimensional noise --- Makefile.am | 4 ++ noise/basis/constant.cpp | 13 ++-- noise/basis/constant.hpp | 5 +- noise/basis/constant.ipp | 4 +- noise/basis/expgrad.hpp | 20 ++++-- noise/basis/expgrad.ipp | 15 ++--- noise/basis/gradient.hpp | 8 ++- noise/basis/gradient.ipp | 20 +++--- noise/basis/patch.hpp | 12 ++-- noise/basis/patch.ipp | 112 +++++++++++++--------------------- noise/basis/perlin.hpp | 8 ++- noise/basis/perlin.ipp | 49 ++++++++------- noise/basis/runtime.cpp | 2 +- noise/basis/runtime.hpp | 8 +-- noise/basis/type/distance.cpp | 43 +++++++++++++ noise/basis/type/distance.hpp | 22 +++++++ noise/basis/type/gradient.cpp | 44 +++++++++++++ noise/basis/type/gradient.hpp | 36 +++++++++++ noise/basis/value.hpp | 9 ++- noise/basis/value.ipp | 50 ++++++++------- noise/basis/worley.hpp | 12 ++-- noise/basis/worley.ipp | 64 +++++++------------ noise/fractal/base.hpp | 6 +- noise/fractal/base.ipp | 84 ++++++++++++------------- noise/fractal/fbm.hpp | 12 ++-- noise/fractal/fbm.ipp | 54 ++++++++-------- noise/fractal/hetero.hpp | 12 ++-- noise/fractal/hetero.ipp | 96 ++++++++++++++--------------- noise/fractal/hmf.hpp | 12 ++-- noise/fractal/hmf.ipp | 58 +++++++++--------- noise/fractal/rmf.hpp | 12 ++-- noise/fractal/rmf.ipp | 66 ++++++++++---------- noise/fractal/runtime.cpp | 5 +- noise/fractal/runtime.hpp | 12 ++-- noise/rand.hpp | 23 +++++-- noise/rand.ipp | 48 ++++++++++----- noise/turbulence.hpp | 26 ++++++-- noise/turbulence.ipp | 44 +++++++------ tools/noise.cpp | 81 ++++++++++++------------ 39 files changed, 711 insertions(+), 500 deletions(-) create mode 100644 noise/basis/type/distance.cpp create mode 100644 noise/basis/type/distance.hpp create mode 100644 noise/basis/type/gradient.cpp create mode 100644 noise/basis/type/gradient.hpp diff --git a/Makefile.am b/Makefile.am index a0413034..0c11a275 100644 --- a/Makefile.am +++ b/Makefile.am @@ -158,6 +158,10 @@ UTIL_FILES = \ noise/basis/perlin.ipp \ noise/basis/runtime.cpp \ noise/basis/runtime.hpp \ + noise/basis/type/distance.cpp \ + noise/basis/type/distance.hpp \ + noise/basis/type/gradient.hpp \ + noise/basis/type/gradient.cpp \ noise/basis/value.hpp \ noise/basis/value.ipp \ noise/basis/worley.hpp \ diff --git a/noise/basis/constant.cpp b/noise/basis/constant.cpp index a156efae..4cce04a5 100644 --- a/noise/basis/constant.cpp +++ b/noise/basis/constant.cpp @@ -19,14 +19,17 @@ using util::noise::basis::constant; -//----------------------------------------------------------------------------- -template -constant::constant (seed_t _seed): +/////////////////////////////////////////////////////////////////////////////// +template +constant::constant (seed_t _seed): seed (_seed), value (42) { ; } /////////////////////////////////////////////////////////////////////////////// -template struct util::noise::basis::constant; -template struct util::noise::basis::constant; +template struct util::noise::basis::constant<2,float>; +template struct util::noise::basis::constant<2,double>; + +template struct util::noise::basis::constant<3,float>; +template struct util::noise::basis::constant<3,double>; diff --git a/noise/basis/constant.hpp b/noise/basis/constant.hpp index 9203a298..75dded55 100644 --- a/noise/basis/constant.hpp +++ b/noise/basis/constant.hpp @@ -22,12 +22,13 @@ #include namespace util { namespace noise { namespace basis { - template + template struct constant { using seed_t = uint64_t; constant (seed_t); - T operator() (util::point<2,T>) const; + + T operator() (point) const; seed_t seed; T value; diff --git a/noise/basis/constant.ipp b/noise/basis/constant.ipp index 3887168c..2f6db204 100644 --- a/noise/basis/constant.ipp +++ b/noise/basis/constant.ipp @@ -20,9 +20,9 @@ #define __UTIL_NOISE_BASIS_CONSTANT_IPP namespace util { namespace noise { namespace basis { - template + template T - constant::operator() (util::point<2,T>) const + constant::operator() (point) const { return value; } diff --git a/noise/basis/expgrad.hpp b/noise/basis/expgrad.hpp index b933205b..cad70218 100644 --- a/noise/basis/expgrad.hpp +++ b/noise/basis/expgrad.hpp @@ -24,10 +24,22 @@ #include "../../point.hpp" #include "../../range.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// modifies a standard uniforma gradient generator to follow an exponential +// distribution, base^(-t*exp) +// +// namespace util { namespace noise { namespace basis { - template L> - struct expgrad : public gradient { - explicit expgrad (seed_t seed, T base = (T)1.02, T exponent = T{256}); + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + lerp_t L // axis interpolation function + > + struct expgrad : public gradient { + explicit expgrad (seed_t seed, + T base = (T)1.02, + T exponent = T{256}); T base (void) const; T base (T); @@ -36,7 +48,7 @@ namespace util { namespace noise { namespace basis { T exponent (T); protected: - vector<2,T> generate (point<2,intmax_t>) const; + vector generate (pointi) const; T m_base; T m_exponent; diff --git a/noise/basis/expgrad.ipp b/noise/basis/expgrad.ipp index dfeb21bf..df29347e 100644 --- a/noise/basis/expgrad.ipp +++ b/noise/basis/expgrad.ipp @@ -24,21 +24,22 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template L> - expgrad::expgrad (seed_t _seed, T _base, T _exponent): - gradient (_seed), + template L + > + expgrad::expgrad (seed_t _seed, T _base, T _exponent): + gradient (_seed), m_base (_base), m_exponent (_exponent) { ; } /////////////////////////////////////////////////////////////////////////// - template L> - vector<2,T> - expgrad::generate (point<2,intmax_t> p) const + template L> + vector + expgrad::generate (pointi p) const { auto t = (noise::rand (this->seed (), p) + 1) / 2; auto factor = std::pow (m_base, -t * m_exponent); - return factor * gradient::generate (p); + return factor * gradient::generate (p); } } } } diff --git a/noise/basis/gradient.hpp b/noise/basis/gradient.hpp index 8762ddfe..e7bfa2d0 100644 --- a/noise/basis/gradient.hpp +++ b/noise/basis/gradient.hpp @@ -24,7 +24,11 @@ namespace util { namespace noise { namespace basis { /// Perlin: interpolated value across each grid space - template L> + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + lerp_t L // axis interpolation function + > struct gradient { gradient (seed_t); @@ -32,7 +36,7 @@ namespace util { namespace noise { namespace basis { seed_t seed (seed_t); protected: - vector<2,T> generate (point<2,intmax_t>) const; + vector generate (pointi) const; seed_t m_seed; }; diff --git a/noise/basis/gradient.ipp b/noise/basis/gradient.ipp index 4ef29e1e..829a8b92 100644 --- a/noise/basis/gradient.ipp +++ b/noise/basis/gradient.ipp @@ -23,36 +23,36 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template L> - gradient::gradient (seed_t _seed): + template L> + gradient::gradient (seed_t _seed): m_seed (_seed) { ; } //------------------------------------------------------------------------- - template L> + template L> seed_t - gradient::seed (void) const + gradient::seed (void) const { return m_seed; } //------------------------------------------------------------------------- - template L> + template L> seed_t - gradient::seed (seed_t _seed) + gradient::seed (seed_t _seed) { return m_seed = _seed; } //------------------------------------------------------------------------- - template L> - vector<2,T> - gradient::generate (point<2,intmax_t> p) const + template L> + vector + gradient::generate (pointi p) const { - return noise::rand<2,T> (m_seed, p); + return noise::rand (m_seed, p); } } } } diff --git a/noise/basis/patch.hpp b/noise/basis/patch.hpp index edc7b3b1..e6aaf92c 100644 --- a/noise/basis/patch.hpp +++ b/noise/basis/patch.hpp @@ -17,16 +17,19 @@ #ifndef __UTIL_NOISE_BASIS_PATCH_HPP #define __UTIL_NOISE_BASIS_PATCH_HPP +#include "./type/distance.hpp" + #include "../fwd.hpp" #include "../../point.hpp" namespace util { namespace noise { namespace basis { - template - struct patch { + template + struct patch : public type::distance { patch (seed_t, T width = 0); range bounds (void) const; - T operator() (point2) const; + + T operator() (point) const; seed_t seed (void) const; seed_t seed (seed_t); @@ -35,9 +38,6 @@ namespace util { namespace noise { namespace basis { T width (T); private: - point2 centroid (util::point2i) const; - T generate (util::point2i) const; - static constexpr T THRESHOLD = 1 - T(0.999); T m_width; diff --git a/noise/basis/patch.ipp b/noise/basis/patch.ipp index 5136697b..7a90bd16 100644 --- a/noise/basis/patch.ipp +++ b/noise/basis/patch.ipp @@ -26,8 +26,8 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template - patch::patch (seed_t _seed, T _width): + template + patch::patch (seed_t _seed, T _width): m_width (_width), m_power (exactly_zero (_width) ? std::numeric_limits::infinity () @@ -37,58 +37,56 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template + template range - patch::bounds (void) const + patch::bounds (void) const { return { T{0}, T{1} }; } /////////////////////////////////////////////////////////////////////////// - template + template T - patch::operator () (point2 p) const + patch::operator () (point p) const { + static const size_t COUNT = type::distance::OFFSET_SIZE; + // extract integer and fractional parts. be careful to always round down auto p_int = floor (p).template cast (); auto p_rem = (p - p_int).template as (); - static const util::vector2i OFFSETS[] = { - { 0, -2 }, - { -1, -1 }, { 0, -1 }, { 1, -1 }, - { -2, 0 }, { -1, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, - { -1, 1 }, { 0, 1 }, { 1, 1 }, - { 0, 2 }, - }; - - static const size_t COUNT = elems (OFFSETS); - - // find the distances to each neighbour's centroid - util::point2 centres[COUNT]; - for (size_t i = 0; i < COUNT; ++i) - centres[i] = centroid (p_int + OFFSETS[i]) + OFFSETS[i]; + // find the distances to each neighbour's centroid. + util::point centres[COUNT]; + std::transform (std::begin (this->OFFSETS), + std::end (this->OFFSETS), + std::begin (centres), + [this,p_int] (auto i) { return (noise::rand (m_seed, p_int + i) + 1) / 2 + i; }); T distances[COUNT]; - for (size_t i = 0; i < COUNT; ++i) - distances[i] = std::sqrt (util::distance2 (p_rem, centres[i])); + std::transform (std::begin (centres), + std::end (centres), + std::begin (distances), + [p_rem] (auto i) { return util::distance (p_rem, i); }); - // sort the distances, using indices so we can use 'offsets' to generate values + // sort the distances using indices so we can reuse indices into + // 'OFFSETS' to generate the random patch values unsigned indices[COUNT]; std::iota (std::begin (indices), std::end (indices), 0); std::sort (std::begin (indices), - std::end (indices), + std::end (indices), [&] (auto a, auto b) { return distances[a] < distances[b]; }); - // calculate normalisation constants for the 9 nearest points. the + // setup normalisation for the distances to the nearest points. the // neighbourhood size is implicitly specified by the 1.5 unit maximum // distance. - constexpr auto MAX_DISTANCE = 2.1213203435596424f; // std::hypot (1.5f, 1.5f); - const auto lo = distances[indices[0]]; - const auto hi = std::min (distances[indices[COUNT-1]], MAX_DISTANCE); + const size_t hi_off = pow(3,S); + + const auto lo = distances[indices[0 ]]; + const auto hi = distances[indices[hi_off]]; T out = 0.f; T sumw = 0.f; @@ -96,11 +94,15 @@ namespace util { namespace noise { namespace basis { // sum the weight values of each neighbour. weight by a function of // the distance. we use an power function which allows a known width // to blend. - for (size_t i = 0; i < COUNT && distances[indices[i]] <= MAX_DISTANCE; ++i) + for (size_t i = 0; i < hi_off; ++i) { - auto v = generate (p_int + OFFSETS[indices[i]]); + auto v = util::noise::rand ( + m_seed, + p_int + this->OFFSETS[indices[i]] + ); + auto d = (distances[indices[i]] - lo) / (hi - lo); - auto w = std::pow (1-d, m_power); + auto w = std::pow (1 - d, m_power); sumw += w; out += v * w; @@ -111,36 +113,36 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template + template seed_t - patch::seed (void) const + patch::seed (void) const { return m_seed; } //------------------------------------------------------------------------- - template + template seed_t - patch::seed (util::noise::seed_t _seed) + patch::seed (util::noise::seed_t _seed) { return m_seed = _seed; } /////////////////////////////////////////////////////////////////////////// - template + template T - patch::width (void) const + patch::width (void) const { return m_width; } //------------------------------------------------------------------------- - template + template T - patch::width (T _width) + patch::width (T _width) { m_width = _width; m_power = exactly_zero (_width) @@ -149,36 +151,4 @@ namespace util { namespace noise { namespace basis { return m_width; } - - - /////////////////////////////////////////////////////////////////////////// - template - util::point2 - patch::centroid (util::point2i 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::point<2,T> { - (u & 0xffff) / T{0xffff}, - (v & 0xffff) / T{0xffff} - }; - - CHECK_LIMIT (r, T{0}, T{1}); - return r; - } - - - //------------------------------------------------------------------------- - template - T - patch::generate (util::point2i p) const - { - using util::hash::murmur2::mix; - - auto u = mix (m_seed, mix (uint64_t (p.x), uint64_t (p.y))); - return (u & 0xffff) / T{0xffff}; - } } } } diff --git a/noise/basis/perlin.hpp b/noise/basis/perlin.hpp index 21c58961..1574286e 100644 --- a/noise/basis/perlin.hpp +++ b/noise/basis/perlin.hpp @@ -19,6 +19,7 @@ #define __UTIL_NOISE_BASIS_PERLIN_HPP #include "./gradient.hpp" +#include "./type/gradient.hpp" #include "../fwd.hpp" #include "../../point.hpp" @@ -27,18 +28,21 @@ namespace util { namespace noise { namespace basis { /// Perlin: interpolated value across each grid space template < + size_t S, // point point dimensionality typename T, // arithmetic and result value_type, must be floating point lerp_t L, // gradient interpolation function template < // gradient provider class, must provide generate(point_t) + size_t, typename, lerp_t > class G = gradient > - struct perlin : public G { + struct perlin : public G, public type::gradient { perlin (seed_t); range bounds (void) const; - T operator() (point<2,T>) const; + + T operator() (point) const; }; } } } diff --git a/noise/basis/perlin.ipp b/noise/basis/perlin.ipp index ebbfc43b..573d9343 100644 --- a/noise/basis/perlin.ipp +++ b/noise/basis/perlin.ipp @@ -20,19 +20,21 @@ #define __UTIL_NOISE_BASIS_PERLIN_IPP #include "../rand.hpp" +#include "../../types.hpp" + namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template L, template > class G> - perlin::perlin (seed_t _seed): - G (_seed) + template L, template > class G> + perlin::perlin (seed_t _seed): + G (_seed) { ; } //------------------------------------------------------------------------- - template L, template > class G> + template L, template > class G> util::range - perlin::bounds (void) const + perlin::bounds (void) const { return { -std::sqrt (T{2}) / 2, @@ -42,37 +44,38 @@ namespace util { namespace noise { namespace basis { //------------------------------------------------------------------------- - template L, template > class G> + template L, template > class G> T - perlin::operator() (util::point<2,T> p) const + perlin::operator() (util::point p) const { // extract integer and fractional parts. be careful to always round down auto p_int = floor (p).template cast (); auto p_rem = p - p_int; // generate the corner positions - auto p0 = p_int + util::vector<2,intmax_t> { 0, 0 }; - auto p1 = p_int + util::vector<2,intmax_t> { 1, 0 }; - auto p2 = p_int + util::vector<2,intmax_t> { 0, 1 }; - auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 }; + pointi p_[pow(2,S)]; + std::transform (std::begin (this->CORNERS), std::end (this->CORNERS), + std::begin (p_), + [p_int] (auto i) { return i + p_int; }); // generate the corner gradients - auto g0 = G::generate (p0); - auto g1 = G::generate (p1); - auto g2 = G::generate (p2); - auto g3 = G::generate (p3); + vector g_[pow(2,S)]; + std::transform (std::begin (p_), std::end (p_), + std::begin (g_), + [this] (auto i) { return this->generate (i); }); // compute the dot products - T v0 = dot (g0, p - p0); - T v1 = dot (g1, p - p1); - T v2 = dot (g2, p - p2); - T v3 = dot (g3, p - p3); + T v_[pow(2,S)]; + for (size_t i = 0; i < elems (v_); ++i) + v_[i] = dot (g_[i], p - p_[i]); // interpolate the results - auto L0 = L (v0, v1, p_rem.x); - auto L1 = L (v2, v3, p_rem.x); - auto L_ = L (L0, L1, p_rem.y); + T l_[pow(2,S)]; + std::copy (std::begin (v_), std::end (v_), std::begin (l_)); - return L_; + for (size_t i = S; i; --i) + for (size_t j = 0; j < std::pow(2,i); j += 2) + l_[j / 2] = L (l_[j], l_[j+1], p_rem[S-i]); + return l_[0]; } } } } diff --git a/noise/basis/runtime.cpp b/noise/basis/runtime.cpp index 2e16eff8..c2fab601 100644 --- a/noise/basis/runtime.cpp +++ b/noise/basis/runtime.cpp @@ -17,4 +17,4 @@ #include "runtime.hpp" -template struct util::noise::basis::runtime; +template struct util::noise::basis::runtime<2,float>; diff --git a/noise/basis/runtime.hpp b/noise/basis/runtime.hpp index 363b24f9..ee411186 100644 --- a/noise/basis/runtime.hpp +++ b/noise/basis/runtime.hpp @@ -25,7 +25,7 @@ #include namespace util { namespace noise { namespace basis { - template + template struct runtime { public: runtime (seed_t) {} @@ -34,7 +34,7 @@ namespace util { namespace noise { namespace basis { runtime& operator= (const runtime&) = delete; // basis functions - T operator () (util::point<2,T> p) const { return (*m_child) (p); } + T operator () (util::point p) const { return (*m_child) (p); } range bounds (void) const { return m_child->bounds (); } seed_t seed (void) const { return m_child->seed (); } @@ -43,7 +43,7 @@ namespace util { namespace noise { namespace basis { private: struct base { virtual ~base () = default; - virtual T operator() (util::point<2,T>) const = 0; + virtual T operator() (util::point) const = 0; virtual range bounds (void) const = 0; virtual seed_t seed (void) const = 0; virtual seed_t seed (seed_t) = 0; @@ -53,7 +53,7 @@ namespace util { namespace noise { namespace basis { struct child : public base { template child (seed_t _seed, Args&& ...args): data (_seed, std::forward (args)...) { } - virtual T operator() (util::point<2,T> p) const override { return data (p); } + virtual T operator() (util::point p) const override { return data (p); } virtual range bounds (void) const override { return data.bounds (); } virtual seed_t seed (void) const override { return data.seed (); } virtual seed_t seed (seed_t _seed) override { return data.seed (_seed); } diff --git a/noise/basis/type/distance.cpp b/noise/basis/type/distance.cpp new file mode 100644 index 00000000..deb1252f --- /dev/null +++ b/noise/basis/type/distance.cpp @@ -0,0 +1,43 @@ +#include "./distance.hpp" +#include "../../../extent.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +template +static const std::array, util::pow(R*2+1,S)> +generate (void) +{ + static const util::extent_range< + S,typename util::vectori::value_type + > area (util::extent::value_type> {R*2+1}); + + std::array< + util::vectori, + util::pow(R*2+1,S) + > out; + + std::transform (area.begin (), area.end (), + out.begin (), + [] (auto i) { return i.template as () - R; }); + + return out; +} + + +/////////////////////////////////////////////////////////////////////////////// +template +const std::array< + util::vectori, + util::pow(R*2+1,S) +> +util::noise::basis::type::distance::OFFSETS = generate (); + + +//----------------------------------------------------------------------------- +template struct util::noise::basis::type::distance<1,1>; +template struct util::noise::basis::type::distance<2,1>; +template struct util::noise::basis::type::distance<3,1>; + +template struct util::noise::basis::type::distance<1,2>; +template struct util::noise::basis::type::distance<2,2>; +template struct util::noise::basis::type::distance<3,2>; diff --git a/noise/basis/type/distance.hpp b/noise/basis/type/distance.hpp new file mode 100644 index 00000000..7111d745 --- /dev/null +++ b/noise/basis/type/distance.hpp @@ -0,0 +1,22 @@ + +#ifndef __UTIL_NOISE_BASIS_TYPE_HPP +#define __UTIL_NOISE_BASIS_TYPE_HPP + +#include "../../../vector.hpp" +#include "../../../maths.hpp" + +#include + +namespace util { namespace noise { namespace basis { namespace type { + template + struct distance { + protected: + static constexpr size_t OFFSET_SIZE = util::pow(R*2+1,S); + + static const std::array< + vectori, util::pow(R*2+1,S) + > OFFSETS; + }; +} } } } + +#endif diff --git a/noise/basis/type/gradient.cpp b/noise/basis/type/gradient.cpp new file mode 100644 index 00000000..c8f1eb05 --- /dev/null +++ b/noise/basis/type/gradient.cpp @@ -0,0 +1,44 @@ +/* + * 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 + */ + +#include "./gradient.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +template +static std::array,util::pow(2,S)> +generate (void) +{ + std::array,util::pow(2,S)> out; + + for (size_t i = 0; i < util::pow(2,S); ++i) + for (size_t s = 0; s < S; ++s) + out[i][s] = (i >> s) & 1; + + return out; +} + + +/////////////////////////////////////////////////////////////////////////////// +template +const std::array,util::pow(2,S)> +util::noise::basis::type::gradient::CORNERS = generate (); + +//----------------------------------------------------------------------------- +template struct util::noise::basis::type::gradient<1>; +template struct util::noise::basis::type::gradient<2>; +template struct util::noise::basis::type::gradient<3>; +template struct util::noise::basis::type::gradient<4>; diff --git a/noise/basis/type/gradient.hpp b/noise/basis/type/gradient.hpp new file mode 100644 index 00000000..36582a93 --- /dev/null +++ b/noise/basis/type/gradient.hpp @@ -0,0 +1,36 @@ +/* + * 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_BASIS_TYPE_GRADIENT_HPP +#define __UTIL_NOISE_BASIS_TYPE_GRADIENT_HPP + +#include "../../../point.hpp" +#include "../../../maths.hpp" + +#include + + +/////////////////////////////////////////////////////////////////////////////// +namespace util { namespace noise { namespace basis { namespace type { + template + struct gradient { + + protected: + static const std::array,util::pow(2,S)> CORNERS; + }; +} } } } + +#endif diff --git a/noise/basis/value.hpp b/noise/basis/value.hpp index 5239b48c..3002157f 100644 --- a/noise/basis/value.hpp +++ b/noise/basis/value.hpp @@ -18,18 +18,21 @@ #ifndef __UTIL_NOISE_BASIS_VALUE_HPP #define __UTIL_NOISE_BASIS_VALUE_HPP +#include "./type/gradient.hpp" + #include "../fwd.hpp" #include "../../range.hpp" #include "../../point.hpp" namespace util { namespace noise { namespace basis { /// Single value per grid space - template > - struct value { + template > + struct value : public type::gradient { value (seed_t); range bounds (void) const; - T operator() (util::point<2,T>) const; + + T operator() (util::point) const; seed_t seed (void) const; seed_t seed (seed_t); diff --git a/noise/basis/value.ipp b/noise/basis/value.ipp index 4c2f3786..82a31f9f 100644 --- a/noise/basis/value.ipp +++ b/noise/basis/value.ipp @@ -20,68 +20,72 @@ #define __UTIL_NOISE_BASIS_VALIE_IPP #include "../rand.hpp" +#include "../../types.hpp" + namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template L> - value::value (seed_t _seed): + template L> + value::value (seed_t _seed): m_seed (_seed) { ; } //------------------------------------------------------------------------- - template L> + template L> util::range - value::bounds (void) const + value::bounds (void) const { return { -1, 1 }; } //------------------------------------------------------------------------- - template L> + template L> seed_t - value::seed (void) const + value::seed (void) const { return m_seed; } //------------------------------------------------------------------------- - template L> + template L> seed_t - value::seed (seed_t _seed) + value::seed (seed_t _seed) { return m_seed = _seed; } //------------------------------------------------------------------------- - template L> + template L> T - value::operator() (util::point<2,T> p) const + value::operator() (util::point p) const { // extract integer and fractional parts. be careful to always round down auto p_int = floor (p).template cast (); auto p_rem = p - p_int; // generate the corner points - auto p0 = p_int + util::vector<2,intmax_t> { 0, 0 }; - auto p1 = p_int + util::vector<2,intmax_t> { 1, 0 }; - auto p2 = p_int + util::vector<2,intmax_t> { 0, 1 }; - auto p3 = p_int + util::vector<2,intmax_t> { 1, 1 }; + std::array,pow(2,S)> p_; + std::transform (std::begin (this->CORNERS), std::end (this->CORNERS), + std::begin (p_), + [p_int] (auto i) { return p_int + i; }); - // Generate the four corner values - 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); + // Generate the corner values + std::array g_; + std::transform (std::begin (p_), std::end (p_), + std::begin (g_), + [this] (auto i) { return noise::rand (m_seed, i); }); // Interpolate on one dimension, then the other. - auto l0 = L (g0, g1, p_rem.x); - auto l1 = L (g2, g3, p_rem.x); - auto l_ = L (l0, l1, p_rem.y); + T l_[pow(2,S)]; + std::copy (std::begin (g_), std::end (g_), std::begin (l_)); - return l_; + for (size_t i = S; i; --i) + for (size_t j = 0; j < std::pow(2,i); j += 2) + l_[j / 2] = L (l_[j], l_[j+1], p_rem[S-i]); + return l_[0]; } } } } diff --git a/noise/basis/worley.hpp b/noise/basis/worley.hpp index 048cbd08..891b961e 100644 --- a/noise/basis/worley.hpp +++ b/noise/basis/worley.hpp @@ -18,23 +18,27 @@ #ifndef __UTIL_NOISE_BASIS_WORLEY_HPP #define __UTIL_NOISE_BASIS_WORLEY_HPP +#include "./type/distance.hpp" + #include "../fwd.hpp" #include "../../point.hpp" #include "../../range.hpp" namespace util { namespace noise { namespace basis { - template - struct worley { + template + struct worley : public type::distance { worley (seed_t); range bounds (void) const; - T operator() (util::point<2,T>) const; + + T operator() (util::point) const; seed_t seed (void) const; seed_t seed (seed_t); private: - point<2,T> generate (point<2,intmax_t>) const; + point generate (point) const; + seed_t m_seed; }; } } } diff --git a/noise/basis/worley.ipp b/noise/basis/worley.ipp index e16e991b..88847082 100644 --- a/noise/basis/worley.ipp +++ b/noise/basis/worley.ipp @@ -25,67 +25,58 @@ namespace util { namespace noise { namespace basis { /////////////////////////////////////////////////////////////////////////// - template - worley::worley (seed_t _seed): + template + worley::worley (seed_t _seed): m_seed (_seed) { ; } //------------------------------------------------------------------------- - template + template util::range - worley::bounds (void) const + worley::bounds (void) const { return { 0.0, 1.5 }; } //------------------------------------------------------------------------- - template + template seed_t - worley::seed (void) const + worley::seed (void) const { return m_seed; } //------------------------------------------------------------------------- - template + template seed_t - worley::seed (seed_t _seed) + worley::seed (seed_t _seed) { return m_seed = _seed; } //------------------------------------------------------------------------- - template + template T - worley::operator() (util::point<2,T> p) const + worley::operator() (point p) const { // extract integer and fractional parts. be careful to always round down auto p_int = floor (p).template cast (); auto p_rem = (p - p_int).template as (); // setup an array of distances - constexpr size_t RADIUS = 1; - constexpr size_t COUNT = pow2 (RADIUS * 2 + 1); - T distances[COUNT] = { std::numeric_limits::quiet_NaN () }; - T *cursor = distances; + constexpr size_t COUNT = type::distance::OFFSET_SIZE; + T distances[COUNT]; - // 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); - - CHECK_LIMIT (pos.x, T{0}, T{1}); - CHECK_LIMIT (pos.y, T{0}, T{1}); - - *cursor = distance2 (pos + off, p_rem); - cursor++; - } - } + std::transform (std::begin (this->OFFSETS), std::end (this->OFFSETS), + distances, + [p_int,p_rem,this] (auto i) { + auto q = this->generate (p_int + i); + return distance2 (q + i, p_rem); + }); // find the f'th lowest value static_assert (F < COUNT, "worley order must be less than search radius"); @@ -96,21 +87,10 @@ namespace util { namespace noise { namespace basis { ////////////////////////////////////////////////////////////////////////// - template - point<2,T> - worley::generate (point<2,intmax_t> p) const + template + point + worley::generate (point 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::point<2,T> { - (u & 0xffff) / T{0xffff}, - (v & 0xffff) / T{0xffff} - }; - - CHECK_LIMIT (r, T{0}, T{1}); - return r; + return (noise::rand (m_seed, p) + 1) / 2; } } } } diff --git a/noise/fractal/base.hpp b/noise/fractal/base.hpp index 32f15ccd..fd083820 100644 --- a/noise/fractal/base.hpp +++ b/noise/fractal/base.hpp @@ -32,7 +32,11 @@ namespace util { namespace noise { namespace fractal { /// lacunarity: per octave frequency scaling factor /// amplitude: maximum absolute value of the noise /// gain: per octave amplitude scaling factor. typically 1/f. - template + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // noise basis function + > struct base { using seed_t = uint64_t; diff --git a/noise/fractal/base.ipp b/noise/fractal/base.ipp index 2599705a..1d5d9dc7 100644 --- a/noise/fractal/base.ipp +++ b/noise/fractal/base.ipp @@ -23,14 +23,14 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template - base::base (seed_t _seed, - unsigned _octaves, - T _H, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain): + template + base::base (seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain): // literals m_octaves (_octaves), m_H (_H), @@ -51,27 +51,27 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template + template unsigned - base::octaves (unsigned _octaves) + base::octaves (unsigned _octaves) { return m_octaves = _octaves; } //------------------------------------------------------------------------- - template + template constexpr unsigned - base::octaves (void) const + base::octaves (void) const { return m_octaves; } //------------------------------------------------------------------------- - template + template T - base::H (T _h) + base::H (T _h) { m_H = _h; m_invAH = std::pow (m_amplitude, -m_H); @@ -81,63 +81,63 @@ namespace util { namespace noise { namespace fractal { //------------------------------------------------------------------------- - template + template constexpr T - base::H (void) const + base::H (void) const { return m_H; } //------------------------------------------------------------------------- - template + template T - base::frequency (T _frequency) + base::frequency (T _frequency) { return m_frequency = _frequency; } //------------------------------------------------------------------------- - template + template constexpr T - base::frequency (void) const + base::frequency (void) const { return m_frequency; } //------------------------------------------------------------------------- - template + template T - base::lacunarity (T _lacunarity) + base::lacunarity (T _lacunarity) { return m_lacunarity = _lacunarity; } //------------------------------------------------------------------------- - template + template constexpr T - base::lacunarity (void) const + base::lacunarity (void) const { return m_lacunarity; } //------------------------------------------------------------------------- - template + template constexpr T - base::amplitude (void) const + base::amplitude (void) const { return m_amplitude; } //------------------------------------------------------------------------- - template + template T - base::amplitude (T _amplitude) + base::amplitude (T _amplitude) { m_amplitude = _amplitude; m_invAH = std::pow (m_amplitude, -m_H); @@ -146,18 +146,18 @@ namespace util { namespace noise { namespace fractal { //------------------------------------------------------------------------- - template + template constexpr T - base::gain (void) const + base::gain (void) const { return m_gain; } //------------------------------------------------------------------------- - template + template T - base::gain (T _gain) + base::gain (T _gain) { m_gain = _gain; m_invGH = std::pow (_gain, m_H); @@ -166,36 +166,36 @@ namespace util { namespace noise { namespace fractal { //------------------------------------------------------------------------- - template - typename base::seed_t - base::seed (seed_t _seed) + template + typename base::seed_t + base::seed (seed_t _seed) { return m_basis.seed (_seed); } //------------------------------------------------------------------------- - template - typename base::seed_t - base::seed (void) const + template + typename base::seed_t + base::seed (void) const { return m_basis.seed (); } //------------------------------------------------------------------------- - template + template const B& - base::basis (void) const + base::basis (void) const { return m_basis; } //------------------------------------------------------------------------- - template + template B& - base::basis (void) + base::basis (void) { return m_basis; } diff --git a/noise/fractal/fbm.hpp b/noise/fractal/fbm.hpp index cebe847a..e8674e7f 100644 --- a/noise/fractal/fbm.hpp +++ b/noise/fractal/fbm.hpp @@ -33,9 +33,13 @@ namespace util { namespace noise { namespace fractal { /// lacunarity: per octave frequency scaling factor /// amplitude: maximum absolute value of the noise /// gain: per octave amplitude scaling factor. typically 1/f. - template - struct fbm : public base { - using seed_t = typename base::seed_t; + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // generating basis function + > + struct fbm : public base { + using seed_t = typename base::seed_t; static constexpr unsigned DEFAULT_OCTAVES = 8; static constexpr T DEFAULT_H = 1; @@ -53,7 +57,7 @@ namespace util { namespace noise { namespace fractal { T gain); fbm (seed_t); - T operator() (util::point<2,T>) const; + T operator() (point) const; }; } } } diff --git a/noise/fractal/fbm.ipp b/noise/fractal/fbm.ipp index b6658113..c62ce6e6 100644 --- a/noise/fractal/fbm.ipp +++ b/noise/fractal/fbm.ipp @@ -23,41 +23,41 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template - fbm::fbm (seed_t _seed, - unsigned _octaves, - T _H, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain): - base (_seed, - _octaves, - _H, - _frequency, - _lacunarity, - _amplitude, - _gain) + template + fbm::fbm (seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain) { ; } //------------------------------------------------------------------------- - template - fbm::fbm (seed_t _seed): - fbm (_seed, - DEFAULT_OCTAVES, - DEFAULT_H, - DEFAULT_FREQUENCY, - DEFAULT_LACUNARITY, - DEFAULT_AMPLITUDE, - DEFAULT_GAIN) + template + fbm::fbm (seed_t _seed): + fbm (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN) { ; } /////////////////////////////////////////////////////////////////////////// - template + template T - fbm::operator() (util::point<2,T> p) const + fbm::operator() (point p) const { T total = 0; T scale = this->m_invAH; @@ -67,7 +67,7 @@ namespace util { namespace noise { namespace fractal { for (size_t i = 0; i < this->m_octaves; ++i) { total += this->m_basis (p) * scale; - p += T{1}; + p += PI; p *= this->m_lacunarity; scale *= this->m_invGH; } diff --git a/noise/fractal/hetero.hpp b/noise/fractal/hetero.hpp index 803a9259..31e15768 100644 --- a/noise/fractal/hetero.hpp +++ b/noise/fractal/hetero.hpp @@ -25,9 +25,13 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////// /// Heterogeneous procedural terrain fucntion: stats by altitude method - template - struct hetero : public base { - using seed_t = typename base::seed_t; + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // generating basis function + > + struct hetero : public base { + using seed_t = typename base::seed_t; static constexpr unsigned DEFAULT_OCTAVES = 6; static constexpr T DEFAULT_H = T(0.75); @@ -59,7 +63,7 @@ namespace util { namespace noise { namespace fractal { constexpr T offset (void) const; T offset (T); - T operator() (util::point<2,T>) const; + T operator() (point) const; private: T m_offset; diff --git a/noise/fractal/hetero.ipp b/noise/fractal/hetero.ipp index 99315aea..5a9888ec 100644 --- a/noise/fractal/hetero.ipp +++ b/noise/fractal/hetero.ipp @@ -21,82 +21,82 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template - hetero::hetero(seed_t _seed, - unsigned _octaves, - T _H, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain): - hetero (_seed, + template + hetero::hetero(seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain): + hetero (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain, + -this->basis ().bounds ().min + this->basis ().bounds ().magnitude () / T{2}) + { ; } + + + //------------------------------------------------------------------------- + template + hetero::hetero(seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain, + T _offset): + base (_seed, _octaves, _H, _frequency, _lacunarity, _amplitude, - _gain, - -this->basis ().bounds ().min + this->basis ().bounds ().magnitude () / T{2}) - { ; } - - - //------------------------------------------------------------------------- - template - hetero::hetero(seed_t _seed, - unsigned _octaves, - T _H, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain, - T _offset): - base (_seed, - _octaves, - _H, - _frequency, - _lacunarity, - _amplitude, - _gain), + _gain), m_offset (_offset) { ; } //------------------------------------------------------------------------- - template - hetero::hetero (seed_t _seed): - hetero (_seed, - DEFAULT_OCTAVES, - DEFAULT_H, - DEFAULT_FREQUENCY, - DEFAULT_LACUNARITY, - DEFAULT_AMPLITUDE, - DEFAULT_GAIN, - DEFAULT_OFFSET) + template + hetero::hetero (seed_t _seed): + hetero (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN, + DEFAULT_OFFSET) { ; } /////////////////////////////////////////////////////////////////////////// - template + template constexpr T - hetero::offset (void) const + hetero::offset (void) const { return m_offset; } //------------------------------------------------------------------------- - template + template T - hetero::offset (T _offset) + hetero::offset (T _offset) { return m_offset = _offset; } /////////////////////////////////////////////////////////////////////////// - template + template T - hetero::operator() (util::point<2,T> p) const + hetero::operator() (point p) const { T scale = this->m_invAH; @@ -115,7 +115,7 @@ namespace util { namespace noise { namespace fractal { result += increment; - p += T{1}; + p += PI; p *= this->m_lacunarity; } diff --git a/noise/fractal/hmf.hpp b/noise/fractal/hmf.hpp index 3ce521d3..491ceeb0 100644 --- a/noise/fractal/hmf.hpp +++ b/noise/fractal/hmf.hpp @@ -24,9 +24,13 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////// /// Musgrave's "Hybrid MultiFractal" - template - struct hmf : public base { - using seed_t = typename base::seed_t; + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // generating basis function + > + struct hmf : public base { + using seed_t = typename base::seed_t; // H should be fairly low due to the decreasing weight parameter in eval static constexpr unsigned DEFAULT_OCTAVES = 6; @@ -48,7 +52,7 @@ namespace util { namespace noise { namespace fractal { hmf (seed_t); - T operator() (point<2,T>) const; + T operator() (point) const; private: T m_offset; diff --git a/noise/fractal/hmf.ipp b/noise/fractal/hmf.ipp index 8d0048bb..2f70313d 100644 --- a/noise/fractal/hmf.ipp +++ b/noise/fractal/hmf.ipp @@ -22,44 +22,44 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template - hmf::hmf (seed_t _seed, - unsigned _octaves, - T _H, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain, - T _offset): - base (_seed, - _octaves, - _H, - _frequency, - _lacunarity, - _amplitude, - _gain), + template + hmf::hmf (seed_t _seed, + unsigned _octaves, + T _H, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain, + T _offset): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain), m_offset (_offset) { ; } //------------------------------------------------------------------------- - template - hmf::hmf (seed_t _seed): - hmf (_seed, - DEFAULT_OCTAVES, - DEFAULT_H, - DEFAULT_FREQUENCY, - DEFAULT_LACUNARITY, - DEFAULT_AMPLITUDE, - DEFAULT_GAIN, - DEFAULT_OFFSET) + template + hmf::hmf (seed_t _seed): + hmf (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN, + DEFAULT_OFFSET) { ; } /////////////////////////////////////////////////////////////////////////// - template + template T - hmf::operator() (util::point<2,T> p) const + hmf::operator() (point p) const { T scale = this->m_invAH; @@ -77,7 +77,7 @@ namespace util { namespace noise { namespace fractal { weight = min (weight, T{1}); scale *= this->m_invGH; - p += T{1}; + p += PI; p *= this->m_lacunarity; } diff --git a/noise/fractal/rmf.hpp b/noise/fractal/rmf.hpp index 496ba92a..50b3f463 100644 --- a/noise/fractal/rmf.hpp +++ b/noise/fractal/rmf.hpp @@ -32,9 +32,13 @@ namespace util { namespace noise { namespace fractal { /// lacunarity: incremental octave frequency scaling factor /// amplitude: value scaling factor for the base octave /// gain: incremental octave value scaling factor - template - struct rmf : public base { - using seed_t = typename base::seed_t; + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // generating basis function + > + struct rmf : public base { + using seed_t = typename base::seed_t; static constexpr unsigned DEFAULT_OCTAVES = 5; static constexpr T DEFAULT_H = 1; @@ -55,7 +59,7 @@ namespace util { namespace noise { namespace fractal { rmf (seed_t); - T operator() (util::point<2,T>) const; + T operator() (point) const; T offset (void) const; T offset (T); diff --git a/noise/fractal/rmf.ipp b/noise/fractal/rmf.ipp index 99d24c8f..27a31198 100644 --- a/noise/fractal/rmf.ipp +++ b/noise/fractal/rmf.ipp @@ -22,46 +22,46 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template - rmf::rmf (seed_t _seed, - unsigned _octaves, - T _H, - T _offset, - T _frequency, - T _lacunarity, - T _amplitude, - T _gain): - base (_seed, - _octaves, - _H, - _frequency, - _lacunarity, - _amplitude, - _gain), + template + rmf::rmf (seed_t _seed, + unsigned _octaves, + T _H, + T _offset, + T _frequency, + T _lacunarity, + T _amplitude, + T _gain): + base (_seed, + _octaves, + _H, + _frequency, + _lacunarity, + _amplitude, + _gain), m_offset (_offset) { ; } //------------------------------------------------------------------------- - template - rmf::rmf (seed_t _seed): - rmf (_seed, - DEFAULT_OCTAVES, - DEFAULT_H, - DEFAULT_FREQUENCY, - DEFAULT_LACUNARITY, - DEFAULT_AMPLITUDE, - DEFAULT_GAIN, - DEFAULT_OFFSET) + template + rmf::rmf (seed_t _seed): + rmf (_seed, + DEFAULT_OCTAVES, + DEFAULT_H, + DEFAULT_FREQUENCY, + DEFAULT_LACUNARITY, + DEFAULT_AMPLITUDE, + DEFAULT_GAIN, + DEFAULT_OFFSET) { ; } /////////////////////////////////////////////////////////////////////////// // we use the name 'amplitude' instead of musgrave's 'gain'. // assumes basis distribution [-1,1] and offset ~= 1 - template + template T - rmf::operator() (util::point<2,T> p) const + rmf::operator() (point p) const { T scale = this->m_invAH; @@ -92,7 +92,7 @@ namespace util { namespace noise { namespace fractal { scale *= this->m_invGH; - p += T{1}; + p += PI; p *= this->m_lacunarity; } @@ -101,18 +101,18 @@ namespace util { namespace noise { namespace fractal { /////////////////////////////////////////////////////////////////////////// - template + template T - rmf::offset (void) const + rmf::offset (void) const { return m_offset; } //------------------------------------------------------------------------- - template + template T - rmf::offset (T _offset) + rmf::offset (T _offset) { return m_offset = _offset; } diff --git a/noise/fractal/runtime.cpp b/noise/fractal/runtime.cpp index 3e54031e..33894f7f 100644 --- a/noise/fractal/runtime.cpp +++ b/noise/fractal/runtime.cpp @@ -17,4 +17,7 @@ #include "runtime.hpp" #include "../basis/runtime.hpp" -template struct util::noise::fractal::runtime>; +template struct util::noise::fractal::runtime< + 2,float, + util::noise::basis::runtime<2,float> +>; diff --git a/noise/fractal/runtime.hpp b/noise/fractal/runtime.hpp index e54f1e2f..27c17f29 100644 --- a/noise/fractal/runtime.hpp +++ b/noise/fractal/runtime.hpp @@ -25,7 +25,11 @@ #include namespace util { namespace noise { namespace fractal { - template + template < + size_t S, // probe point dimensionality + typename T, // probe point value_type + typename B // generating basis function + > struct runtime { public: using seed_t = uint64_t; @@ -37,7 +41,7 @@ namespace util { namespace noise { namespace fractal { runtime& operator= (const runtime&) = delete; // basis functions - T operator () (util::point<2,T> p) const { return (*m_child) (p); } + T operator () (point p) const { return (*m_child) (p); } unsigned octaves (void) const { return m_child->octaves (); } unsigned octaves (unsigned _octaves) { return m_child->octaves (_octaves); } @@ -67,7 +71,7 @@ namespace util { namespace noise { namespace fractal { struct base { virtual ~base () = default; - virtual T operator() (util::point<2,T>) = 0; + virtual T operator() (util::point) = 0; virtual unsigned octaves (void) const = 0; virtual unsigned octaves (unsigned) = 0; @@ -116,7 +120,7 @@ namespace util { namespace noise { namespace fractal { _gain) { ; } - T operator() (util::point<2,T> p) override { return data (p); } + T operator() (util::point p) override { return data (p); } unsigned octaves (void) const override { return data.octaves (); } unsigned octaves (unsigned _octaves) override { return data.octaves (_octaves); } diff --git a/noise/rand.hpp b/noise/rand.hpp index 105ca1bd..7178c4ab 100644 --- a/noise/rand.hpp +++ b/noise/rand.hpp @@ -19,13 +19,24 @@ 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 < + typename U, + size_t S, + typename T, + template class Q + > + U + rand (uint64_t seed, Q value); - template - vector - rand (uint64_t seed, V value); + template < + template class R, + typename U, + size_t S, + typename T, + template class Q + > + R + rand (uint64_t seed, Q value); } } #include "rand.ipp" diff --git a/noise/rand.ipp b/noise/rand.ipp index f8d932d8..dd084e5c 100644 --- a/noise/rand.ipp +++ b/noise/rand.ipp @@ -24,37 +24,53 @@ namespace util { namespace noise { - template - T - rand (uint64_t seed, V value) + //------------------------------------------------------------------------- + template < + typename U, + size_t S, + typename T, + template class Q + > + U + rand (uint64_t seed, Q query) { + static_assert (std::is_integral::value, + "mixing only works on integral types"); + uint64_t accum = seed; - for (auto i: value) + for (auto i: query) accum = hash::murmur2::mix (accum, i); - T out = (accum & 0xFFFF) / T{0xFFFF}; + U result = (accum & 0xFFFF) / U{0xFFFF}; - out *= 2; - out -= 1; + result *= 2; + result -= 1; - return out; + return result; } - template - vector - rand (uint64_t seed, V value) + //------------------------------------------------------------------------- + template < + template class R, + typename U, + size_t S, + typename T, + template class Q + > + R + rand (uint64_t seed, Q query) { uint64_t accum = seed; - for (auto i: value) + for (auto i: query) accum = hash::murmur2::mix (accum, i); - vector out; - for (auto &i: out) { - i = (accum & 0xFFFF) / T{0xFFFF}; + R result; + for (auto &i: result) { + i = (accum & 0xFFFF) / U{0xFFFF}; accum = hash::murmur2::mix (accum, seed); } - return out * 2 - 1; + return result * 2 - 1; } } } diff --git a/noise/turbulence.hpp b/noise/turbulence.hpp index 154d6048..9b0b0ed4 100644 --- a/noise/turbulence.hpp +++ b/noise/turbulence.hpp @@ -29,20 +29,36 @@ namespace util { namespace noise { /// assumes the pertubation function is roughly symetrical around 0. /// nothing will explode if it isn't, but you'll see strong directional /// artefacts with higher scaling factors. - template + template < + size_t S, // dimension + typename T, // value_type + typename D, // data fractal + typename P // pertubation fractal + > struct turbulence { + static constexpr auto dimension = S; + using value_type = T; + using seed_t = uint64_t; - turbulence (seed_t, vector<2,T> scale); + + turbulence (seed_t, vector scale); seed_t seed (seed_t); seed_t seed (void) const; - constexpr T operator() (point<2,T>) const; + constexpr T operator() (point) const; D data; - P perturb[2]; - vector<2,T> scale; + // XXX: use a union to defer initialization of pertubation fractals in + // the constructor. i know this is horrible, but there's no time to + // write the proper generator constructor to pass out the seeds. + union { + char _[0]; + P perturb[S]; + }; + + vector scale; }; } } diff --git a/noise/turbulence.ipp b/noise/turbulence.ipp index dab3822c..c6bee933 100644 --- a/noise/turbulence.ipp +++ b/noise/turbulence.ipp @@ -24,50 +24,48 @@ namespace util { namespace noise { /////////////////////////////////////////////////////////////////////////// - template - turbulence::turbulence (seed_t _seed, - vector<2,T> _scale): + template + turbulence::turbulence (seed_t _seed, + vector _scale): data (_seed), - perturb { - hash::wang (_seed), - hash::wang (hash::wang (_seed)) - }, scale (_scale) - { ; } + { + for (auto &p: perturb) + new (&p) P (_seed = hash::wang (_seed)); + } //////////////////////////////////////////////////////////////////////////// - template - typename turbulence::seed_t - turbulence::seed (void) const + template + typename turbulence::seed_t + turbulence::seed (void) const { return data.seed (); } //------------------------------------------------------------------------- - template - typename turbulence::seed_t - turbulence::seed (seed_t _seed) + template + typename turbulence::seed_t + turbulence::seed (seed_t _seed) { auto ret = _seed; + data.seed (_seed); - data.seed (_seed); _seed = hash::wang (_seed); - perturb[0].seed (_seed); _seed = hash::wang (_seed); - perturb[1].seed (_seed); _seed = hash::wang (_seed); + for (size_t i = 0; i < S; ++i) + perturb[i].seed (_seed = hash::wang (_seed)); return ret; } /////////////////////////////////////////////////////////////////////////// - template + template constexpr T - turbulence::operator() (point<2,T> p) const + turbulence::operator() (point p) const { - vector<2,T> n = { - perturb[0] (p), - perturb[1] (p) - }; + vector n; + for (size_t i = 0; i < S; ++i) + n[i] = perturb[i] (p); // scale by the data frequency so that we match scale return data (p + n * scale / data.frequency ()); diff --git a/tools/noise.cpp b/tools/noise.cpp index 4d23df86..e2bc9810 100644 --- a/tools/noise.cpp +++ b/tools/noise.cpp @@ -25,11 +25,13 @@ #include "region.hpp" +constexpr size_t S = 3; + /////////////////////////////////////////////////////////////////////////////// -template struct util::noise::fractal::fbm>; -template struct util::noise::fractal::hmf>; -template struct util::noise::fractal::rmf>; -template struct util::noise::fractal::hetero>; +template struct util::noise::fractal::fbm>; +template struct util::noise::fractal::hmf>; +template struct util::noise::fractal::rmf>; +template struct util::noise::fractal::hetero>; /////////////////////////////////////////////////////////////////////////////// @@ -221,30 +223,30 @@ main (int argc, char **argv) #endif util::noise::turbulence< - float, + S,float, util::noise::fractal::runtime< - float, - util::noise::basis::runtime + S,float, + util::noise::basis::runtime >, util::noise::fractal::fbm< - float, + S,float, util::noise::basis::perlin< - float, + S,float, util::lerp::cubic > > - > t (seed, { turbulence, turbulence }); + > t (seed, util::vectorf (turbulence)); auto &f = t.data; switch (fractal) { using namespace util::noise; - case FBM: f.reset>> (seed); break; - case HMF: f.reset>> (seed); break; - case RMF: f.reset>> (seed); break; + case FBM: f.reset>> (seed); break; + case HMF: f.reset>> (seed); break; + case RMF: f.reset>> (seed); break; case HETERO: { - auto &child = f.reset>> (seed); + auto &child = f.reset>> (seed); if (!std::isnan (offset)) child.offset (offset); break; @@ -260,11 +262,11 @@ main (int argc, char **argv) case PERLIN: { switch (lerp) { - case LINEAR: b.reset> (seed); break; - case CUBIC: b.reset> (seed); break; - case QUINTIC: b.reset> (seed); break; - case COSINE: b.reset> (seed); break; - case TRUNC: b.reset> (seed); break; + case LINEAR: b.reset> (seed); break; + case CUBIC: b.reset> (seed); break; + case QUINTIC: b.reset> (seed); break; + case COSINE: b.reset> (seed); break; + case TRUNC: b.reset> (seed); break; default: unreachable (); @@ -274,11 +276,11 @@ main (int argc, char **argv) case EXPDIST: { switch (lerp) { - case LINEAR: b.reset> (seed); break; - case CUBIC: b.reset> (seed); break; - case QUINTIC: b.reset> (seed); break; - case COSINE: b.reset> (seed); break; - case TRUNC: b.reset> (seed); break; + case LINEAR: b.reset> (seed); break; + case CUBIC: b.reset> (seed); break; + case QUINTIC: b.reset> (seed); break; + case COSINE: b.reset> (seed); break; + case TRUNC: b.reset> (seed); break; default: unreachable (); @@ -288,11 +290,11 @@ main (int argc, char **argv) case VALUE: { switch (lerp) { - case LINEAR: b.reset> (seed); break; - case CUBIC: b.reset> (seed); break; - case QUINTIC: b.reset> (seed); break; - case COSINE: b.reset> (seed); break; - case TRUNC: b.reset> (seed); break; + case LINEAR: b.reset> (seed); break; + case CUBIC: b.reset> (seed); break; + case QUINTIC: b.reset> (seed); break; + case COSINE: b.reset> (seed); break; + case TRUNC: b.reset> (seed); break; default: unreachable (); @@ -301,12 +303,12 @@ main (int argc, char **argv) } case WORLEY: { - b.reset> (seed); + b.reset> (seed); break; } case PATCH: { - b.reset> (seed, width); + b.reset> (seed, width); break; } @@ -322,9 +324,8 @@ main (int argc, char **argv) if (!std::isnan (amplitude)) f.amplitude (amplitude); if (!std::isnan (gain)) f.gain (gain); - - t.perturb[0].frequency ( scale / res.w); - t.perturb[1].frequency ( scale / res.w); + for (auto &p: t.perturb) + p.frequency (scale / res.w); util::image::buffer img (res); @@ -336,8 +337,10 @@ main (int argc, char **argv) { for (size_t y = 0; y < res.h; ++y) - for (size_t x = 0; x < res.w; ++x) - img[{x, y}] = t (util::point2f {float (x), float (y)} + OFFSET); + for (size_t x = 0; x < res.w; ++x) { + util::point2f p (x, y); + img[{x, y}] = t ((p + OFFSET).redim ()); + } } // working on the assumption that all octave images are based on summation, @@ -350,8 +353,10 @@ main (int argc, char **argv) auto prev = img.clone (); for (size_t y = 0; y < res.h; ++y) - for (size_t x = 0; x < res.w; ++x) - prev[{x,y}] = t (util::point2f {float (x), float (y)} + OFFSET); + for (size_t x = 0; x < res.w; ++x) { + util::point2f p (x, y); + prev[{x,y}] = t ((p + OFFSET).redim ()); + } CHECK_EQ (img.stride (), prev.stride ()); for (size_t i = 0; i < img.size (); ++i)