From be80a5d2432bbe5d93ffa914f754369e42ef014a Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 23 Mar 2026 05:23:53 +0300 Subject: [PATCH] added as_vector3 to view angles --- include/omath/trigonometry/angle.hpp | 1 + include/omath/trigonometry/view_angles.hpp | 13 ++++- tests/engines/unit_test_cry_engine.cpp | 50 +++++++++++++++++++ tests/engines/unit_test_frostbite_engine.cpp | 48 ++++++++++++++++++ tests/engines/unit_test_iw_engine.cpp | 50 +++++++++++++++++++ tests/engines/unit_test_open_gl.cpp | 48 ++++++++++++++++++ tests/engines/unit_test_source_engine.cpp | 50 +++++++++++++++++++ tests/engines/unit_test_unity_engine.cpp | 48 ++++++++++++++++++ tests/engines/unit_test_unreal_engine.cpp | 48 ++++++++++++++++++ .../general/unit_test_reverse_enineering.cpp | 4 +- 10 files changed, 357 insertions(+), 3 deletions(-) diff --git a/include/omath/trigonometry/angle.hpp b/include/omath/trigonometry/angle.hpp index ba78596..4506e0c 100644 --- a/include/omath/trigonometry/angle.hpp +++ b/include/omath/trigonometry/angle.hpp @@ -36,6 +36,7 @@ namespace omath } public: + using ArithmeticType = Type; [[nodiscard]] constexpr static Angle from_degrees(const Type& degrees) noexcept { diff --git a/include/omath/trigonometry/view_angles.hpp b/include/omath/trigonometry/view_angles.hpp index cd63640..2a11f96 100644 --- a/include/omath/trigonometry/view_angles.hpp +++ b/include/omath/trigonometry/view_angles.hpp @@ -2,14 +2,25 @@ // Created by Orange on 11/30/2024. // #pragma once - +#include "omath/linear_algebra/vector3.hpp" +#include namespace omath { template + requires std::is_same_v + && std::is_same_v struct ViewAngles { + using ArithmeticType = PitchType::ArithmeticType; + PitchType pitch; YawType yaw; RollType roll; + + [[nodiscard]] + Vector3 as_vector3() const + { + return {pitch.as_degrees(), yaw.as_degrees(), roll.as_degrees()}; + } }; } // namespace omath diff --git a/tests/engines/unit_test_cry_engine.cpp b/tests/engines/unit_test_cry_engine.cpp index a811fe8..2a80c5e 100644 --- a/tests/engines/unit_test_cry_engine.cpp +++ b/tests/engines/unit_test_cry_engine.cpp @@ -237,4 +237,54 @@ TEST(unit_test_cry_engine, loook_at_random_z_axis) failed_points++; } EXPECT_LE(failed_points, 100); +} + +TEST(unit_test_cry_engine, ViewAnglesAsVector3Zero) +{ + const omath::cry_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_cry_engine, ViewAnglesAsVector3Values) +{ + const omath::cry_engine::ViewAngles angles{ + omath::cry_engine::PitchAngle::from_degrees(45.f), + omath::cry_engine::YawAngle::from_degrees(-90.f), + omath::cry_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_cry_engine, ViewAnglesAsVector3ClampedPitch) +{ + // Pitch is clamped to [-90, 90] + const omath::cry_engine::ViewAngles angles{ + omath::cry_engine::PitchAngle::from_degrees(120.f), + omath::cry_engine::YawAngle::from_degrees(0.f), + omath::cry_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 90.f); +} + +TEST(unit_test_cry_engine, ViewAnglesAsVector3NormalizedYaw) +{ + // Yaw is normalized to [-180, 180], 270 wraps to -90 + const omath::cry_engine::ViewAngles angles{ + omath::cry_engine::PitchAngle::from_degrees(0.f), + omath::cry_engine::YawAngle::from_degrees(270.f), + omath::cry_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); } \ No newline at end of file diff --git a/tests/engines/unit_test_frostbite_engine.cpp b/tests/engines/unit_test_frostbite_engine.cpp index 5a2ee16..141559f 100644 --- a/tests/engines/unit_test_frostbite_engine.cpp +++ b/tests/engines/unit_test_frostbite_engine.cpp @@ -405,3 +405,51 @@ TEST(unit_test_frostbite_engine, look_at_down) std::views::zip(dir_vector.as_array(), (-omath::frostbite_engine::k_abs_up).as_array())) EXPECT_NEAR(result, etalon, 0.0001f); } + +TEST(unit_test_frostbite_engine, ViewAnglesAsVector3Zero) +{ + const omath::frostbite_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_frostbite_engine, ViewAnglesAsVector3Values) +{ + const omath::frostbite_engine::ViewAngles angles{ + omath::frostbite_engine::PitchAngle::from_degrees(45.f), + omath::frostbite_engine::YawAngle::from_degrees(-90.f), + omath::frostbite_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_frostbite_engine, ViewAnglesAsVector3ClampedPitch) +{ + const omath::frostbite_engine::ViewAngles angles{ + omath::frostbite_engine::PitchAngle::from_degrees(120.f), + omath::frostbite_engine::YawAngle::from_degrees(0.f), + omath::frostbite_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 90.f); +} + +TEST(unit_test_frostbite_engine, ViewAnglesAsVector3NormalizedYaw) +{ + const omath::frostbite_engine::ViewAngles angles{ + omath::frostbite_engine::PitchAngle::from_degrees(0.f), + omath::frostbite_engine::YawAngle::from_degrees(270.f), + omath::frostbite_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); +} diff --git a/tests/engines/unit_test_iw_engine.cpp b/tests/engines/unit_test_iw_engine.cpp index 44f2d38..dd4f688 100644 --- a/tests/engines/unit_test_iw_engine.cpp +++ b/tests/engines/unit_test_iw_engine.cpp @@ -280,4 +280,54 @@ TEST(unit_test_iw_engine, look_at_down) EXPECT_NEAR(dir_vector.z, -0.99984f, 0.0001f); EXPECT_NEAR(dir_vector.x,- 0.017f, 0.01f); EXPECT_NEAR(dir_vector.y, 0.f, 0.001f); +} + +TEST(unit_test_iw_engine, ViewAnglesAsVector3Zero) +{ + const omath::iw_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_iw_engine, ViewAnglesAsVector3Values) +{ + const omath::iw_engine::ViewAngles angles{ + omath::iw_engine::PitchAngle::from_degrees(45.f), + omath::iw_engine::YawAngle::from_degrees(-90.f), + omath::iw_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_iw_engine, ViewAnglesAsVector3ClampedPitch) +{ + // Pitch is clamped to [-89, 89] + const omath::iw_engine::ViewAngles angles{ + omath::iw_engine::PitchAngle::from_degrees(120.f), + omath::iw_engine::YawAngle::from_degrees(0.f), + omath::iw_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 89.f); +} + +TEST(unit_test_iw_engine, ViewAnglesAsVector3NormalizedYaw) +{ + // Yaw is normalized to [-180, 180], 270 wraps to -90 + const omath::iw_engine::ViewAngles angles{ + omath::iw_engine::PitchAngle::from_degrees(0.f), + omath::iw_engine::YawAngle::from_degrees(270.f), + omath::iw_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); } \ No newline at end of file diff --git a/tests/engines/unit_test_open_gl.cpp b/tests/engines/unit_test_open_gl.cpp index f784e34..ccb53f4 100644 --- a/tests/engines/unit_test_open_gl.cpp +++ b/tests/engines/unit_test_open_gl.cpp @@ -394,4 +394,52 @@ TEST(unit_test_opengl_engine, look_at_down) const auto dir_vector = omath::opengl_engine::forward_vector(angles); for (const auto& [result, etalon] : std::views::zip(dir_vector.as_array(), (-omath::opengl_engine::k_abs_up).as_array())) EXPECT_NEAR(result, etalon, 0.0001f); +} + +TEST(unit_test_opengl, ViewAnglesAsVector3Zero) +{ + const omath::opengl_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_opengl, ViewAnglesAsVector3Values) +{ + const omath::opengl_engine::ViewAngles angles{ + omath::opengl_engine::PitchAngle::from_degrees(45.f), + omath::opengl_engine::YawAngle::from_degrees(-90.f), + omath::opengl_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_opengl, ViewAnglesAsVector3ClampedPitch) +{ + const omath::opengl_engine::ViewAngles angles{ + omath::opengl_engine::PitchAngle::from_degrees(120.f), + omath::opengl_engine::YawAngle::from_degrees(0.f), + omath::opengl_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 90.f); +} + +TEST(unit_test_opengl, ViewAnglesAsVector3NormalizedYaw) +{ + const omath::opengl_engine::ViewAngles angles{ + omath::opengl_engine::PitchAngle::from_degrees(0.f), + omath::opengl_engine::YawAngle::from_degrees(270.f), + omath::opengl_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); } \ No newline at end of file diff --git a/tests/engines/unit_test_source_engine.cpp b/tests/engines/unit_test_source_engine.cpp index f311185..b75a137 100644 --- a/tests/engines/unit_test_source_engine.cpp +++ b/tests/engines/unit_test_source_engine.cpp @@ -422,4 +422,54 @@ TEST(unit_test_source_engine, look_at_down) EXPECT_NEAR(dir_vector.z, -0.99984f, 0.0001f); EXPECT_NEAR(dir_vector.x,- 0.017f, 0.01f); EXPECT_NEAR(dir_vector.y, 0.f, 0.001f); +} + +TEST(unit_test_source_engine, ViewAnglesAsVector3Zero) +{ + const omath::source_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_source_engine, ViewAnglesAsVector3Values) +{ + const omath::source_engine::ViewAngles angles{ + omath::source_engine::PitchAngle::from_degrees(45.f), + omath::source_engine::YawAngle::from_degrees(-90.f), + omath::source_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_source_engine, ViewAnglesAsVector3ClampedPitch) +{ + // Pitch is clamped to [-89, 89] + const omath::source_engine::ViewAngles angles{ + omath::source_engine::PitchAngle::from_degrees(120.f), + omath::source_engine::YawAngle::from_degrees(0.f), + omath::source_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 89.f); +} + +TEST(unit_test_source_engine, ViewAnglesAsVector3NormalizedYaw) +{ + // Yaw is normalized to [-180, 180], 270 wraps to -90 + const omath::source_engine::ViewAngles angles{ + omath::source_engine::PitchAngle::from_degrees(0.f), + omath::source_engine::YawAngle::from_degrees(270.f), + omath::source_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); } \ No newline at end of file diff --git a/tests/engines/unit_test_unity_engine.cpp b/tests/engines/unit_test_unity_engine.cpp index 6621349..fdf06d0 100644 --- a/tests/engines/unit_test_unity_engine.cpp +++ b/tests/engines/unit_test_unity_engine.cpp @@ -417,3 +417,51 @@ TEST(unit_test_unity_engine, look_at_down) std::views::zip(dir_vector.as_array(), (-omath::unity_engine::k_abs_up).as_array())) EXPECT_NEAR(result, etalon, 0.0001f); } + +TEST(unit_test_unity_engine, ViewAnglesAsVector3Zero) +{ + const omath::unity_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_unity_engine, ViewAnglesAsVector3Values) +{ + const omath::unity_engine::ViewAngles angles{ + omath::unity_engine::PitchAngle::from_degrees(45.f), + omath::unity_engine::YawAngle::from_degrees(-90.f), + omath::unity_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_unity_engine, ViewAnglesAsVector3ClampedPitch) +{ + const omath::unity_engine::ViewAngles angles{ + omath::unity_engine::PitchAngle::from_degrees(120.f), + omath::unity_engine::YawAngle::from_degrees(0.f), + omath::unity_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 90.f); +} + +TEST(unit_test_unity_engine, ViewAnglesAsVector3NormalizedYaw) +{ + const omath::unity_engine::ViewAngles angles{ + omath::unity_engine::PitchAngle::from_degrees(0.f), + omath::unity_engine::YawAngle::from_degrees(270.f), + omath::unity_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); +} diff --git a/tests/engines/unit_test_unreal_engine.cpp b/tests/engines/unit_test_unreal_engine.cpp index e2679c8..e831978 100644 --- a/tests/engines/unit_test_unreal_engine.cpp +++ b/tests/engines/unit_test_unreal_engine.cpp @@ -417,4 +417,52 @@ TEST(unit_test_unreal_engine, look_at_down) const auto dir_vector = omath::unreal_engine::forward_vector(angles); for (const auto& [result, etalon] : std::views::zip(dir_vector.as_array(), (-omath::unreal_engine::k_abs_up).as_array())) EXPECT_NEAR(result, etalon, 0.0001f); +} + +TEST(unit_test_unreal_engine, ViewAnglesAsVector3Zero) +{ + const omath::unreal_engine::ViewAngles angles{}; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 0.f); + EXPECT_FLOAT_EQ(vec.y, 0.f); + EXPECT_FLOAT_EQ(vec.z, 0.f); +} + +TEST(unit_test_unreal_engine, ViewAnglesAsVector3Values) +{ + const omath::unreal_engine::ViewAngles angles{ + omath::unreal_engine::PitchAngle::from_degrees(45.f), + omath::unreal_engine::YawAngle::from_degrees(-90.f), + omath::unreal_engine::RollAngle::from_degrees(30.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 45.f); + EXPECT_FLOAT_EQ(vec.y, -90.f); + EXPECT_FLOAT_EQ(vec.z, 30.f); +} + +TEST(unit_test_unreal_engine, ViewAnglesAsVector3ClampedPitch) +{ + const omath::unreal_engine::ViewAngles angles{ + omath::unreal_engine::PitchAngle::from_degrees(120.f), + omath::unreal_engine::YawAngle::from_degrees(0.f), + omath::unreal_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_FLOAT_EQ(vec.x, 90.f); +} + +TEST(unit_test_unreal_engine, ViewAnglesAsVector3NormalizedYaw) +{ + const omath::unreal_engine::ViewAngles angles{ + omath::unreal_engine::PitchAngle::from_degrees(0.f), + omath::unreal_engine::YawAngle::from_degrees(270.f), + omath::unreal_engine::RollAngle::from_degrees(0.f) + }; + const auto vec = angles.as_vector3(); + + EXPECT_NEAR(vec.y, -90.f, 0.01f); } \ No newline at end of file diff --git a/tests/general/unit_test_reverse_enineering.cpp b/tests/general/unit_test_reverse_enineering.cpp index 1020d83..5d6d5cf 100644 --- a/tests/general/unit_test_reverse_enineering.cpp +++ b/tests/general/unit_test_reverse_enineering.cpp @@ -188,7 +188,7 @@ TEST(unit_test_reverse_enineering, call_virtual_method_table_index_first_table) TEST(unit_test_reverse_enineering, call_virtual_method_table_index_second_table) { - MultiPlayer mp; + constexpr MultiPlayer mp; const auto* rev = reinterpret_cast(&mp); EXPECT_EQ(mp.get_b(), rev->rev_get_b()); @@ -209,7 +209,7 @@ TEST(unit_test_reverse_enineering, call_virtual_method_table_index_non_const) TEST(unit_test_reverse_enineering, call_virtual_method_table_zero_matches_default) { // Table 0 with the TableIndex overload should match the original non-TableIndex overload - MultiPlayer mp; + constexpr MultiPlayer mp; const auto* rev = reinterpret_cast(&mp); // Both access table 0, method index 1 — should return the same value