mirror of
https://github.com/orange-cpp/omath.git
synced 2026-06-08 16:24:35 +00:00
Merge pull request #193 from orange-cpp/feature/nodiscrad-messages
Feature/nodiscrad messages
This commit is contained in:
@@ -59,7 +59,7 @@ namespace omath
|
||||
clear();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use store ordering")]]
|
||||
consteval static MatStoreType get_store_ordering() noexcept
|
||||
{
|
||||
return StoreType;
|
||||
@@ -94,13 +94,13 @@ namespace omath
|
||||
m_data = other.m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use element reference")]]
|
||||
constexpr Type& operator[](const size_t row, const size_t col)
|
||||
{
|
||||
return at(row, col);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use element reference")]]
|
||||
constexpr const Type& operator[](const size_t row, const size_t col) const
|
||||
{
|
||||
return at(row, col);
|
||||
@@ -111,25 +111,25 @@ namespace omath
|
||||
m_data = std::move(other.m_data);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use row count")]]
|
||||
static constexpr size_t row_count() noexcept
|
||||
{
|
||||
return Rows;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use column count")]]
|
||||
static constexpr size_t columns_count() noexcept
|
||||
{
|
||||
return Columns;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use matrix size")]]
|
||||
static constexpr MatSize size() noexcept
|
||||
{
|
||||
return {Rows, Columns};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use element reference")]]
|
||||
constexpr const Type& at(const size_t row_index, const size_t column_index) const
|
||||
{
|
||||
#if !defined(NDEBUG) && defined(OMATH_SUPRESS_SAFETY_CHECKS)
|
||||
@@ -149,12 +149,12 @@ namespace omath
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type& at(const size_t row_index, const size_t column_index)
|
||||
[[nodiscard("You must use element reference")]] constexpr Type& at(const size_t row_index, const size_t column_index)
|
||||
{
|
||||
return const_cast<Type&>(std::as_const(*this).at(row_index, column_index));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use sum of elements")]]
|
||||
constexpr Type sum() const noexcept
|
||||
{
|
||||
return std::accumulate(m_data.begin(), m_data.end(), static_cast<Type>(0));
|
||||
@@ -171,7 +171,7 @@ namespace omath
|
||||
}
|
||||
|
||||
// Operator overloading for multiplication with another Mat
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
template<size_t OtherColumns> [[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, StoreType>
|
||||
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
|
||||
{
|
||||
@@ -202,7 +202,7 @@ namespace omath
|
||||
return *this = *this * other;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat operator*(const Type& value) const noexcept
|
||||
{
|
||||
Mat result(*this);
|
||||
@@ -216,7 +216,7 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat operator/(const Type& value) const noexcept
|
||||
{
|
||||
Mat result(*this);
|
||||
@@ -240,7 +240,7 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use transposed matrix")]]
|
||||
constexpr Mat<Columns, Rows, Type, StoreType> transposed() const noexcept
|
||||
{
|
||||
Mat<Columns, Rows, Type, StoreType> transposed;
|
||||
@@ -251,7 +251,7 @@ namespace omath
|
||||
return transposed;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use determinant")]]
|
||||
constexpr Type determinant() const
|
||||
{
|
||||
static_assert(Rows == Columns, "Determinant is only defined for square matrices.");
|
||||
@@ -276,7 +276,7 @@ namespace omath
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use stripped matrix")]]
|
||||
constexpr Mat<Rows - 1, Columns - 1, Type, StoreType> strip(const size_t row, const size_t column) const
|
||||
{
|
||||
static_assert(Rows - 1 > 0 && Columns - 1 > 0);
|
||||
@@ -297,32 +297,32 @@ namespace omath
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use minor")]]
|
||||
constexpr Type minor(const size_t row, const size_t column) const
|
||||
{
|
||||
return strip(row, column).determinant();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use algebraic complement")]]
|
||||
constexpr Type alg_complement(const size_t row, const size_t column) const
|
||||
{
|
||||
const auto minor_value = minor(row, column);
|
||||
return (row + column + 2) % 2 == 0 ? minor_value : -minor_value;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use raw array")]]
|
||||
constexpr const std::array<Type, Rows * Columns>& raw_array() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use raw array")]]
|
||||
constexpr std::array<Type, Rows * Columns>& raw_array()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use string representation")]]
|
||||
std::string to_string() const noexcept
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@@ -344,14 +344,14 @@ namespace omath
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use wide string representation")]]
|
||||
std::wstring to_wstring() const noexcept
|
||||
{
|
||||
const auto ascii_string = to_string();
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use UTF-8 string representation")]]
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
std::u8string to_u8string() const noexcept
|
||||
{
|
||||
@@ -359,20 +359,20 @@ namespace omath
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator==(const Mat& mat) const
|
||||
{
|
||||
return m_data == mat.m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator!=(const Mat& mat) const
|
||||
{
|
||||
return !operator==(mat);
|
||||
}
|
||||
|
||||
// Static methods that return fixed-size matrices
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use screen matrix")]]
|
||||
constexpr static Mat<4, 4> to_screen_mat(const Type& screen_width, const Type& screen_height) noexcept
|
||||
{
|
||||
return {
|
||||
@@ -383,7 +383,7 @@ namespace omath
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use inverted matrix")]]
|
||||
constexpr std::optional<Mat> inverted() const
|
||||
{
|
||||
const auto det = determinant();
|
||||
@@ -406,7 +406,7 @@ namespace omath
|
||||
private:
|
||||
std::array<Type, Rows * Columns> m_data;
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
template<size_t OtherColumns> [[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
|
||||
cache_friendly_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
|
||||
{
|
||||
@@ -421,7 +421,7 @@ namespace omath
|
||||
return result;
|
||||
}
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
template<size_t OtherColumns> [[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> cache_friendly_multiply_col_major(
|
||||
const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
|
||||
{
|
||||
@@ -436,7 +436,7 @@ namespace omath
|
||||
return result;
|
||||
}
|
||||
#ifdef OMATH_USE_AVX2
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
template<size_t OtherColumns> [[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>
|
||||
avx_multiply_col_major(const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
|
||||
{
|
||||
@@ -506,7 +506,7 @@ namespace omath
|
||||
return result;
|
||||
}
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
template<size_t OtherColumns> [[nodiscard("You must use result matrix")]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
|
||||
avx_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
|
||||
{
|
||||
@@ -577,20 +577,20 @@ namespace omath
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard("You must use row matrix")]]
|
||||
constexpr static Mat<1, 4, Type, St> mat_row_from_vector(const Vector3<Type>& vector) noexcept
|
||||
{
|
||||
return {{vector.x, vector.y, vector.z, 1}};
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard("You must use column matrix")]]
|
||||
constexpr static Mat<4, 1, Type, St> mat_column_from_vector(const Vector3<Type>& vector) noexcept
|
||||
{
|
||||
return {{vector.x}, {vector.y}, {vector.z}, {1}};
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use translation matrix")]]
|
||||
constexpr Mat<4, 4, Type, St> mat_translation(const Vector3<Type>& diff) noexcept
|
||||
{
|
||||
return
|
||||
@@ -602,7 +602,7 @@ namespace omath
|
||||
};
|
||||
}
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use scale matrix")]]
|
||||
constexpr Mat<4, 4, Type, St> mat_scale(const Vector3<Type>& scale) noexcept
|
||||
{
|
||||
return {
|
||||
@@ -614,14 +614,14 @@ namespace omath
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use extracted origin")]]
|
||||
constexpr Vector3<Type> mat_extract_origin(const Mat<4, 4, Type, St>& mat) noexcept
|
||||
{
|
||||
return {mat.at(0, 3), mat.at(1, 3), mat.at(2, 3)};
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use extracted scale")]]
|
||||
Vector3<Type> mat_extract_scale(const Mat<4, 4, Type, St>& mat) noexcept
|
||||
{
|
||||
auto column_length = [](const Type x, const Type y, const Type z) {
|
||||
@@ -643,7 +643,7 @@ namespace omath
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
requires std::is_floating_point_v<Type>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use extracted rotation")]]
|
||||
Vector3<Type> mat_extract_rotation_zyx(const Mat<4, 4, Type, St>& mat) noexcept
|
||||
{
|
||||
const auto scale = mat_extract_scale(mat);
|
||||
@@ -661,7 +661,7 @@ namespace omath
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use rotation matrix")]]
|
||||
Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept
|
||||
{
|
||||
return
|
||||
@@ -674,7 +674,7 @@ namespace omath
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use rotation matrix")]]
|
||||
Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept
|
||||
{
|
||||
return
|
||||
@@ -687,7 +687,7 @@ namespace omath
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use rotation matrix")]]
|
||||
Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept
|
||||
{
|
||||
return
|
||||
@@ -700,7 +700,7 @@ namespace omath
|
||||
}
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use camera view matrix")]]
|
||||
static Mat<4, 4, Type, St> mat_camera_view(const Vector3<Type>& forward, const Vector3<Type>& right,
|
||||
const Vector3<Type>& up, const Vector3<Type>& camera_origin) noexcept
|
||||
{
|
||||
@@ -715,7 +715,7 @@ namespace omath
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use perspective matrix")]]
|
||||
Mat<4, 4, Type, St> mat_perspective_left_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
@@ -737,7 +737,7 @@ namespace omath
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use perspective matrix")]]
|
||||
Mat<4, 4, Type, St> mat_perspective_right_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
@@ -762,7 +762,7 @@ namespace omath
|
||||
// X and Y scales derived as: X = 1 / tan(hfov/2), Y = aspect / tan(hfov/2).
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use perspective matrix")]]
|
||||
Mat<4, 4, Type, St> mat_perspective_left_handed_horizontal_fov(const Type horizontal_fov,
|
||||
const Type aspect_ratio, const Type near,
|
||||
const Type far) noexcept
|
||||
@@ -787,7 +787,7 @@ namespace omath
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use perspective matrix")]]
|
||||
Mat<4, 4, Type, St> mat_perspective_right_handed_horizontal_fov(const Type horizontal_fov,
|
||||
const Type aspect_ratio, const Type near,
|
||||
const Type far) noexcept
|
||||
@@ -811,7 +811,7 @@ namespace omath
|
||||
}
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use ortho matrix")]]
|
||||
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
@@ -836,7 +836,7 @@ namespace omath
|
||||
}
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
|
||||
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use ortho matrix")]]
|
||||
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
@@ -883,14 +883,14 @@ template<size_t Rows, size_t Columns, class Type, omath::MatStoreType StoreType>
|
||||
struct std::formatter<omath::Mat<Rows, Columns, Type, StoreType>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
using MatType = omath::Mat<Rows, Columns, Type, StoreType>;
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use parse iterator")]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use format iterator")]]
|
||||
static auto format(const MatType& mat, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace omath
|
||||
|
||||
template<class CastedType>
|
||||
requires std::is_arithmetic_v<CastedType>
|
||||
[[nodiscard]] constexpr explicit operator Vector2<CastedType>() const noexcept
|
||||
[[nodiscard("You must use casted vector")]] constexpr explicit operator Vector2<CastedType>() const noexcept
|
||||
{
|
||||
return {static_cast<CastedType>(x), static_cast<CastedType>(y)};
|
||||
}
|
||||
@@ -37,13 +37,13 @@ namespace omath
|
||||
}
|
||||
|
||||
// Equality operators
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator==(const Vector2& other) const noexcept
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator!=(const Vector2& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
@@ -115,45 +115,51 @@ namespace omath
|
||||
}
|
||||
|
||||
// Basic vector operations
|
||||
[[nodiscard]] Type distance_to(const Vector2& other) const noexcept
|
||||
[[nodiscard("You must use distance")]]
|
||||
Type distance_to(const Vector2& other) const noexcept
|
||||
{
|
||||
return std::sqrt(distance_to_sqr(other));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type distance_to_sqr(const Vector2& other) const noexcept
|
||||
[[nodiscard("You must use squared distance")]]
|
||||
constexpr Type distance_to_sqr(const Vector2& other) const noexcept
|
||||
{
|
||||
return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type dot(const Vector2& other) const noexcept
|
||||
[[nodiscard("You must use dot product")]]
|
||||
constexpr Type dot(const Vector2& other) const noexcept
|
||||
{
|
||||
return x * other.x + y * other.y;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
[[nodiscard]] constexpr Type length() const noexcept
|
||||
[[nodiscard("You must use length")]] constexpr Type length() const noexcept
|
||||
{
|
||||
return std::hypot(this->x, this->y);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector2 normalized() const noexcept
|
||||
[[nodiscard("You must use normalized vector")]] constexpr Vector2 normalized() const noexcept
|
||||
{
|
||||
const Type len = length();
|
||||
return len > 0.f ? *this / len : *this;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] Type length() const noexcept
|
||||
[[nodiscard("You must use length")]]
|
||||
Type length() const noexcept
|
||||
{
|
||||
return std::hypot(x, y);
|
||||
}
|
||||
|
||||
[[nodiscard]] Vector2 normalized() const noexcept
|
||||
[[nodiscard("You must use normalized vector")]]
|
||||
Vector2 normalized() const noexcept
|
||||
{
|
||||
const Type len = length();
|
||||
return len > static_cast<Type>(0) ? *this / len : *this;
|
||||
}
|
||||
#endif
|
||||
[[nodiscard]] constexpr Type length_sqr() const noexcept
|
||||
[[nodiscard("You must use squared length")]]
|
||||
constexpr Type length_sqr() const noexcept
|
||||
{
|
||||
return x * x + y * y;
|
||||
}
|
||||
@@ -166,79 +172,85 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector2 operator-() const noexcept
|
||||
[[nodiscard("You must use negated vector")]]
|
||||
constexpr Vector2 operator-() const noexcept
|
||||
{
|
||||
return {-x, -y};
|
||||
}
|
||||
|
||||
// Binary arithmetic operators
|
||||
[[nodiscard]] constexpr Vector2 operator+(const Vector2& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector2 operator+(const Vector2& other) const noexcept
|
||||
{
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector2 operator-(const Vector2& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector2 operator-(const Vector2& other) const noexcept
|
||||
{
|
||||
return {x - other.x, y - other.y};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector2 operator*(const Type& value) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector2 operator*(const Type& value) const noexcept
|
||||
{
|
||||
return {x * value, y * value};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector2 operator/(const Type& value) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector2 operator/(const Type& value) const noexcept
|
||||
{
|
||||
return {x / value, y / value};
|
||||
}
|
||||
|
||||
// Sum of elements
|
||||
[[nodiscard]] constexpr Type sum() const noexcept
|
||||
[[nodiscard("You must use sum of elements")]]
|
||||
constexpr Type sum() const noexcept
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<(const Vector2& other) const noexcept
|
||||
{
|
||||
return length() < other.length();
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>(const Vector2& other) const noexcept
|
||||
{
|
||||
return length() > other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<=(const Vector2& other) const noexcept
|
||||
{
|
||||
return length() <= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>=(const Vector2& other) const noexcept
|
||||
{
|
||||
return length() >= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use tuple")]]
|
||||
constexpr std::tuple<Type, Type> as_tuple() const noexcept
|
||||
{
|
||||
return std::make_tuple(x, y);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use array")]]
|
||||
constexpr std::array<Type, 2> as_array() const noexcept
|
||||
{
|
||||
return {x, y};
|
||||
}
|
||||
#ifdef OMATH_IMGUI_INTEGRATION
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use ImVec2")]]
|
||||
constexpr ImVec2 to_im_vec2() const noexcept
|
||||
{
|
||||
return {static_cast<float>(this->x), static_cast<float>(this->y)};
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use vector from ImVec2")]]
|
||||
static Vector2 from_im_vec2(const ImVec2& other) noexcept
|
||||
{
|
||||
return {static_cast<Type>(other.x), static_cast<Type>(other.y)};
|
||||
@@ -249,7 +261,7 @@ namespace omath
|
||||
|
||||
template<> struct std::hash<omath::Vector2<float>>
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use hash value")]]
|
||||
std::size_t operator()(const omath::Vector2<float>& vec) const noexcept
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
@@ -265,14 +277,14 @@ template<> struct std::hash<omath::Vector2<float>>
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use parse iterator")]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use format iterator")]]
|
||||
static auto format(const omath::Vector2<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
|
||||
@@ -32,17 +32,20 @@ namespace omath
|
||||
|
||||
template<class CastedType>
|
||||
requires std::is_arithmetic_v<CastedType>
|
||||
[[nodiscard]] constexpr explicit operator Vector3<CastedType>() const noexcept
|
||||
[[nodiscard("You must use casted vector")]]
|
||||
constexpr explicit operator Vector3<CastedType>() const noexcept
|
||||
{
|
||||
return {static_cast<CastedType>(this->x), static_cast<CastedType>(this->y),
|
||||
static_cast<CastedType>(this->z)};
|
||||
}
|
||||
[[nodiscard]] constexpr bool operator==(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator==(const Vector3& other) const noexcept
|
||||
{
|
||||
return Vector2<Type>::operator==(other) && (other.z == z);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator!=(const Vector3& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
@@ -119,117 +122,134 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type distance_to_sqr(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use squared distance")]]
|
||||
constexpr Type distance_to_sqr(const Vector3& other) const noexcept
|
||||
{
|
||||
return (*this - other).length_sqr();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type dot(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use dot product")]]
|
||||
constexpr Type dot(const Vector3& other) const noexcept
|
||||
{
|
||||
return Vector2<Type>::dot(other) + z * other.z;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
[[nodiscard]] constexpr Type length() const
|
||||
[[nodiscard("You must use length")]] constexpr Type length() const
|
||||
{
|
||||
return std::hypot(this->x, this->y, z);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type length_2d() const
|
||||
[[nodiscard("You must use 2D length")]] constexpr Type length_2d() const
|
||||
{
|
||||
return Vector2<Type>::length();
|
||||
}
|
||||
[[nodiscard]] Type distance_to(const Vector3& other) const
|
||||
[[nodiscard("You must use distance")]] Type distance_to(const Vector3& other) const
|
||||
{
|
||||
return (*this - other).length();
|
||||
}
|
||||
[[nodiscard]] constexpr Vector3 normalized() const
|
||||
[[nodiscard("You must use normalized vector")]] constexpr Vector3 normalized() const
|
||||
{
|
||||
const Type length_value = this->length();
|
||||
|
||||
return length_value != 0 ? *this / length_value : *this;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] Type length() const noexcept
|
||||
[[nodiscard("You must use length")]]
|
||||
Type length() const noexcept
|
||||
{
|
||||
return std::hypot(this->x, this->y, z);
|
||||
}
|
||||
|
||||
[[nodiscard]] Vector3 normalized() const noexcept
|
||||
[[nodiscard("You must use normalized vector")]]
|
||||
Vector3 normalized() const noexcept
|
||||
{
|
||||
const Type len = this->length();
|
||||
|
||||
return len != static_cast<Type>(0) ? *this / len : *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] Type length_2d() const noexcept
|
||||
[[nodiscard("You must use 2D length")]]
|
||||
Type length_2d() const noexcept
|
||||
{
|
||||
return Vector2<Type>::length();
|
||||
}
|
||||
|
||||
[[nodiscard]] Type distance_to(const Vector3& v_other) const noexcept
|
||||
[[nodiscard("You must use distance")]]
|
||||
Type distance_to(const Vector3& v_other) const noexcept
|
||||
{
|
||||
return (*this - v_other).length();
|
||||
}
|
||||
#endif
|
||||
|
||||
[[nodiscard]] constexpr Type length_sqr() const noexcept
|
||||
[[nodiscard("You must use squared length")]]
|
||||
constexpr Type length_sqr() const noexcept
|
||||
{
|
||||
return Vector2<Type>::length_sqr() + z * z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator-() const noexcept
|
||||
[[nodiscard("You must use negated vector")]]
|
||||
constexpr Vector3 operator-() const noexcept
|
||||
{
|
||||
return {-this->x, -this->y, -z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator+(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator+(const Vector3& other) const noexcept
|
||||
{
|
||||
return {this->x + other.x, this->y + other.y, z + other.z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator-(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator-(const Vector3& other) const noexcept
|
||||
{
|
||||
return {this->x - other.x, this->y - other.y, z - other.z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator*(const Type& value) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator*(const Type& value) const noexcept
|
||||
{
|
||||
return {this->x * value, this->y * value, z * value};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator*(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator*(const Vector3& other) const noexcept
|
||||
{
|
||||
return {this->x * other.x, this->y * other.y, z * other.z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator/(const Type& value) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator/(const Type& value) const noexcept
|
||||
{
|
||||
return {this->x / value, this->y / value, z / value};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 operator/(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector3 operator/(const Vector3& other) const noexcept
|
||||
{
|
||||
return {this->x / other.x, this->y / other.y, z / other.z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vector3 cross(const Vector3& other) const noexcept
|
||||
[[nodiscard("You must use cross product")]]
|
||||
constexpr Vector3 cross(const Vector3& other) const noexcept
|
||||
{
|
||||
return {this->y * other.z - z * other.y, z * other.x - this->x * other.z,
|
||||
this->x * other.y - this->y * other.x};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type sum() const noexcept
|
||||
[[nodiscard("You must use sum of elements")]]
|
||||
constexpr Type sum() const noexcept
|
||||
{
|
||||
return sum_2d() + z;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use direction check result")]]
|
||||
bool point_to_same_direction(const Vector3& other) const
|
||||
{
|
||||
return dot(other) > static_cast<Type>(0);
|
||||
}
|
||||
[[nodiscard]] std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
|
||||
[[nodiscard("You must use angle between vectors")]]
|
||||
std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
|
||||
angle_between(const Vector3& other) const noexcept
|
||||
{
|
||||
const auto bottom = length() * other.length();
|
||||
@@ -240,8 +260,8 @@ namespace omath
|
||||
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_perpendicular(const Vector3& other,
|
||||
Type epsilon = static_cast<Type>(0.0001)) const noexcept
|
||||
[[nodiscard("You must use perpendicularity check result")]]
|
||||
bool is_perpendicular(const Vector3& other, Type epsilon = static_cast<Type>(0.0001)) const noexcept
|
||||
{
|
||||
if (const auto angle = angle_between(other))
|
||||
return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon;
|
||||
@@ -249,41 +269,43 @@ namespace omath
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type sum_2d() const noexcept
|
||||
[[nodiscard("You must use 2D sum")]]
|
||||
constexpr Type sum_2d() const noexcept
|
||||
{
|
||||
return Vector2<Type>::sum();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::tuple<Type, Type, Type> as_tuple() const noexcept
|
||||
[[nodiscard("You must use tuple")]]
|
||||
constexpr std::tuple<Type, Type, Type> as_tuple() const noexcept
|
||||
{
|
||||
return std::make_tuple(this->x, this->y, z);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<(const Vector3& other) const noexcept
|
||||
{
|
||||
return length() < other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>(const Vector3& other) const noexcept
|
||||
{
|
||||
return length() > other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<=(const Vector3& other) const noexcept
|
||||
{
|
||||
return length() <= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>=(const Vector3& other) const noexcept
|
||||
{
|
||||
return length() >= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use array")]]
|
||||
constexpr std::array<Type, 3> as_array() const noexcept
|
||||
{
|
||||
return {this->x, this->y, z};
|
||||
@@ -293,7 +315,7 @@ namespace omath
|
||||
|
||||
template<> struct std::hash<omath::Vector3<float>>
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use hash value")]]
|
||||
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
@@ -310,14 +332,14 @@ template<> struct std::hash<omath::Vector3<float>>
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector3<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use parse iterator")]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use format iterator")]]
|
||||
static auto format(const omath::Vector3<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
|
||||
@@ -24,19 +24,19 @@ namespace omath
|
||||
|
||||
template<class CastedType>
|
||||
requires std::is_arithmetic_v<CastedType>
|
||||
[[nodiscard]] constexpr explicit operator Vector4<CastedType>() const noexcept
|
||||
[[nodiscard("You must use casted vector")]] constexpr explicit operator Vector4<CastedType>() const noexcept
|
||||
{
|
||||
return {static_cast<CastedType>(this->x), static_cast<CastedType>(this->y),
|
||||
static_cast<CastedType>(this->z), static_cast<CastedType>(this->w)};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator==(const Vector4& other) const noexcept
|
||||
{
|
||||
return Vector3<Type>::operator==(other) && w == other.w;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
constexpr bool operator!=(const Vector4& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
@@ -89,17 +89,19 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type length_sqr() const noexcept
|
||||
[[nodiscard("You must use squared length")]]
|
||||
constexpr Type length_sqr() const noexcept
|
||||
{
|
||||
return Vector3<Type>::length_sqr() + w * w;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Type dot(const Vector4& other) const noexcept
|
||||
[[nodiscard("You must use dot product")]]
|
||||
constexpr Type dot(const Vector4& other) const noexcept
|
||||
{
|
||||
return Vector3<Type>::dot(other) + w * other.w;
|
||||
}
|
||||
|
||||
[[nodiscard]] Type length() const noexcept
|
||||
[[nodiscard("You must use length")]] Type length() const noexcept
|
||||
{
|
||||
return std::sqrt(length_sqr());
|
||||
}
|
||||
@@ -120,86 +122,86 @@ namespace omath
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use negated vector")]]
|
||||
constexpr Vector4 operator-() const noexcept
|
||||
{
|
||||
return {-this->x, -this->y, -this->z, -w};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator+(const Vector4& other) const noexcept
|
||||
{
|
||||
return {this->x + other.x, this->y + other.y, this->z + other.z, w + other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator-(const Vector4& other) const noexcept
|
||||
{
|
||||
return {this->x - other.x, this->y - other.y, this->z - other.z, w - other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator*(const Type& value) const noexcept
|
||||
{
|
||||
return {this->x * value, this->y * value, this->z * value, w * value};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator*(const Vector4& other) const noexcept
|
||||
{
|
||||
return {this->x * other.x, this->y * other.y, this->z * other.z, w * other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator/(const Type& value) const noexcept
|
||||
{
|
||||
return {this->x / value, this->y / value, this->z / value, w / value};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use result vector")]]
|
||||
constexpr Vector4 operator/(const Vector4& other) const noexcept
|
||||
{
|
||||
return {this->x / other.x, this->y / other.y, this->z / other.z, w / other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use sum of elements")]]
|
||||
constexpr Type sum() const noexcept
|
||||
{
|
||||
return Vector3<Type>::sum() + w;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<(const Vector4& other) const noexcept
|
||||
{
|
||||
return length() < other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>(const Vector4& other) const noexcept
|
||||
{
|
||||
return length() > other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator<=(const Vector4& other) const noexcept
|
||||
{
|
||||
return length() <= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use comparison result")]]
|
||||
bool operator>=(const Vector4& other) const noexcept
|
||||
{
|
||||
return length() >= other.length();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use array")]]
|
||||
constexpr std::array<Type, 4> as_array() const noexcept
|
||||
{
|
||||
return {this->x, this->y, this->z, w};
|
||||
}
|
||||
|
||||
#ifdef OMATH_IMGUI_INTEGRATION
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use ImVec4")]]
|
||||
constexpr ImVec4 to_im_vec4() const noexcept
|
||||
{
|
||||
return {
|
||||
@@ -209,7 +211,7 @@ namespace omath
|
||||
static_cast<float>(w),
|
||||
};
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use vector from ImVec4")]]
|
||||
static Vector4<float> from_im_vec4(const ImVec4& other) noexcept
|
||||
{
|
||||
return {static_cast<Type>(other.x), static_cast<Type>(other.y), static_cast<Type>(other.z)};
|
||||
@@ -220,7 +222,7 @@ namespace omath
|
||||
|
||||
template<> struct std::hash<omath::Vector4<float>>
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use hash value")]]
|
||||
std::size_t operator()(const omath::Vector4<float>& vec) const noexcept
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
@@ -237,13 +239,13 @@ template<> struct std::hash<omath::Vector4<float>>
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use parse iterator")]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use format iterator")]]
|
||||
static auto format(const omath::Vector4<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
@@ -255,4 +257,4 @@ struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace omath::projection
|
||||
float m_width;
|
||||
float m_height;
|
||||
|
||||
[[nodiscard]] constexpr float aspect_ratio() const
|
||||
[[nodiscard("You must use aspect ratio")]] constexpr float aspect_ratio() const
|
||||
{
|
||||
return m_width / m_height;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace omath::projection
|
||||
// built by any of the engine traits. Both variants (ZERO_TO_ONE and
|
||||
// NEGATIVE_ONE_TO_ONE) share the same m[0,0]/m[1,1] layout, so this works
|
||||
// regardless of the NDC depth range.
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use extracted projection params")]]
|
||||
static ProjectionParams extract_projection_params(const Mat4X4Type& proj_matrix) noexcept
|
||||
{
|
||||
// m[1,1] == 1 / tan(fov/2) => fov = 2 * atan(1 / m[1,1])
|
||||
@@ -112,7 +112,7 @@ namespace omath::projection
|
||||
f / proj_matrix.at(0, 0)};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use calculated view angles")]]
|
||||
static ViewAnglesType calc_view_angles_from_view_matrix(const Mat4X4Type& view_matrix) noexcept
|
||||
{
|
||||
Vector3<NumericType> forward_vector = {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
||||
@@ -121,7 +121,7 @@ namespace omath::projection
|
||||
return TraitClass::calc_look_at_angle({}, forward_vector);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use calculated origin")]]
|
||||
static Vector3<NumericType> calc_origin_from_view_matrix(const Mat4X4Type& view_matrix) noexcept
|
||||
{
|
||||
// The view matrix is R * T(-origin), so the last column stores t = -R * origin.
|
||||
@@ -142,33 +142,33 @@ namespace omath::projection
|
||||
m_view_projection_matrix = std::nullopt;
|
||||
m_view_matrix = std::nullopt;
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use calculated look-at angles")]]
|
||||
ViewAnglesType calc_look_at_angles(const Vector3<NumericType>& look_to) const
|
||||
{
|
||||
return TraitClass::calc_look_at_angle(m_origin, look_to);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use forward vector")]]
|
||||
Vector3<NumericType> get_forward() const noexcept
|
||||
{
|
||||
const auto& view_matrix = get_view_matrix();
|
||||
return {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use right vector")]]
|
||||
Vector3<NumericType> get_right() const noexcept
|
||||
{
|
||||
const auto& view_matrix = get_view_matrix();
|
||||
return {view_matrix[0, 0], view_matrix[0, 1], view_matrix[0, 2]};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use up vector")]]
|
||||
Vector3<NumericType> get_up() const noexcept
|
||||
{
|
||||
const auto& view_matrix = get_view_matrix();
|
||||
return {view_matrix[1, 0], view_matrix[1, 1], view_matrix[1, 2]};
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use absolute forward vector")]]
|
||||
Vector3<NumericType> get_abs_forward() const noexcept
|
||||
{
|
||||
if constexpr (axes.inverted_forward)
|
||||
@@ -176,7 +176,7 @@ namespace omath::projection
|
||||
return get_forward();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use absolute right vector")]]
|
||||
Vector3<NumericType> get_abs_right() const noexcept
|
||||
{
|
||||
if constexpr (axes.inverted_right)
|
||||
@@ -184,13 +184,14 @@ namespace omath::projection
|
||||
return get_right();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use absolute up vector")]]
|
||||
Vector3<NumericType> get_abs_up() const noexcept
|
||||
{
|
||||
return get_up();
|
||||
}
|
||||
|
||||
[[nodiscard]] const Mat4X4Type& get_view_projection_matrix() const noexcept
|
||||
[[nodiscard("You must use view-projection matrix")]]
|
||||
const Mat4X4Type& get_view_projection_matrix() const noexcept
|
||||
{
|
||||
if (!m_view_projection_matrix.has_value())
|
||||
m_view_projection_matrix = get_projection_matrix() * get_view_matrix();
|
||||
@@ -198,14 +199,14 @@ namespace omath::projection
|
||||
return m_view_projection_matrix.value();
|
||||
}
|
||||
|
||||
[[nodiscard]] const Mat4X4Type& get_view_matrix() const noexcept
|
||||
[[nodiscard("You must use view matrix")]] const Mat4X4Type& get_view_matrix() const noexcept
|
||||
{
|
||||
if (!m_view_matrix.has_value())
|
||||
m_view_matrix = TraitClass::calc_view_matrix(m_view_angles, m_origin);
|
||||
|
||||
return m_view_matrix.value();
|
||||
}
|
||||
[[nodiscard]] const Mat4X4Type& get_projection_matrix() const noexcept
|
||||
[[nodiscard("You must use projection matrix")]] const Mat4X4Type& get_projection_matrix() const noexcept
|
||||
{
|
||||
if (!m_projection_matrix.has_value())
|
||||
m_projection_matrix = TraitClass::calc_projection_matrix(
|
||||
@@ -255,33 +256,33 @@ namespace omath::projection
|
||||
m_projection_matrix = std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] const FieldOfView& get_field_of_view() const noexcept
|
||||
[[nodiscard("You must use field of view")]] const FieldOfView& get_field_of_view() const noexcept
|
||||
{
|
||||
return m_field_of_view;
|
||||
}
|
||||
|
||||
[[nodiscard]] const NumericType& get_near_plane() const noexcept
|
||||
[[nodiscard("You must use near plane")]] const NumericType& get_near_plane() const noexcept
|
||||
{
|
||||
return m_near_plane_distance;
|
||||
}
|
||||
|
||||
[[nodiscard]] const NumericType& get_far_plane() const noexcept
|
||||
[[nodiscard("You must use far plane")]] const NumericType& get_far_plane() const noexcept
|
||||
{
|
||||
return m_far_plane_distance;
|
||||
}
|
||||
|
||||
[[nodiscard]] const ViewAnglesType& get_view_angles() const noexcept
|
||||
[[nodiscard("You must use view angles")]] const ViewAnglesType& get_view_angles() const noexcept
|
||||
{
|
||||
return m_view_angles;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Vector3<NumericType>& get_origin() const noexcept
|
||||
[[nodiscard("You must use origin")]] const Vector3<NumericType>& get_origin() const noexcept
|
||||
{
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||
[[nodiscard]] std::expected<Vector3<NumericType>, Error>
|
||||
[[nodiscard("You must use screen position")]] std::expected<Vector3<NumericType>, Error>
|
||||
world_to_screen(const Vector3<NumericType>& world_position) const noexcept
|
||||
{
|
||||
const auto normalized_cords = world_to_view_port(world_position);
|
||||
@@ -297,7 +298,7 @@ namespace omath::projection
|
||||
std::unreachable();
|
||||
}
|
||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||
[[nodiscard]] std::expected<Vector3<NumericType>, Error>
|
||||
[[nodiscard("You must use unclipped screen position")]] std::expected<Vector3<NumericType>, Error>
|
||||
world_to_screen_unclipped(const Vector3<NumericType>& world_position) const noexcept
|
||||
{
|
||||
const auto normalized_cords = world_to_view_port(world_position, ViewPortClipping::MANUAL);
|
||||
@@ -313,7 +314,8 @@ namespace omath::projection
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_culled_by_frustum(const Triangle<Vector3<NumericType>>& triangle) const noexcept
|
||||
[[nodiscard("You must use frustum culling result")]] bool
|
||||
is_culled_by_frustum(const Triangle<Vector3<NumericType>>& triangle) const noexcept
|
||||
{
|
||||
// Transform to clip space (before perspective divide)
|
||||
auto to_clip = [this](const Vector3<NumericType>& point)
|
||||
@@ -380,7 +382,8 @@ namespace omath::projection
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_aabb_culled_by_frustum(const primitives::Aabb<NumericType>& aabb) const noexcept
|
||||
[[nodiscard("You must use AABB frustum culling result")]] bool
|
||||
is_aabb_culled_by_frustum(const primitives::Aabb<NumericType>& aabb) const noexcept
|
||||
{
|
||||
// For each plane, find the AABB corner most in the direction of the plane normal
|
||||
// (the "positive vertex"). If it's outside, the entire AABB is outside.
|
||||
@@ -397,7 +400,8 @@ namespace omath::projection
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_obb_culled_by_frustum(const primitives::Obb<NumericType>& obb) const noexcept
|
||||
[[nodiscard("You must use OBB frustum culling result")]] bool
|
||||
is_obb_culled_by_frustum(const primitives::Obb<NumericType>& obb) const noexcept
|
||||
{
|
||||
// For each plane, project the OBB extents onto the plane normal to get the
|
||||
// effective radius, then test the center's signed distance against it.
|
||||
@@ -417,7 +421,7 @@ namespace omath::projection
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::expected<Vector3<NumericType>, Error>
|
||||
[[nodiscard("You must use view port position")]] std::expected<Vector3<NumericType>, Error>
|
||||
world_to_view_port(const Vector3<NumericType>& world_position,
|
||||
const ViewPortClipping& clipping = ViewPortClipping::AUTO) const noexcept
|
||||
{
|
||||
@@ -446,7 +450,7 @@ namespace omath::projection
|
||||
|
||||
return Vector3<NumericType>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
||||
}
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use world position")]]
|
||||
std::expected<Vector3<NumericType>, Error> view_port_to_world(const Vector3<NumericType>& ndc) const noexcept
|
||||
{
|
||||
const auto inv_view_proj = get_view_projection_matrix().inverted();
|
||||
@@ -469,7 +473,7 @@ namespace omath::projection
|
||||
}
|
||||
|
||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use world position")]]
|
||||
std::expected<Vector3<NumericType>, Error>
|
||||
screen_to_world(const Vector3<NumericType>& screen_pos) const noexcept
|
||||
{
|
||||
@@ -477,7 +481,7 @@ namespace omath::projection
|
||||
}
|
||||
|
||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use world position")]]
|
||||
std::expected<Vector3<NumericType>, Error>
|
||||
screen_to_world(const Vector2<NumericType>& screen_pos) const noexcept
|
||||
{
|
||||
@@ -513,7 +517,7 @@ namespace omath::projection
|
||||
// Top = r3 - r1
|
||||
// Near = r3 + r2 ([-1,1]) or r2 ([0,1])
|
||||
// Far = r3 - r2
|
||||
[[nodiscard]] std::array<FrustumPlane, 6> extract_frustum_planes() const noexcept
|
||||
[[nodiscard("You must use frustum planes")]] std::array<FrustumPlane, 6> extract_frustum_planes() const noexcept
|
||||
{
|
||||
const auto& m = get_view_projection_matrix();
|
||||
|
||||
@@ -545,7 +549,8 @@ namespace omath::projection
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
[[nodiscard]] constexpr static bool is_ndc_out_of_bounds(const Type& ndc) noexcept
|
||||
[[nodiscard("You must use NDC bounds check result")]] constexpr static bool
|
||||
is_ndc_out_of_bounds(const Type& ndc) noexcept
|
||||
{
|
||||
constexpr auto eps = std::numeric_limits<NumericType>::epsilon();
|
||||
|
||||
@@ -558,7 +563,7 @@ namespace omath::projection
|
||||
return is_ndc_z_value_out_of_bounds(data[2]);
|
||||
}
|
||||
template<class ZType>
|
||||
[[nodiscard]]
|
||||
[[nodiscard("You must use NDC z bounds check result")]]
|
||||
constexpr static bool is_ndc_z_value_out_of_bounds(const ZType& z_ndc) noexcept
|
||||
{
|
||||
constexpr auto eps = std::numeric_limits<NumericType>::epsilon();
|
||||
@@ -584,7 +589,7 @@ namespace omath::projection
|
||||
v
|
||||
*/
|
||||
|
||||
[[nodiscard]] Vector3<NumericType>
|
||||
[[nodiscard("You must use screen position")]] Vector3<NumericType>
|
||||
ndc_to_screen_position_from_top_left_corner(const Vector3<NumericType>& ndc) const noexcept
|
||||
{
|
||||
/*
|
||||
@@ -602,7 +607,7 @@ namespace omath::projection
|
||||
(ndc.y / -NumericType{2} + NumericType{0.5}) * m_view_port.m_height, ndc.z};
|
||||
}
|
||||
|
||||
[[nodiscard]] Vector3<NumericType>
|
||||
[[nodiscard("You must use screen position")]] Vector3<NumericType>
|
||||
ndc_to_screen_position_from_bottom_left_corner(const Vector3<NumericType>& ndc) const noexcept
|
||||
{
|
||||
/*
|
||||
@@ -621,7 +626,8 @@ namespace omath::projection
|
||||
}
|
||||
|
||||
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||
[[nodiscard]] Vector3<NumericType> screen_to_ndc(const Vector3<NumericType>& screen_pos) const noexcept
|
||||
[[nodiscard("You must use NDC position")]] Vector3<NumericType>
|
||||
screen_to_ndc(const Vector3<NumericType>& screen_pos) const noexcept
|
||||
{
|
||||
if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER)
|
||||
return {screen_pos.x / m_view_port.m_width * NumericType{2} - NumericType{1},
|
||||
|
||||
Reference in New Issue
Block a user