67 lines
1.4 KiB
C++
67 lines
1.4 KiB
C++
#pragma once
|
|
|
|
#include <psemek/geom/easing.hpp>
|
|
#include <psemek/geom/math.hpp>
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
namespace psemek::geom
|
|
{
|
|
|
|
template <typename T, typename R = T>
|
|
struct gradient
|
|
{
|
|
using result_type = R;
|
|
|
|
gradient() = default;
|
|
|
|
template <typename ... Args>
|
|
gradient(Args const & ... args)
|
|
{
|
|
init(args...);
|
|
}
|
|
|
|
gradient(std::vector<std::pair<T, R>> points, std::vector<easing_type> segments)
|
|
{
|
|
assert(points.size() == segments.size() + 1);
|
|
points_ = std::move(points);
|
|
segments_ = std::move(segments);
|
|
}
|
|
|
|
R operator()(T const & t) const
|
|
{
|
|
assert(!points_.empty());
|
|
|
|
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<std::pair<T, R>> points_;
|
|
std::vector<easing_type> segments_;
|
|
|
|
void init(std::pair<T, R> const & p)
|
|
{
|
|
points_.push_back(p);
|
|
}
|
|
|
|
template <typename ... Args>
|
|
void init(std::pair<T, R> const & p, easing_type t, Args const & ... args)
|
|
{
|
|
points_.push_back(p);
|
|
segments_.push_back(t);
|
|
init(args...);
|
|
}
|
|
};
|
|
|
|
}
|