Compare commits

...

206 Commits

Author SHA1 Message Date
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
d1d95d2f36 Merge pull request #77 from orange-cpp/feature/formating_improvement
Feature/formating improvement
2025-09-25 22:03:47 +03:00
6409568334 added plane header 2025-09-25 21:59:59 +03:00
83ba339eb5 fix 2025-09-25 21:57:05 +03:00
c49c93d542 decomposed formatter 2025-09-25 21:55:56 +03:00
92dab52d66 improvement 2025-09-25 21:43:33 +03:00
dac3d8e43f improved encoding for formating 2025-09-25 21:06:46 +03:00
fb0b05d7ef imprvoed code style 2025-09-25 19:33:06 +03:00
993212e7ab Merge pull request #76 from orange-cpp/bugfix/projectile_pred
projectile pred look at fix
2025-09-22 02:43:04 +03:00
380a9f0a16 fix 2025-09-22 02:41:12 +03:00
ba7bce5502 ooops 2025-09-22 02:39:50 +03:00
ce40891e37 added targets specification to ci cd build 2025-09-22 02:38:25 +03:00
c4d10f8872 disable benchmark build for CI/CD 2025-09-22 02:34:52 +03:00
2bb0c82c30 added source engine benchmark 2025-09-22 02:29:36 +03:00
a4dcf8dc3b unreal engine fix 2025-09-22 02:12:20 +03:00
17eaddbc8c fix unity 2025-09-22 02:10:33 +03:00
9005c02499 opengl fix 2025-09-22 02:08:58 +03:00
e7380b5eb6 Merge pull request #75 from orange-cpp/bugfix/fix_look_at
Bugfix/fix look at
2025-09-20 17:12:16 +03:00
f8d6e4b544 unified look at for source iw_engine 2025-09-20 17:09:13 +03:00
893eca296b improved tests 2025-09-20 17:00:49 +03:00
b0bd58ccb2 improved opengl tests stability 2025-09-20 16:36:05 +03:00
44a42d39d0 improved test stability 2025-09-20 16:34:44 +03:00
a8c7e8eb54 fixed test 2025-09-20 16:22:24 +03:00
cef22919a4 added more iterations 2025-09-20 16:08:04 +03:00
f79350e609 style fix 2025-09-20 16:00:30 +03:00
1102cad390 fixed unreal 2025-09-20 15:59:43 +03:00
df4e999c82 fixed unity 2025-09-20 15:54:48 +03:00
3baeb182f0 fixed opengl 2025-09-20 15:48:59 +03:00
5539bbad0d reverted 2025-09-20 15:46:21 +03:00
4d4dfae8f2 fix 2025-09-20 15:44:33 +03:00
03c514104e fixed rotation matrix 2025-09-20 15:44:33 +03:00
792db7a673 added new mat function
more tests
2025-09-20 15:44:33 +03:00
bfd399e631 fixed test 2025-09-20 15:44:33 +03:00
7fef690f5e fixed iw engine
fixed source

revert
2025-09-20 15:44:33 +03:00
3df7d65ac1 Update README.md 2025-09-18 19:39:11 +03:00
e1a1164136 fixed warning 2025-09-18 19:06:56 +03:00
23216279dc fix 2025-09-18 18:42:02 +03:00
9e082f7dfa now its ref 2025-09-18 18:39:28 +03:00
7750819e83 improved naming 2025-09-18 18:38:07 +03:00
2ec0e2f93f Update CREDITS.md to include Billy O'Neal
Added acknowledgment for Billy O'Neal's contributions.
2025-09-18 06:08:49 +03:00
9170ffb1a9 Merge pull request #74 from BillyONeal/fmodf
Don't name std::fmodf.
2025-09-18 06:04:43 +03:00
e05f9ef5a9 Removes FMA check for matrix multiplication
Removes preprocessor check for FMA instructions in matrix multiplication functions.
This simplifies the code and relies on the compiler's ability to optimize the
code based on available hardware support. The assumption is that modern
compilers will automatically utilize FMA instructions if available, and fall
back to alternative implementations if not.
2025-09-18 06:02:37 +03:00
89bb4aa625 Guards AVX2 usage with a preprocessor definition
Ensures that AVX2 intrinsics are only included when the
OMATH_USE_AVX2 preprocessor definition is set. This prevents
compilation errors when AVX2 support is not available or
explicitly disabled.
2025-09-18 05:22:22 +03:00
Billy Robert O'Neal III
9b0845593d Don't name std::fmodf.
The C standard library function fmodf is not guaranteed to be in namespace std, and in fact is not with a default Ubuntu 24.04 installation, leading to the following compile error:

```console
Change Dir: '/vcpkg/buildtrees/vcpkg-ci-orange-math/x64-linux-dbg'

Run Build Command(s): /vcpkg/downloads/tools/ninja/1.12.1-linux/ninja -v -v -j33
[1/2] /usr/bin/c++ -DOMATH_SUPRESS_SAFETY_CHECKS -DOMATH_VERSION=\"3.5.0\" -isystem /vcpkg/installed/x64-linux/include -fPIC -g -std=gnu++23 -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /vcpkg/scripts/test_ports/vcpkg-ci-orange-math/project/main.cpp
FAILED: CMakeFiles/main.dir/main.cpp.o
/usr/bin/c++ -DOMATH_SUPRESS_SAFETY_CHECKS -DOMATH_VERSION=\"3.5.0\" -isystem /vcpkg/installed/x64-linux/include -fPIC -g -std=gnu++23 -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /vcpkg/scripts/test_ports/vcpkg-ci-orange-math/project/main.cpp
In file included from /vcpkg/installed/x64-linux/include/omath/omath.hpp:22,
                 from /vcpkg/scripts/test_ports/vcpkg-ci-orange-math/project/main.cpp:1:
/vcpkg/installed/x64-linux/include/omath/color.hpp: In member function ‘constexpr omath::Hsv omath::Color::to_hsv() const’:
/vcpkg/installed/x64-linux/include/omath/color.hpp:98:45: error: ‘fmodf’ is not a member of ‘std’; did you mean ‘modf’?
   98 |                 hsv_data.hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
      |                                             ^~~~~
      |                                             modf
ninja: build stopped: subcommand failed.
```

Only the 'sufficient additional overloads' of `fmod` are guaranteed to be in `std`. Since this is clearly intended to call the (float, float) overload, explicitly cast `((green - blue) / delta)` (which is a `double`) to `float` and call the name in `std` as suggested by the diagnostic.
2025-09-17 19:15:10 -07:00
617ded2dd4 Merge pull request #73 from orange-cpp/featore/performance_tests
added performance folder
2025-09-17 20:53:11 +03:00
e882a224d2 fix 2025-09-17 20:50:30 +03:00
e04f6573c0 patch 2025-09-17 20:46:00 +03:00
791e3b2313 improved bench 2025-09-17 20:40:03 +03:00
26b56d757c fix 2025-09-17 20:25:22 +03:00
fbb77b9925 patch 2025-09-17 20:22:42 +03:00
7b671dbd90 added benchmark submodule 2025-09-17 20:14:33 +03:00
5875930f1a added benchmark 2025-09-17 19:56:50 +03:00
d773985822 added avx mutiplication 2025-09-17 19:47:29 +03:00
a2de6f8fae renamed folder 2025-09-17 18:07:28 +03:00
d71795006d added performance folder 2025-09-17 17:47:55 +03:00
561438d45c Merge pull request #72 from orange-cpp/feature/mat_refactor
Feature/mat refactor
2025-09-17 17:41:15 +03:00
874b028e86 removed unused var 2025-09-17 17:38:17 +03:00
68ec42d9ed added space 2025-09-17 17:33:05 +03:00
8aeb4667d7 decomposed mutiplication 2025-09-17 17:30:57 +03:00
565464f0cd forgot std 2025-09-17 17:23:02 +03:00
04b50d4545 Merge pull request #71 from orange-cpp/feature/mat_perf_boost
Improves matrix multiplication performance
2025-09-17 17:18:12 +03:00
e01d32fb22 Improves matrix multiplication performance
Optimizes matrix multiplication by specializing the algorithm
based on the matrix storage type (row-major or column-major).

This change significantly improves performance by leveraging
memory access patterns specific to each storage order.
2025-09-17 17:12:41 +03:00
a3a023a664 Add acknowledgment for AmbushedRaccoon's contribution 2025-09-16 16:58:00 +03:00
1b5a7ed4fd Merge pull request #69 from luadebug/patch-1
Repair omath.hpp by removing unexisting header include
2025-09-15 15:01:04 +03:00
Saikari
362b818a71 Update omath.hpp 2025-09-15 13:13:55 +03:00
29a96d64bb Adds 2D screen to world conversion
Adds an overload for screen_to_world that accepts a 2D screen position.

Renames screen_to_dnc to screen_to_ndc for clarity.
2025-09-14 04:48:56 +03:00
256365e52e patch 2025-09-14 04:43:25 +03:00
e333d81b81 Enables formatting support for Angle objects
Adds a partial specialization of `std::formatter` for `omath::Angle`
to provide formatting support using `std::format`.

This allows `Angle` objects to be easily formatted as strings,
including degree symbol representation, using standard formatting
techniques.
2025-09-14 04:43:01 +03:00
d66f60d419 Removes unnecessary div tag
Removes an empty div tag, which streamlines the HTML structure and contributes to cleaner code.
2025-09-13 20:13:35 +03:00
4a4939b604 Repositions YouTube preview link
Moves the YouTube preview link to improve the README's visual flow.
2025-09-13 20:08:48 +03:00
ebe8d1a90e Improves README readability
Adds a newline to the README file for better visual separation
between the contribute button and the horizontal rule.
2025-09-13 19:55:23 +03:00
1a3376fe6c Improves button aesthetics on README
Adds whitespace to the buttons displayed on the README to improve their appearance.
2025-09-13 19:53:09 +03:00
20188d7043 Updates README with gallery, install and usage
Enhances the README by adding a gallery showcasing OMath's capabilities,
providing a clearer installation guide, and improving usage examples
to facilitate easier adoption.
Also restructures the navigation for better user experience.
2025-09-13 19:50:58 +03:00
f59e0d255f Update README.md 2025-09-13 19:20:37 +03:00
071cb15492 Update README.md 2025-09-13 19:16:19 +03:00
f8812ed9e7 Update README.md 2025-09-09 22:15:00 +03:00
19d310d35f Update README.md 2025-09-09 21:48:54 +03:00
c364879b5f Merge pull request #68 from orange-cpp/feature/screen_to_world
Feature/screen to world
2025-09-09 02:58:32 +03:00
418b7c0e7e Fixes float type conversion in world_to_screen
Fixes a potential type conversion issue by explicitly casting the x-coordinate to float in the world_to_screen test. This prevents possible compiler warnings and ensures the intended behavior.
2025-09-09 02:13:45 +03:00
69f46abce1 Adds projection test for world-to-screen consistency
Adds a test to verify the consistency of world-to-screen and
screen-to-world projections. This ensures that projecting a point
from world to screen and back results in the same point, thereby
validating the correctness of the camera projection transformations.
2025-09-09 01:37:38 +03:00
de61f7a5d8 Adds screen to world space conversion
Adds functionality to convert screen coordinates to world space, including handling for cases where the inverse view projection matrix is singular or when the world position is out of screen bounds.

