diff --git a/Makefile.am b/Makefile.am index a352bd97..340eab21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -139,12 +139,12 @@ UTIL_FILES = \ noise/basis/constant.cpp \ noise/basis/constant.hpp \ noise/basis/constant.ipp \ - noise/basis/value.cpp \ noise/basis/value.hpp \ - noise/basis/perlin.cpp \ + noise/basis/value.ipp \ noise/basis/perlin.hpp \ - noise/basis/worley.cpp \ + noise/basis/perlin.ipp \ noise/basis/worley.hpp \ + noise/basis/worley.ipp \ noise/fractal/fbm.hpp \ noise/fractal/fbm.ipp \ noise/fractal/hetero.hpp \ diff --git a/noise/basis/perlin.cpp b/noise/basis/perlin.cpp deleted file mode 100644 index 9656c3c5..00000000 --- a/noise/basis/perlin.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 "perlin.hpp" - -#include "../../hash/murmur/murmur2.hpp" - -using util::noise::basis::perlin; - - -/////////////////////////////////////////////////////////////////////////////// -template -util::vector<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> { - (u & 0xffff) / T{0xffff}, - (v & 0xffff) / T{0xffff} - } * 2 - 1; - - CHECK_GE (r, T{-1}); - CHECK_LE (r, T{ 1}); - - return r; -} - - - -/////////////////////////////////////////////////////////////////////////////// -template L> -perlin::perlin (seed_t _seed): - seed (_seed) -{ ; } - - -//----------------------------------------------------------------------------- -template L> -perlin::perlin (): - seed (time (nullptr)) -{ ; } - - -//----------------------------------------------------------------------------- -template L> -util::range -perlin::bounds (void) const -{ - return { - -std::sqrt (T{2}) / 2, - std::sqrt (T{2}) / 2 - }; -} - - -//----------------------------------------------------------------------------- -template L> -T -perlin::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); - - // 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 }; - - // generate the corner gradients - auto g0 = generate (p0, this->seed); - auto g1 = generate (p1, this->seed); - auto g2 = generate (p2, this->seed); - auto g3 = generate (p3, this->seed); - - // 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); - - // 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); - - return L_; -} - - -/////////////////////////////////////////////////////////////////////////////// -#include "../lerp.hpp" - -namespace util { namespace noise { namespace basis { - template struct perlin; - template struct perlin; - template struct perlin; - template struct perlin; - template struct perlin; - - template struct perlin; - template struct perlin; - template struct perlin; - template struct perlin; - template struct perlin; -} } } diff --git a/noise/basis/perlin.hpp b/noise/basis/perlin.hpp index a2a0be2e..2f15513c 100644 --- a/noise/basis/perlin.hpp +++ b/noise/basis/perlin.hpp @@ -30,10 +30,15 @@ namespace util { namespace noise { namespace basis { perlin (); range bounds (void) const; - T operator() (util::point<2,T>) const; + T operator() (point<2,T>) const; seed_t seed; + + private: + constexpr vector<2,T> gradient (point<2,intmax_t>) const; }; } } } +#include "perlin.ipp" + #endif diff --git a/noise/basis/perlin.ipp b/noise/basis/perlin.ipp new file mode 100644 index 00000000..2e151847 --- /dev/null +++ b/noise/basis/perlin.ipp @@ -0,0 +1,109 @@ +/* + * 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 + */ + +#ifdef __UTIL_NOISE_BASIS_PERLIN_IPP +#error +#endif +#define __UTIL_NOISE_BASIS_PERLIN_IPP + +#include "../../hash/murmur/murmur2.hpp" + +namespace util { namespace noise { namespace basis { + /////////////////////////////////////////////////////////////////////////// + template L> + perlin::perlin (seed_t _seed): + seed (_seed) + { ; } + + + //------------------------------------------------------------------------- + template L> + perlin::perlin (): + seed (time (nullptr)) + { ; } + + + //------------------------------------------------------------------------- + template L> + util::range + perlin::bounds (void) const + { + return { + -std::sqrt (T{2}) / 2, + std::sqrt (T{2}) / 2 + }; + } + + + //------------------------------------------------------------------------- + template L> + T + perlin::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); + + // 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 }; + + // generate the corner gradients + auto g0 = gradient (p0); + auto g1 = gradient (p1); + auto g2 = gradient (p2); + auto g3 = gradient (p3); + + // 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); + + // 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); + + return L_; + } + + /////////////////////////////////////////////////////////////////////////// + template L> + constexpr vector<2,T> + perlin::gradient (point<2,intmax_t> p) const + { + 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> { + (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.cpp b/noise/basis/value.cpp deleted file mode 100644 index dd9747bc..00000000 --- a/noise/basis/value.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 "value.hpp" - -#include "../../hash/murmur/murmur2.hpp" - -using util::noise::basis::value; - - -/////////////////////////////////////////////////////////////////////////////// -// Generate a type from [-UNIT..UNIT] -template -T -generate (util::point<2,intmax_t> p, uint64_t seed) -{ - using util::hash::murmur2::mix; - - T v = mix ( - seed, - mix ( - uint64_t (p.y), - uint64_t (p.x) - ) - ) & 0xffff; - - v = v / T{0xffff} * 2 - 1; - - return v; -} - - -/////////////////////////////////////////////////////////////////////////////// -template L> -value::value (seed_t _seed): - seed (_seed) -{ ; } - - -//----------------------------------------------------------------------------- -template L> -value::value (): - seed (time (nullptr)) -{ ; } - - -//----------------------------------------------------------------------------- -template L> -util::range -value::bounds (void) const -{ - return { -1, 1 }; -} - - -//----------------------------------------------------------------------------- -template L> -T -value::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); - - // 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 }; - - // Generate the four corner values - T g0 = generate (p0, this->seed); - T g1 = generate (p1, this->seed); - T g2 = generate (p2, this->seed); - T g3 = generate (p3, this->seed); - - // 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); - - return l_; -} - - -/////////////////////////////////////////////////////////////////////////////// -#include "../lerp.hpp" - -namespace util { namespace noise { namespace basis { - template struct value; - template struct value; - template struct value; - template struct value; - template struct value; - - template struct value; - template struct value; - template struct value; - template struct value; -} } } diff --git a/noise/basis/value.hpp b/noise/basis/value.hpp index 228e83f4..b7c4016e 100644 --- a/noise/basis/value.hpp +++ b/noise/basis/value.hpp @@ -33,7 +33,12 @@ namespace util { namespace noise { namespace basis { T operator() (util::point<2,T>) const; seed_t seed; + + private: + constexpr T generate (point<2,intmax_t>) const; }; } } } +#include "value.ipp" + #endif diff --git a/noise/basis/value.ipp b/noise/basis/value.ipp new file mode 100644 index 00000000..fbde6e5a --- /dev/null +++ b/noise/basis/value.ipp @@ -0,0 +1,100 @@ +/* + * 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 + */ + +#ifdef __UTIL_NOISE_BASIS_VALUE_IPP +#error +#endif +#define __UTIL_NOISE_BASIS_VALIE_IPP + +#include "../../hash/murmur/murmur2.hpp" + +namespace util { namespace noise { namespace basis { + /////////////////////////////////////////////////////////////////////////// + template L> + value::value (seed_t _seed): + seed (_seed) + { ; } + + + //------------------------------------------------------------------------- + template L> + value::value (): + seed (time (nullptr)) + { ; } + + + //------------------------------------------------------------------------- + template L> + util::range + value::bounds (void) const + { + return { -1, 1 }; + } + + + //------------------------------------------------------------------------- + template L> + T + value::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); + + // 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 }; + + // Generate the four corner values + T g0 = generate (p0); + T g1 = generate (p1); + T g2 = generate (p2); + T g3 = generate (p3); + + // 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); + + return l_; + } + + + /////////////////////////////////////////////////////////////////////////// + // Generate a type from [-UNIT..UNIT] + template L> + constexpr T + value::generate (point<2,intmax_t> p) const + { + using util::hash::murmur2::mix; + + T v = mix ( + 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.cpp b/noise/basis/worley.cpp deleted file mode 100644 index ba80f9d3..00000000 --- a/noise/basis/worley.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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; -} } } diff --git a/noise/basis/worley.hpp b/noise/basis/worley.hpp index 5b2455bf..47755c70 100644 --- a/noise/basis/worley.hpp +++ b/noise/basis/worley.hpp @@ -32,6 +32,12 @@ namespace util { namespace noise { namespace basis { T operator() (util::point<2,T>) const; seed_t seed; + + private: + constexpr point<2,T> generate (point<2,intmax_t>) const; }; } } } + +#include "worley.ipp" + #endif diff --git a/noise/basis/worley.ipp b/noise/basis/worley.ipp new file mode 100644 index 00000000..f0969d9f --- /dev/null +++ b/noise/basis/worley.ipp @@ -0,0 +1,109 @@ +/* + * 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 + */ + +#ifdef __UTIL_NOISE_BASIS_WORLEY_IPP +#error +#endif +#define __UTIL_NOISE_BASIS_WORLEY_IPP + + +#include "../../debug.hpp" +#include "../../hash/murmur/murmur2.hpp" + + +namespace util { namespace noise { namespace basis { + /////////////////////////////////////////////////////////////////////////// + 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); + + 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]; + } + + + ////////////////////////////////////////////////////////////////////////// + template + constexpr point<2,T> + worley::generate (point<2,intmax_t> p) const + { + 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; + } +} } }