mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 15:03:27 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a4026a4fc | |||
| 404c7de594 | |||
| f26f48cc53 | |||
| ed8afb02a1 | |||
| d86695fad7 | |||
| 570c035f27 | |||
| 5657282577 | |||
| 551ac62075 | |||
| 1b1be48ee6 | |||
|
|
1f9ea136b0 | ||
| 8dadb22e75 | |||
| 8dd9860aa1 | |||
| 9a0470f781 | |||
| eb8688c90c | |||
| 9f2f619a21 | |||
| 568883ff1c | |||
| 97003b953a | |||
| 5646654317 | |||
| ee54e3de34 | |||
| 7b0af9cf66 | |||
| 563ae0a656 | |||
| b9e2307d7a | |||
| cd0a864e7c | |||
| 5c30f57c4c | |||
| 3dcd033616 | |||
| f10dc60772 | |||
| 37f624956b | |||
| 20dc4e6730 | |||
| f6c607d84c | |||
| 81ed5f80d7 | |||
|
|
e385686323 |
BIN
.github/images/showcase/tf2.jpg
vendored
Normal file
BIN
.github/images/showcase/tf2.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 324 KiB |
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.26)
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
project(omath VERSION 3.8.2 LANGUAGES CXX)
|
project(omath VERSION 3.9.2 LANGUAGES CXX)
|
||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
@@ -28,22 +28,23 @@ if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
|
|||||||
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
|
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
|
if (${PROJECT_IS_TOP_LEVEL})
|
||||||
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
|
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
|
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
|
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
|
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
|
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
|
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
|
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
|
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
|
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
|
||||||
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
|
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
|
||||||
|
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
|
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
|
||||||
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
|
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
|
||||||
|
|
||||||
|
|
||||||
if (OMATH_BUILD_AS_SHARED_LIBRARY)
|
if (OMATH_BUILD_AS_SHARED_LIBRARY)
|
||||||
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
|
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
|
||||||
else ()
|
else ()
|
||||||
@@ -111,8 +112,8 @@ if (OMATH_USE_AVX2)
|
|||||||
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
|
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||||
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
|
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
|
||||||
endif()
|
endif ()
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
|||||||
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
||||||
- **Engine support**: Supports coordinate systems of Source, Unity, Unreal, IWEngine and canonical OpenGL.
|
- **Engine support**: Supports coordinate systems of Source, Unity, Unreal, IWEngine and canonical OpenGL.
|
||||||
- **Cross platform**: Supports Windows, MacOS and Linux.
|
- **Cross platform**: Supports Windows, MacOS and Linux.
|
||||||
|
- **Algorithms**: Has ability to scan for byte pattern with wildcards in PE files/modules, binary slices, works even with Wine apps.
|
||||||
<div align = center>
|
<div align = center>
|
||||||
|
|
||||||
# Gallery
|
# Gallery
|
||||||
@@ -74,6 +75,10 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
|||||||
|
|
||||||
![CS2 Preview]
|
![CS2 Preview]
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
![TF2 Preview]
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -86,7 +91,7 @@ It provides the latest features, is highly customizable, has all for cheat devel
|
|||||||
[APEX Preview]: .github/images/showcase/apex.png
|
[APEX Preview]: .github/images/showcase/apex.png
|
||||||
[BO2 Preview]: .github/images/showcase/cod_bo2.png
|
[BO2 Preview]: .github/images/showcase/cod_bo2.png
|
||||||
[CS2 Preview]: .github/images/showcase/cs2.jpeg
|
[CS2 Preview]: .github/images/showcase/cs2.jpeg
|
||||||
|
[TF2 Preview]: .github/images/showcase/tf2.jpg
|
||||||
<!----------------------------------{ Buttons }--------------------------------->
|
<!----------------------------------{ Buttons }--------------------------------->
|
||||||
[INSTALL]: INSTALL.md
|
[INSTALL]: INSTALL.md
|
||||||
[DOCUMENTATION]: http://libomath.org
|
[DOCUMENTATION]: http://libomath.org
|
||||||
|
|||||||
13
include/omath/engines/frostbite_engine/camera.hpp
Normal file
13
include/omath/engines/frostbite_engine/camera.hpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 3/22/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/engines/frostbite_engine/constants.hpp"
|
||||||
|
#include "omath/projection/camera.hpp"
|
||||||
|
#include "traits/camera_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait>;
|
||||||
|
} // namespace omath::unity_engine
|
||||||
25
include/omath/engines/frostbite_engine/constants.hpp
Normal file
25
include/omath/engines/frostbite_engine/constants.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 10/21/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/linear_algebra/mat.hpp"
|
||||||
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
#include <omath/trigonometry/angle.hpp>
|
||||||
|
#include <omath/trigonometry/view_angles.hpp>
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
constexpr Vector3<float> k_abs_up = {0, 1, 0};
|
||||||
|
constexpr Vector3<float> k_abs_right = {1, 0, 0};
|
||||||
|
constexpr Vector3<float> k_abs_forward = {0, 0, 1};
|
||||||
|
|
||||||
|
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, -90.f, 90.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>;
|
||||||
|
} // namespace omath::frostbite_engine
|
||||||
26
include/omath/engines/frostbite_engine/formulas.hpp
Normal file
26
include/omath/engines/frostbite_engine/formulas.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 3/22/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/engines/frostbite_engine/constants.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
|
||||||
|
} // namespace omath::unity_engine
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 8/10/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "omath/engines/frostbite_engine/formulas.hpp"
|
||||||
|
#include "omath/projection/camera.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
class CameraTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
static ViewAngles calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
|
||||||
|
[[nodiscard]]
|
||||||
|
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
|
||||||
|
float near, float far) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace omath::unreal_engine
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 8/6/2025.
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#include "omath/engines/frostbite_engine/formulas.hpp"
|
||||||
|
#include "omath/projectile_prediction/projectile.hpp"
|
||||||
|
#include "omath/projectile_prediction/target.hpp"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
class PredEngineTrait final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr static Vector3<float> predict_projectile_position(const projectile_prediction::Projectile& projectile,
|
||||||
|
const float pitch, const float yaw,
|
||||||
|
const float time, const float gravity) noexcept
|
||||||
|
{
|
||||||
|
auto current_pos = projectile.m_origin
|
||||||
|
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
|
||||||
|
RollAngle::from_degrees(0)})
|
||||||
|
* projectile.m_launch_speed * time;
|
||||||
|
current_pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
|
||||||
|
|
||||||
|
return current_pos;
|
||||||
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
static constexpr Vector3<float> predict_target_position(const projectile_prediction::Target& target,
|
||||||
|
const float time, const float gravity) noexcept
|
||||||
|
{
|
||||||
|
auto predicted = target.m_origin + target.m_velocity * time;
|
||||||
|
|
||||||
|
if (target.m_is_airborne)
|
||||||
|
predicted.y -= gravity * (time * time) * 0.5f;
|
||||||
|
|
||||||
|
return predicted;
|
||||||
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
static float calc_vector_2d_distance(const Vector3<float>& delta) noexcept
|
||||||
|
{
|
||||||
|
return std::sqrt(delta.x * delta.x + delta.z * delta.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
|
||||||
|
{
|
||||||
|
return vec.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static Vector3<float> calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
const std::optional<float> projectile_pitch) noexcept
|
||||||
|
{
|
||||||
|
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
|
||||||
|
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
|
||||||
|
|
||||||
|
return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z};
|
||||||
|
}
|
||||||
|
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
|
||||||
|
// 89 look up, -89 look down
|
||||||
|
[[nodiscard]]
|
||||||
|
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||||
|
{
|
||||||
|
const auto direction = (view_to - origin).normalized();
|
||||||
|
return angles::radians_to_degrees(std::asin(direction.y));
|
||||||
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||||
|
{
|
||||||
|
const auto direction = (view_to - origin).normalized();
|
||||||
|
|
||||||
|
return angles::radians_to_degrees(std::atan2(direction.x, direction.z));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace omath::unity_engine
|
||||||
@@ -666,8 +666,7 @@ namespace omath
|
|||||||
}
|
}
|
||||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right,
|
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
|
||||||
const Type bottom, const Type top,
|
|
||||||
const Type near, const Type far) noexcept
|
const Type near, const Type far) noexcept
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
@@ -680,9 +679,8 @@ namespace omath
|
|||||||
}
|
}
|
||||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right,
|
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
|
||||||
const Type bottom, const Type top,
|
const Type near, const Type far) noexcept
|
||||||
const Type near, const Type far) noexcept
|
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -234,6 +234,21 @@ namespace omath
|
|||||||
};
|
};
|
||||||
} // namespace omath
|
} // namespace omath
|
||||||
|
|
||||||
|
template<> struct std::hash<omath::Vector2<float>>
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
std::size_t operator()(const omath::Vector2<float>& vec) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t hash = 0;
|
||||||
|
constexpr std::hash<float> hasher;
|
||||||
|
|
||||||
|
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
|
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -245,15 +245,6 @@ namespace omath
|
|||||||
return std::make_tuple(this->x, this->y, z);
|
return std::make_tuple(this->x, this->y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Vector3 view_angle_to(const Vector3& other) const noexcept
|
|
||||||
{
|
|
||||||
const auto distance = distance_to(other);
|
|
||||||
const auto delta = other - *this;
|
|
||||||
|
|
||||||
return {angles::radians_to_degrees(std::asin(delta.z / distance)),
|
|
||||||
angles::radians_to_degrees(std::atan2(delta.y, delta.x)), 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool operator<(const Vector3& other) const noexcept
|
bool operator<(const Vector3& other) const noexcept
|
||||||
{
|
{
|
||||||
@@ -282,6 +273,7 @@ namespace omath
|
|||||||
|
|
||||||
template<> struct std::hash<omath::Vector3<float>>
|
template<> struct std::hash<omath::Vector3<float>>
|
||||||
{
|
{
|
||||||
|
[[nodiscard]]
|
||||||
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
|
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
|
||||||
{
|
{
|
||||||
std::size_t hash = 0;
|
std::size_t hash = 0;
|
||||||
|
|||||||
@@ -202,6 +202,22 @@ namespace omath
|
|||||||
};
|
};
|
||||||
} // namespace omath
|
} // namespace omath
|
||||||
|
|
||||||
|
template<> struct std::hash<omath::Vector4<float>>
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
std::size_t operator()(const omath::Vector4<float>& vec) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t hash = 0;
|
||||||
|
constexpr std::hash<float> hasher;
|
||||||
|
|
||||||
|
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= hasher(vec.w) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
|
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -89,3 +89,4 @@
|
|||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
#include "omath/utility/pattern_scan.hpp"
|
#include "omath/utility/pattern_scan.hpp"
|
||||||
|
#include "omath/utility/pe_pattern_scan.hpp"
|
||||||
@@ -54,6 +54,12 @@ namespace omath::projection
|
|||||||
friend UnitTestProjection_Projection_Test;
|
friend UnitTestProjection_Projection_Test;
|
||||||
#endif
|
#endif
|
||||||
public:
|
public:
|
||||||
|
enum class ScreenStart
|
||||||
|
{
|
||||||
|
TOP_LEFT_CORNER,
|
||||||
|
BOTTOM_LEFT_CORNER,
|
||||||
|
};
|
||||||
|
|
||||||
~Camera() = default;
|
~Camera() = default;
|
||||||
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
||||||
const FieldOfView& fov, const float near, const float far) noexcept
|
const FieldOfView& fov, const float near, const float far) noexcept
|
||||||
@@ -146,15 +152,22 @@ namespace omath::projection
|
|||||||
return m_origin;
|
return m_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
|
||||||
[[nodiscard]] std::expected<Vector3<float>, Error>
|
[[nodiscard]] std::expected<Vector3<float>, Error>
|
||||||
world_to_screen(const Vector3<float>& world_position) const noexcept
|
world_to_screen(const Vector3<float>& world_position) const noexcept
|
||||||
{
|
{
|
||||||
auto normalized_cords = world_to_view_port(world_position);
|
const auto normalized_cords = world_to_view_port(world_position);
|
||||||
|
|
||||||
if (!normalized_cords.has_value())
|
if (!normalized_cords.has_value())
|
||||||
return std::unexpected{normalized_cords.error()};
|
return std::unexpected{normalized_cords.error()};
|
||||||
|
|
||||||
return ndc_to_screen_position(*normalized_cords);
|
if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER)
|
||||||
|
return ndc_to_screen_position_from_top_left_corner(*normalized_cords);
|
||||||
|
else if constexpr (screen_start == ScreenStart::BOTTOM_LEFT_CORNER)
|
||||||
|
return ndc_to_screen_position_from_bottom_left_corner(*normalized_cords);
|
||||||
|
else
|
||||||
|
std::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::expected<Vector3<float>, Error>
|
[[nodiscard]] std::expected<Vector3<float>, Error>
|
||||||
@@ -225,7 +238,8 @@ namespace omath::projection
|
|||||||
return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; });
|
return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
[[nodiscard]] Vector3<float>
|
||||||
|
ndc_to_screen_position_from_top_left_corner(const Vector3<float>& ndc) const noexcept
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
^
|
^
|
||||||
@@ -239,7 +253,27 @@ namespace omath::projection
|
|||||||
-1 |
|
-1 |
|
||||||
v
|
v
|
||||||
*/
|
*/
|
||||||
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
|
|
||||||
|
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / -2.f + 0.5f) * m_view_port.m_height, ndc.z};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Vector3<float>
|
||||||
|
ndc_to_screen_position_from_bottom_left_corner(const Vector3<float>& ndc) const noexcept
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
^
|
||||||
|
| y
|
||||||
|
1 |
|
||||||
|
|
|
||||||
|
|
|
||||||
|
-1 ---------0--------- 1 --> x
|
||||||
|
|
|
||||||
|
|
|
||||||
|
-1 |
|
||||||
|
v
|
||||||
|
*/
|
||||||
|
|
||||||
|
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / 2.f + 0.5f) * m_view_port.m_height, ndc.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept
|
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace omath::rev_eng
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
||||||
#else
|
#else
|
||||||
using VirtualMethodType = ReturnType(__fastcall*)(void*, decltype(arg_list)...);
|
using VirtualMethodType = ReturnType(*)(void*, decltype(arg_list)...);
|
||||||
#endif
|
#endif
|
||||||
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
|
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/8/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/7/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace omath::system::pe
|
|
||||||
{
|
|
||||||
struct DosHeader final
|
|
||||||
{
|
|
||||||
std::uint16_t e_magic;
|
|
||||||
std::uint16_t e_cblp;
|
|
||||||
std::uint16_t e_cp;
|
|
||||||
std::uint16_t e_crlc;
|
|
||||||
std::uint16_t e_cparhdr;
|
|
||||||
std::uint16_t e_minalloc;
|
|
||||||
std::uint16_t e_maxalloc;
|
|
||||||
std::uint16_t e_ss;
|
|
||||||
std::uint16_t e_sp;
|
|
||||||
std::uint16_t e_csum;
|
|
||||||
std::uint16_t e_ip;
|
|
||||||
std::uint16_t e_cs;
|
|
||||||
std::uint16_t e_lfarlc;
|
|
||||||
std::uint16_t e_ovno;
|
|
||||||
std::uint16_t e_res[4];
|
|
||||||
std::uint16_t e_oemid;
|
|
||||||
std::uint16_t e_oeminfo;
|
|
||||||
std::uint16_t e_res2[10];
|
|
||||||
std::uint32_t e_lfanew;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/7/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace omath::system::pe
|
|
||||||
{
|
|
||||||
enum class MachineId : std::uint16_t
|
|
||||||
{
|
|
||||||
UNKNOWN = 0x0000,
|
|
||||||
TARGET_HOST = 0x0001, // Useful for indicating we want to interact with the host and not a WoW guest.
|
|
||||||
I386 = 0x014C, // Intel 386.
|
|
||||||
R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
|
|
||||||
R4000 = 0x0166, // MIPS little-endian
|
|
||||||
R10000 = 0x0168, // MIPS little-endian
|
|
||||||
WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2
|
|
||||||
ALPHA = 0x0184, // Alpha_AXP
|
|
||||||
SH3 = 0x01A2, // SH3 little-endian
|
|
||||||
SH3DSP = 0x01A3,
|
|
||||||
SH3E = 0x01A4, // SH3E little-endian
|
|
||||||
SH4 = 0x01A6, // SH4 little-endian
|
|
||||||
SH5 = 0x01A8, // SH5
|
|
||||||
ARM = 0x01C0, // ARM Little-Endian
|
|
||||||
THUMB = 0x01C2, // ARM Thumb/Thumb-2 Little-Endian
|
|
||||||
ARMNT = 0x01C4, // ARM Thumb-2 Little-Endian
|
|
||||||
AM33 = 0x01D3,
|
|
||||||
POWERPC = 0x01F0, // IBM PowerPC Little-Endian
|
|
||||||
POWERPCP = 0x01F1,
|
|
||||||
IA64 = 0x0200, // Intel 64
|
|
||||||
MIPS16 = 0x0266, // MIPS
|
|
||||||
ALPHA64 = 0x0284, // ALPHA64
|
|
||||||
MIPSFPU = 0x0366, // MIPS
|
|
||||||
MIPSFPU16 = 0x0466, // MIPS
|
|
||||||
AXP64 = 0x0284,
|
|
||||||
TRICORE = 0x0520, // Infineon
|
|
||||||
CEF = 0x0CEF,
|
|
||||||
EBC = 0x0EBC, // EFI Byte Code
|
|
||||||
AMD64 = 0x8664, // AMD64 (K8)
|
|
||||||
M32R = 0x9041, // M32R little-endian
|
|
||||||
ARM64 = 0xAA64, // ARM64 Little-Endian
|
|
||||||
CEE = 0xC0EE,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileHeader final
|
|
||||||
{
|
|
||||||
MachineId machine;
|
|
||||||
uint16_t num_sections;
|
|
||||||
uint32_t timedate_stamp;
|
|
||||||
uint32_t ptr_symbols;
|
|
||||||
uint32_t num_symbols;
|
|
||||||
uint16_t size_optional_header;
|
|
||||||
std::uint16_t characteristics;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/9/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "file_header.hpp"
|
|
||||||
#include "optional_header.hpp"
|
|
||||||
|
|
||||||
namespace omath::system::pe
|
|
||||||
{
|
|
||||||
enum class NtArchitecture
|
|
||||||
{
|
|
||||||
x32_bit,
|
|
||||||
x64_bit,
|
|
||||||
};
|
|
||||||
template<NtArchitecture architecture>
|
|
||||||
struct ImageNtHeaders final
|
|
||||||
{
|
|
||||||
std::uint32_t signature;
|
|
||||||
FileHeader file_header;
|
|
||||||
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
|
|
||||||
};
|
|
||||||
} // namespace omath::system::pe
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/8/2025.
|
|
||||||
//
|
|
||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace omath::system::pe
|
|
||||||
{
|
|
||||||
static constexpr std::uint16_t opt_hdr32_magic = 0x010B;
|
|
||||||
static constexpr std::uint16_t opt_hdr64_magic = 0x020B;
|
|
||||||
enum class SubsystemId : std::uint16_t
|
|
||||||
{
|
|
||||||
unknown = 0x0000,
|
|
||||||
native = 0x0001,
|
|
||||||
windows_gui = 0x0002,
|
|
||||||
windows_cui = 0x0003,
|
|
||||||
os2_cui = 0x0005,
|
|
||||||
posix_cui = 0x0007,
|
|
||||||
native_windows = 0x0008,
|
|
||||||
windows_ce_gui = 0x0009,
|
|
||||||
efi_application = 0x000A,
|
|
||||||
efi_boot_service_driver = 0x000B,
|
|
||||||
efi_runtime_driver = 0x000C,
|
|
||||||
efi_rom = 0x000D,
|
|
||||||
xbox = 0x000E,
|
|
||||||
windows_boot_application = 0x0010,
|
|
||||||
xbox_code_catalog = 0x0011,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DataDirectory final
|
|
||||||
{
|
|
||||||
std::uint32_t rva;
|
|
||||||
std::uint32_t size;
|
|
||||||
};
|
|
||||||
struct OptionalHeaderX64 final
|
|
||||||
{
|
|
||||||
// Standard fields.
|
|
||||||
std::uint16_t magic;
|
|
||||||
std::uint16_t linker_version;
|
|
||||||
|
|
||||||
std::uint32_t size_code;
|
|
||||||
std::uint32_t size_init_data;
|
|
||||||
std::uint32_t size_uninit_data;
|
|
||||||
|
|
||||||
std::uint32_t entry_point;
|
|
||||||
std::uint32_t base_of_code;
|
|
||||||
|
|
||||||
// NT additional fields.
|
|
||||||
std::uint64_t image_base;
|
|
||||||
std::uint32_t section_alignment;
|
|
||||||
std::uint32_t file_alignment;
|
|
||||||
|
|
||||||
std::uint32_t os_version;
|
|
||||||
std::uint32_t img_version;
|
|
||||||
std::uint32_t subsystem_version;
|
|
||||||
std::uint32_t win32_version_value;
|
|
||||||
|
|
||||||
std::uint32_t size_image;
|
|
||||||
std::uint32_t size_headers;
|
|
||||||
|
|
||||||
std::uint32_t checksum;
|
|
||||||
SubsystemId subsystem;
|
|
||||||
std::uint16_t characteristics;
|
|
||||||
|
|
||||||
std::uint64_t size_stack_reserve;
|
|
||||||
std::uint64_t size_stack_commit;
|
|
||||||
std::uint64_t size_heap_reserve;
|
|
||||||
std::uint64_t size_heap_commit;
|
|
||||||
|
|
||||||
std::uint32_t ldr_flags;
|
|
||||||
|
|
||||||
std::uint32_t num_data_directories;
|
|
||||||
DataDirectory data_directories[16];
|
|
||||||
};
|
|
||||||
struct OptionalHeaderX86 final
|
|
||||||
{
|
|
||||||
// Standard fields.
|
|
||||||
uint16_t magic;
|
|
||||||
uint16_t linker_version;
|
|
||||||
|
|
||||||
uint32_t size_code;
|
|
||||||
uint32_t size_init_data;
|
|
||||||
uint32_t size_uninit_data;
|
|
||||||
|
|
||||||
uint32_t entry_point;
|
|
||||||
uint32_t base_of_code;
|
|
||||||
uint32_t base_of_data;
|
|
||||||
|
|
||||||
// NT additional fields.
|
|
||||||
uint32_t image_base;
|
|
||||||
uint32_t section_alignment;
|
|
||||||
uint32_t file_alignment;
|
|
||||||
|
|
||||||
std::uint32_t os_version;
|
|
||||||
std::uint32_t img_version;
|
|
||||||
std::uint32_t subsystem_version;
|
|
||||||
uint32_t win32_version_value;
|
|
||||||
|
|
||||||
uint32_t size_image;
|
|
||||||
uint32_t size_headers;
|
|
||||||
|
|
||||||
uint32_t checksum;
|
|
||||||
SubsystemId subsystem;
|
|
||||||
std::uint16_t characteristics;
|
|
||||||
|
|
||||||
uint32_t size_stack_reserve;
|
|
||||||
uint32_t size_stack_commit;
|
|
||||||
uint32_t size_heap_reserve;
|
|
||||||
uint32_t size_heap_commit;
|
|
||||||
|
|
||||||
uint32_t ldr_flags;
|
|
||||||
|
|
||||||
uint32_t num_data_directories;
|
|
||||||
DataDirectory data_directories[16];
|
|
||||||
};
|
|
||||||
template<bool x64 = true>
|
|
||||||
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
|
|
||||||
} // namespace omath::system::pe
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Vlad on 10/8/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
// Section header
|
|
||||||
//
|
|
||||||
namespace omath::system::pe
|
|
||||||
{
|
|
||||||
struct SectionHeader final
|
|
||||||
{
|
|
||||||
char name[8];
|
|
||||||
union
|
|
||||||
{
|
|
||||||
std::uint32_t physical_address;
|
|
||||||
std::uint32_t virtual_size;
|
|
||||||
};
|
|
||||||
std::uint32_t virtual_address;
|
|
||||||
|
|
||||||
std::uint32_t size_raw_data;
|
|
||||||
std::uint32_t ptr_raw_data;
|
|
||||||
|
|
||||||
std::uint32_t ptr_relocs;
|
|
||||||
std::uint32_t ptr_line_numbers;
|
|
||||||
std::uint32_t num_relocs;
|
|
||||||
std::uint32_t num_line_numbers;
|
|
||||||
|
|
||||||
std::uint32_t characteristics;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -9,17 +9,13 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable CppInconsistentNaming
|
||||||
class unit_test_pattern_scan_read_test_Test;
|
class unit_test_pattern_scan_read_test_Test;
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
class unit_test_pattern_scan_corner_case_1_Test;
|
class unit_test_pattern_scan_corner_case_1_Test;
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
class unit_test_pattern_scan_corner_case_2_Test;
|
class unit_test_pattern_scan_corner_case_2_Test;
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
class unit_test_pattern_scan_corner_case_3_Test;
|
class unit_test_pattern_scan_corner_case_3_Test;
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
class unit_test_pattern_scan_corner_case_4_Test;
|
class unit_test_pattern_scan_corner_case_4_Test;
|
||||||
|
// ReSharper restore CppInconsistentNaming
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
enum class PatternScanError
|
enum class PatternScanError
|
||||||
@@ -37,11 +33,11 @@ namespace omath
|
|||||||
public:
|
public:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static std::span<std::byte>::iterator scan_for_pattern(const std::span<std::byte>& range,
|
static std::span<std::byte>::iterator scan_for_pattern(const std::span<std::byte>& range,
|
||||||
const std::string_view& pattern);
|
const std::string_view& pattern);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static std::span<std::byte>::iterator scan_for_pattern(std::span<std::byte>&& range,
|
static std::span<std::byte>::iterator scan_for_pattern(std::span<std::byte>&& range,
|
||||||
const std::string_view& pattern) = delete;
|
const std::string_view& pattern) = delete;
|
||||||
|
|
||||||
template<class IteratorType>
|
template<class IteratorType>
|
||||||
requires std::input_or_output_iterator<std::remove_cvref_t<IteratorType>>
|
requires std::input_or_output_iterator<std::remove_cvref_t<IteratorType>>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
struct PeSectionScanResult
|
struct PeSectionScanResult
|
||||||
@@ -18,26 +17,14 @@ namespace omath
|
|||||||
};
|
};
|
||||||
class PePatternScanner final
|
class PePatternScanner final
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
struct Section
|
|
||||||
{
|
|
||||||
std::uint64_t virtual_base_addr;
|
|
||||||
std::uint64_t raw_base_addr;
|
|
||||||
std::vector<std::byte> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const std::string_view& module_name,
|
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const void* module_base_address,
|
||||||
const std::string_view& pattern);
|
const std::string_view& pattern);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static std::optional<PeSectionScanResult>
|
static std::optional<PeSectionScanResult>
|
||||||
scan_for_pattern_in_file(const std::filesystem::path& path_to_file, const std::string_view& pattern,
|
scan_for_pattern_in_file(const std::filesystem::path& path_to_file, const std::string_view& pattern,
|
||||||
const std::string_view& target_section_name = ".text");
|
const std::string_view& target_section_name = ".text");
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static std::optional<Section> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
|
||||||
const std::string_view& section_name);
|
|
||||||
};
|
};
|
||||||
} // namespace omath
|
} // namespace omath
|
||||||
42
source/engines/frostbite_engine/formulas.cpp
Normal file
42
source/engines/frostbite_engine/formulas.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 3/22/2025.
|
||||||
|
//
|
||||||
|
#include "omath/engines/frostbite_engine/formulas.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
|
||||||
|
{
|
||||||
|
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
|
||||||
|
|
||||||
|
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
|
||||||
|
}
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept
|
||||||
|
{
|
||||||
|
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
|
||||||
|
|
||||||
|
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
|
||||||
|
}
|
||||||
|
Vector3<float> up_vector(const ViewAngles& angles) noexcept
|
||||||
|
{
|
||||||
|
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
|
||||||
|
|
||||||
|
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
|
||||||
|
}
|
||||||
|
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||||
|
{
|
||||||
|
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), right_vector(angles),
|
||||||
|
up_vector(angles), cam_origin);
|
||||||
|
}
|
||||||
|
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||||
|
{
|
||||||
|
return mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll)
|
||||||
|
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.yaw)
|
||||||
|
* mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch);
|
||||||
|
}
|
||||||
|
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||||
|
const float far) noexcept
|
||||||
|
{
|
||||||
|
return mat_perspective_left_handed(field_of_view, aspect_ratio, near, far);
|
||||||
|
}
|
||||||
|
} // namespace omath::unity_engine
|
||||||
26
source/engines/frostbite_engine/traits/camera_trait.cpp
Normal file
26
source/engines/frostbite_engine/traits/camera_trait.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 8/11/2025.
|
||||||
|
//
|
||||||
|
#include "omath/engines/frostbite_engine/traits/camera_trait.hpp"
|
||||||
|
|
||||||
|
namespace omath::frostbite_engine
|
||||||
|
{
|
||||||
|
|
||||||
|
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||||
|
{
|
||||||
|
const auto direction = (look_at - cam_origin).normalized();
|
||||||
|
|
||||||
|
return {PitchAngle::from_radians(-std::asin(direction.y)),
|
||||||
|
YawAngle::from_radians(std::atan2(direction.x, direction.z)), RollAngle::from_radians(0.f)};
|
||||||
|
}
|
||||||
|
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||||
|
{
|
||||||
|
return frostbite_engine::calc_view_matrix(angles, cam_origin);
|
||||||
|
}
|
||||||
|
Mat4X4 CameraTrait::calc_projection_matrix(const projection::FieldOfView& fov,
|
||||||
|
const projection::ViewPort& view_port, const float near,
|
||||||
|
const float far) noexcept
|
||||||
|
{
|
||||||
|
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far);
|
||||||
|
}
|
||||||
|
} // namespace omath::unity_engine
|
||||||
@@ -25,7 +25,7 @@ namespace omath::unity_engine
|
|||||||
}
|
}
|
||||||
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||||
{
|
{
|
||||||
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), -right_vector(angles),
|
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(-forward_vector(angles), right_vector(angles),
|
||||||
up_vector(angles), cam_origin);
|
up_vector(angles), cam_origin);
|
||||||
}
|
}
|
||||||
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||||
@@ -37,13 +37,6 @@ namespace omath::unity_engine
|
|||||||
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||||
const float far) noexcept
|
const float far) noexcept
|
||||||
{
|
{
|
||||||
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
|
return omath::mat_perspective_right_handed(field_of_view, aspect_ratio, near, far);
|
||||||
|
|
||||||
return {
|
|
||||||
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
|
|
||||||
{0, 1.f / (fov_half_tan), 0, 0},
|
|
||||||
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
|
|
||||||
{0, 0, -1.f, 0},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::unity_engine
|
||||||
|
|||||||
@@ -2,40 +2,227 @@
|
|||||||
// Created by Vlad on 10/7/2025.
|
// Created by Vlad on 10/7/2025.
|
||||||
//
|
//
|
||||||
#include "omath/utility/pe_pattern_scan.hpp"
|
#include "omath/utility/pe_pattern_scan.hpp"
|
||||||
#include "omath/system/pe/image_nt_headers.hpp"
|
|
||||||
#include "omath/system/pe/section_header.hpp"
|
|
||||||
#include "omath/utility/pattern_scan.hpp"
|
#include "omath/utility/pattern_scan.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <omath/system/pe/dos_header.hpp>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace omath::system::pe;
|
// Internal PE shit defines
|
||||||
using NtHeaderVariant = std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
|
// Big thx for linuxpe sources as ref
|
||||||
|
// Link: https://github.com/can1357/linux-pe
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr std::uint16_t opt_hdr32_magic = 0x010B;
|
||||||
|
constexpr std::uint16_t opt_hdr64_magic = 0x020B;
|
||||||
|
|
||||||
|
// Standard fields.
|
||||||
|
// ReSharper disable CppDeclaratorNeverUsed
|
||||||
|
struct DataDirectory final
|
||||||
|
{
|
||||||
|
std::uint32_t rva;
|
||||||
|
std::uint32_t size;
|
||||||
|
};
|
||||||
|
struct OptionalHeaderX64 final
|
||||||
|
{
|
||||||
|
std::uint16_t magic;
|
||||||
|
|
||||||
|
std::uint16_t linker_version;
|
||||||
|
|
||||||
|
std::uint32_t size_code;
|
||||||
|
std::uint32_t size_init_data;
|
||||||
|
std::uint32_t size_uninit_data;
|
||||||
|
|
||||||
|
std::uint32_t entry_point;
|
||||||
|
std::uint32_t base_of_code;
|
||||||
|
|
||||||
|
// NT additional fields.
|
||||||
|
std::uint64_t image_base;
|
||||||
|
std::uint32_t section_alignment;
|
||||||
|
std::uint32_t file_alignment;
|
||||||
|
|
||||||
|
std::uint32_t os_version;
|
||||||
|
std::uint32_t img_version;
|
||||||
|
std::uint32_t subsystem_version;
|
||||||
|
std::uint32_t win32_version_value;
|
||||||
|
|
||||||
|
std::uint32_t size_image;
|
||||||
|
std::uint32_t size_headers;
|
||||||
|
|
||||||
|
std::uint32_t checksum;
|
||||||
|
std::uint16_t subsystem;
|
||||||
|
std::uint16_t characteristics;
|
||||||
|
|
||||||
|
std::uint64_t size_stack_reserve;
|
||||||
|
std::uint64_t size_stack_commit;
|
||||||
|
std::uint64_t size_heap_reserve;
|
||||||
|
std::uint64_t size_heap_commit;
|
||||||
|
|
||||||
|
std::uint32_t ldr_flags;
|
||||||
|
|
||||||
|
std::uint32_t num_data_directories;
|
||||||
|
DataDirectory data_directories[16];
|
||||||
|
};
|
||||||
|
struct OptionalHeaderX86 final
|
||||||
|
{
|
||||||
|
// Standard fields.
|
||||||
|
std::uint16_t magic{};
|
||||||
|
std::uint16_t linker_version{};
|
||||||
|
|
||||||
|
std::uint32_t size_code{};
|
||||||
|
std::uint32_t size_init_data{};
|
||||||
|
std::uint32_t size_uninit_data{};
|
||||||
|
|
||||||
|
std::uint32_t entry_point{};
|
||||||
|
std::uint32_t base_of_code{};
|
||||||
|
std::uint32_t base_of_data{};
|
||||||
|
|
||||||
|
// NT additional fields.
|
||||||
|
std::uint32_t image_base{};
|
||||||
|
std::uint32_t section_alignment{};
|
||||||
|
std::uint32_t file_alignment{};
|
||||||
|
|
||||||
|
std::uint32_t os_version{};
|
||||||
|
std::uint32_t img_version{};
|
||||||
|
std::uint32_t subsystem_version{};
|
||||||
|
std::uint32_t win32_version_value{};
|
||||||
|
|
||||||
|
std::uint32_t size_image{};
|
||||||
|
std::uint32_t size_headers{};
|
||||||
|
|
||||||
|
std::uint32_t checksum{};
|
||||||
|
std::uint16_t subsystem{};
|
||||||
|
std::uint16_t characteristics{};
|
||||||
|
|
||||||
|
std::uint32_t size_stack_reserve{};
|
||||||
|
std::uint32_t size_stack_commit{};
|
||||||
|
std::uint32_t size_heap_reserve{};
|
||||||
|
std::uint32_t size_heap_commit{};
|
||||||
|
|
||||||
|
std::uint32_t ldr_flags{};
|
||||||
|
|
||||||
|
std::uint32_t num_data_directories{};
|
||||||
|
DataDirectory data_directories[16]{};
|
||||||
|
};
|
||||||
|
template<bool x64 = true>
|
||||||
|
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
|
||||||
|
|
||||||
|
struct FileHeader final
|
||||||
|
{
|
||||||
|
std::uint16_t machine;
|
||||||
|
std::uint16_t num_sections;
|
||||||
|
std::uint32_t timedate_stamp;
|
||||||
|
std::uint32_t ptr_symbols;
|
||||||
|
std::uint32_t num_symbols;
|
||||||
|
std::uint16_t size_optional_header;
|
||||||
|
std::uint16_t characteristics;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DosHeader final
|
||||||
|
{
|
||||||
|
std::uint16_t e_magic;
|
||||||
|
std::uint16_t e_cblp;
|
||||||
|
std::uint16_t e_cp;
|
||||||
|
std::uint16_t e_crlc;
|
||||||
|
std::uint16_t e_cparhdr;
|
||||||
|
std::uint16_t e_minalloc;
|
||||||
|
std::uint16_t e_maxalloc;
|
||||||
|
std::uint16_t e_ss;
|
||||||
|
std::uint16_t e_sp;
|
||||||
|
std::uint16_t e_csum;
|
||||||
|
std::uint16_t e_ip;
|
||||||
|
std::uint16_t e_cs;
|
||||||
|
std::uint16_t e_lfarlc;
|
||||||
|
std::uint16_t e_ovno;
|
||||||
|
std::uint16_t e_res[4];
|
||||||
|
std::uint16_t e_oemid;
|
||||||
|
std::uint16_t e_oeminfo;
|
||||||
|
std::uint16_t e_res2[10];
|
||||||
|
std::uint32_t e_lfanew;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NtArchitecture
|
||||||
|
{
|
||||||
|
x32_bit,
|
||||||
|
x64_bit,
|
||||||
|
};
|
||||||
|
template<NtArchitecture architecture>
|
||||||
|
struct ImageNtHeaders final
|
||||||
|
{
|
||||||
|
std::uint32_t signature;
|
||||||
|
FileHeader file_header;
|
||||||
|
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SectionHeader final
|
||||||
|
{
|
||||||
|
char name[8];
|
||||||
|
union
|
||||||
|
{
|
||||||
|
std::uint32_t physical_address;
|
||||||
|
std::uint32_t virtual_size;
|
||||||
|
};
|
||||||
|
std::uint32_t virtual_address;
|
||||||
|
|
||||||
|
std::uint32_t size_raw_data;
|
||||||
|
std::uint32_t ptr_raw_data;
|
||||||
|
|
||||||
|
std::uint32_t ptr_relocs;
|
||||||
|
std::uint32_t ptr_line_numbers;
|
||||||
|
std::uint32_t num_relocs;
|
||||||
|
std::uint32_t num_line_numbers;
|
||||||
|
|
||||||
|
std::uint32_t characteristics;
|
||||||
|
};
|
||||||
|
// ReSharper restore CppDeclaratorNeverUsed
|
||||||
|
|
||||||
|
using NtHeaderVariant =
|
||||||
|
std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Internal PE scanner functions
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
NtHeaderVariant get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
|
std::optional<NtHeaderVariant> get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
|
||||||
{
|
{
|
||||||
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers;
|
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
|
||||||
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
||||||
file.read(reinterpret_cast<char*>(&x86_headers), sizeof(x86_headers));
|
file.read(reinterpret_cast<char*>(&x86_headers), sizeof(x86_headers));
|
||||||
|
|
||||||
if (x86_headers.optional_header.magic == opt_hdr32_magic)
|
if (x86_headers.optional_header.magic == opt_hdr32_magic)
|
||||||
return x86_headers;
|
return x86_headers;
|
||||||
|
|
||||||
ImageNtHeaders<NtArchitecture::x64_bit> x64_headers;
|
if (x86_headers.optional_header.magic != opt_hdr64_magic)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
ImageNtHeaders<NtArchitecture::x64_bit> x64_headers{};
|
||||||
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
file.seekg(dos_header.e_lfanew, std::ios::beg);
|
||||||
file.read(reinterpret_cast<char*>(&x64_headers), sizeof(x64_headers));
|
file.read(reinterpret_cast<char*>(&x64_headers), sizeof(x64_headers));
|
||||||
|
|
||||||
return x64_headers;
|
return x64_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::optional<NtHeaderVariant> get_nt_header_from_loaded_module(const void* module_base_address)
|
||||||
|
{
|
||||||
|
const auto module_byte_ptr = static_cast<const std::byte*>(module_base_address);
|
||||||
|
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
|
||||||
|
const auto dos_header = static_cast<const DosHeader*>(module_base_address);
|
||||||
|
|
||||||
|
x86_headers = *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x32_bit>*>(module_byte_ptr
|
||||||
|
+ dos_header->e_lfanew);
|
||||||
|
|
||||||
|
if (x86_headers.optional_header.magic == opt_hdr32_magic)
|
||||||
|
return x86_headers;
|
||||||
|
|
||||||
|
if (x86_headers.optional_header.magic != opt_hdr64_magic)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x64_bit>*>(module_byte_ptr
|
||||||
|
+ dos_header->e_lfanew);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
|
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
|
||||||
{
|
{
|
||||||
@@ -48,39 +235,105 @@ namespace
|
|||||||
constexpr std::uint32_t nt_hdr_magic = 0x4550;
|
constexpr std::uint32_t nt_hdr_magic = 0x4550;
|
||||||
return std::visit([](const auto& header) -> bool { return header.signature != nt_hdr_magic; }, variant);
|
return std::visit([](const auto& header) -> bool { return header.signature != nt_hdr_magic; }, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ExtractedSection
|
||||||
|
{
|
||||||
|
std::uint64_t virtual_base_addr;
|
||||||
|
std::uint64_t raw_base_addr;
|
||||||
|
std::vector<std::byte> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::optional<ExtractedSection> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||||
|
const std::string_view& section_name)
|
||||||
|
{
|
||||||
|
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
|
||||||
|
|
||||||
|
if (!file.is_open()) [[unlikely]]
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
DosHeader dos_header{};
|
||||||
|
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
|
||||||
|
|
||||||
|
if (invalid_dos_header_file(dos_header)) [[unlikely]]
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const auto nt_headers = get_nt_header_from_file(file, dos_header);
|
||||||
|
|
||||||
|
if (!nt_headers)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
if (invalid_nt_header_file(nt_headers.value())) [[unlikely]]
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return std::visit(
|
||||||
|
[&file, &dos_header, §ion_name](auto& concrete_headers) -> std::optional<ExtractedSection>
|
||||||
|
{
|
||||||
|
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
|
||||||
|
const auto offset_to_segment_table = dos_header.e_lfanew
|
||||||
|
+ concrete_headers.file_header.size_optional_header
|
||||||
|
+ sizeof(FileHeader) + size_of_signature;
|
||||||
|
|
||||||
|
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
|
||||||
|
{
|
||||||
|
SectionHeader current_section{};
|
||||||
|
file.read(reinterpret_cast<char*>(¤t_section), sizeof(current_section));
|
||||||
|
|
||||||
|
if (std::string_view(current_section.name) != section_name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector<std::byte> section_data(current_section.size_raw_data);
|
||||||
|
|
||||||
|
file.seekg(current_section.ptr_raw_data, std::ios::beg);
|
||||||
|
file.read(reinterpret_cast<char*>(section_data.data()),
|
||||||
|
static_cast<std::streamsize>(section_data.size()));
|
||||||
|
return ExtractedSection{.virtual_base_addr = current_section.virtual_address
|
||||||
|
+ concrete_headers.optional_header.image_base,
|
||||||
|
.raw_base_addr = current_section.ptr_raw_data,
|
||||||
|
.data = std::move(section_data)};
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
},
|
||||||
|
nt_headers.value());
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
|
|
||||||
std::optional<std::uintptr_t>
|
std::optional<std::uintptr_t> PePatternScanner::scan_for_pattern_in_loaded_module(const void* module_base_address,
|
||||||
PePatternScanner::scan_for_pattern_in_loaded_module([[maybe_unused]] const std::string_view& module_name,
|
const std::string_view& pattern)
|
||||||
[[maybe_unused]] const std::string_view& pattern)
|
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
const auto base_address = reinterpret_cast<std::uintptr_t>(module_base_address);
|
||||||
const auto base_address = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(module_name.data()));
|
|
||||||
|
|
||||||
if (!base_address)
|
if (!base_address)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
const auto dos_headers = reinterpret_cast<PIMAGE_DOS_HEADER>(base_address);
|
auto nt_header_variant = get_nt_header_from_loaded_module(module_base_address);
|
||||||
const auto image_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(base_address + dos_headers->e_lfanew);
|
|
||||||
|
|
||||||
// Define .code segment as scan area
|
if (!nt_header_variant)
|
||||||
const auto start = image_nt_headers->OptionalHeader.BaseOfCode;
|
return std::nullopt;
|
||||||
const auto scan_size = image_nt_headers->OptionalHeader.SizeOfCode;
|
|
||||||
|
|
||||||
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
|
return std::visit(
|
||||||
|
[base_address, &pattern](const auto& nt_header) -> std::optional<std::uintptr_t>
|
||||||
|
{
|
||||||
|
// Define .code segment as scan area
|
||||||
|
const auto start = nt_header.optional_header.base_of_code;
|
||||||
|
const auto scan_size = nt_header.optional_header.size_code;
|
||||||
|
|
||||||
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
|
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
|
||||||
|
|
||||||
if (result != scan_range.cend())
|
// ReSharper disable once CppTooWideScopeInitStatement
|
||||||
return reinterpret_cast<std::uintptr_t>(&*result);
|
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
|
||||||
|
|
||||||
return std::nullopt;
|
if (result != scan_range.end())
|
||||||
#else
|
return reinterpret_cast<std::uintptr_t>(&*result);
|
||||||
throw std::runtime_error("Pattern scan for loaded modules is only for windows platform");
|
|
||||||
#endif
|
return std::nullopt;
|
||||||
|
},
|
||||||
|
nt_header_variant.value());
|
||||||
}
|
}
|
||||||
std::optional<PeSectionScanResult>
|
std::optional<PeSectionScanResult>
|
||||||
PePatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
|
PePatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
|
||||||
@@ -103,56 +356,4 @@ namespace omath
|
|||||||
.raw_base_addr = pe_section->raw_base_addr,
|
.raw_base_addr = pe_section->raw_base_addr,
|
||||||
.target_offset = offset};
|
.target_offset = offset};
|
||||||
}
|
}
|
||||||
std::optional<PePatternScanner::Section>
|
|
||||||
PePatternScanner::extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
|
||||||
const std::string_view& section_name)
|
|
||||||
{
|
|
||||||
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
|
|
||||||
|
|
||||||
if (!file.is_open()) [[unlikely]]
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
DosHeader dos_header{};
|
|
||||||
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
|
|
||||||
|
|
||||||
if (invalid_dos_header_file(dos_header)) [[unlikely]]
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
const auto nt_headers = get_nt_header_from_file(file, dos_header);
|
|
||||||
|
|
||||||
if (invalid_nt_header_file(nt_headers)) [[unlikely]]
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
return std::visit(
|
|
||||||
[&file, &dos_header, §ion_name](auto& concrete_headers) -> std::optional<Section>
|
|
||||||
{
|
|
||||||
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
|
|
||||||
const auto offset_to_segment_table = dos_header.e_lfanew
|
|
||||||
+ concrete_headers.file_header.size_optional_header
|
|
||||||
+ sizeof(FileHeader) + size_of_signature;
|
|
||||||
|
|
||||||
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
|
|
||||||
{
|
|
||||||
SectionHeader current_section{};
|
|
||||||
file.read(reinterpret_cast<char*>(¤t_section), sizeof(current_section));
|
|
||||||
|
|
||||||
if (std::string_view(current_section.name) != section_name)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::vector<std::byte> section_data(current_section.size_raw_data);
|
|
||||||
|
|
||||||
file.seekg(current_section.ptr_raw_data, std::ios::beg);
|
|
||||||
file.read(reinterpret_cast<char*>(section_data.data()),
|
|
||||||
static_cast<std::streamsize>(section_data.size()));
|
|
||||||
return Section{.virtual_base_addr = current_section.virtual_address
|
|
||||||
+ concrete_headers.optional_header.image_base,
|
|
||||||
.raw_base_addr = current_section.ptr_raw_data,
|
|
||||||
.data = std::move(section_data)};
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
},
|
|
||||||
nt_headers);
|
|
||||||
}
|
|
||||||
} // namespace omath
|
} // namespace omath
|
||||||
@@ -16,5 +16,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
|
|||||||
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
|
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
|
||||||
|
|
||||||
gtest_discover_tests(${PROJECT_NAME})
|
gtest_discover_tests(${PROJECT_NAME})
|
||||||
236
tests/engines/unit_test_frostbite_engine.cpp
Normal file
236
tests/engines/unit_test_frostbite_engine.cpp
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
//
|
||||||
|
// Created by Vlad on 10/23/2025.
|
||||||
|
//
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <omath/engines/frostbite_engine/camera.hpp>
|
||||||
|
#include <omath/engines/frostbite_engine/constants.hpp>
|
||||||
|
#include <omath/engines/frostbite_engine/formulas.hpp>
|
||||||
|
#include <print>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ForwardVector)
|
||||||
|
{
|
||||||
|
const auto forward = omath::frostbite_engine::forward_vector({});
|
||||||
|
|
||||||
|
EXPECT_EQ(forward, omath::frostbite_engine::k_abs_forward);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ForwardVectorRotationYaw)
|
||||||
|
{
|
||||||
|
omath::frostbite_engine::ViewAngles angles;
|
||||||
|
|
||||||
|
angles.yaw = omath::frostbite_engine::YawAngle::from_degrees(90.f);
|
||||||
|
|
||||||
|
const auto forward = omath::frostbite_engine::forward_vector(angles);
|
||||||
|
EXPECT_NEAR(forward.x, omath::frostbite_engine::k_abs_right.x, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.y, omath::frostbite_engine::k_abs_right.y, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.z, omath::frostbite_engine::k_abs_right.z, 0.00001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ForwardVectorRotationPitch)
|
||||||
|
{
|
||||||
|
omath::frostbite_engine::ViewAngles angles;
|
||||||
|
|
||||||
|
angles.pitch = omath::frostbite_engine::PitchAngle::from_degrees(-90.f);
|
||||||
|
|
||||||
|
const auto forward = omath::frostbite_engine::forward_vector(angles);
|
||||||
|
EXPECT_NEAR(forward.x, omath::frostbite_engine::k_abs_up.x, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.y, omath::frostbite_engine::k_abs_up.y, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.z, omath::frostbite_engine::k_abs_up.z, 0.00001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ForwardVectorRotationRoll)
|
||||||
|
{
|
||||||
|
omath::frostbite_engine::ViewAngles angles;
|
||||||
|
|
||||||
|
angles.roll = omath::frostbite_engine::RollAngle::from_degrees(-90.f);
|
||||||
|
|
||||||
|
const auto forward = omath::frostbite_engine::up_vector(angles);
|
||||||
|
EXPECT_NEAR(forward.x, omath::frostbite_engine::k_abs_right.x, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.y, omath::frostbite_engine::k_abs_right.y, 0.00001f);
|
||||||
|
EXPECT_NEAR(forward.z, omath::frostbite_engine::k_abs_right.z, 0.00001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, RightVector)
|
||||||
|
{
|
||||||
|
const auto right = omath::frostbite_engine::right_vector({});
|
||||||
|
|
||||||
|
EXPECT_EQ(right, omath::frostbite_engine::k_abs_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, UpVector)
|
||||||
|
{
|
||||||
|
const auto up = omath::frostbite_engine::up_vector({});
|
||||||
|
EXPECT_EQ(up, omath::frostbite_engine::k_abs_up);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, ProjectTargetMovedFromCamera)
|
||||||
|
{
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||||
|
const auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.01f, 1000.f);
|
||||||
|
|
||||||
|
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
|
||||||
|
{
|
||||||
|
const auto projected = cam.world_to_screen({0, 0, distance});
|
||||||
|
|
||||||
|
EXPECT_TRUE(projected.has_value());
|
||||||
|
|
||||||
|
if (!projected.has_value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
EXPECT_NEAR(projected->x, 640, 0.00001f);
|
||||||
|
EXPECT_NEAR(projected->y, 360, 0.00001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TEST(unit_test_frostbite_engine, Project)
|
||||||
|
{
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||||
|
|
||||||
|
const auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
|
||||||
|
const auto proj = cam.world_to_screen<omath::frostbite_engine::Camera::ScreenStart::BOTTOM_LEFT_CORNER>({10.f, 3, 10.f});
|
||||||
|
|
||||||
|
EXPECT_NEAR(proj->x, 1263.538, 0.001f);
|
||||||
|
EXPECT_NEAR(proj->y, 547.061f, 0.001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, CameraSetAndGetFov)
|
||||||
|
{
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
|
||||||
|
|
||||||
|
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 90.f);
|
||||||
|
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||||
|
|
||||||
|
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, CameraSetAndGetOrigin)
|
||||||
|
{
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
|
||||||
|
|
||||||
|
EXPECT_EQ(cam.get_origin(), omath::Vector3<float>{});
|
||||||
|
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||||
|
|
||||||
|
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||||
|
}
|
||||||
|
TEST(unit_test_frostbite_engine, loook_at_random_all_axis)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||||
|
|
||||||
|
std::size_t failed_points = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||||
|
|
||||||
|
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cam.look_at(position_to_look);
|
||||||
|
|
||||||
|
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||||
|
|
||||||
|
EXPECT_TRUE(projected_pos.has_value());
|
||||||
|
|
||||||
|
if (!projected_pos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::abs(projected_pos->x - 0.f) >= 0.0001f || std::abs(projected_pos->y - 0.f) >= 0.0001f)
|
||||||
|
failed_points++;
|
||||||
|
}
|
||||||
|
EXPECT_LE(failed_points, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, loook_at_random_x_axis)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||||
|
|
||||||
|
std::size_t failed_points = 0;
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
const auto position_to_look = omath::Vector3<float>{dist(gen), 0.f, 0.f};
|
||||||
|
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cam.look_at(position_to_look);
|
||||||
|
|
||||||
|
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||||
|
|
||||||
|
EXPECT_TRUE(projected_pos.has_value());
|
||||||
|
|
||||||
|
if (!projected_pos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::abs(projected_pos->x - 0.f) >= 0.001f || std::abs(projected_pos->y - 0.f) >= 0.001f)
|
||||||
|
failed_points++;
|
||||||
|
}
|
||||||
|
EXPECT_LE(failed_points, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, loook_at_random_y_axis)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||||
|
|
||||||
|
std::size_t failed_points = 0;
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||||
|
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cam.look_at(position_to_look);
|
||||||
|
|
||||||
|
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||||
|
|
||||||
|
EXPECT_TRUE(projected_pos.has_value());
|
||||||
|
|
||||||
|
if (!projected_pos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||||
|
failed_points++;
|
||||||
|
}
|
||||||
|
EXPECT_LE(failed_points, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unit_test_frostbite_engine, loook_at_random_z_axis)
|
||||||
|
{
|
||||||
|
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||||
|
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||||
|
|
||||||
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||||
|
auto cam = omath::frostbite_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||||
|
|
||||||
|
std::size_t failed_points = 0;
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||||
|
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cam.look_at(position_to_look);
|
||||||
|
|
||||||
|
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||||
|
|
||||||
|
EXPECT_TRUE(projected_pos.has_value());
|
||||||
|
|
||||||
|
if (!projected_pos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||||
|
failed_points++;
|
||||||
|
}
|
||||||
|
EXPECT_LE(failed_points, 100);
|
||||||
|
}
|
||||||
@@ -87,9 +87,9 @@ TEST(unit_test_unity_engine, Project)
|
|||||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||||
|
|
||||||
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
|
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
|
||||||
const auto proj = cam.world_to_screen({5.f, 3, 10.f});
|
const auto proj = cam.world_to_screen<omath::unity_engine::Camera::ScreenStart::BOTTOM_LEFT_CORNER>({10.f, 3, 10.f});
|
||||||
|
|
||||||
EXPECT_NEAR(proj->x, 951.769f, 0.001f);
|
EXPECT_NEAR(proj->x, 1263.538, 0.001f);
|
||||||
EXPECT_NEAR(proj->y, 547.061f, 0.001f);
|
EXPECT_NEAR(proj->y, 547.061f, 0.001f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -214,3 +214,20 @@ TEST(UnitTestMatStandalone, Enverse)
|
|||||||
|
|
||||||
EXPECT_EQ(mv, m.inverted());
|
EXPECT_EQ(mv, m.inverted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, Equanity)
|
||||||
|
{
|
||||||
|
constexpr omath::Vector3<float> left_handed = {0, 2, 10};
|
||||||
|
constexpr omath::Vector3<float> right_handed = {0, 2, -10};
|
||||||
|
|
||||||
|
auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000);
|
||||||
|
auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000);
|
||||||
|
|
||||||
|
auto ndc_left_handed = proj_left_handed * omath::mat_column_from_vector(left_handed);
|
||||||
|
auto ndc_right_handed = proj_right_handed * omath::mat_column_from_vector(right_handed);
|
||||||
|
|
||||||
|
ndc_left_handed /= ndc_left_handed.at(3, 0);
|
||||||
|
ndc_right_handed /= ndc_right_handed.at(3, 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(ndc_left_handed, ndc_right_handed);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
|
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
|
||||||
|
#include <omath/engines/source_engine/traits/camera_trait.hpp>
|
||||||
TEST(UnitTestPrediction, PredictionTest)
|
TEST(UnitTestPrediction, PredictionTest)
|
||||||
{
|
{
|
||||||
constexpr omath::projectile_prediction::Target target{
|
constexpr omath::projectile_prediction::Target target{
|
||||||
@@ -10,8 +10,9 @@ TEST(UnitTestPrediction, PredictionTest)
|
|||||||
const auto viewPoint =
|
const auto viewPoint =
|
||||||
omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).maybe_calculate_aim_point(proj, target);
|
omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).maybe_calculate_aim_point(proj, target);
|
||||||
|
|
||||||
const auto [pitch, yaw, _] = proj.m_origin.view_angle_to(viewPoint.value()).as_tuple();
|
|
||||||
|
|
||||||
EXPECT_NEAR(42.547142, pitch, 0.01f);
|
const auto [pitch, yaw, _] =omath::source_engine::CameraTrait::calc_look_at_angle(proj.m_origin, viewPoint.value());
|
||||||
EXPECT_NEAR(-1.181189, yaw, 0.01f);
|
|
||||||
|
EXPECT_NEAR(-42.547142, pitch.as_degrees(), 0.01f);
|
||||||
|
EXPECT_NEAR(-1.181189, yaw.as_degrees(), 0.01f);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user