Also exposes Camera class to unit tests.
2025-09-09 01:31:23 +03:00
07a449b633 Simplifies raycast early exit condition
Combines the infinite length raycast hit check into a single condition.

This clarifies the logic and avoids redundant checks for early exit
in the ray-triangle intersection test, improving performance.
2025-09-08 23:52:35 +03:00
6bb549ef4c Merge pull request #67 from orange-cpp/feature/angle-improvement
Implements angle class with normalization
2025-09-08 20:18:11 +03:00
14fa810ecb Implements angle class with normalization
Adds an angle class with support for different normalization
and clamping strategies. Includes trigonometric functions and
arithmetic operators. Introduces unit tests to verify correct
functionality.

Disables unity builds to address a compilation issue.
2025-09-08 20:15:59 +03:00
b964661030 Merge pull request #66 from orange-cpp/feature/remove-legacy
Removes deprecated Matrix class
2025-09-08 19:59:34 +03:00
9c11551c9a Removes deprecated Matrix class
Removes the deprecated `Matrix` class and its associated source files and unit tests.

This change is to ensure code cleanliness and prevent accidental usage of the slow and outdated `Matrix` class.
The `Mat` class should be used instead.
2025-09-08 19:56:04 +03:00
21fece7c84 Update LICENSE 2025-09-08 15:52:01 +03:00
996618994d updated logo psd 2025-09-06 23:14:14 +03:00
ce8be6dd52 Update README.md 2025-09-04 23:49:07 +03:00
17aac2f80e Update CREDITS.md 2025-09-04 20:36:12 +03:00
ba927734d2 Update LICENSE 2025-09-04 20:35:25 +03:00
c0d5fd18f5 Update SECURITY.md 2025-09-04 20:35:04 +03:00
996a9cf15a Update LICENSE 2025-09-04 19:35:05 +03:00
91078f5701 Update LICENSE 2025-09-04 19:33:59 +03:00
036d3a8992 updated logo 2025-09-03 22:18:54 +03:00
7534fe8969 removed unused defines 2025-09-03 12:52:00 +03:00
8e4f1812cc fix 2025-09-03 12:50:31 +03:00
e8f40218dd Merge pull request #62 from orange-cpp/feaure/added_logo
Feaure/added logo
2025-09-01 17:04:50 +03:00
50054ca937 Acknowledges logo design contribution
Updates the credits to acknowledge the new initial logo design.
2025-09-01 17:04:29 +03:00
63220c0be7 Adds an omath.psd file.
Adds a binary file named omath.psd.
2025-09-01 17:03:31 +03:00
3b6d19782c Updates README with local image links
Updates the README to use local image links instead of Imgur links for the showcase section.

This improves the project's resilience against external link rot and
ensures the images remain accessible even if Imgur experiences issues.
2025-09-01 17:02:23 +03:00
2d58330508 Replaces banner with logo
Replaces the project banner in the README with a dedicated logo.

This change simplifies the banner implementation and improves maintainability
by using a local image file instead of referencing an external URL.
2025-09-01 16:56:43 +03:00
abf57a55ea Updates include paths and removes dependency
Updates the include paths in omath.hpp to be more explicit,
ensuring correct referencing of header files.

Removes unnecessary include of vector3.hpp from vector2.hpp.
2025-09-01 01:28:04 +03:00
463532ba81 Merge pull request #60 from orange-cpp/feature/moved_to_dear
Refactors: Moves linear algebra to new directory
2025-09-01 00:02:00 +03:00
d74c66990a Refactors: Moves linear algebra to new directory
Moves linear algebra headers to a new subdirectory to improve project structure.

Updates includes to reflect the directory change.
Adds vcpkg to the tracked repositories.
2025-08-31 23:36:05 +03:00
7f1bc51905 Updates project version to 3.5.0
Increments the project version number in CMakeLists.txt
from 3.4.0 to 3.5.0.
2025-08-29 22:04:12 +03:00
71127f1f12 Updates project version to 3.4.0
Bumps the project's version number from 3.3.0 to 3.4.0.

Adds a compile definition to expose the project version via the
`OMATH_VERSION` macro.
2025-08-29 22:03:35 +03:00
89041e20ae Merge pull request #59 from orange-cpp/feature/new_primitives
Adds plane primitive generation
2025-08-29 14:41:36 +03:00
a54dd4b52a Fixes plane triangle generation
Corrects the order of vertices when constructing triangles
for the plane primitive, addressing a potential winding order
issue that could lead to incorrect surface normals and rendering.
2025-08-29 00:11:31 +03:00
d7e497b617 Simplifies plane creation logic
Refactors the plane creation function to directly compute the triangle vertices, removing unnecessary intermediate variables. This results in more concise and readable code.
2025-08-28 23:57:22 +03:00
80938cd913 Adds plane primitive generation
Implements a function to generate a plane primitive from two vertices, a direction vector, and a size, returning an array of two triangles.
2025-08-28 23:18:36 +03:00
830505dbe5 Merge pull request #58 from orange-cpp/feature/ortho-proj
Adds left- and right-handed ortho matrices
2025-08-27 23:23:40 +03:00
75565ecf2d Adds left- and right-handed ortho matrices.
Adds functions to generate left- and right-handed orthographic projection matrices.
This provides more flexibility when defining a projection for rendering.
2025-08-27 23:17:56 +03:00
9a7a4c7fff Removed submodule extlibs/glm 2025-08-27 20:22:33 +03:00
c0f0bb3c2e com 2025-08-27 20:07:47 +03:00
a097c0a2f4 Merge pull request #57 from orange-cpp/feature/added_formatters
Adds std::format support for math types
2025-08-26 12:37:13 +03:00
20ae2b4dd1 Adds formatters for Angle and Color
Adds formatters for `omath::Angle` and `omath::Color` to allow for easy formatting using `std::format`.

This allows users to easily output Angle and Color values in a human-readable format.
2025-08-26 12:35:40 +03:00
115b5a3471 Adds std::format support for math types
Adds `std::formatter` specializations for `Mat`, `Vector2`, `Vector3`, and `Vector4` types, enabling the use of `std::format` for these types.

This simplifies formatting and printing of these mathematical objects, improving code readability and consistency.

Also adds a hash function specialization for Vector3.
2025-08-26 12:22:33 +03:00
123 changed files with 3053 additions and 1265 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
.github/images/logos/omath_logo_mega.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
.github/images/logos/omath_logo_nano.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
.github/images/showcase/apex.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
.github/images/showcase/cod_bo2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
.github/images/showcase/cs2.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

BIN
.github/images/yt_previews/img.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
.github/psd/omath.psd vendored Normal file

Binary file not shown.

View File

@@ -35,11 +35,11 @@ jobs:
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
- name: Build
shell: bash
run: cmake --build cmake-build/build/linux-release --target all
run: cmake --build cmake-build/build/linux-release --target unit_tests omath
- name: Run unit_tests
shell: bash
@@ -68,11 +68,11 @@ jobs:
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
- name: Build
shell: bash
run: cmake --build cmake-build/build/windows-release --target all
run: cmake --build cmake-build/build/windows-release --target unit_tests omath
- name: Run unit_tests.exe
shell: bash

5
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "extlibs/googletest"]
path = extlibs/googletest
url = https://github.com/google/googletest.git
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" />

1
.idea/vcs.xml generated
View File

@@ -2,6 +2,7 @@
<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,44 +1,61 @@
cmake_minimum_required(VERSION 3.26)
project(omath VERSION 3.3.0 LANGUAGES CXX)
project(omath VERSION 3.9.2 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_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" 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)
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
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}]: 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 (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}")
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 ()
add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
endif ()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
if (OMATH_IMGUI_INTEGRATION)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION)
@@ -88,16 +105,28 @@ if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
)
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${PROJECT_NAME} PRIVATE -mavx2 -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(extlibs)
add_subdirectory(tests)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
endif ()
if (OMATH_BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif ()
if (OMATH_BUILD_EXAMPLES)

View File

@@ -8,7 +8,6 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe"
},
"condition": {
@@ -40,7 +39,6 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
},
"condition": {
@@ -72,7 +70,6 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
},
"condition": {

View File

@@ -2,10 +2,12 @@
Thanks to everyone who made this possible, including:
- Saikari aka luadebug for VCPKG port.
- Saikari aka luadebug for VCPKG port and awesome new initial logo design.
- AmbushedRaccoon for telegram post about omath to boost repository activity.
- Billy O'Neal aka BillyONeal for fixing compilation issues due to C math library compatibility.
And a big hand to everyone else who has contributed over the past!
THANKS! <3
-- Orange++ <orange-cpp@yandex.ru>
-- Orange++ <orange_github@proton.me>

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

16
LICENSE
View File

@@ -1,4 +1,4 @@
Copyright (C) 2024-2025 Orange++ <orange-cpp@yandex.ru>
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
@@ -14,4 +14,16 @@ freely, subject to the following restrictions:
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
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 or present)
with any of the following entities:
* "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
its source code, including any derivative works, tools, or information obtained from the Software.

108
README.md
View File

