mirror of
https://github.com/slendidev/smath.git
synced 2026-03-17 02:26:50 +02:00
@@ -1,6 +1,6 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="smath logo" src="https://github.com/user-attachments/assets/d6f2ef4b-eca0-4004-9099-37423528bcba" />
|
<img alt="smath logo" width="100%" src="https://github.com/user-attachments/assets/d6f2ef4b-eca0-4004-9099-37423528bcba" />
|
||||||
<br><br>
|
<br><br>
|
||||||
<a href="https://github.com/slendidev/smath/actions/workflows/build.yml">
|
<a href="https://github.com/slendidev/smath/actions/workflows/build.yml">
|
||||||
<img src="https://github.com/slendidev/smath/actions/workflows/build.yml/badge.svg" alt="Build">
|
<img src="https://github.com/slendidev/smath/actions/workflows/build.yml/badge.svg" alt="Build">
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
27
docs/Doxyfile
Normal file
27
docs/Doxyfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
PROJECT_NAME = "smath"
|
||||||
|
OUTPUT_DIRECTORY = build/docs
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
|
||||||
|
INPUT = include README.md
|
||||||
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
TOC_INCLUDE_HEADINGS = 0
|
||||||
|
RECURSIVE = YES
|
||||||
|
FILE_PATTERNS = *.hpp *.h *.md
|
||||||
|
EXCLUDE = include/smath/interop
|
||||||
|
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
GENERATE_MAN = YES
|
||||||
|
GENERATE_TREEVIEW = YES
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
FULL_SIDEBAR = NO
|
||||||
|
HTML_COLORSTYLE = LIGHT
|
||||||
|
HTML_EXTRA_STYLESHEET = docs/vendor/doxygen-awesome.css
|
||||||
|
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
QUIET = NO
|
||||||
|
EXCLUDE_SYMBOLS = std smath::detail smath::interop_adapter interop_adapter smath::from_external from_external smath::to_external to_external
|
||||||
3020
docs/vendor/doxygen-awesome.css
vendored
Normal file
3020
docs/vendor/doxygen-awesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@
|
|||||||
clang-tools
|
clang-tools
|
||||||
lldb
|
lldb
|
||||||
pkg-config
|
pkg-config
|
||||||
|
doxygen
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,11 @@ template<class T> constexpr auto unpack_snorm8(std::int8_t b) -> T
|
|||||||
|
|
||||||
template<std::size_t N, typename T = float>
|
template<std::size_t N, typename T = float>
|
||||||
requires std::is_arithmetic_v<T>
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Fixed-size arithmetic vector.
|
||||||
|
* @tparam N Number of components.
|
||||||
|
* @tparam T Component type.
|
||||||
|
*/
|
||||||
struct Vec : std::array<T, N>
|
struct Vec : std::array<T, N>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -173,12 +178,17 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
|
/** @brief Constructs a zero-initialized vector. */
|
||||||
constexpr Vec() noexcept
|
constexpr Vec() noexcept
|
||||||
{
|
{
|
||||||
for (auto &v : *this)
|
for (auto &v : *this)
|
||||||
v = T(0);
|
v = T(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fills all components with the same scalar.
|
||||||
|
* @param s Scalar value assigned to every component.
|
||||||
|
*/
|
||||||
explicit constexpr Vec(T const &s) noexcept
|
explicit constexpr Vec(T const &s) noexcept
|
||||||
{
|
{
|
||||||
for (auto &v : *this)
|
for (auto &v : *this)
|
||||||
@@ -189,6 +199,10 @@ public:
|
|||||||
requires((detail::is_scalar_v<Args> || detail::is_Vec_v<Args>) && ...)
|
requires((detail::is_scalar_v<Args> || detail::is_Vec_v<Args>) && ...)
|
||||||
&& (total_extent<Args...>() == N)
|
&& (total_extent<Args...>() == N)
|
||||||
&& (!(sizeof...(Args) == 1 && (detail::is_Vec_v<Args> && ...)))
|
&& (!(sizeof...(Args) == 1 && (detail::is_Vec_v<Args> && ...)))
|
||||||
|
/**
|
||||||
|
* @brief Constructs from scalars and/or vectors whose flattened extent is
|
||||||
|
* N.
|
||||||
|
*/
|
||||||
constexpr Vec(Args &&...args) noexcept
|
constexpr Vec(Args &&...args) noexcept
|
||||||
{
|
{
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
@@ -234,6 +248,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks components into output references.
|
||||||
|
*/
|
||||||
constexpr auto unpack(Args &...args) noexcept -> void
|
constexpr auto unpack(Args &...args) noexcept -> void
|
||||||
{
|
{
|
||||||
unpack_impl(std::index_sequence_for<Args...> {}, args...);
|
unpack_impl(std::index_sequence_for<Args...> {}, args...);
|
||||||
@@ -324,6 +341,7 @@ public:
|
|||||||
return !(*this == v);
|
return !(*this == v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns Euclidean magnitude. */
|
||||||
constexpr auto magnitude() const noexcept -> T
|
constexpr auto magnitude() const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -332,6 +350,7 @@ public:
|
|||||||
total += v * v;
|
total += v * v;
|
||||||
return std::sqrt(total);
|
return std::sqrt(total);
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for magnitude(). */
|
||||||
constexpr auto length() const noexcept -> T
|
constexpr auto length() const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -340,6 +359,9 @@ public:
|
|||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
|
/**
|
||||||
|
* @brief Normalizes with zero fallback for very small magnitudes.
|
||||||
|
*/
|
||||||
constexpr auto normalized_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
constexpr auto normalized_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
auto m = magnitude();
|
auto m = magnitude();
|
||||||
@@ -347,27 +369,32 @@ public:
|
|||||||
}
|
}
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
|
/** @brief Alias for normalized_safe(). */
|
||||||
constexpr auto normalize_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
constexpr auto normalize_safe(U eps = EPS_DEFAULT) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
return normalized_safe(eps);
|
return normalized_safe(eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns normalized vector; undefined for zero magnitude. */
|
||||||
[[nodiscard]] constexpr auto normalized() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto normalized() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return (*this) / this->magnitude();
|
return (*this) / this->magnitude();
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for normalized(). */
|
||||||
[[nodiscard]] constexpr auto normalize() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto normalize() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return this->normalized();
|
return this->normalized();
|
||||||
}
|
}
|
||||||
|
/** @brief Alias for normalized(). */
|
||||||
[[nodiscard]] constexpr auto unit() noexcept -> Vec<N, T>
|
[[nodiscard]] constexpr auto unit() noexcept -> Vec<N, T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return this->normalized();
|
return this->normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Dot product with `other`. */
|
||||||
[[nodiscard]] constexpr auto dot(Vec<N, T> const &other) const noexcept -> T
|
[[nodiscard]] constexpr auto dot(Vec<N, T> const &other) const noexcept -> T
|
||||||
{
|
{
|
||||||
T res = 0;
|
T res = 0;
|
||||||
@@ -378,6 +405,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr T EPS_DEFAULT = T(1e-6);
|
static constexpr T EPS_DEFAULT = T(1e-6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Approximate equality with per-component absolute epsilon.
|
||||||
|
* @param rhs Vec to compare against.
|
||||||
|
* @param eps Absolute tolerance per component.
|
||||||
|
* @return `true` when all components are approximately equal.
|
||||||
|
*/
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
[[nodiscard]] constexpr auto approx_equal(
|
[[nodiscard]] constexpr auto approx_equal(
|
||||||
@@ -391,6 +425,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
|
/** @brief Magnitude computed in promoted type `U` (or `double`). */
|
||||||
constexpr auto magnitude_promoted() const noexcept
|
constexpr auto magnitude_promoted() const noexcept
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -403,6 +438,7 @@ public:
|
|||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
requires(N == 3)
|
requires(N == 3)
|
||||||
|
/** @brief 3D cross product. */
|
||||||
constexpr auto cross(Vec const &r) const noexcept -> Vec
|
constexpr auto cross(Vec const &r) const noexcept -> Vec
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@@ -412,12 +448,14 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Distance between this vector and `r`. */
|
||||||
constexpr auto distance(Vec const &r) const noexcept -> T
|
constexpr auto distance(Vec const &r) const noexcept -> T
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
return (*this - r).magnitude();
|
return (*this - r).magnitude();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Projection of this vector onto `n`. */
|
||||||
constexpr auto project_onto(Vec const &n) const noexcept -> Vec
|
constexpr auto project_onto(Vec const &n) const noexcept -> Vec
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
{
|
{
|
||||||
@@ -507,6 +545,11 @@ constexpr T const &&get(Vec<N, T> const &&v) noexcept
|
|||||||
|
|
||||||
template<std::size_t N, typename T = float>
|
template<std::size_t N, typename T = float>
|
||||||
requires std::is_arithmetic_v<T>
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Return type used by swizzle operations.
|
||||||
|
*
|
||||||
|
* Produces `T` when `N == 1`, otherwise `Vec<N, T>`.
|
||||||
|
*/
|
||||||
using VecOrScalar = std::conditional_t<N == 1, T, Vec<N, T>>;
|
using VecOrScalar = std::conditional_t<N == 1, T, Vec<N, T>>;
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -580,22 +623,39 @@ concept ValidSwizzle
|
|||||||
|
|
||||||
template<detail::FixedString S, std::size_t N, typename T>
|
template<detail::FixedString S, std::size_t N, typename T>
|
||||||
requires detail::ValidSwizzle<S, N>
|
requires detail::ValidSwizzle<S, N>
|
||||||
|
/**
|
||||||
|
* @brief Compile-time swizzle selection.
|
||||||
|
* @tparam S Swizzle pattern like `"xy"`, `"rgba"`, or `"stp"`.
|
||||||
|
* @param v Source vector.
|
||||||
|
* @return Swizzled scalar/vector according to `S`.
|
||||||
|
*/
|
||||||
constexpr auto swizzle(Vec<N, T> const &v) -> VecOrScalar<S.size, T>
|
constexpr auto swizzle(Vec<N, T> const &v) -> VecOrScalar<S.size, T>
|
||||||
{
|
{
|
||||||
return detail::swizzle_impl<S>(v, std::make_index_sequence<S.size> {});
|
return detail::swizzle_impl<S>(v, std::make_index_sequence<S.size> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief 2D float vector alias. */
|
||||||
using Vec2 = Vec<2>;
|
using Vec2 = Vec<2>;
|
||||||
|
/** @brief 3D float vector alias. */
|
||||||
using Vec3 = Vec<3>;
|
using Vec3 = Vec<3>;
|
||||||
|
/** @brief 4D float vector alias. */
|
||||||
using Vec4 = Vec<4>;
|
using Vec4 = Vec<4>;
|
||||||
|
|
||||||
|
/** @brief 2D double vector alias. */
|
||||||
using Vec2d = Vec<2, double>;
|
using Vec2d = Vec<2, double>;
|
||||||
|
/** @brief 3D double vector alias. */
|
||||||
using Vec3d = Vec<3, double>;
|
using Vec3d = Vec<3, double>;
|
||||||
|
/** @brief 4D double vector alias. */
|
||||||
using Vec4d = Vec<4, double>;
|
using Vec4d = Vec<4, double>;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
using angle_ret_t = std::conditional_t<std::is_same_v<T, float>, float, double>;
|
using angle_ret_t = std::conditional_t<std::is_same_v<T, float>, float, double>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert degrees to the configured angle unit.
|
||||||
|
* @param value Angle in degrees.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto deg(T value)
|
template<class T> constexpr auto deg(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -610,6 +670,11 @@ template<class T> constexpr auto deg(T value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert radians to the configured angle unit.
|
||||||
|
* @param value Angle in radians.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto rad(T value)
|
template<class T> constexpr auto rad(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -625,6 +690,11 @@ template<class T> constexpr auto rad(T value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert turns to the configured angle unit.
|
||||||
|
* @param value Angle in turns.
|
||||||
|
* @return Angle in `SMATH_ANGLE_UNIT`.
|
||||||
|
*/
|
||||||
template<class T> constexpr auto turns(T value)
|
template<class T> constexpr auto turns(T value)
|
||||||
{
|
{
|
||||||
using R = angle_ret_t<T>;
|
using R = angle_ret_t<T>;
|
||||||
@@ -643,13 +713,19 @@ template<std::size_t R, std::size_t C, typename T>
|
|||||||
requires std::is_arithmetic_v<T>
|
requires std::is_arithmetic_v<T>
|
||||||
struct Mat;
|
struct Mat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Quaternion represented as `(x, y, z, w)`.
|
||||||
|
* @tparam T Component type.
|
||||||
|
*/
|
||||||
template<class T> struct Quaternion : Vec<4, T>
|
template<class T> struct Quaternion : Vec<4, T>
|
||||||
{
|
{
|
||||||
using Base = Vec<4, T>;
|
using Base = Vec<4, T>;
|
||||||
using Base::Base;
|
using Base::Base;
|
||||||
using Base::operator=;
|
using Base::operator=;
|
||||||
|
|
||||||
|
/** @brief Returns this quaternion as its vector base type. */
|
||||||
constexpr Base &vec() noexcept { return *this; }
|
constexpr Base &vec() noexcept { return *this; }
|
||||||
|
/** @brief Returns this quaternion as its vector base type. */
|
||||||
constexpr Base const &vec() const noexcept { return *this; }
|
constexpr Base const &vec() const noexcept { return *this; }
|
||||||
|
|
||||||
constexpr T &x() noexcept { return Base::x(); }
|
constexpr T &x() noexcept { return Base::x(); }
|
||||||
@@ -661,6 +737,11 @@ template<class T> struct Quaternion : Vec<4, T>
|
|||||||
constexpr T &w() noexcept { return Base::w(); }
|
constexpr T &w() noexcept { return Base::w(); }
|
||||||
constexpr T const &w() const noexcept { return Base::w(); }
|
constexpr T const &w() const noexcept { return Base::w(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hamilton product.
|
||||||
|
* @param rhs Right-hand quaternion.
|
||||||
|
* @return Product quaternion.
|
||||||
|
*/
|
||||||
constexpr auto operator*(Quaternion const &rhs) const noexcept -> Quaternion
|
constexpr auto operator*(Quaternion const &rhs) const noexcept -> Quaternion
|
||||||
{
|
{
|
||||||
Quaternion r;
|
Quaternion r;
|
||||||
@@ -678,6 +759,10 @@ template<class T> struct Quaternion : Vec<4, T>
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts this quaternion to a 4x4 rotation matrix.
|
||||||
|
* @return Homogeneous rotation matrix.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto as_matrix() const noexcept -> Mat<4, 4, T>
|
[[nodiscard]] constexpr auto as_matrix() const noexcept -> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
auto const xx = x() * x();
|
auto const xx = x() * x();
|
||||||
@@ -698,6 +783,12 @@ template<class T> struct Quaternion : Vec<4, T>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a quaternion from axis-angle input.
|
||||||
|
* @param axis Rotation axis.
|
||||||
|
* @param angle Rotation angle in configured angle units.
|
||||||
|
* @return Quaternion representing the rotation.
|
||||||
|
*/
|
||||||
[[nodiscard]] static constexpr auto from_axis_angle(
|
[[nodiscard]] static constexpr auto from_axis_angle(
|
||||||
Vec<3, T> const &axis, T const angle) noexcept -> Quaternion
|
Vec<3, T> const &axis, T const angle) noexcept -> Quaternion
|
||||||
{
|
{
|
||||||
@@ -717,6 +808,10 @@ template<class T> struct Quaternion : Vec<4, T>
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Packs `[0, 1]` RGBA values into 4x8-bit UNORM.
|
||||||
|
* @return Packed 32-bit value in RGBA byte order.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto pack_unorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
[[nodiscard]] constexpr auto pack_unorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
||||||
{
|
{
|
||||||
std::uint32_t r = detail::pack_unorm8(v[0]);
|
std::uint32_t r = detail::pack_unorm8(v[0]);
|
||||||
@@ -729,6 +824,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Packs `[-1, 1]` RGBA values into 4x8-bit SNORM.
|
||||||
|
* @return Packed 32-bit value in RGBA byte order.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto pack_snorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
[[nodiscard]] constexpr auto pack_snorm4x8(Vec<4, T> const &v) -> std::uint32_t
|
||||||
{
|
{
|
||||||
std::uint32_t r = static_cast<std::uint8_t>(detail::pack_snorm8(v[0]));
|
std::uint32_t r = static_cast<std::uint8_t>(detail::pack_snorm8(v[0]));
|
||||||
@@ -741,6 +840,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T = float>
|
template<class T = float>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks a 4x8-bit UNORM RGBA value.
|
||||||
|
* @return RGBA vector with components in `[0, 1]`.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto unpack_unorm4x8(std::uint32_t packed) -> Vec<4, T>
|
[[nodiscard]] constexpr auto unpack_unorm4x8(std::uint32_t packed) -> Vec<4, T>
|
||||||
{
|
{
|
||||||
std::uint8_t r = static_cast<std::uint8_t>(packed & 0xFFu);
|
std::uint8_t r = static_cast<std::uint8_t>(packed & 0xFFu);
|
||||||
@@ -758,6 +861,10 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<class T = float>
|
template<class T = float>
|
||||||
requires std::is_floating_point_v<T>
|
requires std::is_floating_point_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Unpacks a 4x8-bit SNORM RGBA value.
|
||||||
|
* @return RGBA vector with components in `[-1, 1]`.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr auto unpack_snorm4x8(std::uint32_t packed) -> Vec<4, T>
|
[[nodiscard]] constexpr auto unpack_snorm4x8(std::uint32_t packed) -> Vec<4, T>
|
||||||
{
|
{
|
||||||
std::int8_t r = static_cast<std::int8_t>(packed & 0xFFu);
|
std::int8_t r = static_cast<std::int8_t>(packed & 0xFFu);
|
||||||
@@ -775,6 +882,12 @@ requires std::is_floating_point_v<T>
|
|||||||
|
|
||||||
template<std::size_t R, std::size_t C, typename T = float>
|
template<std::size_t R, std::size_t C, typename T = float>
|
||||||
requires std::is_arithmetic_v<T>
|
requires std::is_arithmetic_v<T>
|
||||||
|
/**
|
||||||
|
* @brief Column-major matrix with `R` rows and `C` columns.
|
||||||
|
* @tparam R Row count.
|
||||||
|
* @tparam C Column count.
|
||||||
|
* @tparam T Scalar type.
|
||||||
|
*/
|
||||||
struct Mat : std::array<Vec<R, T>, C>
|
struct Mat : std::array<Vec<R, T>, C>
|
||||||
{
|
{
|
||||||
using Base = std::array<Vec<R, T>, C>;
|
using Base = std::array<Vec<R, T>, C>;
|
||||||
@@ -791,12 +904,17 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
return col(column)[row];
|
return col(column)[row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Constructs a zero matrix. */
|
||||||
constexpr Mat() noexcept
|
constexpr Mat() noexcept
|
||||||
{
|
{
|
||||||
for (auto &col : *this)
|
for (auto &col : *this)
|
||||||
col = Vec<R, T> {};
|
col = Vec<R, T> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs a diagonal matrix.
|
||||||
|
* @param diag Value used for every diagonal component.
|
||||||
|
*/
|
||||||
constexpr explicit Mat(T const &diag) noexcept
|
constexpr explicit Mat(T const &diag) noexcept
|
||||||
requires(R == C)
|
requires(R == C)
|
||||||
{
|
{
|
||||||
@@ -809,6 +927,10 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
template<typename... Cols>
|
template<typename... Cols>
|
||||||
requires(sizeof...(Cols) == C
|
requires(sizeof...(Cols) == C
|
||||||
&& (std::same_as<std::remove_cvref_t<Cols>, Vec<R, T>> && ...))
|
&& (std::same_as<std::remove_cvref_t<Cols>, Vec<R, T>> && ...))
|
||||||
|
/**
|
||||||
|
* @brief Constructs from explicit column vectors.
|
||||||
|
* @param cols Columns in column-major order.
|
||||||
|
*/
|
||||||
constexpr Mat(Cols const &...cols) noexcept : Base { cols... }
|
constexpr Mat(Cols const &...cols) noexcept : Base { cols... }
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -905,6 +1027,13 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr T EPS_DEFAULT = T(1e-6);
|
static constexpr T EPS_DEFAULT = T(1e-6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Approximate matrix equality check.
|
||||||
|
* @param rhs Matrix to compare against.
|
||||||
|
* @param eps Absolute tolerance per component.
|
||||||
|
* @return `true` when all columns are approximately equal.
|
||||||
|
*/
|
||||||
template<class U = T>
|
template<class U = T>
|
||||||
requires std::is_floating_point_v<U>
|
requires std::is_floating_point_v<U>
|
||||||
[[nodiscard]] constexpr auto approx_equal(
|
[[nodiscard]] constexpr auto approx_equal(
|
||||||
@@ -916,6 +1045,7 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns the transposed matrix. */
|
||||||
[[nodiscard]] constexpr auto transposed() const noexcept -> Mat<C, R, T>
|
[[nodiscard]] constexpr auto transposed() const noexcept -> Mat<C, R, T>
|
||||||
{
|
{
|
||||||
Mat<C, R, T> r {};
|
Mat<C, R, T> r {};
|
||||||
@@ -925,6 +1055,7 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Returns an identity matrix. */
|
||||||
[[nodiscard]] static constexpr auto identity() noexcept -> Mat<R, C, T>
|
[[nodiscard]] static constexpr auto identity() noexcept -> Mat<R, C, T>
|
||||||
requires(R == C)
|
requires(R == C)
|
||||||
{
|
{
|
||||||
@@ -935,15 +1066,25 @@ struct Mat : std::array<Vec<R, T>, C>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief 2x2 float matrix alias. */
|
||||||
using Mat2 = Mat<2, 2>;
|
using Mat2 = Mat<2, 2>;
|
||||||
|
/** @brief 3x3 float matrix alias. */
|
||||||
using Mat3 = Mat<3, 3>;
|
using Mat3 = Mat<3, 3>;
|
||||||
|
/** @brief 4x4 float matrix alias. */
|
||||||
using Mat4 = Mat<4, 4>;
|
using Mat4 = Mat<4, 4>;
|
||||||
|
|
||||||
|
/** @brief 2x2 double matrix alias. */
|
||||||
using Mat2d = Mat<2, 2, double>;
|
using Mat2d = Mat<2, 2, double>;
|
||||||
|
/** @brief 3x3 double matrix alias. */
|
||||||
using Mat3d = Mat<3, 3, double>;
|
using Mat3d = Mat<3, 3, double>;
|
||||||
|
/** @brief 4x4 double matrix alias. */
|
||||||
using Mat4d = Mat<4, 4, double>;
|
using Mat4d = Mat<4, 4, double>;
|
||||||
|
|
||||||
template<std::size_t R, std::size_t C, typename T>
|
template<std::size_t R, std::size_t C, typename T>
|
||||||
|
/**
|
||||||
|
* @brief Matrix-vector multiplication.
|
||||||
|
* @return Product vector.
|
||||||
|
*/
|
||||||
[[nodiscard]] constexpr Vec<R, T> operator*(
|
[[nodiscard]] constexpr Vec<R, T> operator*(
|
||||||
Mat<R, C, T> const &m, Vec<C, T> const &v) noexcept
|
Mat<R, C, T> const &m, Vec<C, T> const &v) noexcept
|
||||||
{
|
{
|
||||||
@@ -953,7 +1094,10 @@ template<std::size_t R, std::size_t C, typename T>
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matrix * Matrix
|
/**
|
||||||
|
* @brief Matrix-matrix multiplication.
|
||||||
|
* @return Product matrix.
|
||||||
|
*/
|
||||||
template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
||||||
[[nodiscard]] constexpr Mat<R, K, T> operator*(
|
[[nodiscard]] constexpr Mat<R, K, T> operator*(
|
||||||
Mat<R, C, T> const &a, Mat<C, K, T> const &b) noexcept
|
Mat<R, C, T> const &a, Mat<C, K, T> const &b) noexcept
|
||||||
@@ -970,7 +1114,10 @@ template<std::size_t R, std::size_t C, std::size_t K, typename T>
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mat3 transformations
|
/** @name 2D transforms (Mat3)
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
/** @brief Applies translation to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
[[nodiscard]] inline auto translate(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -980,6 +1127,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Creates a 3x3 translation matrix. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Vec<2, T> const &v) -> Mat<3, 3, T>
|
[[nodiscard]] inline auto translate(Vec<2, T> const &v) -> Mat<3, 3, T>
|
||||||
{
|
{
|
||||||
@@ -989,6 +1137,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies rotation to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto rotate(Mat<3, 3, T> const &m, T const angle)
|
[[nodiscard]] inline auto rotate(Mat<3, 3, T> const &m, T const angle)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1005,6 +1154,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies scaling to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto scale(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
[[nodiscard]] inline auto scale(Mat<3, 3, T> const &m, Vec<2, T> const &v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1018,6 +1168,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies X shear to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_x(Mat<3, 3, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_x(Mat<3, 3, T> const &m, T const v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1027,6 +1178,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Y shear to an existing 3x3 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_y(Mat<3, 3, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_y(Mat<3, 3, T> const &m, T const v)
|
||||||
-> Mat<3, 3, T>
|
-> Mat<3, 3, T>
|
||||||
@@ -1036,7 +1188,12 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mat4 transformations
|
/** @} */
|
||||||
|
|
||||||
|
/** @name 3D transforms (Mat4)
|
||||||
|
* @{ */
|
||||||
|
|
||||||
|
/** @brief Applies translation to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
[[nodiscard]] inline auto translate(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1046,6 +1203,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Creates a 4x4 translation matrix. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto translate(Vec<3, T> const &v) -> Mat<4, 4, T>
|
[[nodiscard]] inline auto translate(Vec<3, T> const &v) -> Mat<4, 4, T>
|
||||||
{
|
{
|
||||||
@@ -1056,6 +1214,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies rotation to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto rotate(Mat<4, 4, T> const &m, T const angle)
|
[[nodiscard]] inline auto rotate(Mat<4, 4, T> const &m, T const angle)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1073,6 +1232,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies scaling to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto scale(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
[[nodiscard]] inline auto scale(Mat<4, 4, T> const &m, Vec<3, T> const &v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1087,6 +1247,7 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies X shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_x(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_x(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1096,6 +1257,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Y shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_y(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_y(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1105,6 +1267,7 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Applies Z shear to an existing 4x4 transform. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto shear_z(Mat<4, 4, T> const &m, T const v)
|
[[nodiscard]] inline auto shear_z(Mat<4, 4, T> const &m, T const v)
|
||||||
-> Mat<4, 4, T>
|
-> Mat<4, 4, T>
|
||||||
@@ -1114,6 +1277,17 @@ template<typename T>
|
|||||||
return m * res;
|
return m * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds an orthographic projection matrix.
|
||||||
|
* @param left Left clipping plane.
|
||||||
|
* @param right Right clipping plane.
|
||||||
|
* @param bottom Bottom clipping plane.
|
||||||
|
* @param top Top clipping plane.
|
||||||
|
* @param near Near clipping plane.
|
||||||
|
* @param far Far clipping plane.
|
||||||
|
* @param flip_z_axis Whether to flip the output Z axis convention.
|
||||||
|
* @return Orthographic projection matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_ortho3d(T const left,
|
[[nodiscard]] inline auto matrix_ortho3d(T const left,
|
||||||
T const right,
|
T const right,
|
||||||
@@ -1140,6 +1314,9 @@ template<typename T>
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a finite perspective projection matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline auto matrix_perspective(
|
inline auto matrix_perspective(
|
||||||
T fovy, T aspect, T znear, T zfar, bool flip_z_axis = false) -> Mat<4, 4, T>
|
T fovy, T aspect, T znear, T zfar, bool flip_z_axis = false) -> Mat<4, 4, T>
|
||||||
@@ -1166,6 +1343,9 @@ inline auto matrix_perspective(
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a right-handed look-at view matrix.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_look_at(
|
[[nodiscard]] inline auto matrix_look_at(
|
||||||
Vec<3, T> const eye, Vec<3, T> const center, Vec<3, T> const up)
|
Vec<3, T> const eye, Vec<3, T> const center, Vec<3, T> const up)
|
||||||
@@ -1183,6 +1363,9 @@ template<typename T>
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds a perspective matrix with an infinite far plane.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] inline auto matrix_infinite_perspective(
|
[[nodiscard]] inline auto matrix_infinite_perspective(
|
||||||
T const fovy, T const aspect, T const znear, bool flip_z_axis = false)
|
T const fovy, T const aspect, T const znear, bool flip_z_axis = false)
|
||||||
@@ -1207,8 +1390,16 @@ template<typename T>
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extension point for external math-type interoperability.
|
||||||
|
*/
|
||||||
template<class Ext> struct interop_adapter;
|
template<class Ext> struct interop_adapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts an external value into its mapped smath type.
|
||||||
|
*/
|
||||||
template<class Ext>
|
template<class Ext>
|
||||||
constexpr auto from_external(Ext const &ext) ->
|
constexpr auto from_external(Ext const &ext) ->
|
||||||
typename interop_adapter<Ext>::smath_type
|
typename interop_adapter<Ext>::smath_type
|
||||||
@@ -1216,6 +1407,9 @@ constexpr auto from_external(Ext const &ext) ->
|
|||||||
return interop_adapter<Ext>::to_smath(ext);
|
return interop_adapter<Ext>::to_smath(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a smath value into an external type.
|
||||||
|
*/
|
||||||
template<class Ext, class SMathT>
|
template<class Ext, class SMathT>
|
||||||
constexpr auto to_external(SMathT const &value) -> Ext
|
constexpr auto to_external(SMathT const &value) -> Ext
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user