From 6b712e2f577efa446e86002003845ede4e6a7ab0 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 1 Jul 2015 01:03:34 +1000 Subject: [PATCH] n/midpoint: extract midpoint displacement funcs --- Makefile.am | 2 + noise/midpoint.cpp | 132 +++++++++++++++++++++++++++++++++++++++++++++ noise/midpoint.hpp | 30 +++++++++++ tools/noise.cpp | 124 ++++++------------------------------------ 4 files changed, 180 insertions(+), 108 deletions(-) create mode 100644 noise/midpoint.cpp create mode 100644 noise/midpoint.hpp diff --git a/Makefile.am b/Makefile.am index 7e073c4e..26dcf0c4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -170,6 +170,8 @@ UTIL_FILES = \ noise/lerp.hpp \ noise/lut.cpp \ noise/lut.hpp \ + noise/midpoint.cpp \ + noise/midpoint.hpp \ noise/turbulence.hpp \ noise/turbulence.ipp \ pascal.cpp \ diff --git a/noise/midpoint.cpp b/noise/midpoint.cpp new file mode 100644 index 00000000..c6e59318 --- /dev/null +++ b/noise/midpoint.cpp @@ -0,0 +1,132 @@ +/* + * 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 "midpoint.hpp" + +#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; +} + + +/////////////////////////////////////////////////////////////////////////////// +// assumes corner points have been assigned their weights +template +static void +fill (util::image::buffer &img, + uint64_t seed, + util::region2u target, + float scale, + float persistence, + float sides) +{ + CHECK_EQ (target.e.w % 2, 1); + CHECK_EQ (target.e.h % 2, 1); + CHECK_GE (target.area (), 9); + + CHECK_GT (scale, 0); + CHECK_GT (persistence, 0); + CHECK_GE (sides, 0); + + const auto w = target.w; + const auto h = target.h; + + // 0--1 + // | | + // 2--3 + + const auto p0 = target.p + util::vector2u {0, 0 }; + const auto p1 = target.p + util::vector2u {w-1, 0 }; + const auto p2 = target.p + util::vector2u {0, h-1}; + const auto p3 = target.p + util::vector2u {w-1, h-1}; + + const auto v0 = img[p0]; + const auto v1 = img[p1]; + const auto v2 = img[p2]; + const auto v3 = img[p3]; + + // do the centre + { + const auto avg = (v0 + v1 + v2 + v3) / 4; + const auto val = avg + scale * gen (seed, target.centre ()); + const auto pos = target.p + target.e / 2; + + img[pos] = val; + } + + // average the sides + { + const auto p01 = target.p + util::vector2u{w/2, 0}; + const auto p13 = target.p + util::vector2u{w-1, h/2}; + 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); + + img[p01] = v01; + img[p13] = v13; + img[p32] = v32; + img[p20] = v20; + } + + // recurse + if (target.area () > 9) { + auto e = target.e / 2 + 1; + + fill (img, seed, {target.p + util::vector2u{ 0, 0 }, e}, scale * persistence, persistence, sides); + fill (img, seed, {target.p + util::vector2u{ w/2, 0 }, e}, scale * persistence, persistence, sides); + fill (img, seed, {target.p + util::vector2u{ 0, h/2 }, e}, scale * persistence, persistence, sides); + fill (img, seed, {target.p + util::vector2u{ w/2, h/2 }, e}, scale * persistence, persistence, sides); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +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 }); + + fill (img, seed, { { 0, 0 }, img.extent () }, 1.f, persistence, sides); +} + + +//----------------------------------------------------------------------------- +template void util::noise::midpoint (image::buffer&, uint64_t, float, float); diff --git a/noise/midpoint.hpp b/noise/midpoint.hpp new file mode 100644 index 00000000..d26468b2 --- /dev/null +++ b/noise/midpoint.hpp @@ -0,0 +1,30 @@ +/* + * 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_MIDPOINT_HPP +#define __UTIL_NOISE_MIDPOINT_HPP + +#include "image.hpp" + +namespace util { namespace noise { + template + void + midpoint (image::buffer&, uint64_t seed, float persistence = 0.65f, float sides = 0.25f); +} } + +#include "midpoint.ipp" + +#endif diff --git a/tools/noise.cpp b/tools/noise.cpp index 5c3ff4d1..6965a65c 100644 --- a/tools/noise.cpp +++ b/tools/noise.cpp @@ -13,15 +13,14 @@ #include "noise/basis/worley.hpp" #include "noise/turbulence.hpp" #include "noise/basis/runtime.hpp" +#include "noise/midpoint.hpp" #include "extent.hpp" #include "colour.hpp" #include "netpbm.hpp" #include "types.hpp" #include "cmdopt.hpp" -#include "hash/murmur/murmur2.hpp" #include "region.hpp" -#include "random.hpp" /////////////////////////////////////////////////////////////////////////////// @@ -157,120 +156,29 @@ operator<< (std::ostream &os, lerp_t &l) } -void -diamond (util::image::buffer &img, util::region2u target, float scale, float persistence) -{ - -} - - -static float -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 / float{0xffff} * 2 - 1; -} - - -// perturb the centre point by at most scale-units -// average the side points (optionally perturb by sides-units) -// -void -midpoint (util::image::buffer &img, uint64_t seed, util::region2u target, float scale, float persistence, float sides = 0.f) -{ - CHECK_EQ (target.e.w % 2, 1); - CHECK_EQ (target.e.h % 2, 1); - CHECK_GE (target.area (), 9); - - CHECK_GT (scale, 0); - CHECK_GT (persistence, 0); - CHECK_GE (sides, 0); - - auto w = target.w; - auto h = target.h; - - // 0--1 - // | | - // 2--3 - - auto p0 = target.p+util::vector2u{0, 0 }; - auto p1 = target.p+util::vector2u{w-1,0 }; - auto p2 = target.p+util::vector2u{0, h-1}; - auto p3 = target.p+util::vector2u{w-1,h-1}; - - auto v0 = img[p0]; - auto v1 = img[p1]; - auto v2 = img[p2]; - auto v3 = img[p3]; - - // do the centre - auto avg = (v0 + v1 + v2 + v3) / 4; - auto val = avg + scale * gen (seed, target.centre ()); - auto pos = target.p + target.e / 2; - - img[pos] = val; - - // average the sides - auto p01 = target.p + util::vector2u{w/2, 0}; - auto p13 = target.p + util::vector2u{w-1, h/2}; - auto p32 = target.p + util::vector2u{w/2, h-1}; - auto p20 = target.p + util::vector2u{0, h/2}; - - auto v01 = (v0 + v1) / 2 + sides * scale * gen (seed, p01); - auto v13 = (v1 + v3) / 2 + sides * scale * gen (seed, p13); - auto v32 = (v3 + v2) / 2 + sides * scale * gen (seed, p32); - auto v20 = (v2 + v0) / 2 + sides * scale * gen (seed, p20); - - img[p01] = v01; - img[p13] = v13; - img[p32] = v32; - img[p20] = v20; - - // recurse - if (target.area () > 9) { - auto e = target.e / 2 + 1; - - midpoint (img, seed, {target.p + util::vector2u{ 0, 0 }, e}, scale * persistence, persistence, sides); - midpoint (img, seed, {target.p + util::vector2u{ w/2, 0 }, e}, scale * persistence, persistence, sides); - midpoint (img, seed, {target.p + util::vector2u{ 0, h/2 }, e}, scale * persistence, persistence, sides); - midpoint (img, seed, {target.p + util::vector2u{ w/2, h/2 }, e}, scale * persistence, persistence, sides); - } -} - - /////////////////////////////////////////////////////////////////////////////// int main (int argc, char **argv) { - //{ - // util::extent2u size { 1025 }; - // util::image::buffer img (size); +#if 0 + { + srand (time (nullptr)); - // img[{0, 0}] = 0.7f; - // img[{0, size.w-1}] = 0.1f; - // img[{size.h-1, 0}] = 0.5f; - // img[{size.h-1, size.w-1}] = 0.2f; - // midpoint (img, { {0, 0}, size }, 1, 0.65f); + util::extent2u size { 1025 }; + util::image::buffer img (size); + util::noise::midpoint (img, time (nullptr)); - // auto range = std::minmax_element (img.begin (), img.end ()); - // auto offset = *range.first; - // auto div = *range.second - *range.first; - // std::cerr << "range: [" << *range.first << ", " << *range.second << "]\n"; + auto range = std::minmax_element (img.begin (), img.end ()); + auto offset = *range.first; + auto div = *range.second - *range.first; + std::cerr << "range: [" << *range.first << ", " << *range.second << "]\n"; - // std::transform (img.begin (), img.end (), img.begin (), [offset,div] (auto i) { return (i - offset) / div; }); - // util::pgm::write (img.cast (), std::cout); - //} + std::transform (img.begin (), img.end (), img.begin (), [offset,div] (auto i) { return (i - offset) / div; }); + util::pgm::write (img.cast (), std::cout); + } - //return 0; + return 0; +#endif #ifndef ENABLE_DEBUGGING