@@ -1,8 +1,8 @@
<div align = center>
![banner](https://github.com/orange-cpp/omath/blob/main/.github/images/banner.png?raw=true)
![banner](.github/images/logos/omath_logo_macro.png)
![GitHub License](https://img.shields.io/github/license/orange-cpp/omath)
![Static Badge](https://img.shields.io/badge/license-libomath-orange)
![GitHub contributors](https://img.shields.io/github/contributors/orange-cpp/omath)
![GitHub top language](https://img.shields.io/github/languages/top/orange-cpp/omath)
[![CodeFactor](https://www.codefactor.io/repository/github/orange-cpp/omath/badge)](https://www.codefactor.io/repository/github/orange-cpp/omath)
@@ -12,9 +12,26 @@
[![discord badge](https://dcbadge.limes.pink/api/server/https://discord.gg/eDgdaWbqwZ?style=flat)](https://discord.gg/eDgdaWbqwZ)
[![telegram badge](https://img.shields.io/badge/Telegram-2CA5E0?style=flat-squeare&logo=telegram&logoColor=white)](https://t.me/orangennotes)
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
<br>
<br>
---
**[<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]**
---
<br>
</div>
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.
<div align = center>
<a href="https://www.star-history.com/#orange-cpp/omath&Date">
@@ -26,7 +43,7 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
</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.
@@ -35,68 +52,49 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
- **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
## Supported Render Pipelines
| ENGINE | SUPPORT |
|----------|---------|
| Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| OpenGL | ✅YES |
| Unreal | ✅YES |
<br>
## Supported Operating Systems
[![Youtube Video](.github/images/yt_previews/img.png)](https://youtu.be/lM_NJ1yCunw?si=-Qf5yzDcWbaxAXGQ)
| OS | SUPPORT |
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
<br>
## ⏬ 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.
![APEX Preview]
## ❔ Usage
ESP example
```c++
omath::source_engine::Camera cam{localPlayer.GetCameraOrigin(),
localPlayer.GetAimPunch(),
{1920.f, 1080.f},
localPlayer.GetFieldOfView(),
0.01.f, 30000.f};
<br>
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});
![BO2 Preview]
const auto ent_health = ent.GetHealth();
<br>
if (!top || !bottom || ent_health <= 0)
continue;
// esp rendering...
}
```
## Showcase
<details>
<summary>OMATH for making cheats (click to open)</summary>
![CS2 Preview]
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/).
<br>
![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)
</details>
![TF2 Preview]
## 🫵🏻 Contributing
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests.
<br>
<br>
## 📜 License
This project is licensed under the ZLIB - see the `LICENSE` file for details.
</div>
## 💘 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

View File

@@ -2,4 +2,4 @@
## Reporting a Vulnerability
Please report security issues to `orange-cpp@yandex.ru`
Please report security issues to `orange_github@proton.me`

1
VERSION Normal file
View File

@@ -0,0 +1 @@
3.9.2

15
benchmark/CMakeLists.txt Normal file
View File

@@ -0,0 +1,15 @@
project(omath_benchmark)
file(GLOB_RECURSE OMATH_BENCHMARK_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${OMATH_BENCHMARK_SOURCES})
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)

View File

@@ -0,0 +1,65 @@
//
// Created by Vlad on 9/17/2025.
//
#include <benchmark/benchmark.h>
#include <omath/omath.hpp>
using namespace omath;
void mat_float_multiplication_col_major(benchmark::State& state)
{
using MatType = Mat<128, 128, float, MatStoreType::COLUMN_MAJOR>;
MatType a;
MatType b;
a.set(3.f);
b.set(7.f);
for ([[maybe_unused]] const auto _ : state)
std::ignore = a * b;
}
void mat_float_multiplication_row_major(benchmark::State& state)
{
using MatType = Mat<128, 128, float, MatStoreType::ROW_MAJOR>;
MatType a;
MatType b;
a.set(3.f);
b.set(7.f);
for ([[maybe_unused]] const auto _ : state)
std::ignore = a * b;
}
void mat_double_multiplication_row_major(benchmark::State& state)
{
using MatType = Mat<128, 128, double, MatStoreType::ROW_MAJOR>;
MatType a;
MatType b;
a.set(3.f);
b.set(7.f);
for ([[maybe_unused]] const auto _ : state)
std::ignore = a * b;
}
void mat_double_multiplication_col_major(benchmark::State& state)
{
using MatType = Mat<128, 128, double, MatStoreType::COLUMN_MAJOR>;
MatType a;
MatType b;
a.set(3.f);
b.set(7.f);
for ([[maybe_unused]] const auto _ : state)
std::ignore = a * b;
}
BENCHMARK(mat_float_multiplication_col_major)->Iterations(5000);
BENCHMARK(mat_float_multiplication_row_major)->Iterations(5000);
BENCHMARK(mat_double_multiplication_col_major)->Iterations(5000);
BENCHMARK(mat_double_multiplication_row_major)->Iterations(5000);

View File

@@ -0,0 +1,23 @@
//
// Created by Vlad on 9/18/2025.
//
#include <benchmark/benchmark.h>
#include <omath/omath.hpp>
using namespace omath;
using namespace omath::projectile_prediction;
constexpr float simulation_time_step = 1.f / 1000.f;
constexpr float hit_distance_tolerance = 5.f;
void source_engine_projectile_prediction(benchmark::State& state)
{
constexpr Target target{.m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_is_airborne = false};
constexpr Projectile projectile = {.m_origin = {3, 2, 1}, .m_launch_speed = 5000, .m_gravity_scale = 0.4};
for ([[maybe_unused]] const auto _: state)
std::ignore = ProjPredEngineLegacy(400, simulation_time_step, 50, hit_distance_tolerance)
.maybe_calculate_aim_point(projectile, target);
}
BENCHMARK(source_engine_projectile_prediction)->Iterations(10'000);

5
benchmark/main.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by Vlad on 9/17/2025.
//
#include <benchmark/benchmark.h>
BENCHMARK_MAIN();

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 +1,9 @@
add_subdirectory(googletest)
if (OMATH_BUILD_TESTS)
add_subdirectory(googletest)
endif ()
if (OMATH_BUILD_BENCHMARK)
set(BENCHMARK_ENABLE_TESTING OFF)
add_subdirectory(benchmark)
endif ()

1
extlibs/benchmark Submodule

Submodule extlibs/benchmark added at 2948b6a2e6

View File

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

View File

@@ -0,0 +1,16 @@
//
// Created by Vlad on 8/28/2025.
//
#pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <array>
namespace omath::primitives
{
[[nodiscard]]
std::array<Triangle<Vector3<float>>, 2> create_plane(const Vector3<float>& vertex_a,
const Vector3<float>& vertex_b,
const Vector3<float>& direction, float size) noexcept;
}

View File

@@ -3,8 +3,8 @@
//
#pragma once
#include "omath/triangle.hpp"
#include "omath/vector3.hpp"
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.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

@@ -3,10 +3,10 @@
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
#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::iw_engine
{

View File

@@ -3,10 +3,10 @@
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
#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::opengl_engine
{

View File

@@ -62,17 +62,15 @@ namespace omath::opengl_engine
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto distance = origin.distance_to(view_to);
const auto delta = view_to - origin;
return angles::radians_to_degrees(std::asin(delta.y / distance));
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 delta = view_to - origin;
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::atan2(delta.z, delta.x));
return angles::radians_to_degrees(-std::atan2(direction.x, -direction.z));
};
};
} // namespace omath::opengl_engine

View File

@@ -3,10 +3,10 @@
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
#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::source_engine
{

View File

@@ -4,10 +4,10 @@
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
#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::unity_engine
{

View File

@@ -62,17 +62,15 @@ namespace omath::unity_engine
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto distance = origin.distance_to(view_to);
const auto delta = view_to - origin;
return angles::radians_to_degrees(std::asin(delta.y / distance));
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 delta = view_to - origin;
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::atan2(delta.z, delta.x));
return angles::radians_to_degrees(std::atan2(direction.x, direction.z));
};
};
} // namespace omath::unity_engine

View File

@@ -4,10 +4,10 @@
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
#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::unreal_engine
{

View File

@@ -62,17 +62,16 @@ namespace omath::unreal_engine
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto distance = origin.distance_to(view_to);
const auto delta = view_to - origin;
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::asin(delta.z / distance));
return angles::radians_to_degrees(std::asin(direction.z));
}
[[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto delta = view_to - origin;
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::atan2(delta.y, delta.x));
return angles::radians_to_degrees(std::atan2(direction.y, direction.x));
};
};
} // namespace omath::unreal_engine

View File

@@ -2,7 +2,7 @@
// Created by vlad on 9/29/2024.
//
#pragma once
#include "omath/vector3.hpp"
#include "vector3.hpp"
#include <algorithm>
#include <array>
#include <iomanip>
@@ -11,14 +11,12 @@
#include <stdexcept>
#include <utility>
#ifdef near
#ifdef OMATH_USE_AVX2
#include <immintrin.h>
#endif
#undef near
#endif
#ifdef far
#undef far
#endif
namespace omath
{
struct MatSize
@@ -88,7 +86,7 @@ namespace omath
}
[[nodiscard]]
constexpr Type& operator[](const size_t row, const size_t col) const
constexpr const Type& operator[](const size_t row, const size_t col) const
{
return at(row, col);
}
@@ -162,17 +160,19 @@ namespace omath
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{
Mat<Rows, OtherColumns, Type, StoreType> result;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < OtherColumns; ++j)
{
Type sum = 0;
for (size_t k = 0; k < Columns; ++k)
sum += at(i, k) * other.at(k, j);
result.at(i, j) = sum;
}
return result;
#ifdef OMATH_USE_AVX2
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return avx_multiply_row_major(other);
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
return avx_multiply_col_major(other);
#else
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return cache_friendly_multiply_row_major(other);
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
return cache_friendly_multiply_col_major(other);
#endif
else
std::unreachable();
}
constexpr Mat& operator*=(const Type& f) noexcept
@@ -328,6 +328,21 @@ namespace omath
return oss.str();
}
[[nodiscard]]
std::wstring to_wstring() const noexcept
{
const auto ascii_string = to_string();
return {ascii_string.cbegin(), ascii_string.cend()};
}
[[nodiscard]]
// ReSharper disable once CppInconsistentNaming
std::u8string to_u8string() const noexcept
{
const auto ascii_string = to_string();
return {ascii_string.cbegin(), ascii_string.cend()};
}
[[nodiscard]]
bool operator==(const Mat& mat) const
{
@@ -374,6 +389,176 @@ namespace omath
private:
std::array<Type, Rows * Columns> m_data;
template<size_t OtherColumns> [[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
cache_friendly_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
{
Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR> result;
for (std::size_t row_index = 0; row_index < Rows; ++row_index)
for (std::size_t column_index = 0; column_index < Columns; ++column_index)
{
const Type& current_number = at(row_index, column_index);
for (std::size_t other_column = 0; other_column < OtherColumns; ++other_column)
result.at(row_index, other_column) += current_number * other.at(column_index, other_column);
}
return result;
}
template<size_t OtherColumns> [[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> cache_friendly_multiply_col_major(
const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
{
Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> result;
for (std::size_t other_column = 0; other_column < OtherColumns; ++other_column)
for (std::size_t column_index = 0; column_index < Columns; ++column_index)
{
const Type& current_number = other.at(column_index, other_column);
for (std::size_t row_index = 0; row_index < Rows; ++row_index)
result.at(row_index, other_column) += at(row_index, column_index) * current_number;
}
return result;
}
#ifdef OMATH_USE_AVX2
template<size_t OtherColumns> [[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>
avx_multiply_col_major(const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
{
Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> result;
const Type* this_mat_data = this->raw_array().data();
const Type* other_mat_data = other.raw_array().data();
Type* result_mat_data = result.raw_array().data();
if constexpr (std::is_same_v<Type, float>)
{
// ReSharper disable once CppTooWideScopeInitStatement
constexpr std::size_t vector_size = 8;
for (std::size_t j = 0; j < OtherColumns; ++j)
{
auto* c_col = reinterpret_cast<float*>(result_mat_data + j * Rows);
for (std::size_t k = 0; k < Columns; ++k)
{
const float bkj = reinterpret_cast<const float*>(other_mat_data)[k + j * Columns];
const __m256 bkj_vec = _mm256_set1_ps(bkj);
const auto* a_col_k = reinterpret_cast<const float*>(this_mat_data + k * Rows);
std::size_t i = 0;
for (; i + vector_size <= Rows; i += vector_size)
{
__m256 cvec = _mm256_loadu_ps(c_col + i);
const __m256 a_vec = _mm256_loadu_ps(a_col_k + i);
cvec = _mm256_fmadd_ps(a_vec, bkj_vec, cvec);
_mm256_storeu_ps(c_col + i, cvec);
}
for (; i < Rows; ++i)
c_col[i] += a_col_k[i] * bkj;
}
}
}
else if (std::is_same_v<Type, double>)
{ // double
// ReSharper disable once CppTooWideScopeInitStatement
constexpr std::size_t vector_size = 4;
for (std::size_t j = 0; j < OtherColumns; ++j)
{
auto* c_col = reinterpret_cast<double*>(result_mat_data + j * Rows);
for (std::size_t k = 0; k < Columns; ++k)
{
const double bkj = reinterpret_cast<const double*>(other_mat_data)[k + j * Columns];
const __m256d bkj_vec = _mm256_set1_pd(bkj);
const auto* a_col_k = reinterpret_cast<const double*>(this_mat_data + k * Rows);
std::size_t i = 0;
for (; i + vector_size <= Rows; i += vector_size)
{
__m256d cvec = _mm256_loadu_pd(c_col + i);
const __m256d a_vec = _mm256_loadu_pd(a_col_k + i);
cvec = _mm256_fmadd_pd(a_vec, bkj_vec, cvec);
_mm256_storeu_pd(c_col + i, cvec);
}
for (; i < Rows; ++i)
c_col[i] += a_col_k[i] * bkj;
}
}
}
else
std::unreachable();
return result;
}
template<size_t OtherColumns> [[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
avx_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
{
Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR> result;
const Type* this_mat_data = this->raw_array().data();
const Type* other_mat_data = other.raw_array().data();
Type* result_mat_data = result.raw_array().data();
if constexpr (std::is_same_v<Type, float>)
{
// ReSharper disable once CppTooWideScopeInitStatement
constexpr std::size_t vector_size = 8;
for (std::size_t i = 0; i < Rows; ++i)
{
Type* c_row = result_mat_data + i * OtherColumns;
for (std::size_t k = 0; k < Columns; ++k)
{
const auto aik = static_cast<float>(this_mat_data[i * Columns + k]);
const __m256 aik_vec = _mm256_set1_ps(aik);
const auto* b_row = reinterpret_cast<const float*>(other_mat_data + k * OtherColumns);
std::size_t j = 0;
for (; j + vector_size <= OtherColumns; j += vector_size)
{
__m256 cvec = _mm256_loadu_ps(c_row + j);
const __m256 b_vec = _mm256_loadu_ps(b_row + j);
cvec = _mm256_fmadd_ps(b_vec, aik_vec, cvec);
_mm256_storeu_ps(c_row + j, cvec);
}
for (; j < OtherColumns; ++j)
c_row[j] += aik * b_row[j];
}
}
}
else if (std::is_same_v<Type, double>)
{ // double
// ReSharper disable once CppTooWideScopeInitStatement
constexpr std::size_t vector_size = 4;
for (std::size_t i = 0; i < Rows; ++i)
{
Type* c_row = result_mat_data + i * OtherColumns;
for (std::size_t k = 0; k < Columns; ++k)
{
const auto aik = static_cast<double>(this_mat_data[i * Columns + k]);
const __m256d aik_vec = _mm256_set1_pd(aik);
const auto* b_row = reinterpret_cast<const double*>(other_mat_data + k * OtherColumns);
std::size_t j = 0;
for (; j + vector_size <= OtherColumns; j += vector_size)
{
__m256d cvec = _mm256_loadu_pd(c_row + j);
const __m256d b_vec = _mm256_loadu_pd(b_row + j);
cvec = _mm256_fmadd_pd(b_vec, aik_vec, cvec);
_mm256_storeu_pd(c_row + j, cvec);
}
for (; j < OtherColumns; ++j)
c_row[j] += aik * b_row[j];
}
}
}
else
std::unreachable();
return result;
}
#endif
};
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
@@ -479,4 +664,73 @@ namespace omath
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
}
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,
const Type near, const Type far) noexcept
{
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
}
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
{
return
{
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
{ 0.f, 0.f, -static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
{ 0.f, 0.f, 0.f, 1.f }
};
}
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
{
const Vector3<T> f = (center - eye).normalized();
const Vector3<T> s = f.cross(up).normalized();
const Vector3<T> u = s.cross(f);
return mat_camera_view<T, St>(f, s, u, eye);
}
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
Mat<4, 4, T, St>mat_look_at_right_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
{
const Vector3<T> f = (center - eye).normalized();
const Vector3<T> s = f.cross(up).normalized();
const Vector3<T> u = s.cross(f);
return mat_camera_view<T, St>(-f, s, u, eye);
}
} // namespace omath
template<size_t Rows, size_t Columns, class Type, omath::MatStoreType StoreType>
struct std::formatter<omath::Mat<Rows, Columns, Type, StoreType>> // NOLINT(*-dcl58-cpp)
{
using MatType = omath::Mat<Rows, Columns, Type, StoreType>;
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const MatType& mat, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "{}", mat.to_string());
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"{}", mat.to_wstring());
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"{}", mat.to_u8string());
}
};

View File

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

View File

@@ -4,6 +4,7 @@
#pragma once
#include <cmath>
#include <format>
#include <tuple>
#ifdef OMATH_IMGUI_INTEGRATION
@@ -218,7 +219,6 @@ namespace omath
{
return std::make_tuple(x, y);
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec2 to_im_vec2() const noexcept
@@ -233,3 +233,42 @@ namespace omath
#endif
};
} // 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)
{
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const omath::Vector2<Type>& vec, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y);
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"[{}, {}]", vec.x, vec.y);
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"[{}, {}]", vec.x, vec.y);
}
};

View File

@@ -4,8 +4,8 @@
#pragma once
#include "omath/angle.hpp"
#include "omath/vector2.hpp"
#include "omath/trigonometry/angle.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include <cstdint>
#include <expected>
#include <functional>
@@ -159,9 +159,9 @@ namespace omath
return Vector2<Type>::length();
}
[[nodiscard]] Type distance_to(const Vector3& vOther) const noexcept
[[nodiscard]] Type distance_to(const Vector3& v_other) const noexcept
{
return (*this - vOther).length();
return (*this - v_other).length();
}
#endif
@@ -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
{
@@ -279,21 +270,43 @@ namespace omath
}
};
} // namespace omath
// ReSharper disable once CppRedundantNamespaceDefinition
namespace std
template<> struct std::hash<omath::Vector3<float>>
{
template<> struct hash<omath::Vector3<float>>
[[nodiscard]]
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{
std::size_t hash = 0;
constexpr std::hash<float> hasher;
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.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
return hash;
}
};
} // namespace std
return hash;
}
};
template<class Type>
struct std::formatter<omath::Vector3<Type>> // NOLINT(*-dcl58-cpp)
{
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const omath::Vector3<Type>& vec, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "[{}, {}, {}]", vec.x, vec.y, vec.z);
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"[{}, {}, {}]", vec.x, vec.y, vec.z);
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"[{}, {}, {}]", vec.x, vec.y, vec.z);
}
};

