From 37128d18e70f7f407a150b2d8cbc334574978b37 Mon Sep 17 00:00:00 2001 From: Orange Date: Fri, 22 May 2026 08:50:21 +0300 Subject: [PATCH 1/2] camera message --- include/omath/projection/camera.hpp | 68 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/include/omath/projection/camera.hpp b/include/omath/projection/camera.hpp index 30da3547..e6126669 100644 --- a/include/omath/projection/camera.hpp +++ b/include/omath/projection/camera.hpp @@ -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 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 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& look_to) const { return TraitClass::calc_look_at_angle(m_origin, look_to); } - [[nodiscard]] + [[nodiscard("You must use forward vector")]] Vector3 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 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 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 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 get_abs_right() const noexcept { if constexpr (axes.inverted_right) @@ -184,13 +184,13 @@ namespace omath::projection return get_right(); } - [[nodiscard]] + [[nodiscard("You must use absolute up vector")]] Vector3 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 +198,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 +255,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& get_origin() const noexcept + [[nodiscard("You must use origin")]] const Vector3& get_origin() const noexcept { return m_origin; } template - [[nodiscard]] std::expected, Error> + [[nodiscard("You must use screen position")]] std::expected, Error> world_to_screen(const Vector3& world_position) const noexcept { const auto normalized_cords = world_to_view_port(world_position); @@ -297,7 +297,7 @@ namespace omath::projection std::unreachable(); } template - [[nodiscard]] std::expected, Error> + [[nodiscard("You must use unclipped screen position")]] std::expected, Error> world_to_screen_unclipped(const Vector3& world_position) const noexcept { const auto normalized_cords = world_to_view_port(world_position, ViewPortClipping::MANUAL); @@ -313,7 +313,7 @@ namespace omath::projection std::unreachable(); } - [[nodiscard]] bool is_culled_by_frustum(const Triangle>& triangle) const noexcept + [[nodiscard("You must use frustum culling result")]] bool is_culled_by_frustum(const Triangle>& triangle) const noexcept { // Transform to clip space (before perspective divide) auto to_clip = [this](const Vector3& point) @@ -380,7 +380,7 @@ namespace omath::projection return false; } - [[nodiscard]] bool is_aabb_culled_by_frustum(const primitives::Aabb& aabb) const noexcept + [[nodiscard("You must use AABB frustum culling result")]] bool is_aabb_culled_by_frustum(const primitives::Aabb& 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 +397,7 @@ namespace omath::projection return false; } - [[nodiscard]] bool is_obb_culled_by_frustum(const primitives::Obb& obb) const noexcept + [[nodiscard("You must use OBB frustum culling result")]] bool is_obb_culled_by_frustum(const primitives::Obb& 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 +417,7 @@ namespace omath::projection return false; } - [[nodiscard]] std::expected, Error> + [[nodiscard("You must use view port position")]] std::expected, Error> world_to_view_port(const Vector3& world_position, const ViewPortClipping& clipping = ViewPortClipping::AUTO) const noexcept { @@ -446,7 +446,7 @@ namespace omath::projection return Vector3{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)}; } - [[nodiscard]] + [[nodiscard("You must use world position")]] std::expected, Error> view_port_to_world(const Vector3& ndc) const noexcept { const auto inv_view_proj = get_view_projection_matrix().inverted(); @@ -469,7 +469,7 @@ namespace omath::projection } template - [[nodiscard]] + [[nodiscard("You must use world position")]] std::expected, Error> screen_to_world(const Vector3& screen_pos) const noexcept { @@ -477,7 +477,7 @@ namespace omath::projection } template - [[nodiscard]] + [[nodiscard("You must use world position")]] std::expected, Error> screen_to_world(const Vector2& screen_pos) const noexcept { @@ -513,7 +513,7 @@ namespace omath::projection // Top = r3 - r1 // Near = r3 + r2 ([-1,1]) or r2 ([0,1]) // Far = r3 - r2 - [[nodiscard]] std::array extract_frustum_planes() const noexcept + [[nodiscard("You must use frustum planes")]] std::array extract_frustum_planes() const noexcept { const auto& m = get_view_projection_matrix(); @@ -545,7 +545,7 @@ namespace omath::projection } template - [[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::epsilon(); @@ -558,7 +558,7 @@ namespace omath::projection return is_ndc_z_value_out_of_bounds(data[2]); } template - [[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::epsilon(); @@ -584,7 +584,7 @@ namespace omath::projection v */ - [[nodiscard]] Vector3 + [[nodiscard("You must use screen position")]] Vector3 ndc_to_screen_position_from_top_left_corner(const Vector3& ndc) const noexcept { /* @@ -602,7 +602,7 @@ namespace omath::projection (ndc.y / -NumericType{2} + NumericType{0.5}) * m_view_port.m_height, ndc.z}; } - [[nodiscard]] Vector3 + [[nodiscard("You must use screen position")]] Vector3 ndc_to_screen_position_from_bottom_left_corner(const Vector3& ndc) const noexcept { /* @@ -621,7 +621,7 @@ namespace omath::projection } template - [[nodiscard]] Vector3 screen_to_ndc(const Vector3& screen_pos) const noexcept + [[nodiscard("You must use NDC position")]] Vector3 screen_to_ndc(const Vector3& 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}, From 848202cbd8839ed9e0ad84c6dff034386851b21f Mon Sep 17 00:00:00 2001 From: Orange Date: Fri, 22 May 2026 09:00:32 +0300 Subject: [PATCH 2/2] added nodiscard messages --- include/omath/linear_algebra/mat.hpp | 98 ++++++++++++------------ include/omath/linear_algebra/vector2.hpp | 68 +++++++++------- include/omath/linear_algebra/vector3.hpp | 96 ++++++++++++++--------- include/omath/linear_algebra/vector4.hpp | 52 +++++++------ include/omath/projection/camera.hpp | 18 +++-- 5 files changed, 187 insertions(+), 145 deletions(-) diff --git a/include/omath/linear_algebra/mat.hpp b/include/omath/linear_algebra/mat.hpp index df7e4294..2cbf0788 100644 --- a/include/omath/linear_algebra/mat.hpp +++ b/include/omath/linear_algebra/mat.hpp @@ -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(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(0)); @@ -171,7 +171,7 @@ namespace omath } // Operator overloading for multiplication with another Mat - template [[nodiscard]] + template [[nodiscard("You must use result matrix")]] constexpr Mat operator*(const Mat& 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 transposed() const noexcept { Mat 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 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& raw_array() const { return m_data; } - [[nodiscard]] + [[nodiscard("You must use raw array")]] constexpr std::array& 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 inverted() const { const auto det = determinant(); @@ -406,7 +406,7 @@ namespace omath private: std::array m_data; - template [[nodiscard]] + template [[nodiscard("You must use result matrix")]] constexpr Mat cache_friendly_multiply_row_major(const Mat& other) const { @@ -421,7 +421,7 @@ namespace omath return result; } - template [[nodiscard]] + template [[nodiscard("You must use result matrix")]] constexpr Mat cache_friendly_multiply_col_major( const Mat& other) const { @@ -436,7 +436,7 @@ namespace omath return result; } #ifdef OMATH_USE_AVX2 - template [[nodiscard]] + template [[nodiscard("You must use result matrix")]] constexpr Mat avx_multiply_col_major(const Mat& other) const { @@ -506,7 +506,7 @@ namespace omath return result; } - template [[nodiscard]] + template [[nodiscard("You must use result matrix")]] constexpr Mat avx_multiply_row_major(const Mat& other) const { @@ -577,20 +577,20 @@ namespace omath #endif }; - template [[nodiscard]] + template [[nodiscard("You must use row matrix")]] constexpr static Mat<1, 4, Type, St> mat_row_from_vector(const Vector3& vector) noexcept { return {{vector.x, vector.y, vector.z, 1}}; } - template [[nodiscard]] + template [[nodiscard("You must use column matrix")]] constexpr static Mat<4, 1, Type, St> mat_column_from_vector(const Vector3& vector) noexcept { return {{vector.x}, {vector.y}, {vector.z}, {1}}; } template - [[nodiscard]] + [[nodiscard("You must use translation matrix")]] constexpr Mat<4, 4, Type, St> mat_translation(const Vector3& diff) noexcept { return @@ -602,7 +602,7 @@ namespace omath }; } template - [[nodiscard]] + [[nodiscard("You must use scale matrix")]] constexpr Mat<4, 4, Type, St> mat_scale(const Vector3& scale) noexcept { return { @@ -614,14 +614,14 @@ namespace omath } template - [[nodiscard]] + [[nodiscard("You must use extracted origin")]] constexpr Vector3 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 - [[nodiscard]] + [[nodiscard("You must use extracted scale")]] Vector3 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 requires std::is_floating_point_v - [[nodiscard]] + [[nodiscard("You must use extracted rotation")]] Vector3 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 - [[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 - [[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 - [[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 - [[nodiscard]] + [[nodiscard("You must use camera view matrix")]] static Mat<4, 4, Type, St> mat_camera_view(const Vector3& forward, const Vector3& right, const Vector3& up, const Vector3& camera_origin) noexcept { @@ -715,7 +715,7 @@ namespace omath template - [[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 - [[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 - [[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 - [[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 - [[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 - [[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 struct std::formatter> // NOLINT(*-dcl58-cpp) { using MatType = omath::Mat; - [[nodiscard]] + [[nodiscard("You must use parse iterator")]] static constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } template - [[nodiscard]] + [[nodiscard("You must use format iterator")]] static auto format(const MatType& mat, FormatContext& ctx) { if constexpr (std::is_same_v) diff --git a/include/omath/linear_algebra/vector2.hpp b/include/omath/linear_algebra/vector2.hpp index 44622392..13a08f97 100644 --- a/include/omath/linear_algebra/vector2.hpp +++ b/include/omath/linear_algebra/vector2.hpp @@ -28,7 +28,7 @@ namespace omath template requires std::is_arithmetic_v - [[nodiscard]] constexpr explicit operator Vector2() const noexcept + [[nodiscard("You must use casted vector")]] constexpr explicit operator Vector2() const noexcept { return {static_cast(x), static_cast(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(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 as_tuple() const noexcept { return std::make_tuple(x, y); } - [[nodiscard]] + [[nodiscard("You must use array")]] constexpr std::array 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(this->x), static_cast(this->y)}; } - [[nodiscard]] + [[nodiscard("You must use vector from ImVec2")]] static Vector2 from_im_vec2(const ImVec2& other) noexcept { return {static_cast(other.x), static_cast(other.y)}; @@ -249,7 +261,7 @@ namespace omath template<> struct std::hash> { - [[nodiscard]] + [[nodiscard("You must use hash value")]] std::size_t operator()(const omath::Vector2& vec) const noexcept { std::size_t hash = 0; @@ -265,14 +277,14 @@ template<> struct std::hash> template struct std::formatter> // NOLINT(*-dcl58-cpp) { - [[nodiscard]] + [[nodiscard("You must use parse iterator")]] static constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } template - [[nodiscard]] + [[nodiscard("You must use format iterator")]] static auto format(const omath::Vector2& vec, FormatContext& ctx) { if constexpr (std::is_same_v) diff --git a/include/omath/linear_algebra/vector3.hpp b/include/omath/linear_algebra/vector3.hpp index 18f921be..4ad5eccb 100644 --- a/include/omath/linear_algebra/vector3.hpp +++ b/include/omath/linear_algebra/vector3.hpp @@ -32,17 +32,20 @@ namespace omath template requires std::is_arithmetic_v - [[nodiscard]] constexpr explicit operator Vector3() const noexcept + [[nodiscard("You must use casted vector")]] + constexpr explicit operator Vector3() const noexcept { return {static_cast(this->x), static_cast(this->y), static_cast(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::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::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::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(0) ? *this / len : *this; } - [[nodiscard]] Type length_2d() const noexcept + [[nodiscard("You must use 2D length")]] + Type length_2d() const noexcept { return Vector2::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::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(0); } - [[nodiscard]] std::expected, Vector3Error> + [[nodiscard("You must use angle between vectors")]] + std::expected, Vector3Error> angle_between(const Vector3& other) const noexcept { const auto bottom = length() * other.length(); @@ -240,8 +260,8 @@ namespace omath return Angle::from_radians(std::acos(dot(other) / bottom)); } - [[nodiscard]] bool is_perpendicular(const Vector3& other, - Type epsilon = static_cast(0.0001)) const noexcept + [[nodiscard("You must use perpendicularity check result")]] + bool is_perpendicular(const Vector3& other, Type epsilon = static_cast(0.0001)) const noexcept { if (const auto angle = angle_between(other)) return std::abs(angle->as_degrees() - static_cast(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::sum(); } - [[nodiscard]] constexpr std::tuple as_tuple() const noexcept + [[nodiscard("You must use tuple")]] + constexpr std::tuple 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 as_array() const noexcept { return {this->x, this->y, z}; @@ -293,7 +315,7 @@ namespace omath template<> struct std::hash> { - [[nodiscard]] + [[nodiscard("You must use hash value")]] std::size_t operator()(const omath::Vector3& vec) const noexcept { std::size_t hash = 0; @@ -310,14 +332,14 @@ template<> struct std::hash> template struct std::formatter> // NOLINT(*-dcl58-cpp) { - [[nodiscard]] + [[nodiscard("You must use parse iterator")]] static constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } template - [[nodiscard]] + [[nodiscard("You must use format iterator")]] static auto format(const omath::Vector3& vec, FormatContext& ctx) { if constexpr (std::is_same_v) diff --git a/include/omath/linear_algebra/vector4.hpp b/include/omath/linear_algebra/vector4.hpp index bc20221c..99781585 100644 --- a/include/omath/linear_algebra/vector4.hpp +++ b/include/omath/linear_algebra/vector4.hpp @@ -24,19 +24,19 @@ namespace omath template requires std::is_arithmetic_v - [[nodiscard]] constexpr explicit operator Vector4() const noexcept + [[nodiscard("You must use casted vector")]] constexpr explicit operator Vector4() const noexcept { return {static_cast(this->x), static_cast(this->y), static_cast(this->z), static_cast(this->w)}; } - [[nodiscard]] + [[nodiscard("You must use comparison result")]] constexpr bool operator==(const Vector4& other) const noexcept { return Vector3::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::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::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::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 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(w), }; } - [[nodiscard]] + [[nodiscard("You must use vector from ImVec4")]] static Vector4 from_im_vec4(const ImVec4& other) noexcept { return {static_cast(other.x), static_cast(other.y), static_cast(other.z)}; @@ -220,7 +222,7 @@ namespace omath template<> struct std::hash> { - [[nodiscard]] + [[nodiscard("You must use hash value")]] std::size_t operator()(const omath::Vector4& vec) const noexcept { std::size_t hash = 0; @@ -237,13 +239,13 @@ template<> struct std::hash> template struct std::formatter> // NOLINT(*-dcl58-cpp) { - [[nodiscard]] + [[nodiscard("You must use parse iterator")]] static constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } template - [[nodiscard]] + [[nodiscard("You must use format iterator")]] static auto format(const omath::Vector4& vec, FormatContext& ctx) { if constexpr (std::is_same_v) @@ -255,4 +257,4 @@ struct std::formatter> // NOLINT(*-dcl58-cpp) if constexpr (std::is_same_v) return std::format_to(ctx.out(), u8"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w); } -}; \ No newline at end of file +}; diff --git a/include/omath/projection/camera.hpp b/include/omath/projection/camera.hpp index e6126669..42baf736 100644 --- a/include/omath/projection/camera.hpp +++ b/include/omath/projection/camera.hpp @@ -190,7 +190,8 @@ namespace omath::projection return get_up(); } - [[nodiscard("You must use view-projection matrix")]] 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(); @@ -313,7 +314,8 @@ namespace omath::projection std::unreachable(); } - [[nodiscard("You must use frustum culling result")]] bool is_culled_by_frustum(const Triangle>& triangle) const noexcept + [[nodiscard("You must use frustum culling result")]] bool + is_culled_by_frustum(const Triangle>& triangle) const noexcept { // Transform to clip space (before perspective divide) auto to_clip = [this](const Vector3& point) @@ -380,7 +382,8 @@ namespace omath::projection return false; } - [[nodiscard("You must use AABB frustum culling result")]] bool is_aabb_culled_by_frustum(const primitives::Aabb& aabb) const noexcept + [[nodiscard("You must use AABB frustum culling result")]] bool + is_aabb_culled_by_frustum(const primitives::Aabb& 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("You must use OBB frustum culling result")]] bool is_obb_culled_by_frustum(const primitives::Obb& obb) const noexcept + [[nodiscard("You must use OBB frustum culling result")]] bool + is_obb_culled_by_frustum(const primitives::Obb& 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. @@ -545,7 +549,8 @@ namespace omath::projection } template - [[nodiscard("You must use NDC bounds check result")]] 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::epsilon(); @@ -621,7 +626,8 @@ namespace omath::projection } template - [[nodiscard("You must use NDC position")]] Vector3 screen_to_ndc(const Vector3& screen_pos) const noexcept + [[nodiscard("You must use NDC position")]] Vector3 + screen_to_ndc(const Vector3& 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},