Compare commits

...

128 Commits

Author SHA1 Message Date
7d194a5c36 Merge pull request #95 from orange-cpp/pathfinding_improvement
removed brackets
2025-10-30 05:44:00 +03:00
eec34c1efb removed brackets
Initial plan

Initial exploration and analysis complete

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

Optimize performance: A* pathfinding, Vector3 hash, pattern scanner, AVX2 code, and serialization

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

Add bounds check for navigation mesh serialization

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

Document serialization limitation for large neighbor counts

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

Add _codeql_build_dir to gitignore

Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>

Removes codeql detected source root

Eliminates the automatically generated file that was causing issues.

This file was added by codeql and no longer needed.

revert
cleaned up gitignore

moved to anon namespace

Improves navigation mesh serialization and clamping

Ensures correct serialization of navigation meshes by clamping neighbor counts to prevent data corruption when exceeding uint16_t limits.

Updates data types to `std::uint8_t` and `std::size_t` for consistency.
Uses `std::copy_n` instead of `std::memcpy` for deserialization.
2025-10-30 05:38:58 +03:00
765d5e7216 fixed typo 2025-10-30 05:37:34 +03:00
7cb8a4de52 Clarifies release process for stable builds
Explains that changes merged into master won't reach stable users unless the `stable` tag is updated.
2025-10-28 01:21:41 +03:00
d2fbc286b1 Merge pull request #93 from orange-cpp/feaure/small_improvement
removed useless option
2025-10-28 01:19:21 +03:00
64385757af fix 2025-10-28 01:15:36 +03:00
ea7b812645 removed 2025-10-28 01:11:02 +03:00
b214cdf3a1 removed useless option 2025-10-28 01:09:47 +03:00
dccc12ee30 added some comments 2025-10-27 11:25:31 +03:00
60e744978c force disabled tests 2025-10-27 11:22:24 +03:00
495a2a80e4 Merge pull request #92 from orange-cpp/feature/projection_utility
added vcpkg integration
2025-10-27 11:11:28 +03:00
6fbc010fa1 considered to switch to v4 2025-10-27 11:05:55 +03:00
c8f77de4f2 updated version 2025-10-27 10:59:30 +03:00
5c2d09b175 patch 2025-10-27 10:58:26 +03:00
b3646ab708 Adds default and artifact registries
Configures the default Vcpkg registry and adds an artifact registry
for the microsoft catalog. This enables the tool to find and use
pre-built packages from the Microsoft catalog.
2025-10-27 10:57:57 +03:00
d751eaf132 Adds Darwin build presets with Vcpkg support
Adds new CMake presets for Darwin platforms, including debug and release configurations with optional Vcpkg integration.
This allows for easier builds on Darwin systems utilizing pre-built libraries from Vcpkg.
2025-10-27 09:57:12 +03:00
62e7ccb054 Update CMake configuration for Vcpkg integration and feature enablement.
Enables features and sets build configurations via Vcpkg manifest.
Adds new presets for Windows and Linux debug/release builds using Vcpkg.
Conditionally enables features (imgui, avx2, tests, benchmark) based on Vcpkg manifest features.
2025-10-27 09:55:49 +03:00
4d9e055bb3 Fixes invalid NT header check in variant
Ensures the NT header signature check uses a capture to avoid potential issues with variable scope.
2025-10-27 09:22:00 +03:00
9be7ca886d Disables Vcpkg build override
Disables the automatic override of build options by Vcpkg.

This prevents unintended consequences when using Vcpkg and allows for more control over the build process.
2025-10-27 09:19:51 +03:00
30568f3633 Disables tests and benchmarks by default for VCPKG
Changes the default state of `OMATH_BUILD_TESTS` and `OMATH_BUILD_BENCHMARK` to OFF when built via VCPKG.

Previously, these flags were inherited from the project's top level. This change ensures that these are explicitly enabled via VCPKG manifest features, providing better control over build configuration.
2025-10-27 09:19:09 +03:00
5f22499b66 Links tests to gtest when available
Conditionally links the test target to gtest when it is available,
rather than requiring the OMATH_BUILD_VIA_VCPKG flag to be false.
This allows for a more flexible test setup.
2025-10-27 09:05:40 +03:00
f75afb8354 fix 2025-10-27 08:59:42 +03:00
e38df8bd23 Removes baseline from omath vcpkg.json
Eliminates the `builtin-baseline` setting from the omath vcpkg.json file.
This setting is no longer necessary.
2025-10-27 08:56:37 +03:00
ae347c8509 fix 2025-10-27 08:51:58 +03:00
ee40979a2d fix 2025-10-27 08:41:22 +03:00
69d0b7b829 fix 2025-10-27 08:37:55 +03:00
490ccfe983 fix 2025-10-27 08:36:48 +03:00
5630c2708e Update build system and enable VCPKG
Migrates to CMake presets and enables VCPKG to manage dependencies.
Removes explicit submodule configuration.
Updates benchmark and googletest to be integrated or linked properly.
The goal is to ease the build process and reduce complexity related to linking and dependency management.
2025-10-27 08:34:05 +03:00
ed7220dc9c Configures CMake for Vcpkg integration
Sets up CMake presets to utilize the Vcpkg toolchain.

Specifies the Vcpkg root directory and manifest features.

Defines the installation directory for Vcpkg packages.

Forces the usage of Ninja as the make program.
2025-10-27 08:11:13 +03:00
5e4fae9e42 Enables Vcpkg usage for CMake builds
Configures CMake to utilize vcpkg for dependency management on both Linux and Windows platforms.
This ensures consistent build environments across different operating systems and simplifies the integration of external libraries.
2025-10-27 08:07:25 +03:00
063f43e74c fix 2025-10-27 08:03:42 +03:00
171b4ca3da Adds Vcpkg setup to CI workflows
Adds vcpkg setup for Arch Linux and Windows CI jobs.

This ensures consistent dependency management and builds via Vcpkg for both platforms and enables OMath to build via vcpkg.
Clones the vcpkg repository and bootstraps it during the job execution.
2025-10-27 08:00:53 +03:00
878e3358c0 Adds vcpkg integration and updates build configuration
Configures CMakePresets.json to utilize vcpkg for dependency management.
Adds support for building with vcpkg.

Adds error message for missing VCPKG_ROOT environment variable.
Adds explicit VCPKG_MANIFEST_FEATURES and VCPKG_INSTALLED_DIR to CMakePresets.json.
Adds benchmark dependency to vcpkg.json.
2025-10-27 07:53:53 +03:00
81aef68143 Adds support for tests and benchmarks via Vcpkg features
Enables building unit tests using GTest and benchmarks using Benchmark,
through Vcpkg features.

Adds `tests` and `benchmark` features to `vcpkg.json`,
and adds corresponding CMake logic to control their build based on
Vcpkg manifest features.
2025-10-27 06:42:43 +03:00
e2a37f2c81 Fix formatting and spacing in LICENSE file
Corrected formatting and removed extra spaces in the LICENSE file.
2025-10-27 02:32:06 +03:00
69575c1cb3 added additional check 2025-10-23 06:43:09 +03:00
8adf5db409 added vcpkg manifest file 2025-10-23 06:35:22 +03:00
2c7e443f52 added contained type alias 2025-10-23 06:26:57 +03:00
6ad4ef29e9 fix 2025-10-23 01:08:19 +03:00
8feb805067 Remove 'future' from affiliation clause in LICENSE 2025-10-23 01:00:40 +03:00
816da38987 added frostbite into global header 2025-10-23 00:55:49 +03:00
0ba795c767 added Frostbite into readme 2025-10-23 00:50:35 +03:00
88b709f531 deleted not needed header 2025-10-23 00:49:54 +03:00
a7eacb529e updated comments 2025-10-23 00:48:54 +03:00
5a4026a4fc Merge pull request #91 from orange-cpp/feature/frostbite_engine
Defines constants for Frostbite engine
2025-10-23 00:18:07 +03:00
404c7de594 added frostbite sources 2025-10-23 00:08:17 +03:00
f26f48cc53 Defines constants for Frostbite engine
Introduces a constants header file for the Frostbite engine,
including common vectors, matrices, and angle types.
This provides a centralized location for defining and accessing
essential mathematical constants used throughout the engine.
2025-10-21 04:56:49 +03:00
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
ee54e3de34 Merge pull request #86 from orange-cpp/feature/improved_pe_scanner_interface
Feature/improved pe scanner interface
2025-10-12 20:20:28 +03:00
7b0af9cf66 Removes unnecessary code in PE scanner
Simplifies the PePatternScanner class by removing extraneous code.
This cleans up the codebase and improves readability.
2025-10-12 20:00:52 +03:00
563ae0a656 Moves namespace declaration to end of file
Refactors the source file layout to improve readability and consistency.
Moves the namespace declaration to the end of the file.
2025-10-12 19:59:47 +03:00
b9e2307d7a Organizes PE scanner code into namespaces
Refactors the PE scanner implementation to group related definitions and functions within namespaces.

This improves code organization and readability, particularly for internal PE handling and scanning logic.

The included link to the `linux-pe` repository served as a reference during this refactoring.
2025-10-12 19:57:47 +03:00
cd0a864e7c Refactors PE scanner to eliminate redundant section extraction
Simplifies the PE pattern scanner by removing the redundant `extract_section_from_pe_file` function.

