Move Vectormath main
C++20 game and graphics mathematics
Loading...
Searching...
No Matches
Scalar.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <concepts>
6#include <optional>
7#include <type_traits>
8
10
11namespace mv::math
12{
13 template <typename T>
14 concept Arithmetic = std::is_arithmetic_v<T>;
15
16 template <Arithmetic T>
17 [[nodiscard]] constexpr T Saturate(T value) noexcept
18 {
19 return std::clamp(value, T(0), T(1));
20 }
21
22 template <std::floating_point T>
23 [[nodiscard]] inline std::optional<T> TryInverseLerp(T from,
24 T to,
25 T value) noexcept
26 {
27 // Algebraic inverse of linear interpolation. The scaled fallback uses
28 // the overflow-avoidance principle described by David Goldberg,
29 // "What Every Computer Scientist Should Know About Floating-Point
30 // Arithmetic" (ACM CSUR 1991, doi:10.1145/103162.103163).
31 if (!std::isfinite(from) || !std::isfinite(to) ||
32 !std::isfinite(value) || from == to)
33 {
34 return std::nullopt;
35 }
36
37 const T difference = to - from;
38 const T offset = value - from;
39 if (difference != T(0) && std::isfinite(difference) &&
40 std::isfinite(offset))
41 {
42 const T result = offset / difference;
43 return std::isfinite(result) ? std::optional<T>(result)
44 : std::nullopt;
45 }
46
47 // Scaling preserves the affine ratio while avoiding overflow for
48 // finite values near the limits of the floating-point type.
49 const T scale =
50 std::max({std::abs(from), std::abs(to), std::abs(value)});
51 if (!(scale > T(0)) || !std::isfinite(scale))
52 {
53 return std::nullopt;
54 }
55
56 const T scaledFrom = from / scale;
58 if (scaledDifference == T(0))
59 {
60 return std::nullopt;
61 }
62
64 return std::isfinite(result) ? std::optional<T>(result) : std::nullopt;
65 }
66
67 template <std::floating_point T>
68 [[nodiscard]] inline std::optional<T> TryInverseLerpClamped(
69 T from, T to, T value) noexcept
70 {
71 const auto result = TryInverseLerp(from, to, value);
72 return result ? std::optional<T>(Saturate(*result)) : std::nullopt;
73 }
74
75 template <std::floating_point T>
76 [[nodiscard]] constexpr T SmoothStep(T amount) noexcept
77 {
78 // Cubic Hermite smoothstep as specified by GLSL 4.60, section 8.3.
79 const T t = Saturate(amount);
80 return t * t * (T(3) - T(2) * t);
81 }
82
83 template <std::floating_point T>
84 [[nodiscard]] constexpr T SmootherStep(T amount) noexcept
85 {
86 // Quintic fade polynomial from Ken Perlin, "Improving Noise",
87 // SIGGRAPH 2002, doi:10.1145/566570.566636.
88 const T t = Saturate(amount);
89 return t * t * t * (t * (t * T(6) - T(15)) + T(10));
90 }
91} // namespace mv::math
std::optional< T > TryInverseLerp(T from, T to, T value) noexcept
Definition Scalar.hpp:23
std::optional< T > TryInverseLerpClamped(T from, T to, T value) noexcept
Definition Scalar.hpp:68
constexpr T SmootherStep(T amount) noexcept
Definition Scalar.hpp:84
constexpr T SmoothStep(T amount) noexcept
Definition Scalar.hpp:76
constexpr T Saturate(T value) noexcept
Definition Scalar.hpp:17