From d421fc8c65a9438d334cf5b669d0c8c640b59f30 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Thu, 1 Oct 2020 09:37:35 +0300 Subject: [PATCH] Add easing function, move gradient to a separate header --- examples/cloud.cpp | 6 +- libs/geom/include/psemek/geom/easing.hpp | 73 ++++------------------ libs/geom/include/psemek/geom/gradient.hpp | 63 +++++++++++++++++++ 3 files changed, 79 insertions(+), 63 deletions(-) create mode 100644 libs/geom/include/psemek/geom/gradient.hpp diff --git a/examples/cloud.cpp b/examples/cloud.cpp index 5e9890ed..3d70dac0 100644 --- a/examples/cloud.cpp +++ b/examples/cloud.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -164,7 +164,7 @@ struct cloud_app float step; - float max_density = 8.f; + float max_density = 6.f; geom::interval harmonic_range; util::clock> clock; @@ -241,7 +241,7 @@ struct cloud_app pcg::fractal> perlin(std::move(grad), std::move(weights)); - geom::gradient g(geom::vector{0.2f, 0.f}, geom::easing::cubic, geom::vector{0.4f, max_density}); + geom::gradient g(std::make_pair(0.2f, 0.f), geom::easing_type::cubic, std::pair{0.4f, max_density}); util::array cloud_data({cloud_size[0], cloud_size[1], cloud_size[2]}); diff --git a/libs/geom/include/psemek/geom/easing.hpp b/libs/geom/include/psemek/geom/easing.hpp index efc68db1..40adce6b 100644 --- a/libs/geom/include/psemek/geom/easing.hpp +++ b/libs/geom/include/psemek/geom/easing.hpp @@ -1,14 +1,11 @@ #pragma once -#include #include -#include - namespace psemek::geom { - enum class easing + enum class easing_type { nearest, constant_left, @@ -20,64 +17,20 @@ namespace psemek::geom }; template - struct gradient + T easing(easing_type type, T t) { - template - gradient(Args const & ... args) - { - init(args...); + switch (type) { + case easing_type::nearest: return (2 * t < 1) ? 0 : 1; + case easing_type::constant_left: return 0; + case easing_type::constant_right: return 1; + case easing_type::linear: return t; + case easing_type::quadratic_in: return t * t; + case easing_type::quadratic_out: return t * (2 - t); + case easing_type::cubic: return t * t * (3 - 2 * t); + default: assert(false); } - gradient(std::vector> points, std::vector segments) - { - assert(points.size() == segments.size() + 1); - points_ = std::move(points); - segments_ = std::move(segments); - } - - T operator()(T const & t) const - { - auto it = std::upper_bound(points_.begin(), points_.end(), t, [](T const & t, auto const & p){ return t < p[0]; }); - if (it == points_.begin()) - return points_.front()[1]; - if (it == points_.end()) - return points_.back()[1]; - - std::size_t i = (it - points_.begin()) - 1; - - T s = (t - points_[i][0]) * (points_[i + 1][1] - points_[i][1]); - - switch (segments_[i]) { - case easing::nearest: s = (2 * s < 1) ? 0 : 1; break; - case easing::constant_left: s = 0; break; - case easing::constant_right: s = 1; break; - case easing::linear: break; - case easing::quadratic_in: s = s * s; break; - case easing::quadratic_out: s = s * (2 - s); break; - case easing::cubic: s = s * s * (3 - 2 * s); break; - default: - assert(false); - } - - return points_[i][1] + s * (points_[i + 1][1] - points_[i][1]); - } - - private: - std::vector> points_; - std::vector segments_; - - void init(geom::vector const & p) - { - points_.push_back(p); - } - - template - void init(geom::vector const & p, easing t, Args const & ... args) - { - points_.push_back(p); - segments_.push_back(t); - init(args...); - } - }; + return {}; + } } diff --git a/libs/geom/include/psemek/geom/gradient.hpp b/libs/geom/include/psemek/geom/gradient.hpp new file mode 100644 index 00000000..e7b33b8a --- /dev/null +++ b/libs/geom/include/psemek/geom/gradient.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +#include +#include + +namespace psemek::geom +{ + + template + struct gradient + { + using result_type = R; + + template + gradient(Args const & ... args) + { + init(args...); + } + + gradient(std::vector> points, std::vector segments) + { + assert(points.size() == segments.size() + 1); + points_ = std::move(points); + segments_ = std::move(segments); + } + + R operator()(T const & t) const + { + auto it = std::upper_bound(points_.begin(), points_.end(), t, [](T const & t, auto const & p){ return t < p.first; }); + if (it == points_.begin()) + return points_.front().second; + if (it == points_.end()) + return points_.back().second; + + std::size_t i = (it - points_.begin()) - 1; + + T s = easing(segments_[i], (t - points_[i].first) / (points_[i + 1].first - points_[i].first)); + + return lerp(points_[i].second, points_[i + 1].second, s); + } + + private: + std::vector> points_; + std::vector segments_; + + void init(std::pair const & p) + { + points_.push_back(p); + } + + template + void init(std::pair const & p, easing_type t, Args const & ... args) + { + points_.push_back(p); + segments_.push_back(t); + init(args...); + } + }; + +}