Add a gradient helper class
This commit is contained in:
parent
b7950a0520
commit
d72e01e34e
1 changed files with 83 additions and 0 deletions
83
libs/geom/include/psemek/geom/easing.hpp
Normal file
83
libs/geom/include/psemek/geom/easing.hpp
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/geom/vector.hpp>
|
||||||
|
#include <psemek/util/assert.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace psemek::geom
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class easing
|
||||||
|
{
|
||||||
|
nearest,
|
||||||
|
constant_left,
|
||||||
|
constant_right,
|
||||||
|
linear,
|
||||||
|
quadratic_in,
|
||||||
|
quadratic_out,
|
||||||
|
cubic,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct gradient
|
||||||
|
{
|
||||||
|
template <typename ... Args>
|
||||||
|
gradient(Args const & ... args)
|
||||||
|
{
|
||||||
|
init(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
gradient(std::vector<geom::vector<T, 2>> points, std::vector<easing> 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<geom::vector<T, 2>> points_;
|
||||||
|
std::vector<easing> segments_;
|
||||||
|
|
||||||
|
void init(geom::vector<T, 2> const & p)
|
||||||
|
{
|
||||||
|
points_.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ... Args>
|
||||||
|
void init(geom::vector<T, 2> const & p, easing t, Args const & ... args)
|
||||||
|
{
|
||||||
|
points_.push_back(p);
|
||||||
|
segments_.push_back(t);
|
||||||
|
init(args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue