18[[nodiscard]]
constexpr T
map(T x, T in_lo, T in_hi, T out_lo, T out_hi)
noexcept
20 const T in_range = in_hi - in_lo;
21 if (in_range == T { 0 })
23 return out_lo + (x - in_lo) / in_range * (out_hi - out_lo);
31[[nodiscard]]
constexpr T
map_clamped(T x, T in_lo, T in_hi, T out_lo, T out_hi)
noexcept
33 const T v =
map(x, in_lo, in_hi, out_lo, out_hi);
34 return std::clamp(v, std::min(out_lo, out_hi), std::max(out_lo, out_hi));
46[[nodiscard]]
constexpr T normalize(T x, T lo, T hi)
noexcept
48 const T range = hi - lo;
51 return (x - lo) / range;
61[[nodiscard]]
constexpr T
denormalize(T t, T lo, T hi)
noexcept
63 return lo + t * (hi - lo);
79[[nodiscard]]
inline double sample_table(std::span<const double> table,
double t)
noexcept
81 const size_t n = table.size();
87 const double x = std::clamp(t, 0.0, 1.0) *
static_cast<double>(n - 1);
88 const auto i = std::min(
static_cast<size_t>(x), n - 2);
89 const double f = x -
static_cast<double>(i);
90 return table[i] + (table[i + 1] - table[i]) * f;
107[[nodiscard]]
constexpr T
smoothstep(T lo, T hi, T x)
noexcept
109 const T t = std::clamp((x - lo) / (hi - lo), T { 0 }, T { 1 });
110 return t * t * (T { 3 } - T { 2 } * t);
123 const T t = std::clamp((x - lo) / (hi - lo), T { 0 }, T { 1 });
124 return t * t * t * (t * (t * T { 6 } - T { 15 }) + T { 10 });
143[[nodiscard]]
inline T
damp(T
current, T target, T smoothing, T dt)
noexcept
145 if (smoothing <= T { 0 })
147 return current + (target -
current) * (T { 1 } - std::exp(-dt / smoothing));
177 std::span<const double> target,
178 std::span<const double> rise,
179 std::span<const double> fall,
182 const size_t count = std::min({
current.size(), target.size(), rise.size(), fall.size() });
183 for (
size_t i = 0; i <
count; ++i)
198[[nodiscard]]
inline T
soft_clip(T x, T limit = T { 1 })
noexcept
200 if (limit <= T { 0 })
202 return limit * std::tanh(x / limit);
218[[nodiscard]]
inline T
wrap(T x, T lo, T hi)
noexcept
220 const T range = hi - lo;
221 if (range <= T { 0 })
223 return x - range * std::floor((x - lo) / range);
236[[nodiscard]]
inline T
ping_pong(T x, T lo, T hi)
noexcept
238 const T range = hi - lo;
239 if (range <= T { 0 })
241 const T shifted = x - lo;
242 const T period = T { 2 } * range;
243 const T t = shifted - period * std::floor(shifted / period);
244 return lo + (t < range ? t : period - t);
259[[nodiscard]]
inline T
snap(T x, T step)
noexcept
263 return std::round(x / step) * step;
270[[nodiscard]]
inline T
snap(T x, T lo, T hi, T step)
noexcept
272 return std::clamp(
snap(x, step), lo, hi);
284[[nodiscard]]
constexpr T
ease_in(T t)
noexcept
296 const T u = T { 1 } - t;
297 return T { 1 } - u * u * u;
308 ? T { 4 } * t * t * t
309 : T { 1 } - T { 4 } * (T { 1 } - t) * (T { 1 } - t) * (T { 1 } - t) * T { 0.5 };
331 const T sign = x > T { 0 } ? T { 1 } : T { -1 };
344 return x < T { 0 } ? T { -1 } : T { 1 };
T ping_pong(T x, T lo, T hi) noexcept
Ping-pong (triangle wave): fold x back and forth in [lo, hi].
T damp(T current, T target, T smoothing, T dt) noexcept
Exponential smoothing: move current toward target at rate smoothing over time step dt.
T damp_asymmetric(T current, T target, T rise, T fall, T dt) noexcept
damp with separate time constants for rising and falling.
constexpr T denormalize(T t, T lo, T hi) noexcept
Denormalize t from [0, 1] to [lo, hi].
T snap(T x, T step) noexcept
Round x to the nearest multiple of step.
double sample_table(std::span< const double > table, double t) noexcept
Read an evenly spaced table at a position in [0, 1], interpolating linearly.
constexpr T ease_in(T t) noexcept
Cubic ease-in: slow start, fast end.
constexpr T smootherstep(T lo, T hi, T x) noexcept
Ken Perlin's quintic smootherstep: C2-continuous in [lo, hi].
T soft_clip(T x, T limit=T { 1 }) noexcept
Smooth bound to (-limit, limit): limit * tanh(x / limit).
constexpr T ease_in_out(T t) noexcept
Cubic ease-in-out: slow start, fast middle, slow end.
constexpr T map(T x, T in_lo, T in_hi, T out_lo, T out_hi) noexcept
Map x from [in_lo, in_hi] to [out_lo, out_hi], unclamped.
constexpr T ease_out(T t) noexcept
Cubic ease-out: fast start, slow end.
constexpr T map_clamped(T x, T in_lo, T in_hi, T out_lo, T out_hi) noexcept
Map x from [in_lo, in_hi] to [out_lo, out_hi], clamped to [out_lo, out_hi].
constexpr T smoothstep(T lo, T hi, T x) noexcept
GLSL smoothstep: Hermite interpolation in [lo, hi].
T wrap(T x, T lo, T hi) noexcept
Wrap x into [lo, hi) with modulo semantics.
constexpr T sign_nonzero(T x) noexcept
Sign of x, returning -1 or +1, never 0.
constexpr T deadzone(T x, T threshold) noexcept
Zero values within [-threshold, threshold] and rescale the remainder to fill [0, 1] (or [-1,...