Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions include/omath/engines/iw_engine/Camera.hpp
Original file line number Diff line number Diff line change
@@ -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<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4x4 CalcViewMatrix() const override;
[[nodiscard]] Mat4x4 CalcProjectionMatrix() const override;
};
}
25 changes: 25 additions & 0 deletions include/omath/engines/iw_engine/Constants.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Created by Vlad on 3/17/2025.
//

#pragma once
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <omath/Angle.hpp>
#include <omath/ViewAngles.hpp>

namespace omath::iw_engine
{
constexpr Vector3<float> kAbsUp = {0, 0, 1};
constexpr Vector3<float> kAbsRight = {0, -1, 0};
constexpr Vector3<float> 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<float, -89.f, 89.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;

using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
}
56 changes: 56 additions & 0 deletions include/omath/engines/iw_engine/Formulas.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Created by Vlad on 3/17/2025.
//

#pragma once
#include "Constants.hpp"

namespace omath::iw_engine
{
[[nodiscard]]
inline Vector3<float> 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<float> 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<float> 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<float>& 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)
{
// 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
{
{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
3 changes: 1 addition & 2 deletions include/omath/engines/source_engine/Formulas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion source/engines/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(source_engine)
add_subdirectory(opengl_engine)
add_subdirectory(opengl_engine)
add_subdirectory(iw_engine)
1 change: 1 addition & 0 deletions source/engines/iw_engine/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target_sources(omath PRIVATE Camera.cpp)
34 changes: 34 additions & 0 deletions source/engines/iw_engine/Camera.cpp
Original file line number Diff line number Diff line change
@@ -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<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{
}
void Camera::LookAt([[maybe_unused]] const Vector3<float>& 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
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_executable(unit-tests
engines/UnitTestOpenGL.cpp
engines/UnitTestUnityEngine.cpp
engines/UnitTestSourceEngine.cpp
engines/UnitTestIwEngine.cpp

)

Expand Down
69 changes: 69 additions & 0 deletions tests/engines/UnitTestIwEngine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Created by Vlad on 3/17/2025.
//
#include <gtest/gtest.h>
#include <omath/engines/iw_engine/Camera.hpp>
#include <omath/engines/iw_engine/Constants.hpp>
#include <omath/engines/iw_engine/Formulas.hpp>


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<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));

EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}