View File

@@ -4,7 +4,7 @@
#pragma once
#include <algorithm>
#include <omath/vector3.hpp>
#include "omath/linear_algebra/vector3.hpp"
namespace omath
{
@@ -201,3 +201,42 @@ namespace omath
#endif
};
} // 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)
{
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const omath::Vector4<Type>& vec, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
}
};

View File

@@ -1,112 +0,0 @@
#pragma once
#ifdef OMATH_ENABLE_LEGACY
#include "omath/vector3.hpp"
#include <initializer_list>
#include <memory>
#include <string>
namespace omath
{
class Matrix final
{
public:
Matrix();
Matrix(size_t rows, size_t columns);
Matrix(const std::initializer_list<std::initializer_list<float>>& rows);
[[nodiscard]]
static Matrix to_screen_matrix(float screen_width, float screen_height);
[[nodiscard]]
static Matrix translation_matrix(const Vector3<float>& diff);
[[nodiscard]]
static Matrix orientation_matrix(const Vector3<float>& forward, const Vector3<float>& right,
const Vector3<float>& up);
[[nodiscard]]
static Matrix projection_matrix(float field_of_view, float aspect_ratio, float near, float far);
Matrix(const Matrix& other);
Matrix(size_t rows, size_t columns, const float* raw_data);
Matrix(Matrix&& other) noexcept;
[[nodiscard]]
size_t row_count() const noexcept;
[[nodiscard]]
float& operator[](size_t row, size_t column);
[[nodiscard]]
size_t columns_count() const noexcept;
[[nodiscard]]
std::pair<size_t, size_t> size() const noexcept;
[[nodiscard]]
float& at(size_t row, size_t col);
[[nodiscard]]
float sum();
void set_data_from_raw(const float* raw_matrix);
[[nodiscard]]
Matrix transpose() const;
void set(float val);
[[nodiscard]]
const float& at(size_t row, size_t col) const;
Matrix operator*(const Matrix& other) const;
Matrix& operator*=(const Matrix& other);
Matrix operator*(float f) const;
Matrix& operator*=(float f);
Matrix& operator/=(float f);
void clear();
[[nodiscard]]
Matrix strip(size_t row, size_t column) const;
[[nodiscard]]
float minor(size_t i, size_t j) const;
[[nodiscard]]
float alg_complement(size_t i, size_t j) const;
[[nodiscard]]
float determinant() const;
[[nodiscard]]
const float* raw() const;
Matrix& operator=(const Matrix& other);
Matrix& operator=(Matrix&& other) noexcept;
Matrix operator/(float f) const;
[[nodiscard]]
std::string to_string() const;
~Matrix();
private:
size_t m_rows;
size_t m_columns;
std::unique_ptr<float[]> m_data;
};
} // namespace omath
#endif