The extracted data is now returned directly from a new `ExtractedSection` struct within the main scanning function, streamlining the code and reducing duplication. This improves readability and maintainability of the PE scanner.
2025-10-12 19:53:41 +03:00
5c30f57c4c Merge pull request #85 from orange-cpp/feature/hide_pe_defs
Feature/hide pe defs
2025-10-12 19:46:22 +03:00
3dcd033616 Removes redundant NtHeaderVariant field declarations
Simplifies NtHeaderVariant structure by removing redundant field declarations.
This improves code readability and reduces unnecessary code duplication.
2025-10-12 19:43:29 +03:00
f10dc60772 Removes redundant NtHeaderVariant declaration
Moves the `NtHeaderVariant` definition outside the unnamed namespace,
to avoid repetition and improve code consistency.
This change is part of the ongoing work on feature/hide_pe_defs.
2025-10-12 19:42:53 +03:00
37f624956b Removes PE definition files
Removes the PE definition files and related functions as they are no longer needed.
2025-10-12 19:41:18 +03:00
20dc4e6730 Updates omath version to 3.9.2 2025-10-11 17:22:16 +03:00
f6c607d84c Uses source engine camera trait for view angle calculation
Replaces the custom `view_angle_to` function with `omath::source_engine::CameraTrait::calc_look_at_angle` for vector3 view angle calculations.
This change aligns with source engine conventions and improves code consistency.
2025-10-11 15:46:52 +03:00
81ed5f80d7 Merge pull request #84 from luadebug/patch-1
internal_rev_object.hpp: do not use __fastcall for non-Windows platforms
2025-10-10 07:47:25 +03:00
Saikari
e385686323 Update internal_rev_object.hpp 2025-10-09 21:34:19 +03:00
086eda4ee3 Merge pull request #82 from orange-cpp/feature/pe_scanner
Updates PE header structure for x64
2025-10-09 20:45:21 +03:00
9419e390da Allows specifying target section for file scan
Enables users to specify the target section name when scanning a PE file for a pattern.
This provides more flexibility in locating patterns within a PE file, as it's not limited to the ".text" section.
2025-10-09 20:42:03 +03:00
d919600ac2 Removes unused path parameter from function.
Simplifies `extract_section_from_pe_file` by removing the unused path parameter.
This clarifies the function's purpose and improves readability.
2025-10-09 20:36:10 +03:00
11681ac601 Refactors PE header parsing for improved robustness
Simplifies PE header reading and validation logic, extracting common functionality into helper functions.

Introduces `get_nt_header_from_file` to handle both x86 and x64 PE headers.

Adds validation checks for both DOS and NT headers to ensure file integrity.

Improves code readability and maintainability by reducing redundancy in header parsing.

Relates to feature/pe_scanner
2025-10-09 20:32:36 +03:00
6c5152297a Uses correct calling convention for virtual methods
Adjusts the virtual method calling convention based on the compiler (_MSC_VER).
This ensures compatibility and correct behavior on different platforms.
2025-10-09 20:08:04 +03:00
547f64e4c4 Removes platform-specific error handling
Simplifies pattern scanner logic by removing conditional compilation for non-Windows platforms.

The error handling previously thrown on non-Windows platforms was unnecessary as this functionality is not intended for those systems. This change streamlines the code and removes a misleading error message.
2025-10-09 20:03:43 +03:00
3129e32f0c Uses std::uint16_t for SubsystemId enum
Ensures consistency by using `std::uint16_t` instead of `uint16_t` for the `SubsystemId` enum.

Relates to feature/pe_scanner
2025-10-09 20:01:34 +03:00
72b54e9673 Removes PE scanner test code
Eliminates the PE scanner test code from the unit tests.

This removes a test that appears to be broken or no longer relevant, since the test directly references a file path.
2025-10-09 19:58:58 +03:00
2ff291b255 Supports broader architectures in PE scanner
Updates the PE scanner implementation to support both 32-bit and 64-bit architectures.
Leverages `std::variant` and a generic `ImageNtHeaders` to abstract architecture-specific details.
Simplifies the logic for retrieving section data, generalizing the process for improved maintainability.
2025-10-09 19:58:19 +03:00
8eda1ce4bc Adds PE scanner infrastructure and data structures
Initializes infrastructure for PE file scanning.

Adds data structures for PE headers (DOS, optional, section),
including user-defined types for section characteristics.

Refactors existing pattern scanning code to utilize new PE data structures.

Adds basic parsing of PE headers.
2025-10-08 19:22:20 +03:00
e1b4375621 fixed for mac improved readability 2025-10-08 19:22:20 +03:00
d84259fdcc Adds PE file header definitions
Defines `DosHeader` and `FileHeader` structures to represent PE file header information.
Includes definitions for `MachineId` enum and `FileCharacteristics` union.
These definitions are prerequisite for PE file parsing and analysis.
2025-10-08 19:22:20 +03:00
d64c7ad756 Adds PE section extraction and pattern scanning
Adds functionality to extract a specific section from a PE file and scan for a given pattern within that section.

Introduces `extract_section_from_pe_file` to isolate a section, enabling more targeted pattern searches.
Overhauls `scan_for_pattern_in_file` to utilize extracted section data and improve accuracy.
2025-10-08 19:22:20 +03:00
710f91999f Adds scan functionality for PE files
Introduces a method to scan for patterns within specified PE files.
This facilitates searching for patterns outside of loaded modules.
2025-10-08 19:22:20 +03:00
f3fe0e3cee added pe pattern scan 2025-10-08 19:22:20 +03:00
c5c5c2e972 Clarifies build preset usage in INSTALL.md
Rephrases the explanation regarding build presets for clarity in the INSTALL.md file.
The text now more explicitly advises users on selecting appropriate presets.
2025-10-08 19:22:20 +03:00
a7cb056ce7 Moves PE headers file to omath directory
Organizes the project by relocating the PE headers file to the omath directory structure.
This improves code organization and maintainability.
2025-10-08 19:22:20 +03:00
dae1555ec4 added mkdoc 2025-10-08 19:22:19 +03:00
2c6ef1b8cc Defines PE header structure for x64
Introduces a structure for representing the DOS header
within a PE (Portable Executable) file for x64 architectures.
This definition enables easier parsing and manipulation of PE header information.
2025-10-08 19:22:19 +03:00
d70e8853e8 Add Kaspersky LLC to license restrictions 2025-10-08 17:48:24 +03:00
e35d64b486 Disables rvalue overload of scan_for_pattern
Prevents implicit conversions and unexpected behavior by deleting the rvalue overload of `scan_for_pattern`.
2025-10-06 15:05:04 +03:00
9868c832a1 Corrects function signature
Adjusts the `scan_for_pattern` function signature to correctly use `const std::string_view&`.
2025-10-06 14:46:40 +03:00
42e46f9921 added global header 2025-10-06 14:36:00 +03:00
e7ccc2ead0 added concept for iterators, reworked interface 2025-10-06 14:25:52 +03:00
170f969697 improved scanner interface 2025-10-06 14:21:52 +03:00
131fd891b0 added unlikely 2025-10-06 14:04:43 +03:00
a5396b72cb Merge pull request #81 from orange-cpp/feature/pattern_scan
Improves pattern scanning functionality and adds corner case tests
2025-10-05 15:59:59 +03:00
ec876ea292 Includes header for fixed-width integer types
Adds `#include ` to ensure platform-independent use of fixed-width integer types.
2025-10-05 15:56:35 +03:00
8021050fad Uses std::ranges::find for pattern scanning
Replaces `std::find` with `std::ranges::find` for improved code consistency and potentially better performance when dealing with ranges.
2025-10-05 15:54:54 +03:00
bd585b5412 Uses parsed pattern size in pattern scan
Updates the pattern scan loop to iterate over the size of the parsed pattern, ensuring correct iteration when using parsed patterns.
2025-10-05 14:14:31 +03:00
06f9a8c9ee Adds pattern scanning functionality and corner case tests
Implements a pattern scanning feature that allows searching for byte patterns within a byte range.

Adds `scan_for_pattern` method to `PatternScanner` to locate a pattern within a byte span.

Adds corner case tests to verify functionality and handle invalid inputs.
2025-10-05 06:37:20 +03:00
160b51da94 Adds corner case tests for pattern scanning
Adds new test cases to cover additional scenarios for pattern scanning, including tests for leading/trailing whitespace and spacing variations to ensure robustness.
2025-10-04 18:43:05 +03:00
064edf9ef1 Handles empty pattern strings
Skips processing when encountering an empty string slice during pattern scanning.
This prevents unexpected behavior and potential errors when the pattern string contains sections that result in an empty byte string.
2025-10-04 18:33:57 +03:00
f17d36dcd3 Adds pattern scanning functionality
Implements a pattern scanner for byte sequence parsing.

Introduces `omath::PatternScanner` to parse pattern strings, which represent byte sequences.
Adds support for wildcard characters ('?' and '?') to represent optional bytes in the pattern.
Includes unit tests for basic read operations to ensure proper functionality.
2025-10-04 18:30:43 +03:00
ec4f9f6c90 Merge pull request #80 from orange-cpp/feature/rev_eng
Feature: Reverse Engineering classes
2025-10-04 10:09:07 +03:00
cbee8c2c95 finished test 2025-10-04 10:04:34 +03:00
dc6edbb67f update global header 2025-10-04 09:52:14 +03:00
74381eda5c added external class 2025-10-04 09:47:48 +03:00
1ef7833bd9 reordored omath headers 2025-10-03 13:51:53 +03:00
c10386f3f6 added rev_object 2025-10-03 13:43:47 +03:00
413cef4f23 version update 2025-10-03 13:16:48 +03:00
867cee41c3 femoved useless file 2025-10-03 13:14:11 +03:00
990fe78a33 fixed wrong spam of command option into build log 2025-10-03 12:40:18 +03:00
1efdb50f73 Merge pull request #78 from luadebug/patch-1
CMakeLists.txt: support AVX2 detection
2025-10-01 03:10:24 +03:00
Saikari
86fea065e7 CMakeLists.txt: do not use /ARCH:AVX since we have /ARCH:AVX2 already 2025-09-30 23:40:07 +03:00
Saikari
ac046aae6c Update CMakeLists.txt 2025-09-30 23:18:00 +03:00
Saikari
9646054877 CMakeLists.txt: support AVX2 detection for https://github.com/xmake-io/xmake-repo/pull/8277 2025-09-30 21:40:25 +03:00
6334002639 forgot linux macos 2025-09-29 11:23:28 +03:00
72e0c0c90b removed useless fields of C compiler 2025-09-29 11:21:43 +03:00
2f2a5a00c4 added another clangformat 2025-09-27 10:55:05 +03:00
c394993418 Add documentation link to README 2025-09-27 10:40:54 +03:00
476048583d added version file update cmake version 2025-09-27 10:38:31 +03:00
76ae67c968 Revise features and clean up README
Updated features section and removed usage examples.
2025-09-27 10:35:14 +03:00
89 changed files with 1806 additions and 575 deletions

View File

@@ -56,7 +56,7 @@ SpaceBeforeParensOptions:
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

