Compare commits

...

15 Commits

Author SHA1 Message Date
ed8afb02a1 Merge pull request #90 from orange-cpp/feature/ndc_invalid_calc_fix
Fixes NDC calculation and updates formulas
2025-10-21 04:45:07 +03:00
d86695fad7 nuked not needed test 2025-10-21 04:38:43 +03:00
570c035f27 added second method of w2s 2025-10-21 04:38:43 +03:00
5657282577 Fixes incorrect NDC calculation and updates formulas
Corrects the NDC calculation in `world_to_screen` to improve accuracy.
Replaces custom perspective projection matrix calculation with `omath::mat_perspective_right_handed` for correctness and consistency.
Updates test cases and provides debugging information by printing view and projection matrices.
Addresses an issue in the feature/ndc_invalid_calc_fix branch.
2025-10-21 04:38:43 +03:00
551ac62075 Added TF2 into gallery 2025-10-19 04:00:20 +03:00
1b1be48ee6 Merge pull request #89 from luadebug/wasm
Fix pattern scan range check to use end() instead of cend()
2025-10-17 15:27:03 +03:00
Saikari
1f9ea136b0 Fix pattern scan range check to use end() instead of cend() 2025-10-16 19:47:27 +03:00
8dadb22e75 Removes ReSharper disable comments
Removes the `ReSharper disable CppInconsistentNaming` comments
from the header file.
2025-10-14 13:23:09 +03:00
8dd9860aa1 Adds PE pattern scan utility
Includes a new utility for scanning PE patterns.
2025-10-14 13:20:14 +03:00
9a0470f781 Merge pull request #88 from orange-cpp/feaute/more_support_for_hash
Adds hash support for Vector2, Vector3, and Vector4
2025-10-14 13:08:28 +03:00
eb8688c90c Unifies orthographic matrix generation
Consolidates the generation of left-handed and right-handed orthographic matrices into a shared implementation to reduce code duplication.
2025-10-14 13:06:23 +03:00
9f2f619a21 Adds hash support for Vector2, Vector3, and Vector4
Implements `std::hash` specialization for `omath::Vector2`, `omath::Vector3`, and `omath::Vector4` with float components.

This enables usage of these vector types as keys in hash-based containers, such as `std::unordered_map` and `std::unordered_set`.
2025-10-14 13:00:28 +03:00
568883ff1c Merge pull request #87 from orange-cpp/feature/no_win_api
Removes Windows-specific API dependencies for pattern scanning
2025-10-13 14:25:03 +03:00
97003b953a Update README.md 2025-10-13 14:24:53 +03:00
5646654317 Removes Windows-specific API dependencies for pattern scanning
Replaces calls to Windows API functions (GetModuleHandleA) with a void pointer parameter.

Simplifies pattern scanning for loaded modules by removing Windows-specific code and replacing it with a generic approach.
2025-10-13 14:17:30 +03:00
14 changed files with 148 additions and 53 deletions

BIN
.github/images/showcase/tf2.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

View File

@@ -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

View File

@@ -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
{ {

View File

@@ -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)
{ {

View File

@@ -273,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;

View File

@@ -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)
{ {

View File

@@ -88,4 +88,5 @@
#include "omath/rev_eng/internal_rev_object.hpp" #include "omath/rev_eng/internal_rev_object.hpp"
// Utility // Utility
#include "omath/utility/pattern_scan.hpp" #include "omath/utility/pattern_scan.hpp"
#include "omath/utility/pe_pattern_scan.hpp"

View File

@@ -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

View File

@@ -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>>

View File

@@ -19,7 +19,7 @@ namespace omath
{ {
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]]

View File

@@ -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

View File

@@ -7,9 +7,6 @@
#include <span> #include <span>
#include <stdexcept> #include <stdexcept>
#include <variant> #include <variant>
#ifdef _WIN32
#include <Windows.h>
#endif
// Internal PE shit defines // Internal PE shit defines
// Big thx for linuxpe sources as ref // Big thx for linuxpe sources as ref
@@ -206,6 +203,26 @@ namespace
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)
{ {
@@ -286,35 +303,37 @@ 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;
// ReSharper disable once CppTooWideScopeInitStatement const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
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,

View File

@@ -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);
} }

View File

@@ -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);
}