View File

@@ -6,27 +6,27 @@
#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/vector2.hpp"
#include "omath/vector3.hpp"
#include "omath/vector4.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include "omath/linear_algebra/vector4.hpp"
#include "omath/linear_algebra/vector3.hpp"
// Matrix classes
#include "omath/mat.hpp"
#include "omath/matrix.hpp"
#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"
#include "omath/3d_primitives/plane.hpp"
// Collision detection
#include "omath/collision/line_tracer.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"
#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

@@ -3,8 +3,8 @@
//
#pragma once
#include "omath/linear_algebra/vector3.hpp"
#include "omath/pathfinding/navigation_mesh.hpp"
#include "omath/vector3.hpp"
#include <vector>
namespace omath::pathfinding

View File

@@ -4,7 +4,7 @@
#pragma once
#include "omath/vector3.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <expected>
#include <string>
#include <vector>

View File

@@ -2,9 +2,9 @@
// Created by Vlad on 2/23/2025.
//
#pragma once
#include "omath/linear_algebra/vector3.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include "omath/vector3.hpp"
namespace omath::projectile_prediction
{

View File

@@ -5,10 +5,10 @@
#pragma once
#include "omath/engines/source_engine/traits/pred_engine_trait.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include "omath/projectile_prediction/proj_pred_engine.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include "omath/vector3.hpp"
#include <optional>
namespace omath::projectile_prediction
@@ -20,7 +20,9 @@ namespace omath::projectile_prediction
Vector3<float> v3, // by-value for calc_viewpoint_from_angles
float pitch, float yaw, float time, float gravity, std::optional<float> maybe_pitch) {
// Presence + return types
{ T::predict_projectile_position(projectile, pitch, yaw, time, gravity) } -> std::same_as<Vector3<float>>;
{
T::predict_projectile_position(projectile, pitch, yaw, time, gravity)
} -> std::same_as<Vector3<float>>;
{ T::predict_target_position(target, time, gravity) } -> std::same_as<Vector3<float>>;
{ T::calc_vector_2d_distance(vec_a) } -> std::same_as<float>;
{ T::get_vector_height_coordinate(vec_b) } -> std::same_as<float>;

View File

@@ -3,7 +3,7 @@
//
#pragma once
#include "omath/vector3.hpp"
#include "omath/linear_algebra/vector3.hpp"
namespace omath::projectile_prediction
{

View File

@@ -3,7 +3,7 @@
//
#pragma once
#include "omath/vector3.hpp"
#include "omath/linear_algebra/vector3.hpp"
namespace omath::projectile_prediction
{

View File

@@ -4,13 +4,18 @@
#pragma once
#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 <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <type_traits>
#ifdef OMATH_BUILD_TESTS
// ReSharper disable once CppInconsistentNaming
class UnitTestProjection_Projection_Test;
#endif
namespace omath::projection
{
class ViewPort final
@@ -45,7 +50,16 @@ namespace omath::projection
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
class Camera final
{
#ifdef OMATH_BUILD_TESTS
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
@@ -54,12 +68,13 @@ namespace omath::projection
{
}
protected:
void look_at(const Vector3<float>& target)
{
m_view_angles = TraitClass::calc_look_at_angle(m_origin, target);
m_view_projection_matrix = std::nullopt;
}
protected:
[[nodiscard]] Mat4X4Type calc_view_projection_matrix() const noexcept
{
return TraitClass::calc_projection_matrix(m_field_of_view, m_view_port, m_near_plane_distance,
@@ -137,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>
@@ -164,6 +186,38 @@ namespace omath::projection
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
}
[[nodiscard]]
std::expected<Vector3<float>, Error> view_port_to_screen(const Vector3<float>& ndc) const noexcept
{
const auto inv_view_proj = get_view_projection_matrix().inverted();
if (!inv_view_proj)
return std::unexpected(Error::INV_VIEW_PROJ_MAT_DET_EQ_ZERO);
auto inverted_projection =
inv_view_proj.value() * mat_column_from_vector<float, Mat4X4Type::get_store_ordering()>(ndc);
if (!inverted_projection.at(3, 0))
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
inverted_projection /= inverted_projection.at(3, 0);
return Vector3<float>{inverted_projection.at(0, 0), inverted_projection.at(1, 0),
inverted_projection.at(2, 0)};
}
[[nodiscard]]
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
{
return view_port_to_screen(screen_to_ndc(screen_pos));
}
[[nodiscard]]
std::expected<Vector3<float>, Error> screen_to_world(const Vector2<float>& screen_pos) const noexcept
{
const auto& [x, y] = screen_pos;
return screen_to_world({x, y, 1.f});
}
protected:
ViewPort m_view_port{};
@@ -184,21 +238,58 @@ 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 |
|
|
-1 ---------0--------- 1 --> x
|
|
-1 |
v
*/
[[nodiscard]] Vector3<float>
ndc_to_screen_position_from_top_left_corner(const Vector3<float>& ndc) const noexcept
{
/*
^
| y
1 |
|
|
-1 ---------0--------- 1 --> x
|
|
-1 |
v
*/
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
/*
+------------------------>
| (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
{
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f,
screen_pos.z};
}
};
} // namespace omath::projection

View File

@@ -10,5 +10,6 @@ namespace omath::projection
enum class Error : uint16_t
{
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
INV_VIEW_PROJ_MAT_DET_EQ_ZERO,
};
}

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,8 +3,9 @@
//
#pragma once
#include "omath/angles.hpp"
#include "omath/trigonometry/angles.hpp"
#include <algorithm>
#include <format>
#include <utility>
namespace omath
@@ -122,13 +123,13 @@ namespace omath
}
[[nodiscard]]
constexpr Angle& operator+(const Angle& other) noexcept
constexpr Angle operator+(const Angle& other) noexcept
{
if constexpr (flags == AngleFlags::Normalized)
return {angles::wrap_angle(m_angle + other.m_angle, min, max)};
return Angle{angles::wrap_angle(m_angle + other.m_angle, min, max)};
else if constexpr (flags == AngleFlags::Clamped)
return {std::clamp(m_angle + other.m_angle, min, max)};
return Angle{std::clamp(m_angle + other.m_angle, min, max)};
else
static_assert(false);
@@ -137,7 +138,7 @@ namespace omath
}
[[nodiscard]]
constexpr Angle& operator-(const Angle& other) noexcept
constexpr Angle operator-(const Angle& other) noexcept
{
return operator+(-other);
}
@@ -149,3 +150,62 @@ namespace omath
}
};
} // namespace omath
template<class T, T MinV, T MaxV, omath::AngleFlags F>
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, char> // NOLINT(*-dcl58-cpp)
{
using AngleT = omath::Angle<T, MinV, MaxV, F>;
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
auto format(const AngleT& a, FormatContext& ctx) const
{
static_assert(std::is_same_v<typename FormatContext::char_type, char>);
return std::format_to(ctx.out(), "{}deg", a.as_degrees());
}
};
// wchar_t formatter
template<class T, T MinV, T MaxV, omath::AngleFlags F>
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, wchar_t> // NOLINT(*-dcl58-cpp)
{
using AngleT = omath::Angle<T, MinV, MaxV, F>;
static constexpr auto parse(std::wformat_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
auto format(const AngleT& a, FormatContext& ctx) const
{
static_assert(std::is_same_v<typename FormatContext::char_type, wchar_t>);
return std::format_to(ctx.out(), L"{}deg", a.as_degrees());
}
};
// wchar_t formatter
template<class T, T MinV, T MaxV, omath::AngleFlags F>
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, char8_t> // NOLINT(*-dcl58-cpp)
{
using AngleT = omath::Angle<T, MinV, MaxV, F>;
static constexpr auto parse(std::wformat_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
auto format(const AngleT& a, FormatContext& ctx) const
{
static_assert(std::is_same_v<typename FormatContext::char_type, char8_t>);
return std::format_to(ctx.out(), u8"{}deg", a.as_degrees());
}
};

View File

@@ -4,8 +4,7 @@
#pragma once
#include "omath/vector3.hpp"
#include "omath/vector4.hpp"
#include "omath/linear_algebra/vector4.hpp"
#include <cstdint>
namespace omath
@@ -96,7 +95,7 @@ namespace omath
hsv_data.hue = 0.f;
else if (max == red)
hsv_data.hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
hsv_data.hue = 60.f * (std::fmod(static_cast<float>((green - blue) / delta), 6.f));
else if (max == green)
hsv_data.hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue)
@@ -165,5 +164,49 @@ namespace omath
return {to_im_vec4()};
}
#endif
[[nodiscard]] std::string to_string() const noexcept
{
return std::format("[r:{}, g:{}, b:{}, a:{}]",
static_cast<int>(x * 255.f),
static_cast<int>(y * 255.f),
static_cast<int>(z * 255.f),
static_cast<int>(w * 255.f));
}
[[nodiscard]] std::wstring to_wstring() const noexcept
{
const auto ascii_string = to_string();
return {ascii_string.cbegin(), ascii_string.cend()};
}
// ReSharper disable once CppInconsistentNaming
[[nodiscard]] std::u8string to_u8string() const noexcept
{
const auto ascii_string = to_string();
return {ascii_string.cbegin(), ascii_string.cend()};
}
};
} // namespace omath
template<>
struct std::formatter<omath::Color> // NOLINT(*-dcl58-cpp)
{
[[nodiscard]]
static constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin();
}
template<class FormatContext>
[[nodiscard]]
static auto format(const omath::Color& col, FormatContext& ctx)
{
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
return std::format_to(ctx.out(), "{}", col.to_string());
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
return std::format_to(ctx.out(), L"{}", col.to_wstring());
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
return std::format_to(ctx.out(), u8"{}", col.to_u8string());
return std::unreachable();
}
};

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,19 @@
//
// Created by Vlad on 8/28/2025.
//
#include "omath/3d_primitives/plane.hpp"
namespace omath::primitives
{
std::array<Triangle<Vector3<float>>, 2> create_plane(const Vector3<float>& vertex_a,
const Vector3<float>& vertex_b,
const Vector3<float>& direction, const float size) noexcept
{
const auto second_vertex_a = vertex_a + direction * size;
return std::array
{
Triangle{second_vertex_a, vertex_a, vertex_b},
Triangle{second_vertex_a, vertex_b + direction * size, vertex_b}
};
}
} // namespace omath::primitives

View File

@@ -50,12 +50,10 @@ namespace omath::collision
const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length)
{
if (t_hit <= k_epsilon)
return ray.end;
}
else if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
if (ray.infinite_length && t_hit <= k_epsilon)
return ray.end;
if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
return ray.end;
return ray.start + ray_dir * t_hit;

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

@@ -8,11 +8,10 @@ namespace omath::iw_engine
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto distance = cam_origin.distance_to(look_at);
const auto delta = cam_origin - look_at;
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
YawAngle::from_radians(std::atan2(delta.y, delta.x)), RollAngle::from_radians(0.f)};
return {PitchAngle::from_radians(-std::asin(direction.z)),
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
}
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{

View File

@@ -28,14 +28,13 @@ namespace omath::opengl_engine
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view<float, MatStoreType::COLUMN_MAJOR>(-forward_vector(angles), right_vector(angles),
up_vector(angles), cam_origin);
return mat_look_at_right_handed(cam_origin, cam_origin+forward_vector(angles), up_vector(angles));
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(-angles.pitch)
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(-angles.yaw)
* mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll);
return mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll)
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(angles.yaw)
* mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(angles.pitch);
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept

View File

@@ -9,11 +9,10 @@ namespace omath::opengl_engine
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto distance = cam_origin.distance_to(look_at);
const auto delta = cam_origin - look_at;
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(-std::asin(delta.y / distance)),
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)};
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
{

View File

@@ -8,11 +8,11 @@ namespace omath::source_engine
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto distance = cam_origin.distance_to(look_at);
const auto delta = cam_origin - look_at;
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
YawAngle::from_radians(std::atan2(delta.y, delta.x)), RollAngle::from_radians(0.f)};
return {PitchAngle::from_radians(-std::asin(direction.z)),
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
}
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{

View File

@@ -25,25 +25,18 @@ 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
{
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch)
return mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll)
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.yaw)
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll);
* 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
{
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

@@ -8,11 +8,10 @@ namespace omath::unity_engine
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto distance = cam_origin.distance_to(look_at);
const auto delta = cam_origin - look_at;
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(-std::asin(delta.y / distance)),
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)};
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
{

View File

@@ -31,8 +31,8 @@ namespace omath::unreal_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.roll)
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.pitch)
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw);
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw)
* mat_rotation_axis_y<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

View File

@@ -8,11 +8,10 @@ namespace omath::unreal_engine
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto distance = cam_origin.distance_to(look_at);
const auto delta = cam_origin - look_at;
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
YawAngle::from_radians(std::atan2(delta.x, delta.y)), RollAngle::from_radians(0.f)};
return {PitchAngle::from_radians(-std::asin(direction.z)),
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
}
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{

View File

@@ -1,364 +0,0 @@
#ifdef OMATH_ENABLE_LEGACY
#include "omath/matrix.hpp"
#include "omath/angles.hpp"
#include "omath/vector3.hpp"
#include <complex>
#include <format>
#include <stdexcept>
#include <utility>
namespace omath
{
Matrix::Matrix(const size_t rows, const size_t columns)
{
if (rows == 0 and columns == 0)
throw std::runtime_error("Matrix cannot be 0x0");
m_rows = rows;
m_columns = columns;
m_data = std::make_unique<float[]>(m_rows * m_columns);
set(0.f);
}
Matrix::Matrix(const std::initializer_list<std::initializer_list<float>>& rows)
{
m_rows = rows.size();
m_columns = rows.begin()->size();
for (const auto& row: rows)
if (row.size() != m_columns)
throw std::invalid_argument("All rows must have the same number of columns.");
m_data = std::make_unique<float[]>(m_rows * m_columns);
size_t i = 0;
for (const auto& row: rows)
{
size_t j = 0;
for (const auto& value: row)
at(i, j++) = value;
++i;
}
}
Matrix::Matrix(const Matrix& other)
{
m_rows = other.m_rows;
m_columns = other.m_columns;
m_data = std::make_unique<float[]>(m_rows * m_columns);
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
at(i, j) = other.at(i, j);
}
Matrix::Matrix(const size_t rows, const size_t columns, const float* raw_data)
{
m_rows = rows;
m_columns = columns;
m_data = std::make_unique<float[]>(m_rows * m_columns);
for (size_t i = 0; i < rows * columns; ++i)
at(i / rows, i % columns) = raw_data[i];
}
size_t Matrix::row_count() const noexcept
{
return m_rows;
}
float& Matrix::operator[](const size_t row, const size_t column)
{
return at(row, column);
}
Matrix::Matrix(Matrix&& other) noexcept
{
m_rows = other.m_rows;
m_columns = other.m_columns;
m_data = std::move(other.m_data);
other.m_rows = 0;
other.m_columns = 0;
other.m_data = nullptr;
}
size_t Matrix::columns_count() const noexcept
{
return m_columns;
}
std::pair<size_t, size_t> Matrix::size() const noexcept
{
return {row_count(), columns_count()};
}
float& Matrix::at(const size_t row, const size_t col)
{
return const_cast<float&>(std::as_const(*this).at(row, col));
}
float Matrix::sum()
{
float sum = 0;
for (size_t i = 0; i < row_count(); i++)
for (size_t j = 0; j < columns_count(); j++)
sum += at(i, j);
return sum;
}
const float& Matrix::at(const size_t row, const size_t col) const
{
return m_data[row * m_columns + col];
}
Matrix Matrix::operator*(const Matrix& other) const
{
if (m_columns != other.m_rows)
throw std::runtime_error("n != m");
auto out_mat = Matrix(m_rows, other.m_columns);
for (size_t d = 0; d < m_rows; ++d)
for (size_t i = 0; i < other.m_columns; ++i)
for (size_t j = 0; j < other.m_rows; ++j)
out_mat.at(d, i) += at(d, j) * other.at(j, i);
return out_mat;
}
Matrix& Matrix::operator*=(const Matrix& other)
{
*this = *this * other;
return *this;
}
Matrix Matrix::operator*(const float f) const
{
auto out = *this;
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
out.at(i, j) *= f;
return out;
}
Matrix& Matrix::operator*=(const float f)
{
for (size_t i = 0; i < row_count(); i++)
for (size_t j = 0; j < columns_count(); j++)
at(i, j) *= f;
return *this;
}
void Matrix::clear()
{
set(0.f);
}
Matrix& Matrix::operator=(const Matrix& other)
{
if (this == &other)
return *this;
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
at(i, j) = other.at(i, j);
return *this;
}
Matrix& Matrix::operator=(Matrix&& other) noexcept
{
if (this == &other)
return *this;
m_rows = other.m_rows;
m_columns = other.m_columns;
m_data = std::move(other.m_data);
other.m_rows = 0;
other.m_columns = 0;
return *this;
}
Matrix& Matrix::operator/=(const float f)
{
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
at(i, j) /= f;
return *this;
}
Matrix Matrix::operator/(const float f) const
{
auto out = *this;
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
out.at(i, j) /= f;
return out;
}
std::string Matrix::to_string() const
{
std::string str;
for (size_t i = 0; i < m_rows; i++)
{
for (size_t j = 0; j < m_columns; ++j)
{
str += std::format("{:.1f}", at(i, j));
if (j == m_columns - 1)
str += '\n';
else
str += ' ';
}
}
return str;
}
float Matrix::determinant() const // NOLINT(*-no-recursion)
{
if (m_rows + m_columns == 2)
return at(0, 0);
if (m_rows == 2 and m_columns == 2)
return at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0);
float det = 0;
for (size_t i = 0; i < m_columns; i++)
det += alg_complement(0, i) * at(0, i);
return det;
}
float Matrix::alg_complement(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
{
const auto tmp = minor(i, j);
return ((i + j + 2) % 2 == 0) ? tmp : -tmp;
}
Matrix Matrix::transpose() const
{
Matrix transposed = {m_columns, m_rows};
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
transposed.at(j, i) = at(i, j);
return transposed;
}
Matrix::~Matrix() = default;
void Matrix::set(const float val)
{
for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j)
at(i, j) = val;
}
Matrix Matrix::strip(const size_t row, const size_t column) const
{
Matrix stripped = {m_rows - 1, m_columns - 1};
size_t strip_row_index = 0;
for (size_t i = 0; i < m_rows; i++)
{
if (i == row)
continue;
size_t strip_column_index = 0;
for (size_t j = 0; j < m_columns; ++j)
{
if (j == column)
continue;
stripped.at(strip_row_index, strip_column_index) = at(i, j);
strip_column_index++;
}
strip_row_index++;
}
return stripped;
}
float Matrix::minor(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
{
return strip(i, j).determinant();
}
Matrix Matrix::to_screen_matrix(const float screen_width, const float screen_height)
{
return {
{screen_width / 2.f, 0.f, 0.f, 0.f},
{0.f, -screen_height / 2.f, 0.f, 0.f},
{0.f, 0.f, 1.f, 0.f},
{screen_width / 2.f, screen_height / 2.f, 0.f, 1.f},
};
}
Matrix Matrix::translation_matrix(const Vector3<float>& diff)
{
return {
{1.f, 0.f, 0.f, 0.f},
{0.f, 1.f, 0.f, 0.f},
{0.f, 0.f, 1.f, 0.f},
{diff.x, diff.y, diff.z, 1.f},
};
}
Matrix Matrix::orientation_matrix(const Vector3<float>& forward, const Vector3<float>& right,
const Vector3<float>& up)
{
return {
{right.x, up.x, forward.x, 0.f},
{right.y, up.y, forward.y, 0.f},
{right.z, up.z, forward.z, 0.f},
{0.f, 0.f, 0.f, 1.f},
};
}
Matrix Matrix::projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far)
{
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.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
}
const float* Matrix::raw() const
{
return m_data.get();
}
void Matrix::set_data_from_raw(const float* raw_matrix)
{
for (size_t i = 0; i < m_columns * m_rows; ++i)
at(i / m_rows, i % m_columns) = raw_matrix[i];
}
Matrix::Matrix()
{
m_columns = 0;
m_rows = 0;
m_data = nullptr;
}
} // namespace omath
#endif

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,359 @@
//
// 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([](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

@@ -7,16 +7,13 @@ include(GoogleTest)
file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${UNIT_TESTS_SOURCES})
set_target_properties(unit_tests PROPERTIES
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
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

@@ -5,7 +5,7 @@
#include <omath/engines/iw_engine/camera.hpp>
#include <omath/engines/iw_engine/constants.hpp>
#include <omath/engines/iw_engine/formulas.hpp>
#include <random>
TEST(unit_test_iw_engine, ForwardVector)
{
@@ -68,7 +68,6 @@ TEST(unit_test_iw_engine, ProjectTargetMovedFromCamera)
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
const auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
{
const auto projected = cam.world_to_screen({distance, 0, 0});
@@ -102,4 +101,126 @@ TEST(unit_test_iw_engine, CameraSetAndGetOrigin)
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_iw_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::iw_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.001f || std::abs(projected_pos->y - 0.f) >= 0.001f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}
TEST(unit_test_iw_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::iw_engine::Camera({dist(gen), dist(gen), dist(gen)}, {}, {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.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}
TEST(unit_test_iw_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::iw_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_iw_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::iw_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.025f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}

View File

@@ -5,7 +5,7 @@
#include <omath/engines/opengl_engine/camera.hpp>
#include <omath/engines/opengl_engine/constants.hpp>
#include <omath/engines/opengl_engine/formulas.hpp>
#include <random>
TEST(unit_test_opengl, ForwardVector)
{
@@ -29,7 +29,7 @@ TEST(unit_test_opengl, ForwardVectorRotationYaw)
{
omath::opengl_engine::ViewAngles angles;
angles.yaw = omath::opengl_engine::YawAngle::from_degrees(90.f);
angles.yaw = omath::opengl_engine::YawAngle::from_degrees(-90.f);
const auto forward = omath::opengl_engine::forward_vector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_right.x, 0.00001f);
@@ -37,13 +37,11 @@ TEST(unit_test_opengl, ForwardVectorRotationYaw)
EXPECT_NEAR(forward.z, omath::opengl_engine::k_abs_right.z, 0.00001f);
}
TEST(unit_test_opengl, ForwardVectorRotationPitch)
{
omath::opengl_engine::ViewAngles angles;
angles.pitch = omath::opengl_engine::PitchAngle::from_degrees(-90.f);
angles.pitch = omath::opengl_engine::PitchAngle::from_degrees(90.f);
const auto forward = omath::opengl_engine::forward_vector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_up.x, 0.00001f);
@@ -68,7 +66,6 @@ TEST(unit_test_opengl, ProjectTargetMovedFromCamera)
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
const auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
for (float distance = -10.f; distance > -1000.f; distance -= 0.01f)
{
const auto projected = cam.world_to_screen({0, 0, distance});
@@ -102,4 +99,123 @@ TEST(unit_test_opengl, CameraSetAndGetOrigin)
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_opengl_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::opengl_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_opengl_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::opengl_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.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}
TEST(unit_test_opengl_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::opengl_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_opengl_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::opengl_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

@@ -5,7 +5,7 @@
#include <omath/engines/source_engine/camera.hpp>
#include <omath/engines/source_engine/constants.hpp>
#include <omath/engines/source_engine/formulas.hpp>
#include <random>
TEST(unit_test_source_engine, ForwardVector)
{
@@ -68,7 +68,6 @@ TEST(unit_test_source_engine, ProjectTargetMovedFromCamera)
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
const auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
{
const auto projected = cam.world_to_screen({distance, 0, 0});
@@ -122,4 +121,125 @@ TEST(unit_test_source_engine, CameraSetAndGetOrigin)
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_source_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::source_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_source_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::source_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.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}
TEST(unit_test_source_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::source_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_source_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::source_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.025f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}

View File

@@ -6,6 +6,7 @@
#include <omath/engines/unity_engine/constants.hpp>
#include <omath/engines/unity_engine/formulas.hpp>
#include <print>
#include <random>
TEST(unit_test_unity_engine, ForwardVector)
{
@@ -68,7 +69,6 @@ TEST(unit_test_unity_engine, ProjectTargetMovedFromCamera)
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.01f, 1000.f);
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
{
const auto projected = cam.world_to_screen({0, 0, distance});
@@ -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);
}
@@ -112,4 +112,125 @@ TEST(unit_test_unity_engine, CameraSetAndGetOrigin)
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_unity_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::unity_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_unity_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::unity_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_unity_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::unity_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_unity_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::unity_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

@@ -6,6 +6,7 @@
#include <omath/engines/unreal_engine/constants.hpp>
#include <omath/engines/unreal_engine/formulas.hpp>
#include <print>
#include <random>
TEST(unit_test_unreal_engine, ForwardVector)
{
@@ -68,7 +69,6 @@ TEST(unit_test_unreal_engine, ProjectTargetMovedFromCamera)
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
const auto cam = omath::unreal_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({distance, 0, 0});
@@ -102,4 +102,128 @@ TEST(unit_test_unreal_engine, CameraSetAndGetOrigin)
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_unreal_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::unreal_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 < 100; 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_unreal_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::unreal_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.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
failed_points++;
}
EXPECT_LE(failed_points, 100);
}
TEST(unit_test_unreal_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::unreal_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_unreal_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::unreal_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

@@ -1,3 +1,192 @@
//
// Created by Orange on 11/30/2024.
//
#include <omath/trigonometry/angle.hpp>
#include <cmath>
#include <gtest/gtest.h>
#include <numbers>
using namespace omath;
namespace
{
// Handy aliases (defaults: Type=float, [0,360], Normalized)
using Deg = Angle<float, float(0), float(360), AngleFlags::Normalized>;
using Pitch = Angle<float, float(-90), float(90), AngleFlags::Clamped>;
using Turn = Angle<float, float(-180), float(180), AngleFlags::Normalized>;
constexpr float kEps = 1e-5f;
} // namespace
// ---------- Construction / factories ----------
TEST(UnitTestAngle, DefaultConstructor_IsZeroDegrees)
{
Deg a; // default ctor
EXPECT_FLOAT_EQ(*a, 0.0f);
EXPECT_FLOAT_EQ(a.as_degrees(), 0.0f);
}
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsAboveMax)
{
const Deg a = Deg::from_degrees(370.0f);
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
}
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsBelowMin)
{
const Deg a = Deg::from_degrees(-10.0f);
EXPECT_FLOAT_EQ(a.as_degrees(), 350.0f);
}
TEST(UnitTestAngle, FromDegrees_Clamped_ClampsToRange)
{
const Pitch hi = Pitch::from_degrees(100.0f);
const Pitch lo = Pitch::from_degrees(-120.0f);
EXPECT_FLOAT_EQ(hi.as_degrees(), 90.0f);
EXPECT_FLOAT_EQ(lo.as_degrees(), -90.0f);
}
TEST(UnitTestAngle, FromRadians_And_AsRadians)
{
const Deg a = Deg::from_radians(std::numbers::pi_v<float>);
EXPECT_FLOAT_EQ(a.as_degrees(), 180.0f);
const Deg b = Deg::from_degrees(180.0f);
EXPECT_NEAR(b.as_radians(), std::numbers::pi_v<float>, 1e-6f);
}
// ---------- Unary minus & deref ----------
TEST(UnitTestAngle, UnaryMinus_Normalized)
{
const Deg a = Deg::from_degrees(30.0f);
const Deg b = -a; // wraps to 330 in [0,360)
EXPECT_FLOAT_EQ(b.as_degrees(), 330.0f);
}
TEST(UnitTestAngle, DereferenceReturnsDegrees)
{
const Deg a = Deg::from_degrees(42.0f);
EXPECT_FLOAT_EQ(*a, 42.0f);
}
// ---------- Trigonometric helpers ----------
TEST(UnitTestAngle, SinCosTanCot_BasicCases)
{
const Deg a0 = Deg::from_degrees(0.0f);
EXPECT_NEAR(a0.sin(), 0.0f, kEps);
EXPECT_NEAR(a0.cos(), 1.0f, kEps);
// cot(0) -> cos/sin -> div by 0: allow inf or nan
const float cot0 = a0.cot();
EXPECT_TRUE(std::isinf(cot0) || std::isnan(cot0));
const Deg a45 = Deg::from_degrees(45.0f);
EXPECT_NEAR(a45.tan(), 1.0f, 1e-4f);
EXPECT_NEAR(a45.cot(), 1.0f, 1e-4f);
const Deg a90 = Deg::from_degrees(90.0f);
EXPECT_NEAR(a90.sin(), 1.0f, 1e-4f);
EXPECT_NEAR(a90.cos(), 0.0f, 1e-4f);
}
TEST(UnitTestAngle, Atan_IsAtanOfRadians)
{
// atan(as_radians). For 0° -> atan(0)=0.
const Deg a0 = Deg::from_degrees(0.0f);
EXPECT_NEAR(a0.atan(), 0.0f, kEps);
const Deg a45 = Deg::from_degrees(45.0f);
// atan(pi/4) ≈ 0.665773...
EXPECT_NEAR(a45.atan(), 0.66577375f, 1e-6f);
}
// ---------- Compound arithmetic ----------
TEST(UnitTestAngle, PlusEquals_Normalized_Wraps)
{
Deg a = Deg::from_degrees(350.0f);
a += Deg::from_degrees(20.0f); // 370 -> 10
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
}
TEST(UnitTestAngle, MinusEquals_Normalized_Wraps)
{
Deg a = Deg::from_degrees(10.0f);
a -= Deg::from_degrees(30.0f); // -20 -> 340
EXPECT_FLOAT_EQ(a.as_degrees(), 340.0f);
}
TEST(UnitTestAngle, PlusEquals_Clamped_Clamps)
{
Pitch p = Pitch::from_degrees(80.0f);
p += Pitch::from_degrees(30.0f); // 110 -> clamp to 90
EXPECT_FLOAT_EQ(p.as_degrees(), 90.0f);
}
TEST(UnitTestAngle, MinusEquals_Clamped_Clamps)
{
Pitch p = Pitch::from_degrees(-70.0f);
p -= Pitch::from_degrees(40.0f); // -110 -> clamp to -90
EXPECT_FLOAT_EQ(p.as_degrees(), -90.0f);
}
// ---------- Alternative ranges ----------
TEST(UnitTestAngle, NormalizedRange_Neg180To180)
{
const Turn a = Turn::from_degrees(190.0f); // -> -170
const Turn b = Turn::from_degrees(-190.0f); // -> 170
EXPECT_FLOAT_EQ(a.as_degrees(), -170.0f);
EXPECT_FLOAT_EQ(b.as_degrees(), 170.0f);
}
// ---------- Comparisons (via <=>) ----------
TEST(UnitTestAngle, Comparisons_WorkWithPartialOrdering)
{
const Deg a = Deg::from_degrees(10.0f);
const Deg b = Deg::from_degrees(20.0f);
const Deg c = Deg::from_degrees(10.0f);
EXPECT_TRUE(a < b);
EXPECT_TRUE(b > a);
EXPECT_TRUE(a <= c);
EXPECT_TRUE(c >= a);
}
// ---------- std::format formatter ----------
TEST(UnitTestAngle, Formatter_PrintsDegreesWithSuffix)
{
const Deg a = Deg::from_degrees(15.0f);
EXPECT_EQ(std::format("{}", a), "15deg");
const Deg b = Deg::from_degrees(10.5f);
EXPECT_EQ(std::format("{}", b), "10.5deg");
const Turn t = Turn::from_degrees(-170.0f);
EXPECT_EQ(std::format("{}", t), "-170deg");
}
TEST(UnitTestAngle, BinaryPlus_ReturnsWrappedSum)
{
Angle<> a = Deg::from_degrees(350.0f);
const Deg b = Deg::from_degrees(20.0f);
const Deg c = a + b; // expect 10°
EXPECT_FLOAT_EQ(c.as_degrees(), 10.0f);
}
TEST(UnitTestAngle, BinaryMinus_ReturnsWrappedDiff)
{
Angle<> a = Deg::from_degrees(10.0f);
const Deg b = Deg::from_degrees(30.0f);
const Deg c = a - b; // expect 340°
EXPECT_FLOAT_EQ(c.as_degrees(), 340.0f);
}

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

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

View File

@@ -1,7 +1,7 @@
// UnitTestMat.cpp
#include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp"
#include <gtest/gtest.h>
#include "omath/mat.hpp"
#include "omath/vector3.hpp"
using namespace omath;
@@ -125,7 +125,7 @@ TEST_F(UnitTestMat, Clear)
TEST_F(UnitTestMat, ToString)
{
const std::string str = m2.to_string();
const std::string str = std::format("{}", m2);
EXPECT_FALSE(str.empty());
EXPECT_EQ(str, "[[ 1.000, 2.000]\n [ 3.000, 4.000]]");
}
@@ -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

@@ -1,184 +0,0 @@
//
// Created by vlad on 5/18/2024.
//
#ifdef OMATH_ENABLE_LEGACY
#include <gtest/gtest.h>
#include <omath/matrix.hpp>
#include "omath/vector3.hpp"
using namespace omath;
class UnitTestMatrix : public ::testing::Test
{
protected:
Matrix m1;
Matrix m2;
void SetUp() override
{
m1 = Matrix(2, 2);
m2 = Matrix{{1.0f, 2.0f}, {3.0f, 4.0f}};
}
};
// Test constructors
TEST_F(UnitTestMatrix, Constructor_Size)
{
const Matrix m(3, 3);
EXPECT_EQ(m.row_count(), 3);
EXPECT_EQ(m.columns_count(), 3);
}
TEST_F(UnitTestMatrix, Operator_SquareBrackets)
{
EXPECT_EQ((m2[0, 0]), 1.0f);
EXPECT_EQ((m2[0, 1]), 2.0f);
EXPECT_EQ((m2[1, 0]), 3.0f);
EXPECT_EQ((m2[1, 1]), 4.0f);
}
TEST_F(UnitTestMatrix, Constructor_InitializerList)
{
Matrix m{{1.0f, 2.0f}, {3.0f, 4.0f}};
EXPECT_EQ(m.row_count(), 2);
EXPECT_EQ(m.columns_count(), 2);
EXPECT_FLOAT_EQ(m.at(0, 0), 1.0f);
EXPECT_FLOAT_EQ(m.at(1, 1), 4.0f);
}
TEST_F(UnitTestMatrix, Constructor_Copy)
{
Matrix m3 = m2;
EXPECT_EQ(m3.row_count(), m2.row_count());
EXPECT_EQ(m3.columns_count(), m2.columns_count());
EXPECT_FLOAT_EQ(m3.at(0, 0), m2.at(0, 0));
}
TEST_F(UnitTestMatrix, Constructor_Move)
{
Matrix m3 = std::move(m2);
EXPECT_EQ(m3.row_count(), 2);
EXPECT_EQ(m3.columns_count(), 2);
EXPECT_FLOAT_EQ(m3.at(0, 0), 1.0f);
EXPECT_EQ(m2.row_count(), 0); // m2 should be empty after the move
EXPECT_EQ(m2.columns_count(), 0);
}
// Test matrix operations
TEST_F(UnitTestMatrix, Operator_Multiplication_Matrix)
{
Matrix m3 = m2 * m2;
EXPECT_EQ(m3.row_count(), 2);
EXPECT_EQ(m3.columns_count(), 2);
EXPECT_FLOAT_EQ(m3.at(0, 0), 7.0f);
EXPECT_FLOAT_EQ(m3.at(1, 1), 22.0f);
}
TEST_F(UnitTestMatrix, Operator_Multiplication_Scalar)
{
Matrix m3 = m2 * 2.0f;
EXPECT_FLOAT_EQ(m3.at(0, 0), 2.0f);
EXPECT_FLOAT_EQ(m3.at(1, 1), 8.0f);
}
TEST_F(UnitTestMatrix, Operator_Division_Scalar)
{
Matrix m3 = m2 / 2.0f;
EXPECT_FLOAT_EQ(m3.at(0, 0), 0.5f);
EXPECT_FLOAT_EQ(m3.at(1, 1), 2.0f);
}
// Test matrix functions
TEST_F(UnitTestMatrix, Transpose)
{
Matrix m3 = m2.transpose();
EXPECT_FLOAT_EQ(m3.at(0, 1), 3.0f);
EXPECT_FLOAT_EQ(m3.at(1, 0), 2.0f);
}
TEST_F(UnitTestMatrix, Determinant)
{
const float det = m2.determinant();
EXPECT_FLOAT_EQ(det, -2.0f);
}
TEST_F(UnitTestMatrix, Minor)
{
const float minor = m2.minor(0, 0);
EXPECT_FLOAT_EQ(minor, 4.0f);
}
TEST_F(UnitTestMatrix, AlgComplement)
{
const float algComp = m2.alg_complement(0, 0);
EXPECT_FLOAT_EQ(algComp, 4.0f);
}
TEST_F(UnitTestMatrix, Strip)
{
Matrix m3 = m2.strip(0, 0);
EXPECT_EQ(m3.row_count(), 1);
EXPECT_EQ(m3.columns_count(), 1);
EXPECT_FLOAT_EQ(m3.at(0, 0), 4.0f);
}
TEST_F(UnitTestMatrix, ProjectionMatrix)
{
const Matrix proj = Matrix::projection_matrix(45.0f, 1.33f, 0.1f, 100.0f);
EXPECT_EQ(proj.row_count(), 4);
EXPECT_EQ(proj.columns_count(), 4);
// Further checks on projection matrix elements could be added
}
// Test other member functions
TEST_F(UnitTestMatrix, Set)
{
m1.set(3.0f);
EXPECT_FLOAT_EQ(m1.at(0, 0), 3.0f);
EXPECT_FLOAT_EQ(m1.at(1, 1), 3.0f);
}
TEST_F(UnitTestMatrix, Sum)
{
const float sum = m2.sum();
EXPECT_FLOAT_EQ(sum, 10.0f);
}
TEST_F(UnitTestMatrix, Clear)
{
m2.clear();
EXPECT_FLOAT_EQ(m2.at(0, 0), 0.0f);
EXPECT_FLOAT_EQ(m2.at(1, 1), 0.0f);
}
TEST_F(UnitTestMatrix, ToString)
{
const std::string str = m2.to_string();
EXPECT_FALSE(str.empty());
}
// Test assignment operators
TEST_F(UnitTestMatrix, AssignmentOperator_Copy)
{
Matrix m3(2, 2);
m3 = m2;
EXPECT_EQ(m3.row_count(), m2.row_count());
EXPECT_EQ(m3.columns_count(), m2.columns_count());
EXPECT_FLOAT_EQ(m3.at(0, 0), m2.at(0, 0));
}
TEST_F(UnitTestMatrix, AssignmentOperator_Move)
{
Matrix m3(2, 2);
m3 = std::move(m2);
EXPECT_EQ(m3.row_count(), 2);
EXPECT_EQ(m3.columns_count(), 2);
EXPECT_FLOAT_EQ(m3.at(0, 0), 1.0f);
EXPECT_EQ(m2.row_count(), 0); // m2 should be empty after the move
EXPECT_EQ(m2.columns_count(), 0);
}
#endif

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

@@ -13,8 +13,12 @@ TEST(UnitTestProjection, Projection)
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
0.01f, 1000.f);
const auto projected = cam.world_to_screen({1000, 0, 50});
const auto projected = cam.world_to_screen({1000.f, 0, 50.f});
const auto result = cam.screen_to_world(projected.value());
const auto result2 = cam.world_to_screen(result.value());
EXPECT_EQ(static_cast<omath::Vector2<float>>(projected.value()),
static_cast<omath::Vector2<float>>(result2.value()));
EXPECT_NEAR(projected->x, 960.f, 0.001f);
EXPECT_NEAR(projected->y, 504.f, 0.001f);
EXPECT_NEAR(projected->z, 1.f, 0.001f);

Some files were not shown because too many files have changed in this diff Show More