From 0740d0778c77202f6abda448f161a17eb5e89bdf Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 17 Mar 2025 07:20:13 +0300 Subject: [PATCH 1/3] added iw engine files --- CMakeLists.txt | 2 +- include/omath/engines/iw_engine/Camera.hpp | 21 ++++++++ include/omath/engines/iw_engine/Constants.hpp | 25 +++++++++ include/omath/engines/iw_engine/Formulas.hpp | 54 +++++++++++++++++++ source/engines/CMakeLists.txt | 3 +- source/engines/iw_engine/CMakeLists.txt | 1 + source/engines/iw_engine/Camera.cpp | 34 ++++++++++++ tests/engines/UnitTestIwEngine.cpp | 3 ++ 8 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 include/omath/engines/iw_engine/Camera.hpp create mode 100644 include/omath/engines/iw_engine/Constants.hpp create mode 100644 include/omath/engines/iw_engine/Formulas.hpp create mode 100644 source/engines/iw_engine/CMakeLists.txt create mode 100644 source/engines/iw_engine/Camera.cpp create mode 100644 tests/engines/UnitTestIwEngine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b2bf4526..dab8ddf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(omath VERSION 1.0.1 LANGUAGES CXX) include(CMakePackageConfigHelpers) -option(OMATH_BUILD_TESTS "Build unit tests" OFF) +option(OMATH_BUILD_TESTS "Build unit tests" ON) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON) diff --git a/include/omath/engines/iw_engine/Camera.hpp b/include/omath/engines/iw_engine/Camera.hpp new file mode 100644 index 00000000..cd413f3b --- /dev/null +++ b/include/omath/engines/iw_engine/Camera.hpp @@ -0,0 +1,21 @@ +// +// Created by Vlad on 3/17/2025. +// + +#pragma once +#include "Constants.hpp" +#include "omath/projection/Camera.hpp" + +namespace omath::iw_engine +{ + class Camera final : public projection::Camera + { + public: + Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, + const Angle& fov, float near, float far); + void LookAt(const Vector3& target) override; + protected: + [[nodiscard]] Mat4x4 CalcViewMatrix() const override; + [[nodiscard]] Mat4x4 CalcProjectionMatrix() const override; + }; +} \ No newline at end of file diff --git a/include/omath/engines/iw_engine/Constants.hpp b/include/omath/engines/iw_engine/Constants.hpp new file mode 100644 index 00000000..88979158 --- /dev/null +++ b/include/omath/engines/iw_engine/Constants.hpp @@ -0,0 +1,25 @@ +// +// Created by Vlad on 3/17/2025. +// + +#pragma once +#include +#include +#include +#include + +namespace omath::iw_engine +{ + constexpr Vector3 kAbsUp = {0, 0, 1}; + constexpr Vector3 kAbsRight = {0, -1, 0}; + constexpr Vector3 kAbsForward = {1, 0, 0}; + + using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat1x3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>; + using PitchAngle = Angle; + using YawAngle = Angle; + using RollAngle = Angle; + + using ViewAngles = omath::ViewAngles; +} \ No newline at end of file diff --git a/include/omath/engines/iw_engine/Formulas.hpp b/include/omath/engines/iw_engine/Formulas.hpp new file mode 100644 index 00000000..bd757d25 --- /dev/null +++ b/include/omath/engines/iw_engine/Formulas.hpp @@ -0,0 +1,54 @@ +// +// Created by Vlad on 3/17/2025. +// + +#pragma once +#include "Constants.hpp" + +namespace omath::iw_engine +{ + [[nodiscard]] + inline Vector3 ForwardVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] + inline Vector3 RightVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] + inline Vector3 UpVector(const ViewAngles& angles) + { + const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp); + + return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; + } + + [[nodiscard]] inline Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3& cam_origin) + { + return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin); + } + + + [[nodiscard]] + inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, + const float far) + { + const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f); + + return + { + {1.f / (aspectRatio * fovHalfTan), 0, 0, 0}, + {0, 1.f / fovHalfTan, 0, 0}, + {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, + {0, 0, 1, 0}, + }; + } +} // namespace omath::source diff --git a/source/engines/CMakeLists.txt b/source/engines/CMakeLists.txt index bfb07650..eb223b0e 100644 --- a/source/engines/CMakeLists.txt +++ b/source/engines/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(source_engine) -add_subdirectory(opengl_engine) \ No newline at end of file +add_subdirectory(opengl_engine) +add_subdirectory(iw_engine) diff --git a/source/engines/iw_engine/CMakeLists.txt b/source/engines/iw_engine/CMakeLists.txt new file mode 100644 index 00000000..0abf8686 --- /dev/null +++ b/source/engines/iw_engine/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(omath PRIVATE Camera.cpp) \ No newline at end of file diff --git a/source/engines/iw_engine/Camera.cpp b/source/engines/iw_engine/Camera.cpp new file mode 100644 index 00000000..5b7cfe09 --- /dev/null +++ b/source/engines/iw_engine/Camera.cpp @@ -0,0 +1,34 @@ +// +// Created by Vlad on 3/17/2025. +// +#include "omath/engines/iw_engine/Camera.hpp" +#include "omath/engines/iw_engine/Formulas.hpp" + +namespace omath::iw_engine +{ + + Camera::Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, + const Angle& fov, const float near, const float far) : + projection::Camera(position, viewAngles, viewPort, fov, near, far) + { + } + void Camera::LookAt([[maybe_unused]] const Vector3& target) + { + const float distance = m_origin.DistTo(target); + const auto delta = target - m_origin; + + + m_viewAngles.pitch = PitchAngle::FromRadians(std::asin(delta.z / distance)); + m_viewAngles.yaw = -YawAngle::FromRadians(std::atan2(delta.y, delta.x)); + m_viewAngles.roll = RollAngle::FromRadians(0.f); + } + Mat4x4 Camera::CalcViewMatrix() const + { + return iw_engine::CalcViewMatrix(m_viewAngles, m_origin); + } + Mat4x4 Camera::CalcProjectionMatrix() const + { + return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance, + m_farPlaneDistance); + } +} // namespace omath::openg \ No newline at end of file diff --git a/tests/engines/UnitTestIwEngine.cpp b/tests/engines/UnitTestIwEngine.cpp new file mode 100644 index 00000000..9df832cc --- /dev/null +++ b/tests/engines/UnitTestIwEngine.cpp @@ -0,0 +1,3 @@ +// +// Created by Vlad on 3/17/2025. +// From 2fa0c500a777be8ec2729efa3d45df3c3a81c3a6 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 17 Mar 2025 08:59:41 +0300 Subject: [PATCH 2/3] added magic number --- include/omath/engines/iw_engine/Formulas.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/omath/engines/iw_engine/Formulas.hpp b/include/omath/engines/iw_engine/Formulas.hpp index bd757d25..3af95c7c 100644 --- a/include/omath/engines/iw_engine/Formulas.hpp +++ b/include/omath/engines/iw_engine/Formulas.hpp @@ -41,7 +41,7 @@ namespace omath::iw_engine inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, const float far) { - const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f); + const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * 0.75f; return { From cd452b0397ceb36e6787276b6af377333800c3c6 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 17 Mar 2025 09:14:42 +0300 Subject: [PATCH 3/3] updated comment --- CMakeLists.txt | 2 +- include/omath/engines/iw_engine/Formulas.hpp | 4 +- .../omath/engines/source_engine/Formulas.hpp | 3 +- tests/CMakeLists.txt | 1 + tests/engines/UnitTestIwEngine.cpp | 66 +++++++++++++++++++ 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dab8ddf4..b2bf4526 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(omath VERSION 1.0.1 LANGUAGES CXX) include(CMakePackageConfigHelpers) -option(OMATH_BUILD_TESTS "Build unit tests" ON) +option(OMATH_BUILD_TESTS "Build unit tests" OFF) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON) diff --git a/include/omath/engines/iw_engine/Formulas.hpp b/include/omath/engines/iw_engine/Formulas.hpp index 3af95c7c..c98e7278 100644 --- a/include/omath/engines/iw_engine/Formulas.hpp +++ b/include/omath/engines/iw_engine/Formulas.hpp @@ -41,7 +41,9 @@ namespace omath::iw_engine inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, const float far) { - const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * 0.75f; + // NOTE: Need magic number to fix fov calculation, since source inherit Quake proj matrix calculation + constexpr auto kMultiplyFactor = 0.75f; + const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor; return { diff --git a/include/omath/engines/source_engine/Formulas.hpp b/include/omath/engines/source_engine/Formulas.hpp index 9e272986..549d16a5 100644 --- a/include/omath/engines/source_engine/Formulas.hpp +++ b/include/omath/engines/source_engine/Formulas.hpp @@ -40,8 +40,7 @@ namespace omath::source_engine inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, const float far) { - // NOTE: Needed tp make thing draw normal, since source is wierd - // and use tricky projection matrix formula. + // NOTE: Need magic number to fix fov calculation, since source inherit Quake proj matrix calculation constexpr auto kMultiplyFactor = 0.75f; const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 55b9d831..bc043bd3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable(unit-tests engines/UnitTestOpenGL.cpp engines/UnitTestUnityEngine.cpp engines/UnitTestSourceEngine.cpp + engines/UnitTestIwEngine.cpp ) diff --git a/tests/engines/UnitTestIwEngine.cpp b/tests/engines/UnitTestIwEngine.cpp index 9df832cc..00bdc409 100644 --- a/tests/engines/UnitTestIwEngine.cpp +++ b/tests/engines/UnitTestIwEngine.cpp @@ -1,3 +1,69 @@ // // Created by Vlad on 3/17/2025. // +#include +#include +#include +#include + + +TEST(UnitTestEwEngine, ForwardVector) +{ + const auto forward = omath::source_engine::ForwardVector({}); + + EXPECT_EQ(forward, omath::source_engine::kAbsForward); +} + +TEST(UnitTestEwEngine, RightVector) +{ + const auto right = omath::source_engine::RightVector({}); + + EXPECT_EQ(right, omath::source_engine::kAbsRight); +} + +TEST(UnitTestEwEngine, UpVector) +{ + const auto up = omath::source_engine::UpVector({}); + EXPECT_EQ(up, omath::source_engine::kAbsUp); +} + +TEST(UnitTestEwEngine, ProjectTargetMovedFromCamera) +{ + constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); + const auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); + + + for (float distance = 0.02f; distance < 1000.f; distance += 0.01f) + { + const auto projected = cam.WorldToScreen({distance, 0, 0}); + + EXPECT_TRUE(projected.has_value()); + + if (!projected.has_value()) + continue; + + EXPECT_NEAR(projected->x, 960, 0.00001f); + EXPECT_NEAR(projected->y, 540, 0.00001f); + } +} + +TEST(UnitTestEwEngine, CameraSetAndGetFov) +{ + constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); + auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); + + EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f); + cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); + + EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f); +} + +TEST(UnitTestEwEngine, CameraSetAndGetOrigin) +{ + auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f); + + EXPECT_EQ(cam.GetOrigin(), omath::Vector3{}); + cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); + + EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f); +} \ No newline at end of file