From 854b50f317c5cb10bf62890e0a1ae4acdb6d8a06 Mon Sep 17 00:00:00 2001 From: Orange Date: Thu, 11 Jun 2026 23:49:03 +0300 Subject: [PATCH] added mat tests and triangle tests --- include/omath/linear_algebra/mat.hpp | 44 +++++++++++------ include/omath/linear_algebra/triangle.hpp | 6 ++- tests/general/unit_test_mat.cpp | 60 ++++++++++++++++++++++- tests/general/unit_test_triangle.cpp | 28 +++++++++++ 4 files changed, 122 insertions(+), 16 deletions(-) diff --git a/include/omath/linear_algebra/mat.hpp b/include/omath/linear_algebra/mat.hpp index a3ee0ee..d8e3cb9 100644 --- a/include/omath/linear_algebra/mat.hpp +++ b/include/omath/linear_algebra/mat.hpp @@ -679,7 +679,7 @@ namespace omath template [[nodiscard("You must use rotation matrix")]] - Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept + OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept { return { @@ -692,7 +692,7 @@ namespace omath template [[nodiscard("You must use rotation matrix")]] - Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept + OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept { return { @@ -705,7 +705,7 @@ namespace omath template [[nodiscard("You must use rotation matrix")]] - Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept + OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept { return { @@ -718,7 +718,7 @@ namespace omath template [[nodiscard("You must use camera view matrix")]] - static Mat<4, 4, Type, St> mat_camera_view(const Vector3& forward, const Vector3& right, + OMATH_CONSTEXPR static Mat<4, 4, Type, St> mat_camera_view(const Vector3& forward, const Vector3& right, const Vector3& up, const Vector3& camera_origin) noexcept { return Mat<4, 4, Type, St> @@ -732,12 +732,15 @@ namespace omath template - [[nodiscard("You must use perspective matrix")]] + [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR 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 { - const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2}); - +#ifdef OMATH_USE_GCEM + const auto fov_half_tan = gcem::tan(angles::degrees_to_radians(field_of_view) / Type{2}); +#else + const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2}) +#endif if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE) return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}}, {Type{0}, Type{1} / fov_half_tan, Type{0}, Type{0}}, @@ -754,11 +757,15 @@ namespace omath template - [[nodiscard("You must use perspective matrix")]] + [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR 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 { +#ifdef OMATH_USE_GCEM + const auto fov_half_tan = gcem::tan(angles::degrees_to_radians(field_of_view) / Type{2}); +#else const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2}); +#endif if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE) return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}}, @@ -779,12 +786,16 @@ namespace omath // X and Y scales derived as: X = 1 / tan(hfov/2), Y = aspect / tan(hfov/2). template - [[nodiscard("You must use perspective matrix")]] + [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR 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 { +#ifdef OMATH_USE_GCEM + const auto inv_tan_half_hfov = Type{1} / gcem::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); +#else const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); +#endif const auto x_axis = inv_tan_half_hfov; const auto y_axis = inv_tan_half_hfov * aspect_ratio; @@ -804,12 +815,17 @@ namespace omath template - [[nodiscard("You must use perspective matrix")]] + [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR 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 { +#ifdef OMATH_USE_GCEM + const auto inv_tan_half_hfov = Type{1} / gcem::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); +#else const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); +#endif + const auto x_axis = inv_tan_half_hfov; const auto y_axis = inv_tan_half_hfov * aspect_ratio; @@ -828,7 +844,7 @@ namespace omath } template - [[nodiscard("You must use ortho matrix")]] + [[nodiscard("You must use ortho matrix")]] OMATH_CONSTEXPR 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 { @@ -853,7 +869,7 @@ namespace omath } template - [[nodiscard("You must use ortho matrix")]] + [[nodiscard("You must use ortho matrix")]] OMATH_CONSTEXPR 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 { @@ -877,7 +893,7 @@ namespace omath std::unreachable(); } template - Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3& eye, const Vector3& center, const Vector3& up) + OMATH_CONSTEXPR Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3& eye, const Vector3& center, const Vector3& up) { const Vector3 f = (center - eye).normalized(); const Vector3 s = f.cross(up).normalized(); @@ -886,7 +902,7 @@ namespace omath } template - Mat<4, 4, T, St>mat_look_at_right_handed(const Vector3& eye, const Vector3& center, const Vector3& up) + OMATH_CONSTEXPR Mat<4, 4, T, St> mat_look_at_right_handed(const Vector3& eye, const Vector3& center, const Vector3& up) { const Vector3 f = (center - eye).normalized(); const Vector3 s = f.cross(up).normalized(); diff --git a/include/omath/linear_algebra/triangle.hpp b/include/omath/linear_algebra/triangle.hpp index a62f888..8e051be 100644 --- a/include/omath/linear_algebra/triangle.hpp +++ b/include/omath/linear_algebra/triangle.hpp @@ -2,8 +2,8 @@ // Created by Orange on 11/13/2024. // #pragma once -#include "vector3.hpp" #include "omath/internal/optional_constexpr_math.hpp" +#include "vector3.hpp" namespace omath { /* @@ -69,7 +69,11 @@ namespace omath const auto side_b = side_b_length(); const auto hypot_value = hypot(); +#ifdef OMATH_USE_GCEM + return gcem::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f; +#else return std::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f; +#endif } [[nodiscard]] constexpr Vector side_b_vector() const diff --git a/tests/general/unit_test_mat.cpp b/tests/general/unit_test_mat.cpp index 0cc51c3..63bfd64 100644 --- a/tests/general/unit_test_mat.cpp +++ b/tests/general/unit_test_mat.cpp @@ -1,11 +1,25 @@ // UnitTestMat.cpp #include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/vector3.hpp" +#include "omath/trigonometry/angle.hpp" #include "omath/trigonometry/angles.hpp" #include using namespace omath; +#ifdef OMATH_USE_GCEM +namespace +{ + using Pitch = Angle(-90), static_cast(90), AngleFlags::Clamped>; + + constexpr bool close_to(const float actual, const float expected, const float epsilon) + { + const float diff = actual - expected; + return (diff < 0.0f ? -diff : diff) <= epsilon; + } +} // namespace +#endif + class UnitTestMat : public ::testing::Test { protected: @@ -522,4 +536,48 @@ TEST(UnitTestMatStandalone, MatOrthoNegativeOneToOneDefault) NDCDepthRange::NEGATIVE_ONE_TO_ONE>(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f); EXPECT_EQ(ortho_default, ortho_explicit); -} \ No newline at end of file +} + +#ifdef OMATH_USE_GCEM +static_assert( + [] + { + constexpr auto scale = mat_extract_scale(mat_scale(Vector3{2.0f, 3.0f, 4.0f})); + return close_to(scale.x, 2.0f, 1e-5f) && close_to(scale.y, 3.0f, 1e-5f) && close_to(scale.z, 4.0f, 1e-5f); + }(), + "Mat scale extraction should be constexpr with gcem"); + +static_assert( + [] + { + constexpr auto rotation = mat_rotation_axis_z(Pitch::from_degrees(90.0f)); + return close_to(rotation.at(0, 0), 0.0f, 1e-5f) && close_to(rotation.at(0, 1), -1.0f, 1e-5f) + && close_to(rotation.at(1, 0), 1.0f, 1e-5f) && close_to(rotation.at(1, 1), 0.0f, 1e-5f) + && close_to(rotation.at(2, 2), 1.0f, 1e-5f) && close_to(rotation.at(3, 3), 1.0f, 1e-5f); + }(), + "Mat rotation should be constexpr with gcem"); + +static_assert( + [] + { + constexpr auto projection = + mat_perspective_left_handed_vertical_fov(90.0f, 1.0f, 1.0f, 11.0f); + return close_to(projection.at(0, 0), 1.0f, 1e-5f) && close_to(projection.at(1, 1), 1.0f, 1e-5f) + && close_to(projection.at(2, 2), 1.1f, 1e-5f) && close_to(projection.at(2, 3), -1.1f, 1e-5f) + && close_to(projection.at(3, 2), 1.0f, 1e-5f); + }(), + "Mat vertical-FOV perspective should be constexpr with gcem"); + +static_assert( + [] + { + constexpr auto projection = + mat_perspective_right_handed_horizontal_fov(90.0f, 2.0f, 1.0f, 11.0f); + return close_to(projection.at(0, 0), 1.0f, 1e-5f) && close_to(projection.at(1, 1), 2.0f, 1e-5f) + && close_to(projection.at(2, 2), -1.1f, 1e-5f) && close_to(projection.at(2, 3), -1.1f, 1e-5f) + && close_to(projection.at(3, 2), -1.0f, 1e-5f); + }(), + "Mat horizontal-FOV perspective should be constexpr with gcem"); +#endif diff --git a/tests/general/unit_test_triangle.cpp b/tests/general/unit_test_triangle.cpp index f972a8a..e327689 100644 --- a/tests/general/unit_test_triangle.cpp +++ b/tests/general/unit_test_triangle.cpp @@ -8,6 +8,17 @@ using namespace omath; +#ifdef OMATH_USE_GCEM +namespace +{ + constexpr bool close_to(const float actual, const float expected, const float epsilon) + { + const float diff = actual - expected; + return (diff < 0.0f ? -diff : diff) <= epsilon; + } +} // namespace +#endif + class UnitTestTriangle : public ::testing::Test { protected: @@ -129,3 +140,20 @@ TEST_F(UnitTestTriangle, MidPoint) EXPECT_FLOAT_EQ(mid2.y, (2.0f + 5.0f + 8.0f) / 3.0f); EXPECT_FLOAT_EQ(mid2.z, (3.0f + 6.0f + 9.0f) / 3.0f); } + +#ifdef OMATH_USE_GCEM +static_assert( + [] + { + constexpr Triangle> triangle{{3.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 4.0f, 0.0f}}; + constexpr auto normal = triangle.calculate_normal(); + constexpr auto mid_point = triangle.mid_point(); + + return close_to(triangle.side_a_length(), 3.0f, 1e-5f) && close_to(triangle.side_b_length(), 4.0f, 1e-5f) + && close_to(triangle.hypot(), 5.0f, 1e-5f) && triangle.is_rectangular() + && close_to(normal.length(), 1.0f, 1e-5f) && close_to(normal.z, -1.0f, 1e-5f) + && close_to(mid_point.x, 1.0f, 1e-5f) && close_to(mid_point.y, 4.0f / 3.0f, 1e-5f) + && close_to(mid_point.z, 0.0f, 1e-5f); + }(), + "Triangle helpers should be constexpr with gcem"); +#endif