View File

@@ -19,27 +19,32 @@ jobs:
name: Arch Linux (Clang)
runs-on: ubuntu-latest
container: archlinux:latest
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps:
- name: Install basic tool-chain with pacman
shell: bash
run: |
pacman -Sy --noconfirm archlinux-keyring
pacman -Syu --noconfirm --needed \
git base-devel clang cmake ninja
git base-devel clang cmake ninja zip unzip fmt
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
run: cmake --preset linux-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
- name: Build
shell: bash
run: cmake --build cmake-build/build/linux-release --target unit_tests omath
run: cmake --build cmake-build/build/linux-release-vcpkg --target unit_tests omath
- name: Run unit_tests
shell: bash
@@ -47,12 +52,14 @@ jobs:
##############################################################################
# 2) Windows MSVC / Ninja
##############################################################################
##############################################################################
# 2) Windows MSVC / Ninja
##############################################################################
windows-build-and-test:
name: Windows (MSVC)
runs-on: windows-latest
env:
OMATH_BUILD_VIA_VCPKG: ON
steps:
- name: Checkout repository (with sub-modules)
@@ -68,11 +75,11 @@ jobs:
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
run: cmake --preset windows-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
- name: Build
shell: bash
run: cmake --build cmake-build/build/windows-release --target unit_tests omath
run: cmake --build cmake-build/build/windows-release-vcpkg --target unit_tests omath
- name: Run unit_tests.exe
shell: bash

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "extlibs/googletest"]
path = extlibs/googletest
url = https://github.com/google/googletest.git
[submodule "extlibs/benchmark"]
path = extlibs/benchmark
url = https://github.com/google/benchmark.git

4
.idea/editor.xml generated
View File

@@ -201,7 +201,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
@@ -215,7 +215,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />

2
.idea/vcs.xml generated
View File

@@ -2,7 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/benchmark" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
</component>
</project>

View File

@@ -1,38 +1,67 @@
cmake_minimum_required(VERSION 3.26)
project(omath VERSION 3.5.0 LANGUAGES CXX)
project(omath VERSION 4.0.0 LANGUAGES CXX)
include(CMakePackageConfigHelpers)
include(CheckCXXCompilerFlag)
if (MSVC)
check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2)
else ()
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
endif ()
option(OMATH_BUILD_TESTS "Build unit tests" ${PROJECT_IS_TOP_LEVEL})
option(OMATH_BUILD_BENCHMARK "Build benchmarks" ${PROJECT_IS_TOP_LEVEL})
option(OMATH_BUILD_TESTS "Build unit tests" OFF)
option(OMATH_BUILD_BENCHMARK "Build benchmarks" OFF)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ${COMPILER_SUPPORTS_AVX2})
option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF)
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF)
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" OFF)
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" ON)
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
if (VCPKG_MANIFEST_FEATURES)
foreach (omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
if (omath_feature STREQUAL "imgui")
set(OMATH_IMGUI_INTEGRATION ON)
elseif (omath_feature STREQUAL "avx2")
set(OMATH_USE_AVX2 ${COMPILER_SUPPORTS_AVX2})
elseif (omath_feature STREQUAL "tests")
set(OMATH_BUILD_TESTS ON)
elseif (omath_feature STREQUAL "benchmark")
set(OMATH_BUILD_BENCHMARK ON)
endif ()
endforeach ()
endif ()
if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
message(WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
endif ()
if (${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
message(STATUS "[${PROJECT_NAME}]: Building using vcpkg ${OMATH_BUILD_VIA_VCPKG}")
endif ()
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")
if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
else ()
@@ -72,7 +101,7 @@ if (OMATH_SUPRESS_SAFETY_CHECKS)
endif ()
if (OMATH_ENABLE_LEGACY)
target_compile_options(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY)
endif ()
set_target_properties(${PROJECT_NAME} PROPERTIES
@@ -93,15 +122,18 @@ if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
)
endif ()
if (OMATH_USE_AVX2 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${PROJECT_NAME} PUBLIC -mavx2 -mavx -mfma)
if (OMATH_USE_AVX2)
if (MSVC)
target_compile_options(${PROJECT_NAME} PUBLIC /arch:AVX2)
elseif (EMSCRIPTEN)
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
endif ()
endif ()
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
add_subdirectory(extlibs)
if (OMATH_BUILD_TESTS)
add_subdirectory(tests)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)

View File

@@ -8,8 +8,8 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe"
"CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_MAKE_PROGRAM": "Ninja"
},
"condition": {
"type": "equals",
@@ -17,6 +17,17 @@
"rhs": "Windows"
}
},
{
"name": "windows-base-vcpkg",
"hidden": true,
"inherits": "windows-base",
"cacheVariables": {
"OMATH_BUILD_VIA_VCPKG": "ON",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed",
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
}
},
{
"name": "windows-debug",
"displayName": "Debug",
@@ -25,6 +36,23 @@
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-debug-vcpkg",
"displayName": "Debug",
"inherits": "windows-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-release-vcpkg",
"displayName": "Release",
"inherits": "windows-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"OMATH_BUILD_VIA_VCPKG": "ON"
}
},
{
"name": "windows-release",
"displayName": "Release",
@@ -40,8 +68,8 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_MAKE_PROGRAM": "ninja"
},
"condition": {
"type": "equals",
@@ -49,6 +77,17 @@
"rhs": "Linux"
}
},
{
"name": "linux-base-vcpkg",
"hidden": true,
"inherits": "linux-base",
"cacheVariables": {
"OMATH_BUILD_VIA_VCPKG": "ON",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed",
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
@@ -57,6 +96,14 @@
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "linux-debug-vcpkg",
"displayName": "Linux Debug",
"inherits": "linux-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "linux-release",
"displayName": "Linux Release",
@@ -65,6 +112,14 @@
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-release-vcpkg",
"displayName": "Linux Release",
"inherits": "linux-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "darwin-base",
"hidden": true,
@@ -72,7 +127,6 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
},
"condition": {
@@ -89,6 +143,14 @@
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "darwin-debug-vcpkg",
"displayName": "Darwin Debug",
"inherits": "darwin-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "darwin-release",
"displayName": "Darwin Release",
@@ -96,6 +158,14 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "darwin-release-vcpkg",
"displayName": "Darwin Release",
"inherits": "darwin-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

View File

@@ -18,7 +18,7 @@ In order to send code back to the official OMath repository, you must first crea
account ([fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)) and
then [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) back to OMath.
OMath developement is performed on multiple branches. Changes are then pull requested into master. By default, changes
OMath development is performed on multiple branches. Changes are then pull requested into master. By default, changes
merged into master will not roll out to stable build users unless the `stable` tag is updated.
### 📜 Code-Style

View File

@@ -59,7 +59,7 @@ target("...")
cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target omath -j 6
```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
Use **\<platform\>-\<build configuration\>** preset to build suitable version for yourself. Like **windows-release** or **linux-release**.
| Platform Name | Build Config |
|---------------|---------------|

39
LICENSE
View File

@@ -1,7 +1,7 @@
Copyright (C) 2024-2025 Orange++ <orange_github@proton.me>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
@@ -16,13 +16,44 @@ freely, subject to the following restrictions:
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
4. If you are an employee, contractor, volunteer, representative,
or have any other affiliation (past, present, or future)
or have any other affiliation (past or present)
with any of the following entities:
* "Advertising Placement Services" LLC
* "NEW SOLUTIONS VERTICALS" LLC
* "Autoexpert" LLC
* "Creditit" LLC
* "Yandex.Taxi" LLC
* "Yandex.Eda" LLC
* "Yandex.Lavka" LLC
* "Yandex.Telecom" LLC
* "Yandex.Cloud" LLC
* "Micromobility" LLC
* "MM-Tech" LLC
* "Carsharing" LLC
* "Yandex.Drive" LLC
* "EDADIL PROMO" LLC
* "Kinopoisk" LLC
* "Yandex.Music" LLC
* "Refueling (Yandex.Zapravki)" LLC
* "Yandex.Pay" LLC
* "Financial and Payment Technologies" LLC
* "Yandex.Delivery" LLC
* "Delivery Club" LLC
* "Yandex.Check" LLC
* "SMB-Service" LLC
* "ADV-TECH" LLC
* "Yandex Fantech" LLC
* "Yandex Smena" LLC
* "Market.Operations" LLC
* "Yandex.Market" LLC
* "ID Tech" LLC
* "Yandex.Crowd" LLC
* "Yandex" LLC
* "Rutube" LLC
* "Kaspersky" LLC
Or if you represent or are associated with any legal, organizational, or
professional entity providing services to or on behalf of the aforementioned entities:
You are expressly forbidden from accessing, using, modifying, distributing, or
interacting with the Software and its source code in any form. You must immediately
delete or destroy any physical or digital copies of the Software and/or
interacting with the Software and its source code in any form. You must immediately
delete or destroy any physical or digital copies of the Software and/or
its source code, including any derivative works, tools, or information obtained from the Software.

View File

@@ -22,6 +22,7 @@ It provides the latest features, is highly customizable, has all for cheat devel
**[<kbd><br>Install<br></kbd>][INSTALL]**
**[<kbd><br>Examples<br></kbd>][EXAMPLES]**
**[<kbd><br>Documentation<br></kbd>][DOCUMENTATION]**
**[<kbd><br>Contribute<br></kbd>][CONTRIBUTING]**
**[<kbd><br>Donate<br></kbd>][SPONSOR]**
@@ -42,7 +43,7 @@ It provides the latest features, is highly customizable, has all for cheat devel
</a>
</div>
## 👁‍🗨 Features
# Features
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
- **Versatility**: Includes a wide array of mathematical functions and algorithms.
- **Ease of Use**: Simplified interface for convenient integration into various projects.
@@ -51,7 +52,11 @@ It provides the latest features, is highly customizable, has all for cheat devel
- **Collision Detection**: Production ready code to handle collision detection by using simple interfaces.
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
- **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, Frostbite, IWEngine and canonical OpenGL**.
- **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>
# Gallery
<br>
@@ -70,60 +75,26 @@ It provides the latest features, is highly customizable, has all for cheat devel
![CS2 Preview]
<br>
![TF2 Preview]
<br>
<br>
</div>
## Supported Render Pipelines
| ENGINE | SUPPORT |
|----------|---------|
| Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| OpenGL | ✅YES |
| Unreal | ✅YES |
## Supported Operating Systems
| OS | SUPPORT |
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
## ❔ Usage
ESP example
```c++
omath::source_engine::Camera cam{localPlayer.GetCameraOrigin(),
localPlayer.GetAimPunch(),
{1920.f, 1080.f},
localPlayer.GetFieldOfView(),
0.01.f, 30000.f};
for (auto ent: apex_sdk::EntityList::GetAllEntities())
{
const auto bottom = cam.world_to_screen(ent.GetOrigin());
const auto top = cam.world_to_screen(ent.GetBonePosition(8) + omath::Vector3<float>{0, 0, 10});
const auto ent_health = ent.GetHealth();
if (!top || !bottom || ent_health <= 0)
continue;
// esp rendering...
}
```
## 💘 Acknowledgments
# 💘 Acknowledgments
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)
<!----------------------------------{ Images }--------------------------------->
[APEX Preview]: .github/images/showcase/apex.png
[BO2 Preview]: .github/images/showcase/cod_bo2.png
[CS2 Preview]: .github/images/showcase/cs2.jpeg
[TF2 Preview]: .github/images/showcase/tf2.jpg
<!----------------------------------{ Buttons }--------------------------------->
[INSTALL]: INSTALL.md
[DOCUMENTATION]: http://libomath.org
[CONTRIBUTING]: CONTRIBUTING.md
[EXAMPLES]: examples
[SPONSOR]: https://boosty.to/orangecpp/purchase/3568644?ssource=DIRECT&share=subscription_link

1
VERSION Normal file
View File

@@ -0,0 +1 @@
4.0.0

View File

@@ -11,5 +11,9 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
if (TARGET benchmark::benchmark) # Benchmark is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
else()
find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg package
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
endif ()

17
docs/index.md Normal file
View File

@@ -0,0 +1,17 @@
# Welcome to MkDocs
For full documentation visit [mkdocs.org](https://www.mkdocs.org).
## Commands
* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.
## Project layout
mkdocs.yml # The configuration file.
docs/
index.md # The documentation homepage.
... # Other markdown pages, images and other files.

View File

@@ -1,9 +0,0 @@
if (OMATH_BUILD_TESTS)
add_subdirectory(googletest)
endif ()
if (OMATH_BUILD_BENCHMARK)
set(BENCHMARK_ENABLE_TESTING OFF)
add_subdirectory(benchmark)
endif ()

View File

@@ -3,8 +3,8 @@
//
#pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
#include <array>
namespace omath::primitives

View File

@@ -3,8 +3,8 @@
//
#pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
#include <array>
namespace omath::primitives

View File

@@ -3,8 +3,8 @@
//
#pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
namespace omath::collision
{

View 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

View 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

View 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

View File

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

View File

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

View File

@@ -5,8 +5,8 @@
#pragma once
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::iw_engine
{

View File

@@ -5,8 +5,8 @@
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::opengl_engine
{

View File

@@ -5,8 +5,8 @@
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::source_engine
{

View File

@@ -6,8 +6,8 @@
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::unity_engine
{

View File

@@ -6,8 +6,8 @@
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
#include <omath/trigonometry/angle.hpp>
#include <omath/trigonometry/view_angles.hpp>
namespace omath::unreal_engine
{

View File

@@ -39,6 +39,7 @@ namespace omath
class Mat final
{
public:
using ContainedType = Type;
constexpr Mat() noexcept
{
clear();
@@ -666,8 +667,7 @@ namespace omath
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right,
const Type bottom, const Type top,
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept
{
return
@@ -680,9 +680,8 @@ namespace omath
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right,
const Type bottom, const Type top,
const Type near, const Type far) noexcept
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept
{
return
{

View File

@@ -2,7 +2,7 @@
// Created by Orange on 11/13/2024.
//
#pragma once
#include "linear_algebra/vector3.hpp"
#include "vector3.hpp"
namespace omath
{

View File

@@ -221,7 +221,7 @@ namespace omath
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec2 to_im_vec2() const noexcept
constexpr ImVec2 to_im_vec2() const noexcept
{
return {static_cast<float>(this->x), static_cast<float>(this->y)};
}
@@ -234,6 +234,21 @@ 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>
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
{

View File

@@ -4,7 +4,7 @@
#pragma once
#include "omath/angle.hpp"
#include "omath/trigonometry/angle.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include <cstdint>
#include <expected>
@@ -245,15 +245,6 @@ namespace omath
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]]
bool operator<(const Vector3& other) const noexcept
{
@@ -282,6 +273,7 @@ namespace omath
template<> struct std::hash<omath::Vector3<float>>
{
[[nodiscard]]
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{
std::size_t hash = 0;

View File

@@ -184,7 +184,7 @@ namespace omath
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec4 to_im_vec4() const noexcept
constexpr ImVec4 to_im_vec4() const noexcept
{
return {
static_cast<float>(this->x),
@@ -202,6 +202,22 @@ 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>
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
{

View File

@@ -6,8 +6,8 @@
#pragma once
// Basic math utilities
#include "omath/angles.hpp"
#include "omath/angle.hpp"
#include "omath/trigonometry/angles.hpp"
#include "omath/trigonometry/angle.hpp"
// Vector classes (in dependency order)
#include "omath/linear_algebra/vector2.hpp"
@@ -18,11 +18,11 @@
#include "omath/linear_algebra/mat.hpp"
// Color functionality
#include "omath/color.hpp"
#include "omath/utility/color.hpp"
// Geometric primitives
#include "omath/triangle.hpp"
#include "omath/view_angles.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/trigonometry/view_angles.hpp"
// 3D primitives
#include "omath/3d_primitives/box.hpp"
@@ -76,9 +76,25 @@
#include "omath/engines/unity_engine/traits/camera_trait.hpp"
#include "omath/engines/unity_engine/traits/pred_engine_trait.hpp"
//Frostbite Engine
#include "omath/engines/frostbite_engine/constants.hpp"
#include "omath/engines/frostbite_engine/formulas.hpp"
#include "omath/engines/frostbite_engine/camera.hpp"
#include "omath/engines/frostbite_engine/traits/camera_trait.hpp"
#include "omath/engines/frostbite_engine/traits/pred_engine_trait.hpp"
// Unreal Engine
#include "omath/engines/unreal_engine/constants.hpp"
#include "omath/engines/unreal_engine/formulas.hpp"
#include "omath/engines/unreal_engine/camera.hpp"
#include "omath/engines/unreal_engine/traits/camera_trait.hpp"
#include "omath/engines/unreal_engine/traits/pred_engine_trait.hpp"
// Reverse Engineering
#include "omath/rev_eng/external_rev_object.hpp"
#include "omath/rev_eng/internal_rev_object.hpp"
// Utility
#include "omath/utility/pattern_scan.hpp"
#include "omath/utility/pe_pattern_scan.hpp"

View File

@@ -22,9 +22,5 @@ namespace omath::pathfinding
static std::vector<Vector3<float>>
reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
const Vector3<float>& current) noexcept;
[[nodiscard]]
static auto get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept;
};
} // namespace omath::pathfinding

View File

@@ -7,8 +7,8 @@
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "omath/projection/error_codes.hpp"
#include <omath/trigonometry/angle.hpp>
#include <expected>
#include <omath/angle.hpp>
#include <type_traits>
#ifdef OMATH_BUILD_TESTS
@@ -54,6 +54,12 @@ namespace omath::projection
friend UnitTestProjection_Projection_Test;
#endif
public:
enum class ScreenStart
{
TOP_LEFT_CORNER,
BOTTOM_LEFT_CORNER,
};
~Camera() = default;
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
const FieldOfView& fov, const float near, const float far) noexcept
@@ -146,15 +152,22 @@ namespace omath::projection
return m_origin;
}
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
[[nodiscard]] std::expected<Vector3<float>, Error>
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())
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>
@@ -225,9 +238,8 @@ namespace omath::projection
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
{
/*
// NDC REPRESENTATION:
/*
^
| y
1 |
@@ -239,7 +251,39 @@ namespace omath::projection
-1 |
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};
[[nodiscard]] Vector3<float>
ndc_to_screen_position_from_top_left_corner(const Vector3<float>& ndc) const noexcept
{
/*
+------------------------>
| (0, 0)
|
|
|
|
|
|
*/
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
{
/*
^
|
|
|
|
|
|
| (0, 0)
+------------------------>
*/
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

View File

@@ -0,0 +1,35 @@
//
// Created by Vlad on 10/4/2025.
//
#pragma once
#include <cstddef>
#include <cstdint>
namespace omath::rev_eng
{
template<class ExternalMemoryManagementTrait>
class ExternalReverseEngineeredObject
{
public:
explicit ExternalReverseEngineeredObject(const std::uintptr_t addr): m_object_address(addr)
{
}
private:
std::uintptr_t m_object_address{};
protected:
template<class Type>
[[nodiscard]]
Type get_by_offset(const std::ptrdiff_t offset) const
{
return ExternalMemoryManagementTrait::read_memory(m_object_address+offset);
}
template<class Type>
void set_by_offset(const std::ptrdiff_t offset, const Type& value) const
{
return ExternalMemoryManagementTrait::write_memory(m_object_address+offset, value);
}
};
} // namespace omath::rev_eng

View File

@@ -0,0 +1,37 @@
//
// Created by Vlad on 8/8/2025.
//
#pragma once
#include <cstddef>
#include <cstdint>
namespace omath::rev_eng
{
class InternalReverseEngineeredObject
{
protected:
template<class Type>
[[nodiscard]] Type& get_by_offset(const std::ptrdiff_t offset)
{
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
}
template<class Type>
[[nodiscard]] const Type& get_by_offset(const std::ptrdiff_t offset) const
{
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
}
template<std::size_t id, class ReturnType>
ReturnType call_virtual_method(auto... arg_list)
{
#ifdef _MSC_VER
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
#else
using VirtualMethodType = ReturnType(*)(void*, decltype(arg_list)...);
#endif
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
}
};
} // namespace omath::rev_eng

View File

@@ -3,7 +3,7 @@
//
#pragma once
#include "omath/angles.hpp"
#include "omath/trigonometry/angles.hpp"
#include <algorithm>
#include <format>
#include <utility>

View File

@@ -4,7 +4,7 @@
#pragma once
#include "linear_algebra/vector4.hpp"
#include "omath/linear_algebra/vector4.hpp"
#include <cstdint>
namespace omath

View File

@@ -0,0 +1,78 @@
//
// Created by Vlad on 10/4/2025.
//
#pragma once
#include <expected>
#include <optional>
#include <span>
#include <string_view>
#include <vector>
// ReSharper disable CppInconsistentNaming
class unit_test_pattern_scan_read_test_Test;
class unit_test_pattern_scan_corner_case_1_Test;
class unit_test_pattern_scan_corner_case_2_Test;
class unit_test_pattern_scan_corner_case_3_Test;
class unit_test_pattern_scan_corner_case_4_Test;
// ReSharper restore CppInconsistentNaming
namespace omath
{
enum class PatternScanError
{
INVALID_PATTERN_STRING
};
class PatternScanner final
{
friend unit_test_pattern_scan_read_test_Test;
friend unit_test_pattern_scan_corner_case_1_Test;
friend unit_test_pattern_scan_corner_case_2_Test;
friend unit_test_pattern_scan_corner_case_3_Test;
friend unit_test_pattern_scan_corner_case_4_Test;
public:
[[nodiscard]]
static std::span<std::byte>::iterator scan_for_pattern(const std::span<std::byte>& range,
const std::string_view& pattern);
[[nodiscard]]
static std::span<std::byte>::iterator scan_for_pattern(std::span<std::byte>&& range,
const std::string_view& pattern) = delete;
template<class IteratorType>
requires std::input_or_output_iterator<std::remove_cvref_t<IteratorType>>
static IteratorType scan_for_pattern(const IteratorType& begin, const IteratorType& end,
const std::string_view& pattern)
{
const auto parsed_pattern = parse_pattern(pattern);
if (!parsed_pattern) [[unlikely]]
return end;
const auto whole_range_size = static_cast<std::ptrdiff_t>(std::distance(begin, end));
const std::ptrdiff_t scan_size = whole_range_size - static_cast<std::ptrdiff_t>(pattern.size());
for (std::ptrdiff_t i = 0; i < scan_size; i++)
{
bool found = true;
for (std::ptrdiff_t j = 0; j < static_cast<std::ptrdiff_t>(parsed_pattern->size()); j++)
{
found = parsed_pattern->at(j) == std::nullopt || parsed_pattern->at(j) == *(begin + i + j);
if (!found)
break;
}
if (found)
return begin + i;
}
return end;
}
private:
[[nodiscard]]
static std::expected<std::vector<std::optional<std::byte>>, PatternScanError>
parse_pattern(const std::string_view& pattern_string);
};
} // namespace omath

View File

@@ -0,0 +1,30 @@
//
// Created by Vlad on 10/7/2025.
//
#pragma once
#include <cstdint>
#include <filesystem>
#include <optional>
#include <string_view>
namespace omath
{
struct PeSectionScanResult
{
std::uint64_t virtual_base_addr;
std::uint64_t raw_base_addr;
std::ptrdiff_t target_offset;
};
class PePatternScanner final
{
public:
[[nodiscard]]
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const void* module_base_address,
const std::string_view& pattern);
[[nodiscard]]
static std::optional<PeSectionScanResult>
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");
};
} // namespace omath

1
mkdocs.yml Normal file
View File

@@ -0,0 +1 @@
site_name: My Docs

View 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

View 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

View File

@@ -25,7 +25,7 @@ namespace omath::unity_engine
}
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);
}
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,
const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
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},
};
return omath::mat_perspective_right_handed(field_of_view, aspect_ratio, near, far);
}
} // namespace omath::unity_engine

View File

@@ -4,9 +4,25 @@
#include "omath/pathfinding/a_star.hpp"
#include <algorithm>
#include <optional>
#include <queue>
#include <unordered_map>
#include <unordered_set>
namespace
{
struct OpenListNode final
{
omath::Vector3<float> position;
float f_cost;
[[nodiscard]]
bool operator>(const OpenListNode& other) const noexcept
{
return f_cost > other.f_cost;
}
};
}
namespace omath::pathfinding
{
struct PathNode final
@@ -37,23 +53,13 @@ namespace omath::pathfinding
std::ranges::reverse(path);
return path;
}
auto Astar::get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept
{
return std::ranges::min_element(open_list,
[&end_vertex](const auto& a, const auto& b)
{
const float fa = a.second.g_cost + a.first.distance_to(end_vertex);
const float fb = b.second.g_cost + b.first.distance_to(end_vertex);
return fa < fb;
});
}
std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end,
const NavigationMesh& nav_mesh) noexcept
{
std::unordered_map<Vector3<float>, PathNode> closed_list;
std::unordered_map<Vector3<float>, PathNode> open_list;
std::unordered_map<Vector3<float>, PathNode> node_data;
std::priority_queue<OpenListNode, std::vector<OpenListNode>, std::greater<>> open_list;
auto maybe_start_vertex = nav_mesh.get_closest_vertex(start);
auto maybe_end_vertex = nav_mesh.get_closest_vertex(end);
@@ -64,20 +70,27 @@ namespace omath::pathfinding
const auto start_vertex = maybe_start_vertex.value();
const auto end_vertex = maybe_end_vertex.value();
open_list.emplace(start_vertex, PathNode{std::nullopt, 0.f});
node_data.emplace(start_vertex, PathNode{std::nullopt, 0.f});
open_list.push({start_vertex, start_vertex.distance_to(end_vertex)});
while (!open_list.empty())
{
auto current_it = get_perfect_node(open_list, end_vertex);
auto current = open_list.top().position;
open_list.pop();
const auto current = current_it->first;
const auto current_node = current_it->second;
if (closed_list.contains(current))
continue;
auto current_node_it = node_data.find(current);
if (current_node_it == node_data.end())
continue;
const auto current_node = current_node_it->second;
if (current == end_vertex)
return reconstruct_final_path(closed_list, current);
closed_list.emplace(current, current_node);
open_list.erase(current_it);
for (const auto& neighbor: nav_mesh.get_neighbors(current))
{
@@ -86,11 +99,14 @@ namespace omath::pathfinding
const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current);
// ReSharper disable once CppTooWideScopeInitStatement
const auto open_it = open_list.find(neighbor);
auto node_it = node_data.find(neighbor);
if (open_it == open_list.end() || tentative_g_cost < open_it->second.g_cost)
open_list[neighbor] = PathNode{current, tentative_g_cost};
if (node_it == node_data.end() || tentative_g_cost < node_it->second.g_cost)
{
node_data[neighbor] = PathNode{current, tentative_g_cost};
const float f_cost = tentative_g_cost + neighbor.distance_to(end_vertex);
open_list.push({neighbor, f_cost});
}
}
}

View File

@@ -3,6 +3,8 @@
//
#include "omath/pathfinding/navigation_mesh.hpp"
#include <algorithm>
#include <cstring>
#include <limits>
#include <stdexcept>
namespace omath::pathfinding
{
@@ -13,7 +15,7 @@ namespace omath::pathfinding
{ return a.first.distance_to(point) < b.first.distance_to(point); });
if (res == m_vertex_map.cend())
return std::unexpected("Failed to get clossest point");
return std::unexpected("Failed to get closest point");
return res->first;
}
@@ -30,55 +32,68 @@ namespace omath::pathfinding
std::vector<uint8_t> NavigationMesh::serialize() const noexcept
{
auto dump_to_vector = []<typename T>(const T& t, std::vector<uint8_t>& vec)
std::vector<std::uint8_t> raw;
// Pre-calculate total size for better performance
std::size_t total_size = 0;
for (const auto& [vertex, neighbors] : m_vertex_map)
{
for (size_t i = 0; i < sizeof(t); i++)
vec.push_back(*(reinterpret_cast<const uint8_t*>(&t) + i));
total_size += sizeof(vertex) + sizeof(std::uint16_t) + sizeof(Vector3<float>) * neighbors.size();
}
raw.reserve(total_size);
auto dump_to_vector = [&raw]<typename T>(const T& t)
{
const auto* byte_ptr = reinterpret_cast<const std::uint8_t*>(&t);
raw.insert(raw.end(), byte_ptr, byte_ptr + sizeof(T));
};
std::vector<uint8_t> raw;
for (const auto& [vertex, neighbors]: m_vertex_map)
for (const auto& [vertex, neighbors] : m_vertex_map)
{
const auto neighbors_count = neighbors.size();
// Clamp neighbors count to fit in uint16_t (prevents silent data corruption)
// NOTE: If neighbors.size() > 65535, only the first 65535 neighbors will be serialized.
// This is a limitation of the current serialization format using uint16_t for count.
const auto clamped_count =
std::min<std::size_t>(neighbors.size(), std::numeric_limits<std::uint16_t>::max());
const auto neighbors_count = static_cast<std::uint16_t>(clamped_count);
dump_to_vector(vertex, raw);
dump_to_vector(neighbors_count, raw);
dump_to_vector(vertex);
dump_to_vector(neighbors_count);
for (const auto& neighbor: neighbors)
dump_to_vector(neighbor, raw);
// Only serialize up to the clamped count
for (std::size_t i = 0; i < clamped_count; ++i)
dump_to_vector(neighbors[i]);
}
return raw;
}
void NavigationMesh::deserialize(const std::vector<uint8_t>& raw) noexcept
{
auto load_from_vector = [](const std::vector<uint8_t>& vec, size_t& offset, auto& value)
auto load_from_vector = [](const std::vector<uint8_t>& vec, std::size_t& offset, auto& value)
{
if (offset + sizeof(value) > vec.size())
{
throw std::runtime_error("Deserialize: Invalid input data size.");
}
std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast<uint8_t*>(&value));
offset += sizeof(value);
};
m_vertex_map.clear();
size_t offset = 0;
std::size_t offset = 0;
while (offset < raw.size())
{
Vector3<float> vertex;
load_from_vector(raw, offset, vertex);
uint16_t neighbors_count;
std::uint16_t neighbors_count;
load_from_vector(raw, offset, neighbors_count);
std::vector<Vector3<float>> neighbors;
neighbors.reserve(neighbors_count);
for (size_t i = 0; i < neighbors_count; ++i)
for (std::size_t i = 0; i < neighbors_count; ++i)
{
Vector3<float> neighbor;
load_from_vector(raw, offset, neighbor);

View File

@@ -18,97 +18,104 @@ namespace omath::projectile_prediction
[[maybe_unused]] const Target& target) const
{
#if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__)
const float bulletGravity = m_gravityConstant * projectile.m_gravityScale;
const float v0 = projectile.m_launchSpeed;
const float v0Sqr = v0 * v0;
const Vector3 projOrigin = projectile.m_origin;
const float bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
const float v0 = projectile.m_launch_speed;
const float v0_sqr = v0 * v0;
const Vector3 proj_origin = projectile.m_origin;
constexpr int SIMD_FACTOR = 8;
float currentTime = m_simulationTimeStep;
float current_time = m_simulation_time_step;
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR)
for (; current_time <= m_maximum_simulation_time; current_time += m_simulation_time_step * SIMD_FACTOR)
{
const __m256 times
= _mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep,
currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3,
currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5,
currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7);
= _mm256_setr_ps(current_time, current_time + m_simulation_time_step,
current_time + m_simulation_time_step * 2, current_time + m_simulation_time_step * 3,
current_time + m_simulation_time_step * 4, current_time + m_simulation_time_step * 5,
current_time + m_simulation_time_step * 6, current_time + m_simulation_time_step * 7);
const __m256 targetX
const __m256 target_x
= _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x));
const __m256 targetY
const __m256 target_y
= _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y));
const __m256 timesSq = _mm256_mul_ps(times, times);
const __m256 targetZ = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times,
_mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravityConstant), timesSq,
const __m256 times_sq = _mm256_mul_ps(times, times);
const __m256 target_z = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times,
_mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravity_constant), times_sq,
_mm256_set1_ps(target.m_origin.z)));
const __m256 deltaX = _mm256_sub_ps(targetX, _mm256_set1_ps(projOrigin.x));
const __m256 deltaY = _mm256_sub_ps(targetY, _mm256_set1_ps(projOrigin.y));
const __m256 deltaZ = _mm256_sub_ps(targetZ, _mm256_set1_ps(projOrigin.z));
const __m256 delta_x = _mm256_sub_ps(target_x, _mm256_set1_ps(proj_origin.x));
const __m256 delta_y = _mm256_sub_ps(target_y, _mm256_set1_ps(proj_origin.y));
const __m256 delta_z = _mm256_sub_ps(target_z, _mm256_set1_ps(proj_origin.z));
const __m256 dSqr = _mm256_add_ps(_mm256_mul_ps(deltaX, deltaX), _mm256_mul_ps(deltaY, deltaY));
const __m256 d_sqr = _mm256_add_ps(_mm256_mul_ps(delta_x, delta_x), _mm256_mul_ps(delta_y, delta_y));
const __m256 bgTimesSq = _mm256_mul_ps(_mm256_set1_ps(bulletGravity), timesSq);
const __m256 term = _mm256_add_ps(deltaZ, _mm256_mul_ps(_mm256_set1_ps(0.5f), bgTimesSq));
const __m256 termSq = _mm256_mul_ps(term, term);
const __m256 numerator = _mm256_add_ps(dSqr, termSq);
const __m256 denominator = _mm256_add_ps(timesSq, _mm256_set1_ps(1e-8f)); // Avoid division by zero
const __m256 requiredV0Sqr = _mm256_div_ps(numerator, denominator);
const __m256 bg_times_sq = _mm256_mul_ps(_mm256_set1_ps(bullet_gravity), times_sq);
const __m256 term = _mm256_add_ps(delta_z, _mm256_mul_ps(_mm256_set1_ps(0.5f), bg_times_sq));
const __m256 term_sq = _mm256_mul_ps(term, term);
const __m256 numerator = _mm256_add_ps(d_sqr, term_sq);
const __m256 denominator = _mm256_add_ps(times_sq, _mm256_set1_ps(1e-8f)); // Avoid division by zero
const __m256 required_v0_sqr = _mm256_div_ps(numerator, denominator);
const __m256 v0SqrVec = _mm256_set1_ps(v0Sqr + 1e-3f);
const __m256 mask = _mm256_cmp_ps(requiredV0Sqr, v0SqrVec, _CMP_LE_OQ);
const __m256 v0_sqr_vec = _mm256_set1_ps(v0_sqr + 1e-3f);
const __m256 mask = _mm256_cmp_ps(required_v0_sqr, v0_sqr_vec, _CMP_LE_OQ);
const unsigned validMask = _mm256_movemask_ps(mask);
const unsigned valid_mask = _mm256_movemask_ps(mask);
if (!validMask)
if (!valid_mask)
continue;
alignas(32) float validTimes[SIMD_FACTOR];
_mm256_store_ps(validTimes, times);
alignas(32) float valid_times[SIMD_FACTOR];
_mm256_store_ps(valid_times, times);
for (int i = 0; i < SIMD_FACTOR; ++i)
{
if (!(validMask & (1 << i)))
if (!(valid_mask & (1 << i)))
continue;
const float candidateTime = validTimes[i];
const float candidate_time = valid_times[i];
if (candidateTime > m_maximumSimulationTime)
if (candidate_time > m_maximum_simulation_time)
continue;
// Fine search around candidate time
for (float fineTime = candidateTime - m_simulationTimeStep * 2;
fineTime <= candidateTime + m_simulationTimeStep * 2; fineTime += m_simulationTimeStep)
for (float fine_time = candidate_time - m_simulation_time_step * 2;
fine_time <= candidate_time + m_simulation_time_step * 2; fine_time += m_simulation_time_step)
{
if (fineTime < 0)
if (fine_time < 0)
continue;
const Vector3 targetPos = target.PredictPosition(fineTime, m_gravityConstant);
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, fineTime);
// Manually compute predicted target position to avoid adding method to Target
Vector3 target_pos = target.m_origin + target.m_velocity * fine_time;
if (target.m_is_airborne)
target_pos.z -= 0.5f * m_gravity_constant * fine_time * fine_time;
const auto pitch = calculate_pitch(proj_origin, target_pos, bullet_gravity, v0, fine_time);
if (!pitch)
continue;
const Vector3 delta = targetPos - projOrigin;
const Vector3 delta = target_pos - proj_origin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height);
const float height = d * std::tan(angles::degrees_to_radians(*pitch));
return Vector3(target_pos.x, target_pos.y, proj_origin.z + height);
}
}
}
// Fallback scalar processing for remaining times
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep)
for (; current_time <= m_maximum_simulation_time; current_time += m_simulation_time_step)
{
const Vector3 targetPos = target.PredictPosition(currentTime, m_gravityConstant);
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, currentTime);
Vector3 target_pos = target.m_origin + target.m_velocity * current_time;
if (target.m_is_airborne)
target_pos.z -= 0.5f * m_gravity_constant * current_time * current_time;
const auto pitch = calculate_pitch(proj_origin, target_pos, bullet_gravity, v0, current_time);
if (!pitch)
continue;
const Vector3 delta = targetPos - projOrigin;
const Vector3 delta = target_pos - proj_origin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height);
const float height = d * std::tan(angles::degrees_to_radians(*pitch));
return Vector3(target_pos.x, target_pos.y, proj_origin.z + height);
}
return std::nullopt;
@@ -134,22 +141,22 @@ namespace omath::projectile_prediction
return std::nullopt;
const Vector3 delta = target_pos - proj_origin;
const float dSqr = delta.x * delta.x + delta.y * delta.y;
const float d_sqr = delta.x * delta.x + delta.y * delta.y;
const float h = delta.z;
const float term = h + 0.5f * bullet_gravity * time * time;
const float requiredV0Sqr = (dSqr + term * term) / (time * time);
const float v0Sqr = v0 * v0;
const float required_v0_sqr = (d_sqr + term * term) / (time * time);
const float v0_sqr = v0 * v0;
if (requiredV0Sqr > v0Sqr + 1e-3f)
if (required_v0_sqr > v0_sqr + 1e-3f)
return std::nullopt;
if (dSqr == 0.0f)
if (d_sqr == 0.0f)
return term >= 0.0f ? 90.0f : -90.0f;
const float d = std::sqrt(dSqr);
const float tanTheta = term / d;
return angles::RadiansToDegrees(std::atan(tanTheta));
const float d = std::sqrt(d_sqr);
const float tan_theta = term / d;
return angles::radians_to_degrees(std::atan(tan_theta));
#else
throw std::runtime_error(
std::format("{} AVX2 feature is not enabled!", std::source_location::current().function_name()));

View File

@@ -0,0 +1,75 @@
//
// Created by Vlad on 10/4/2025.
//
#include "omath/utility/pattern_scan.hpp"
#include <charconv>
#include <cstdint>
#include <algorithm>
namespace
{
[[nodiscard]]
constexpr bool is_wildcard(const std::string_view& byte_str)
{
return byte_str == "?" || byte_str == "??";
}
[[nodiscard]]
constexpr bool invalid_byte_str_size(const std::string_view& byte_str)
{
return byte_str.empty() || byte_str.size() >= 3;
}
}
namespace omath
{
std::span<std::byte>::iterator
PatternScanner::scan_for_pattern(const std::span<std::byte>& range, const std::string_view& pattern)
{
return scan_for_pattern(range.begin(), range.end(), pattern);
}
std::expected<std::vector<std::optional<std::byte>>, PatternScanError>
PatternScanner::parse_pattern(const std::string_view& pattern_string)
{
std::vector<std::optional<std::byte>> pattern;
auto start = pattern_string.cbegin();
while (start != pattern_string.cend())
{
const auto end = std::ranges::find(start, pattern_string.cend(), ' ');
const auto sting_view_start = std::distance(pattern_string.cbegin(), start);
const auto sting_view_end = std::distance(start, end);
const std::string_view byte_str = pattern_string.substr(sting_view_start, sting_view_end);
if (invalid_byte_str_size(byte_str)) [[unlikely]]
{
start = end != pattern_string.end() ? std::next(end) : end;
continue;
}
if (is_wildcard(byte_str))
{
pattern.emplace_back(std::nullopt);
start = end != pattern_string.end() ? std::next(end) : end;
continue;
}
std::uint8_t value = 0;
// ReSharper disable once CppTooWideScopeInitStatement
const auto [_, error_code] = std::from_chars(byte_str.data(), byte_str.data() + byte_str.size(), value, 16);
if (error_code != std::errc{}) [[unlikely]]
return std::unexpected(PatternScanError::INVALID_PATTERN_STRING);
pattern.emplace_back(static_cast<std::byte>(value));
start = end != pattern_string.end() ? std::next(end) : end;
}
return pattern;
}
} // namespace omath

View File

@@ -0,0 +1,360 @@
//
// Created by Vlad on 10/7/2025.
//
#include "omath/utility/pe_pattern_scan.hpp"
#include "omath/utility/pattern_scan.hpp"
#include <fstream>
#include <span>
#include <stdexcept>
#include <variant>
// Internal PE shit defines
// 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
{
[[nodiscard]]
std::optional<NtHeaderVariant> get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
{
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
file.seekg(dos_header.e_lfanew, std::ios::beg);
file.read(reinterpret_cast<char*>(&x86_headers), sizeof(x86_headers));
if (x86_headers.optional_header.magic == opt_hdr32_magic)
return x86_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.read(reinterpret_cast<char*>(&x64_headers), sizeof(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]]
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
{
constexpr std::uint16_t dos_hdr_magic = 0x5A4D;
return dos_header.e_magic != dos_hdr_magic;
}
[[nodiscard]]
constexpr bool invalid_nt_header_file(const NtHeaderVariant& variant)
{
constexpr std::uint32_t nt_hdr_magic = 0x4550;
return std::visit([&nt_hdr_magic](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, &section_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*>(&current_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 omath
{
std::optional<std::uintptr_t> PePatternScanner::scan_for_pattern_in_loaded_module(const void* module_base_address,
const std::string_view& pattern)
{
const auto base_address = reinterpret_cast<std::uintptr_t>(module_base_address);
if (!base_address)
return std::nullopt;
auto nt_header_variant = get_nt_header_from_loaded_module(module_base_address);
if (!nt_header_variant)
return std::nullopt;
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 scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
// ReSharper disable once CppTooWideScopeInitStatement
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
if (result != scan_range.end())
return reinterpret_cast<std::uintptr_t>(&*result);
return std::nullopt;
},
nt_header_variant.value());
}
std::optional<PeSectionScanResult>
PePatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
const std::string_view& pattern,
const std::string_view& target_section_name)
{
const auto pe_section = extract_section_from_pe_file(path_to_file, target_section_name);
if (!pe_section.has_value())
return std::nullopt;
const auto scan_result =
PatternScanner::scan_for_pattern(pe_section->data.cbegin(), pe_section->data.cend(), pattern);
if (scan_result == pe_section->data.cend())
return std::nullopt;
const auto offset = std::distance(pe_section->data.begin(), scan_result);
return PeSectionScanResult{.virtual_base_addr = pe_section->virtual_base_addr,
.raw_base_addr = pe_section->raw_base_addr,
.target_offset = offset};
}
} // namespace omath

View File

@@ -15,6 +15,11 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD_REQUIRED ON)
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
if (TARGET gtest) # GTest is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
else() # GTest is being linked as vcpkg package
find_package(GTest CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest GTest::gtest_main omath::omath)
endif()
gtest_discover_tests(${PROJECT_NAME})

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

View File

@@ -87,9 +87,9 @@ TEST(unit_test_unity_engine, Project)
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 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);
}

View File

@@ -2,10 +2,10 @@
// Created by Orange on 11/30/2024.
//
#include <omath/trigonometry/angle.hpp>
#include <cmath>
#include <gtest/gtest.h>
#include <numbers>
#include <omath/angle.hpp>
using namespace omath;

View File

@@ -1,8 +1,8 @@
//
// Created by Orange on 11/30/2024.
//
#include <omath/trigonometry/angles.hpp>
#include <gtest/gtest.h>
#include <omath/angles.hpp>
TEST(unit_test_angles, radians_to_deg)
{

View File

@@ -1,9 +1,8 @@
//
// Created by Vlad on 01.09.2024.
//
#include <omath/utility/color.hpp>
#include <gtest/gtest.h>
#include <omath/color.hpp>
using namespace omath;

View File

@@ -0,0 +1,39 @@
//
// Created by Vlad on 10/23/2025.
//
#ifdef OMATH_IMGUI_INTEGRATION
#include <omath/omath.hpp>
#include <gtest/gtest.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
using namespace omath;
TEST(unit_test_imgui_intergration, Vector2ToImVec2)
{
constexpr Vector2 omath_vector_2d = {1.f, 2.f};
constexpr ImVec2 imgui_vector_2d = {1, 2.f};
constexpr auto converted = omath_vector_2d.to_im_vec2();
EXPECT_NEAR(converted.x, imgui_vector_2d.x, 1.e-5f);
EXPECT_NEAR(converted.y, imgui_vector_2d.y, 1.e-5f);
}
TEST(unit_test_imgui_intergration, Vector4ToImVec4)
{
constexpr Vector4 omath_vector_2d = {1.f, 2.f, 3.f, 4.f};
constexpr ImVec4 imgui_vector_4d = {1, 2.f, 3.f, 4.f};
constexpr auto converted = omath_vector_2d.to_im_vec4();
EXPECT_NEAR(converted.x, imgui_vector_4d.x, 1.e-5f);
EXPECT_NEAR(converted.y, imgui_vector_4d.y, 1.e-5f);
EXPECT_NEAR(converted.z, imgui_vector_4d.z, 1.e-5f);
EXPECT_NEAR(converted.w, imgui_vector_4d.w, 1.e-5f);
}
#endif

View File

@@ -2,9 +2,9 @@
// Revised unittest suite for LineTracer (segmentbased MöllerTrumbore)
// Pure ASCII: avoids nonstandard characters that MSVC rejects.
//
#include "omath/linear_algebra/vector3.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/collision/line_tracer.hpp"
#include "omath/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "gtest/gtest.h"
#include <cmath>

View File

@@ -214,3 +214,20 @@ TEST(UnitTestMatStandalone, Enverse)
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);
}

View File

@@ -0,0 +1,53 @@
//
// Created by Vlad on 10/4/2025.
//
#include "omath/utility/pe_pattern_scan.hpp"
#include "gtest/gtest.h"
#include <omath/utility/pattern_scan.hpp>
#include <source_location>
#include <print>
TEST(unit_test_pattern_scan, read_test)
{
const auto result = omath::PatternScanner::parse_pattern("FF ? ?? E9");
EXPECT_EQ(result->at(0), static_cast<std::byte>(0xFF));
EXPECT_EQ(result->at(1), std::nullopt);
EXPECT_EQ(result->at(2), std::nullopt);
EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9));
}
TEST(unit_test_pattern_scan, corner_case_1)
{
const auto result = omath::PatternScanner::parse_pattern(" FF ? ?? E9");
EXPECT_EQ(result->at(0), static_cast<std::byte>(0xFF));
EXPECT_EQ(result->at(1), std::nullopt);
EXPECT_EQ(result->at(2), std::nullopt);
EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9));
}
TEST(unit_test_pattern_scan, corner_case_2)
{
const auto result = omath::PatternScanner::parse_pattern(" FF ? ?? E9 ");
EXPECT_EQ(result->at(0), static_cast<std::byte>(0xFF));
EXPECT_EQ(result->at(1), std::nullopt);
EXPECT_EQ(result->at(2), std::nullopt);
EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9));
}
TEST(unit_test_pattern_scan, corner_case_3)
{
const auto result = omath::PatternScanner::parse_pattern(" FF ? ?? E9 ");
EXPECT_EQ(result->at(0), static_cast<std::byte>(0xFF));
EXPECT_EQ(result->at(1), std::nullopt);
EXPECT_EQ(result->at(2), std::nullopt);
EXPECT_EQ(result->at(3), static_cast<std::byte>(0xE9));
}
TEST(unit_test_pattern_scan, corner_case_4)
{
const auto result = omath::PatternScanner::parse_pattern("X ? ?? E9 ");
EXPECT_FALSE(result.has_value());
}

View File

@@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
#include <omath/engines/source_engine/traits/camera_trait.hpp>
TEST(UnitTestPrediction, PredictionTest)
{
constexpr omath::projectile_prediction::Target target{
@@ -10,8 +10,9 @@ TEST(UnitTestPrediction, PredictionTest)
const auto viewPoint =
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);
EXPECT_NEAR(-1.181189, yaw, 0.01f);
const auto [pitch, yaw, _] =omath::source_engine::CameraTrait::calc_look_at_angle(proj.m_origin, viewPoint.value());
EXPECT_NEAR(-42.547142, pitch.as_degrees(), 0.01f);
EXPECT_NEAR(-1.181189, yaw.as_degrees(), 0.01f);
}

View File

@@ -0,0 +1,50 @@
//
// Created by Vlad on 10/4/2025.
//
#include "omath/linear_algebra/vector3.hpp"
#include <gtest/gtest.h>
#include <omath/rev_eng/internal_rev_object.hpp>
class Player final
{
public:
virtual int foo() {return 1;}
virtual int bar() {return 2;}
omath::Vector3<float> m_origin{1.f, 2.f, 3.f};
int m_health{123};
};
class RevPlayer : omath::rev_eng::InternalReverseEngineeredObject
{
public:
omath::Vector3<float> get_origin()
{
return get_by_offset<omath::Vector3<float>>(sizeof(std::uintptr_t));
}
int get_health()
{
return get_by_offset<int>(sizeof(std::uintptr_t)+sizeof(omath::Vector3<float>));
}
int rev_foo()
{
return call_virtual_method<0, int>();
}
int rev_bar()
{
return call_virtual_method<1, int>();
}
};
TEST(unit_test_reverse_enineering, read_test)
{
Player player_original;
const auto player_reversed = reinterpret_cast<RevPlayer*>(&player_original);
EXPECT_EQ(player_original.m_origin, player_reversed->get_origin());
EXPECT_EQ(player_original.m_health, player_reversed->get_health());
EXPECT_EQ(player_original.bar(), player_reversed->rev_bar());
EXPECT_EQ(player_original.foo(), player_reversed->rev_foo());
}

View File

@@ -1,7 +1,7 @@
//
// Created by Orange on 1/6/2025.
//
#include "omath/triangle.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <cmath> // For std::sqrt, std::isinf, std::isnan
#include <gtest/gtest.h>

View File

@@ -1,4 +1,4 @@
//
// Created by Orange on 11/30/2024.
//
#include <omath/view_angles.hpp>
#include <omath/trigonometry/view_angles.hpp>

14
vcpkg-configuration.json Normal file
View File

@@ -0,0 +1,14 @@
{
"default-registry": {
"kind": "git",
"baseline": "b1b19307e2d2ec1eefbdb7ea069de7d4bcd31f01",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}

42
vcpkg.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "omath",
"version": "3.10.1",
"description": "General purpose math library",
"homepage": "https://github.com/orange-cpp/omath",
"license": "Zlib",
"supports": "windows | linux",
"dependencies": [
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"features": {
"avx2": {
"description": "Omath will use AVX2 to boost performance",
"supports": "!arm"
},
"benchmark": {
"description": "Build benchmarks",
"dependencies": [
"benchmark"
]
},
"imgui": {
"description": "Omath will define method to convert omath types to imgui types",
"dependencies": [
"imgui"
]
},
"tests": {
"description": "Build unit-tests using GTest",
"dependencies": [
"gtest"
]
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE categories
SYSTEM "https://resources.jetbrains.com/writerside/1.0/categories.dtd">
<categories>
<category id="wrs" name="Writerside documentation" order="1"/>
<category id="inf" name="Learn more" order="2"/>
</categories>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE buildprofiles SYSTEM "https://resources.jetbrains.com/writerside/1.0/build-profiles.dtd">
<buildprofiles xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/build-profiles.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variables></variables>
<build-profile instance="o">
<variables>
<noindex-content>true</noindex-content>
</variables>
</build-profile>
</buildprofiles>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE instance-profile
SYSTEM "https://resources.jetbrains.com/writerside/1.0/product-profile.dtd">
<instance-profile id="o"
name="OMATH"
start-page="starter-topic.md">
<toc-element topic="starter-topic.md"/>
<toc-element topic="Documentation.md"/>
<toc-element topic="Code-Of-Conduct.md"/>
<toc-element topic="Community.md"/>
<toc-element topic="License.md"/>
</instance-profile>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rules SYSTEM "https://resources.jetbrains.com/writerside/1.0/redirection-rules.dtd">
<rules>
<!-- format is as follows
<rule id="<unique id>">
<accepts>page.html</accepts>
</rule>
-->
<rule id="4e037516">
<description><![CDATA[Created after removal of "<Empty-MD-Topic.md>" from OMATH]]></description>
<accepts>Empty-MD-Topic.html</accepts>
</rule>
</rules>

View File

@@ -1,95 +0,0 @@
# Code Of Conduct
## 🎯 Goal
My goal is to provide a space where it is safe for everyone to contribute to,
and get support for, open-source software in a respectful and cooperative
manner.
I value all contributions and want to make this project and its
surrounding community a place for everyone.
As members, contributors, and everyone else who may participate in the
development, I strive to keep the entire experience civil.
## 📜 Standards
Our community standards exist in order to make sure everyone feels comfortable
contributing to the project(s) together.
Our standards are:
- Do not harass, attack, or in any other way discriminate against anyone, including
for their protected traits, including, but not limited to, sex, religion, race,
appearance, gender, identity, nationality, sexuality, etc.
- Do not go off-topic, do not post spam.
- Treat everyone with respect.
Examples of breaking each rule respectively include:
- Harassment, bullying or inappropriate jokes about another person.
- Posting distasteful imagery, trolling, or posting things unrelated to the topic at hand.
- Treating someone as worse because of their lack of understanding of an issue.
## ⚡ Enforcement
Enforcement of this CoC is done by Orange++ and/or other core contributors.
I, as the core developer, will strive my best to keep this community civil and
following the standards outlined above.
### 🚩 Reporting incidents
If you believe an incident of breaking these standards has occurred, but nobody has
taken appropriate action, you can privately contact the people responsible for dealing
with such incidents in multiple ways:
***E-Mail***
- `orange-cpp@yandex.ru`
***Discord***
- `@orange_cpp`
***Telegram***
- `@orange_cpp`
I guarantee your privacy and will not share those reports with anyone.
## ⚖️ Enforcement Strategy
Depending on the severity of the infraction, any action from the list below may be applied.
Please keep in mind cases are reviewed on a per-case basis and members are the ultimate
deciding factor in the type of punishment.
If the matter benefited from an outside opinion, a member might reach for more opinions
from people unrelated, however, the final decision regarding the action
to be taken is still up to the member.
For example, if the matter at hand regards a representative of a marginalized group or minority,
the member might ask for a first-hand opinion from another representative of such group.
### ✏️ Correction/Edit
If your message is found to be misleading or poorly worded, a member might
edit your message.
### ⚠️ Warning/Deletion
If your message is found inappropriate, a member might give you a public or private warning,
and/or delete your message.
### 🔇 Mute
If your message is disruptive, or you have been repeatedly violating the standards,
a member might mute (or temporarily ban) you.
### ⛔ Ban
If your message is hateful, very disruptive, or other, less serious infractions are repeated
ignoring previous punishments, a member might ban you permanently.
## 🔎 Scope
This CoC shall apply to all projects ran under the Orange++ lead and all _official_ communities
outside of GitHub.
However, it is worth noting that official communities outside of GitHub might have their own,
additional sets of rules.

View File

@@ -1,11 +0,0 @@
# Credits
Thanks to everyone who made this possible, including:
- Saikari aka luadebug for VCPKG port.
And a big hand to everyone else who has contributed over the past!
THANKS! <3
-- Orange++ <orange-cpp@yandex.ru>

View File

@@ -1,54 +0,0 @@
# 📥Installation Guide
## Using vcpkg
**Note**: Support vcpkg for package management
1. Install [vcpkg](https://github.com/microsoft/vcpkg)
2. Run the following command to install the orange-math package:
```
vcpkg install orange-math
```
CMakeLists.txt
```cmake
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
For detailed commands on installing different versions and more information, please refer to Microsoft's [official instructions](https://learn.microsoft.com/en-us/vcpkg/get_started/overview).
## Build from source using CMake
1. **Preparation**
Install needed tools: cmake, clang, git, msvc (windows only).
1. **Linux:**
```bash
sudo pacman -Sy cmake ninja clang git
```
2. **MacOS:**
```bash
brew install llvm git cmake ninja
```
3. **Windows:**
Install Visual Studio from [here](https://visualstudio.microsoft.com/downloads/) and Git from [here](https://git-scm.com/downloads).
Use x64 Native Tools shell to execute needed commands down below.
2. **Clone the repository:**
```bash
git clone https://github.com/orange-cpp/omath.git
```
3. **Navigate to the project directory:**
```bash
cd omath
```
4. **Build the project using CMake:**
```bash
cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target omath -j 6
```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
| Platform Name | Build Config |
|---------------|---------------|
| windows | release/debug |
| linux | release/debug |
| darwin | release/debug |

View File

@@ -1,9 +0,0 @@
# License
Copyright (c) 2025 Orange++
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,67 +0,0 @@
# Intro
![banner](https://i.imgur.com/SM9ccP6.png)
Oranges's Math Library (omath) is a comprehensive, open-source library aimed at providing efficient, reliable, and versatile mathematical functions and algorithms. Developed primarily in C++, this library is designed to cater to a wide range of mathematical operations essential in scientific computing, engineering, and academic research.
## 👁‍🗨 Features
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
- **Versatility**: Includes a wide array of mathematical functions and algorithms.
- **Ease of Use**: Simplified interface for convenient integration into various projects.
- **Projectile Prediction**: Projectile prediction engine with O(N) algo complexity, that can power you projectile aim-bot.
- **3D Projection**: No need to find view-projection matrix anymore you can make your own projection pipeline.
- **Collision Detection**: Production ready code to handle collision detection by using simple interfaces.
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
## Supported Render Pipelines
| ENGINE | SUPPORT |
|----------|---------|
| Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| Unreal | ❌NO |
## Supported Operating Systems
| OS | SUPPORT |
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
## ⏬ Installation
Please read our [installation guide](https://github.com/orange-cpp/omath/blob/main/INSTALL.md). If this link doesn't work check out INSTALL.md file.
## ❔ Usage
Simple world to screen function
```c++
TEST(UnitTestProjection, IsPointOnScreen)
{
const omath::projection::Camera camera({0.f, 0.f, 0.f}, {0, 0.f, 0.f} , {1920.f, 1080.f}, 110.f, 0.1f, 500.f);
const auto proj = camera.WorldToScreen({100, 0, 15});
EXPECT_TRUE(proj.has_value());
}
```
## Showcase
With `omath/projection` module you can achieve simple ESP hack for powered by Source/Unreal/Unity engine games, like [Apex Legends](https://store.steampowered.com/app/1172470/Apex_Legends/).
![banner](https://i.imgur.com/lcJrfcZ.png)
Or for InfinityWard Engine based games. Like Call of Duty Black Ops 2!
![banner](https://i.imgur.com/F8dmdoo.png)
Or create simple trigger bot with embeded traceline from omath::collision::LineTrace
![banner](https://i.imgur.com/fxMjRKo.jpeg)
Or even advanced projectile aimbot
[Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E)
## 🫵🏻 Contributing
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests.
## 📜 License
This project is licensed under the MIT - see the `LICENSE` file for details.
## 💘 Acknowledgments
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE vars SYSTEM "https://resources.jetbrains.com/writerside/1.0/vars.dtd">
<vars>
<var name="product" value="Writerside"/>
</vars>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ihp SYSTEM "https://resources.jetbrains.com/writerside/1.0/ihp.dtd">
<ihp version="2.0">
<topics dir="topics" web-path="topics"/>
<images dir="images" web-path="images"/>
<instance src="o.tree"/>
</ihp>