Compare commits

...

229 Commits

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

Initial exploration and analysis complete

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

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

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

Add bounds check for navigation mesh serialization

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

Document serialization limitation for large neighbor counts

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

Add _codeql_build_dir to gitignore

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

Removes codeql detected source root

Eliminates the automatically generated file that was causing issues.

This file was added by codeql and no longer needed.

revert
cleaned up gitignore

moved to anon namespace

Improves navigation mesh serialization and clamping

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

Updates data types to `std::uint8_t` and `std::size_t` for consistency.
Uses `std::copy_n` instead of `std::memcpy` for deserialization.
2025-10-30 05:38:58 +03:00
orange 87d2577937 fixed typo 2025-10-30 05:37:34 +03:00
orange c4f4685ce5 Clarifies release process for stable builds
Explains that changes merged into master won't reach stable users unless the `stable` tag is updated.
2025-10-28 01:21:41 +03:00
orange 89b60083f9 Merge pull request #93 from orange-cpp/feaure/small_improvement
removed useless option
2025-10-28 01:19:21 +03:00
orange cbd3ca9a73 fix 2025-10-28 01:15:36 +03:00
orange 20c4890b20 removed 2025-10-28 01:11:02 +03:00
orange ab5fb0ee35 removed useless option 2025-10-28 01:09:47 +03:00
orange bcbe90737f added some comments 2025-10-27 11:25:31 +03:00
orange 812850393b force disabled tests 2025-10-27 11:22:24 +03:00
orange 98f8875dfc Merge pull request #92 from orange-cpp/feature/projection_utility
added vcpkg integration
2025-10-27 11:11:28 +03:00
orange 659072cf4c considered to switch to v4 2025-10-27 11:05:55 +03:00
orange 0e05e013fe updated version 2025-10-27 10:59:30 +03:00
orange f4f385bc46 patch 2025-10-27 10:58:26 +03:00
orange dd5d2d5541 Adds default and artifact registries
Configures the default Vcpkg registry and adds an artifact registry
for the microsoft catalog. This enables the tool to find and use
pre-built packages from the Microsoft catalog.
2025-10-27 10:57:57 +03:00
orange 5c37e39358 Adds Darwin build presets with Vcpkg support
Adds new CMake presets for Darwin platforms, including debug and release configurations with optional Vcpkg integration.
This allows for easier builds on Darwin systems utilizing pre-built libraries from Vcpkg.
2025-10-27 09:57:12 +03:00
orange 0a7f69aeb0 Update CMake configuration for Vcpkg integration and feature enablement.
Enables features and sets build configurations via Vcpkg manifest.
Adds new presets for Windows and Linux debug/release builds using Vcpkg.
Conditionally enables features (imgui, avx2, tests, benchmark) based on Vcpkg manifest features.
2025-10-27 09:55:49 +03:00
orange eea6195ec2 Fixes invalid NT header check in variant
Ensures the NT header signature check uses a capture to avoid potential issues with variable scope.
2025-10-27 09:22:00 +03:00
orange 969ba6fd34 Disables Vcpkg build override
Disables the automatic override of build options by Vcpkg.

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

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

Specifies the Vcpkg root directory and manifest features.

Defines the installation directory for Vcpkg packages.

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

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

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

Adds `tests` and `benchmark` features to `vcpkg.json`,
and adds corresponding CMake logic to control their build based on
Vcpkg manifest features.
2025-10-27 06:42:43 +03:00
orange e6a5f00f15 Fix formatting and spacing in LICENSE file
Corrected formatting and removed extra spaces in the LICENSE file.
2025-10-27 02:32:06 +03:00
orange 65ba237c6e added additional check 2025-10-23 06:43:09 +03:00
orange 55041384c5 added vcpkg manifest file 2025-10-23 06:35:22 +03:00
orange 25dc212b08 added contained type alias 2025-10-23 06:26:57 +03:00
orange 4f4c911e4d fix 2025-10-23 01:08:19 +03:00
orange 652147f0bb Remove 'future' from affiliation clause in LICENSE 2025-10-23 01:00:40 +03:00
orange 44f8a52c44 added frostbite into global header 2025-10-23 00:55:49 +03:00
orange 555786819f added Frostbite into readme 2025-10-23 00:50:35 +03:00
orange 41bec6c6cd deleted not needed header 2025-10-23 00:49:54 +03:00
orange 93ab7a9b79 updated comments 2025-10-23 00:48:54 +03:00
orange c0481ef3fa Merge pull request #91 from orange-cpp/feature/frostbite_engine
Defines constants for Frostbite engine
2025-10-23 00:18:07 +03:00
orange a22feeb1b9 added frostbite sources 2025-10-23 00:08:17 +03:00
orange 2e41aa496f 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
orange 762edc2a37 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
orange afb8f9cb80 nuked not needed test 2025-10-21 04:38:43 +03:00
orange 10215e6e1c added second method of w2s 2025-10-21 04:38:43 +03:00
orange 9af201069a 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
orange 5d692b4dbd Added TF2 into gallery 2025-10-19 04:00:20 +03:00
orange 4ebc5f83e9 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 4241f0cf89 Fix pattern scan range check to use end() instead of cend() 2025-10-16 19:47:27 +03:00
orange 4fc5eade06 Removes ReSharper disable comments
Removes the `ReSharper disable CppInconsistentNaming` comments
from the header file.
2025-10-14 13:23:09 +03:00
orange e00dc482e6 Adds PE pattern scan utility
Includes a new utility for scanning PE patterns.
2025-10-14 13:20:14 +03:00
orange b330265f45 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
orange 6832799040 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
orange 7be3bde498 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
orange a8eac87f02 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
orange 9fd666c2df Update README.md 2025-10-13 14:24:53 +03:00
orange 5921004bfd 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
orange 697c9f2768 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
orange 937b5c2b8c 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
orange 44d923766c 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
orange 515076b741 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
orange 0d01309bf8 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
orange 17e32d5a5c Merge pull request #85 from orange-cpp/feature/hide_pe_defs
Feature/hide pe defs
2025-10-12 19:46:22 +03:00
orange 96ac0ba6a6 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
orange e49f93fbc9 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
orange 8d815389b8 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
orange f32496896d Updates omath version to 3.9.2 2025-10-11 17:22:16 +03:00
orange 9d5984093d 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
orange 104067a8c7 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 4c3b76f7d2 Update internal_rev_object.hpp 2025-10-09 21:34:19 +03:00
orange 6573363683 Merge pull request #82 from orange-cpp/feature/pe_scanner
Updates PE header structure for x64
2025-10-09 20:45:21 +03:00
orange 656b1a2267 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
orange a4cc02dff5 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
orange bc94f49759 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
orange 852f5ad556 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
orange 84b9500837 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
orange 83e48343dd 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
orange 3d130fd1fb 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
orange f1ee6e9e35 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
orange 5ea1f00d09 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
orange 63debc635e fixed for mac improved readability 2025-10-08 19:22:20 +03:00
orange 007340edaa 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
orange b9c5dcc2c5 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
orange a304672ca9 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
orange 1b45fdc7b3 added pe pattern scan 2025-10-08 19:22:20 +03:00
orange 0e824ef320 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
orange cbf627c9f8 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
orange dea896c6cb added mkdoc 2025-10-08 19:22:19 +03:00
orange a057b8c1e9 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
orange 416f8c86c1 Add Kaspersky LLC to license restrictions 2025-10-08 17:48:24 +03:00
orange b230051258 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
orange ffb1e70552 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
orange 70b9505166 added global header 2025-10-06 14:36:00 +03:00
orange 9ccb25dd26 added concept for iterators, reworked interface 2025-10-06 14:25:52 +03:00
orange 8344b745b7 improved scanner interface 2025-10-06 14:21:52 +03:00
orange d2b64a52b0 added unlikely 2025-10-06 14:04:43 +03:00
orange fd3d003251 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
orange e93a6dc214 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
orange 7329410f94 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
orange 7bb23d3f7a 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
orange 932b0d8deb 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
orange 64e6ba3632 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
orange 6319aa81ab 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
orange 544fa313c1 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
orange 4e0c74a256 Merge pull request #80 from orange-cpp/feature/rev_eng
Feature: Reverse Engineering classes
2025-10-04 10:09:07 +03:00
orange d0684c388e finished test 2025-10-04 10:04:34 +03:00
orange 137f1f6826 update global header 2025-10-04 09:52:14 +03:00
orange 46457b81ac added external class 2025-10-04 09:47:48 +03:00
orange 70f2f90100 reordored omath headers 2025-10-03 13:51:53 +03:00
orange c8b2d963db added rev_object 2025-10-03 13:43:47 +03:00
orange 033935918b version update 2025-10-03 13:16:48 +03:00
orange d27b3ebd53 femoved useless file 2025-10-03 13:14:11 +03:00
orange b69303faca fixed wrong spam of command option into build log 2025-10-03 12:40:18 +03:00
orange 4241e738f4 Merge pull request #78 from luadebug/patch-1
CMakeLists.txt: support AVX2 detection
2025-10-01 03:10:24 +03:00
Saikari e3d77e8681 CMakeLists.txt: do not use /ARCH:AVX since we have /ARCH:AVX2 already 2025-09-30 23:40:07 +03:00
Saikari 259242b582 Update CMakeLists.txt 2025-09-30 23:18:00 +03:00
Saikari 9d256901dd CMakeLists.txt: support AVX2 detection for https://github.com/xmake-io/xmake-repo/pull/8277 2025-09-30 21:40:25 +03:00
orange 253361e1b7 forgot linux macos 2025-09-29 11:23:28 +03:00
orange f7fe21d924 removed useless fields of C compiler 2025-09-29 11:21:43 +03:00
orange 769261a584 added another clangformat 2025-09-27 10:55:05 +03:00
orange 988f81eeb4 Add documentation link to README 2025-09-27 10:40:54 +03:00
orange 28e48dabc9 added version file update cmake version 2025-09-27 10:38:31 +03:00
orange c4e61e3aa2 Revise features and clean up README
Updated features section and removed usage examples.
2025-09-27 10:35:14 +03:00
orange eb6f0302a9 Merge pull request #77 from orange-cpp/feature/formating_improvement
Feature/formating improvement
2025-09-25 22:03:47 +03:00
orange 5ad1d763bb added plane header 2025-09-25 21:59:59 +03:00
orange cc68d4e2b7 fix 2025-09-25 21:57:05 +03:00
orange 899a9825a0 decomposed formatter 2025-09-25 21:55:56 +03:00
orange 800435b407 improvement 2025-09-25 21:43:33 +03:00
orange 0a72f8541a improved encoding for formating 2025-09-25 21:06:46 +03:00
orange a5ed088ce0 imprvoed code style 2025-09-25 19:33:06 +03:00
orange 1e0cec2762 Merge pull request #76 from orange-cpp/bugfix/projectile_pred
projectile pred look at fix
2025-09-22 02:43:04 +03:00
orange 423dca43e4 fix 2025-09-22 02:41:12 +03:00
orange 7318644027 ooops 2025-09-22 02:39:50 +03:00
orange 0515018605 added targets specification to ci cd build 2025-09-22 02:38:25 +03:00
orange 152eafb78f disable benchmark build for CI/CD 2025-09-22 02:34:52 +03:00
orange f8beaa4bab added source engine benchmark 2025-09-22 02:29:36 +03:00
orange 614e5ebb35 unreal engine fix 2025-09-22 02:12:20 +03:00
orange 36e4cef2f3 fix unity 2025-09-22 02:10:33 +03:00
orange 577afd4d4a opengl fix 2025-09-22 02:08:58 +03:00
orange aebb29d773 Merge pull request #75 from orange-cpp/bugfix/fix_look_at
Bugfix/fix look at
2025-09-20 17:12:16 +03:00
orange 3c81aea2ca unified look at for source iw_engine 2025-09-20 17:09:13 +03:00
orange 32d88f0881 improved tests 2025-09-20 17:00:49 +03:00
orange 15898e9b3d improved opengl tests stability 2025-09-20 16:36:05 +03:00
orange e37fefae23 improved test stability 2025-09-20 16:34:44 +03:00
orange f8f3f2c45d fixed test 2025-09-20 16:22:24 +03:00
orange aee78d7671 added more iterations 2025-09-20 16:08:04 +03:00
orange eb443d533c style fix 2025-09-20 16:00:30 +03:00
orange 5466638330 fixed unreal 2025-09-20 15:59:43 +03:00
orange 19350b2618 fixed unity 2025-09-20 15:54:48 +03:00
orange 53b495a413 fixed opengl 2025-09-20 15:48:59 +03:00
orange 18a1349693 reverted 2025-09-20 15:46:21 +03:00
orange 584a66b20c fix 2025-09-20 15:44:33 +03:00
orange 3e5fb1bdb5 fixed rotation matrix 2025-09-20 15:44:33 +03:00
orange 3fa85f4c4d added new mat function
more tests
2025-09-20 15:44:33 +03:00
orange d3c90253f7 fixed test 2025-09-20 15:44:33 +03:00
orange eeb4dccb12 fixed iw engine
fixed source

revert
2025-09-20 15:44:33 +03:00
orange 708c8c082b Update README.md 2025-09-18 19:39:11 +03:00
orange e9dbec778d fixed warning 2025-09-18 19:06:56 +03:00
orange 99d77d7790 fix 2025-09-18 18:42:02 +03:00
orange df5ca54b90 now its ref 2025-09-18 18:39:28 +03:00
orange 80bae265c0 improved naming 2025-09-18 18:38:07 +03:00
orange 4929c96e5b Update CREDITS.md to include Billy O'Neal
Added acknowledgment for Billy O'Neal's contributions.
2025-09-18 06:08:49 +03:00
orange f66f028317 Merge pull request #74 from BillyONeal/fmodf
Don't name std::fmodf.
2025-09-18 06:04:43 +03:00
orange dc3f2980db 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
orange 4505aee3c2 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 ee8073ceb4 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
orange 800965a16c Merge pull request #73 from orange-cpp/featore/performance_tests
added performance folder
2025-09-17 20:53:11 +03:00
orange 3e560cbfa4 fix 2025-09-17 20:50:30 +03:00
orange fbebed3d16 patch 2025-09-17 20:46:00 +03:00
orange 439da31334 improved bench 2025-09-17 20:40:03 +03:00
orange f7cb5eef1f fix 2025-09-17 20:25:22 +03:00
orange f6254c6a8c patch 2025-09-17 20:22:42 +03:00
orange e0c5c1c56b added benchmark submodule 2025-09-17 20:14:33 +03:00
orange e090ac1d9a added benchmark 2025-09-17 19:56:50 +03:00
orange dc3606301d added avx mutiplication 2025-09-17 19:47:29 +03:00
orange eb0ca6627f renamed folder 2025-09-17 18:07:28 +03:00
orange e2be30f505 added performance folder 2025-09-17 17:47:55 +03:00
orange a742d99205 Merge pull request #72 from orange-cpp/feature/mat_refactor
Feature/mat refactor
2025-09-17 17:41:15 +03:00
orange 578a4e1d32 removed unused var 2025-09-17 17:38:17 +03:00
orange 13e0bb3262 added space 2025-09-17 17:33:05 +03:00
orange 619c15072c decomposed mutiplication 2025-09-17 17:30:57 +03:00
orange 242fc45ffa forgot std 2025-09-17 17:23:02 +03:00
orange 36628c0400 Merge pull request #71 from orange-cpp/feature/mat_perf_boost
Improves matrix multiplication performance
2025-09-17 17:18:12 +03:00
orange a630da39e3 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
orange 910100c6dd Add acknowledgment for AmbushedRaccoon's contribution 2025-09-16 16:58:00 +03:00
orange dbae07546f 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 d1d26352d6 Update omath.hpp 2025-09-15 13:13:55 +03:00
orange 4f0cfd4cef 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
orange 8c03a07600 patch 2025-09-14 04:43:25 +03:00
orange 498df95e3e 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
orange 7ad0e3f10b 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
orange 4372f429ae Repositions YouTube preview link
Moves the YouTube preview link to improve the README's visual flow.
2025-09-13 20:08:48 +03:00
orange 077653e5ce 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
orange 5ec26f9def 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
orange f48232cc1d 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
orange 32b1b90414 Update README.md 2025-09-13 19:20:37 +03:00
orange 0b18129eac Update README.md 2025-09-13 19:16:19 +03:00
orange 8983cfc6d9 Update README.md 2025-09-09 22:15:00 +03:00
orange 123184987f Update README.md 2025-09-09 21:48:54 +03:00
orange ac7aeee9be Merge pull request #68 from orange-cpp/feature/screen_to_world
Feature/screen to world
2025-09-09 02:58:32 +03:00
orange 1d8dba6487 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
orange 18b0b210cf 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
orange 9e08f5bb5c 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
orange a61d3f20b7 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
orange 4340e83914 Merge pull request #67 from orange-cpp/feature/angle-improvement
Implements angle class with normalization
2025-09-08 20:18:11 +03:00
orange 1efa28d676 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
orange f393d0c1c3 Merge pull request #66 from orange-cpp/feature/remove-legacy
Removes deprecated Matrix class
2025-09-08 19:59:34 +03:00
orange 55c5bb92da 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
orange 6f203e3a20 Update LICENSE 2025-09-08 15:52:01 +03:00
orange 038de53783 updated logo psd 2025-09-06 23:14:14 +03:00
orange fde3e1dcb9 Update README.md 2025-09-04 23:49:07 +03:00
orange 6153478d6e Update CREDITS.md 2025-09-04 20:36:12 +03:00
orange 4a6ddb230b Update LICENSE 2025-09-04 20:35:25 +03:00
orange bb61e2303e Update SECURITY.md 2025-09-04 20:35:04 +03:00
orange 522597c196 Update LICENSE 2025-09-04 19:35:05 +03:00
orange 9709ba8f61 Update LICENSE 2025-09-04 19:33:59 +03:00
orange 5111695d84 updated logo 2025-09-03 22:18:54 +03:00
orange 50bfc3e943 removed unused defines 2025-09-03 12:52:00 +03:00
orange 15f2a3917f fix 2025-09-03 12:50:31 +03:00
orange dede0a145d Merge pull request #62 from orange-cpp/feaure/added_logo
Feaure/added logo
2025-09-01 17:04:50 +03:00
orange 4238c94fc0 Acknowledges logo design contribution
Updates the credits to acknowledge the new initial logo design.
2025-09-01 17:04:29 +03:00
orange 6a6c265501 Adds an omath.psd file.
Adds a binary file named omath.psd.
2025-09-01 17:03:31 +03:00
orange d061f67d13 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
orange 1546d8a90f 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
123 changed files with 3268 additions and 1392 deletions
+1 -1
View File
@@ -56,7 +56,7 @@ SpaceBeforeParensOptions:
AfterIfMacros: true AfterIfMacros: true
AfterOverloadedOperator: false AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false SpacesInConditionalStatement: false
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+16 -9
View File
@@ -19,27 +19,32 @@ jobs:
name: Arch Linux (Clang) name: Arch Linux (Clang)
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: archlinux:latest container: archlinux:latest
env:
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
steps: steps:
- name: Install basic tool-chain with pacman - name: Install basic tool-chain with pacman
shell: bash shell: bash
run: | run: |
pacman -Sy --noconfirm archlinux-keyring pacman -Sy --noconfirm archlinux-keyring
pacman -Syu --noconfirm --needed \ pacman -Syu --noconfirm --needed \
git base-devel clang cmake ninja git base-devel clang cmake ninja zip unzip fmt
- name: Checkout repository (with sub-modules) - name: Checkout repository (with sub-modules)
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Set up vcpkg
shell: bash
run: |
git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
- name: Configure (cmake --preset) - name: Configure (cmake --preset)
shell: bash shell: bash
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON run: cmake --preset linux-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
- name: Build - name: Build
shell: bash shell: bash
run: cmake --build cmake-build/build/linux-release --target all run: cmake --build cmake-build/build/linux-release-vcpkg --target unit_tests omath
- name: Run unit_tests - name: Run unit_tests
shell: bash shell: bash
@@ -47,12 +52,14 @@ jobs:
############################################################################## ##############################################################################
# 2) Windows MSVC / Ninja # 2) Windows MSVC / Ninja
############################################################################## ##############################################################################
windows-build-and-test: windows-build-and-test:
name: Windows (MSVC) name: Windows (MSVC)
runs-on: windows-latest runs-on: windows-latest
env:
OMATH_BUILD_VIA_VCPKG: ON
steps: steps:
- name: Checkout repository (with sub-modules) - name: Checkout repository (with sub-modules)
@@ -68,11 +75,11 @@ jobs:
- name: Configure (cmake --preset) - name: Configure (cmake --preset)
shell: bash shell: bash
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON run: cmake --preset windows-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests"
- name: Build - name: Build
shell: bash shell: bash
run: cmake --build cmake-build/build/windows-release --target all run: cmake --build cmake-build/build/windows-release-vcpkg --target unit_tests omath
- name: Run unit_tests.exe - name: Run unit_tests.exe
shell: bash shell: bash
-3
View File
@@ -1,3 +0,0 @@
[submodule "extlibs/googletest"]
path = extlibs/googletest
url = https://github.com/google/googletest.git
+2 -2
View File
@@ -201,7 +201,7 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" /> <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/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" 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/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@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" /> <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/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@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/=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/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@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" /> <option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
Generated
-2
View File
@@ -2,7 +2,5 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/vcpkg" vcs="Git" />
</component> </component>
</project> </project>
+62 -21
View File
@@ -1,42 +1,74 @@
cmake_minimum_required(VERSION 3.26) cmake_minimum_required(VERSION 3.26)
project(omath VERSION 3.5.0 LANGUAGES CXX) project(omath VERSION 4.0.0 LANGUAGES CXX)
include(CMakePackageConfigHelpers) include(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_TESTS "Build unit tests" OFF)
option(OMATH_BUILD_BENCHMARK "Build benchmarks" OFF)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_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_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_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_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_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_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) option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" ON)
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}") if (VCPKG_MANIFEST_FEATURES)
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}") foreach (omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}") if (omath_feature STREQUAL "imgui")
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}") set(OMATH_IMGUI_INTEGRATION ON)
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}") elseif (omath_feature STREQUAL "avx2")
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}") set(OMATH_USE_AVX2 ${COMPILER_SUPPORTS_AVX2})
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}") elseif (omath_feature STREQUAL "tests")
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}") set(OMATH_BUILD_TESTS ON)
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}") elseif (omath_feature STREQUAL "benchmark")
set(OMATH_BUILD_BENCHMARK ON)
endif ()
endforeach ()
endif ()
if (OMATH_USE_AVX2 AND NOT COMPILER_SUPPORTS_AVX2)
message(WARNING "OMATH_USE_AVX2 requested, but compiler/target does not support AVX2. Disabling.")
set(OMATH_USE_AVX2 OFF CACHE BOOL "Omath will use AVX2 to boost performance" FORCE)
endif ()
if (${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}, compiler ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "[${PROJECT_NAME}]: Warnings as errors ${OMATH_THREAT_WARNING_AS_ERROR}")
message(STATUS "[${PROJECT_NAME}]: Build unit tests ${OMATH_BUILD_TESTS}")
message(STATUS "[${PROJECT_NAME}]: Build benchmark ${OMATH_BUILD_BENCHMARK}")
message(STATUS "[${PROJECT_NAME}]: As dynamic library ${OMATH_BUILD_AS_SHARED_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: Static C++ runtime ${OMATH_STATIC_MSVC_RUNTIME_LIBRARY}")
message(STATUS "[${PROJECT_NAME}]: CMake unity build ${OMATH_USE_UNITY_BUILD}")
message(STATUS "[${PROJECT_NAME}]: Example projects ${OMATH_BUILD_EXAMPLES}")
message(STATUS "[${PROJECT_NAME}]: AVX2 feature status ${OMATH_USE_AVX2}")
message(STATUS "[${PROJECT_NAME}]: ImGUI integration feature status ${OMATH_IMGUI_INTEGRATION}")
message(STATUS "[${PROJECT_NAME}]: Legacy features support ${OMATH_ENABLE_LEGACY}")
message(STATUS "[${PROJECT_NAME}]: Building using vcpkg ${OMATH_BUILD_VIA_VCPKG}")
endif ()
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp") file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp") file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
if (OMATH_BUILD_AS_SHARED_LIBRARY) if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS}) add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
else () else ()
add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS}) add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
endif () endif ()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}") target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
@@ -69,7 +101,7 @@ if (OMATH_SUPRESS_SAFETY_CHECKS)
endif () endif ()
if (OMATH_ENABLE_LEGACY) if (OMATH_ENABLE_LEGACY)
target_compile_options(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY) target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_ENABLE_LEGACY)
endif () endif ()
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
@@ -90,16 +122,25 @@ if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
) )
endif () endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (OMATH_USE_AVX2)
target_compile_options(${PROJECT_NAME} PRIVATE -mavx2 -mfma) 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 () endif ()
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
if (OMATH_BUILD_TESTS) if (OMATH_BUILD_TESTS)
add_subdirectory(extlibs)
add_subdirectory(tests) add_subdirectory(tests)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
endif ()
if (OMATH_BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif () endif ()
if (OMATH_BUILD_EXAMPLES) if (OMATH_BUILD_EXAMPLES)
+75 -5
View File
@@ -8,8 +8,8 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}", "binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}", "installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe", "CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe" "CMAKE_MAKE_PROGRAM": "Ninja"
}, },
"condition": { "condition": {
"type": "equals", "type": "equals",
@@ -17,6 +17,17 @@
"rhs": "Windows" "rhs": "Windows"
} }
}, },
{
"name": "windows-base-vcpkg",
"hidden": true,
"inherits": "windows-base",
"cacheVariables": {
"OMATH_BUILD_VIA_VCPKG": "ON",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed",
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
}
},
{ {
"name": "windows-debug", "name": "windows-debug",
"displayName": "Debug", "displayName": "Debug",
@@ -25,6 +36,23 @@
"CMAKE_BUILD_TYPE": "Debug" "CMAKE_BUILD_TYPE": "Debug"
} }
}, },
{
"name": "windows-debug-vcpkg",
"displayName": "Debug",
"inherits": "windows-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-release-vcpkg",
"displayName": "Release",
"inherits": "windows-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"OMATH_BUILD_VIA_VCPKG": "ON"
}
},
{ {
"name": "windows-release", "name": "windows-release",
"displayName": "Release", "displayName": "Release",
@@ -40,8 +68,8 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}", "binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}", "installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "clang", "CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_COMPILER": "clang++" "CMAKE_MAKE_PROGRAM": "ninja"
}, },
"condition": { "condition": {
"type": "equals", "type": "equals",
@@ -49,6 +77,17 @@
"rhs": "Linux" "rhs": "Linux"
} }
}, },
{
"name": "linux-base-vcpkg",
"hidden": true,
"inherits": "linux-base",
"cacheVariables": {
"OMATH_BUILD_VIA_VCPKG": "ON",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed",
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2"
}
},
{ {
"name": "linux-debug", "name": "linux-debug",
"displayName": "Linux Debug", "displayName": "Linux Debug",
@@ -57,6 +96,14 @@
"CMAKE_BUILD_TYPE": "Debug" "CMAKE_BUILD_TYPE": "Debug"
} }
}, },
{
"name": "linux-debug-vcpkg",
"displayName": "Linux Debug",
"inherits": "linux-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{ {
"name": "linux-release", "name": "linux-release",
"displayName": "Linux Release", "displayName": "Linux Release",
@@ -65,6 +112,14 @@
"CMAKE_BUILD_TYPE": "Release" "CMAKE_BUILD_TYPE": "Release"
} }
}, },
{
"name": "linux-release-vcpkg",
"displayName": "Linux Release",
"inherits": "linux-base-vcpkg",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{ {
"name": "darwin-base", "name": "darwin-base",
"hidden": true, "hidden": true,
@@ -72,7 +127,6 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}", "binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}", "installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++" "CMAKE_CXX_COMPILER": "clang++"
}, },
"condition": { "condition": {
@@ -89,6 +143,14 @@
"CMAKE_BUILD_TYPE": "Debug" "CMAKE_BUILD_TYPE": "Debug"
} }
}, },
{
"name": "darwin-debug-vcpkg",
"displayName": "Darwin Debug",
"inherits": "darwin-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{ {
"name": "darwin-release", "name": "darwin-release",
"displayName": "Darwin Release", "displayName": "Darwin Release",
@@ -96,6 +158,14 @@
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release" "CMAKE_BUILD_TYPE": "Release"
} }
},
{
"name": "darwin-release-vcpkg",
"displayName": "Darwin Release",
"inherits": "darwin-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
} }
] ]
} }
+1 -1
View File
@@ -18,7 +18,7 @@ In order to send code back to the official OMath repository, you must first crea
account ([fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)) and account ([fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)) and
then [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) back to OMath. then [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) back to OMath.
OMath developement is performed on multiple branches. Changes are then pull requested into master. By default, changes OMath development is performed on multiple branches. Changes are then pull requested into master. By default, changes
merged into master will not roll out to stable build users unless the `stable` tag is updated. merged into master will not roll out to stable build users unless the `stable` tag is updated.
### 📜 Code-Style ### 📜 Code-Style
+4 -2
View File
@@ -2,10 +2,12 @@
Thanks to everyone who made this possible, including: 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! And a big hand to everyone else who has contributed over the past!
THANKS! <3 THANKS! <3
-- Orange++ <orange-cpp@yandex.ru> -- Orange++ <orange_github@proton.me>
+1 -1
View File
@@ -59,7 +59,7 @@ target("...")
cmake --preset windows-release -S . cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target omath -j 6 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 | | Platform Name | Build Config |
|---------------|---------------| |---------------|---------------|
+45 -3
View File
@@ -1,7 +1,7 @@
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 This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
arising from the use of this software. arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
@@ -14,4 +14,46 @@ freely, subject to the following restrictions:
appreciated but is not required. appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. 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:
* "Advertising Placement Services" LLC
* "NEW SOLUTIONS VERTICALS" LLC
* "Autoexpert" LLC
* "Creditit" LLC
* "Yandex.Taxi" LLC
* "Yandex.Eda" LLC
* "Yandex.Lavka" LLC
* "Yandex.Telecom" LLC
* "Yandex.Cloud" LLC
* "Micromobility" LLC
* "MM-Tech" LLC
* "Carsharing" LLC
* "Yandex.Drive" LLC
* "EDADIL PROMO" LLC
* "Kinopoisk" LLC
* "Yandex.Music" LLC
* "Refueling (Yandex.Zapravki)" LLC
* "Yandex.Pay" LLC
* "Financial and Payment Technologies" LLC
* "Yandex.Delivery" LLC
* "Delivery Club" LLC
* "Yandex.Check" LLC
* "SMB-Service" LLC
* "ADV-TECH" LLC
* "Yandex Fantech" LLC
* "Yandex Smena" LLC
* "Market.Operations" LLC
* "Yandex.Market" LLC
* "ID Tech" LLC
* "Yandex.Crowd" LLC
* "Yandex" LLC
* "Rutube" LLC
* "Kaspersky" LLC
Or if you represent or are associated with any legal, organizational, or
professional entity providing services to or on behalf of the aforementioned entities:
You are expressly forbidden from accessing, using, modifying, distributing, or
interacting with the Software and its source code in any form. You must immediately
delete or destroy any physical or digital copies of the Software and/or
its source code, including any derivative works, tools, or information obtained from the Software.
+53 -55
View File
@@ -1,8 +1,8 @@
<div align = center> <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 contributors](https://img.shields.io/github/contributors/orange-cpp/omath)
![GitHub top language](https://img.shields.io/github/languages/top/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) [![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) [![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) [![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> </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> <div align = center>
<a href="https://www.star-history.com/#orange-cpp/omath&Date"> <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> </a>
</div> </div>
## 👁‍🗨 Features # Features
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2. - **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
- **Versatility**: Includes a wide array of mathematical functions and algorithms. - **Versatility**: Includes a wide array of mathematical functions and algorithms.
- **Ease of Use**: Simplified interface for convenient integration into various projects. - **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. - **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 - **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! - **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 <br>
| ENGINE | SUPPORT |
|----------|---------|
| Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| OpenGL | ✅YES |
| Unreal | ✅YES |
## Supported Operating Systems [![Youtube Video](.github/images/yt_previews/img.png)](https://youtu.be/lM_NJ1yCunw?si=-Qf5yzDcWbaxAXGQ)
| OS | SUPPORT | <br>
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
## ⏬ Installation ![APEX Preview]
Please read our [installation guide](https://github.com/orange-cpp/omath/blob/main/INSTALL.md). If this link doesn't work check out INSTALL.md file.
## ❔ Usage <br>
ESP example
```c++
omath::source_engine::Camera cam{localPlayer.GetCameraOrigin(),
localPlayer.GetAimPunch(),
{1920.f, 1080.f},
localPlayer.GetFieldOfView(),
0.01.f, 30000.f};
for (auto ent: apex_sdk::EntityList::GetAllEntities()) ![BO2 Preview]
{
const auto bottom = cam.world_to_screen(ent.GetOrigin());
const auto top = cam.world_to_screen(ent.GetBonePosition(8) + omath::Vector3<float>{0, 0, 10});
const auto ent_health = ent.GetHealth(); <br>
if (!top || !bottom || ent_health <= 0) ![CS2 Preview]
continue;
// esp rendering...
}
```
## Showcase
<details>
<summary>OMATH for making cheats (click to open)</summary>
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) ![TF2 Preview]
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>
## 🫵🏻 Contributing <br>
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests. <br>
## 📜 License </div>
This project is licensed under the ZLIB - see the `LICENSE` file for details.
## 💘 Acknowledgments # 💘 Acknowledgments
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors) - [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)
<!----------------------------------{ Images }--------------------------------->
[APEX Preview]: .github/images/showcase/apex.png
[BO2 Preview]: .github/images/showcase/cod_bo2.png
[CS2 Preview]: .github/images/showcase/cs2.jpeg
[TF2 Preview]: .github/images/showcase/tf2.jpg
<!----------------------------------{ Buttons }--------------------------------->
[INSTALL]: INSTALL.md
[DOCUMENTATION]: http://libomath.org
[CONTRIBUTING]: CONTRIBUTING.md
[EXAMPLES]: examples
[SPONSOR]: https://boosty.to/orangecpp/purchase/3568644?ssource=DIRECT&share=subscription_link
+1 -1
View File
@@ -2,4 +2,4 @@
## Reporting a Vulnerability ## Reporting a Vulnerability
Please report security issues to `orange-cpp@yandex.ru` Please report security issues to `orange_github@proton.me`
+1
View File
@@ -0,0 +1 @@
4.0.0
+19
View File
@@ -0,0 +1,19 @@
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)
if (TARGET benchmark::benchmark) # Benchmark is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
else()
find_package(benchmark CONFIG REQUIRED) # Benchmark is being linked as vcpkg package
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
endif ()
+65
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);
+23
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
View File
@@ -0,0 +1,5 @@
//
// Created by Vlad on 9/17/2025.
//
#include <benchmark/benchmark.h>
BENCHMARK_MAIN();
+17
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.
-1
View File
@@ -1 +0,0 @@
add_subdirectory(googletest)
+1 -1
View File
@@ -3,8 +3,8 @@
// //
#pragma once #pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
#include <array> #include <array>
namespace omath::primitives namespace omath::primitives
+1 -1
View File
@@ -3,8 +3,8 @@
// //
#pragma once #pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
#include <array> #include <array>
namespace omath::primitives namespace omath::primitives
+1 -1
View File
@@ -3,8 +3,8 @@
// //
#pragma once #pragma once
#include "omath/linear_algebra/triangle.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "omath/triangle.hpp"
namespace omath::collision namespace omath::collision
{ {
@@ -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
@@ -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
@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include "omath/engines/frostbite_engine/constants.hpp"
namespace omath::frostbite_engine
{
[[nodiscard]]
Vector3<float> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::unity_engine
@@ -0,0 +1,24 @@
//
// Created by Vlad on 8/10/2025.
//
#pragma once
#include "omath/engines/frostbite_engine/formulas.hpp"
#include "omath/projection/camera.hpp"
namespace omath::frostbite_engine
{
class CameraTrait final
{
public:
[[nodiscard]]
static ViewAngles calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept;
[[nodiscard]]
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
float near, float far) noexcept;
};
} // namespace omath::unreal_engine
@@ -0,0 +1,76 @@
//
// Created by Vlad on 8/6/2025.
//
#pragma once
#include "omath/engines/frostbite_engine/formulas.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include <optional>
namespace omath::frostbite_engine
{
class PredEngineTrait final
{
public:
constexpr static Vector3<float> predict_projectile_position(const projectile_prediction::Projectile& projectile,
const float pitch, const float yaw,
const float time, const float gravity) noexcept
{
auto current_pos = projectile.m_origin
+ forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw),
RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
current_pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
return current_pos;
}
[[nodiscard]]
static constexpr Vector3<float> predict_target_position(const projectile_prediction::Target& target,
const float time, const float gravity) noexcept
{
auto predicted = target.m_origin + target.m_velocity * time;
if (target.m_is_airborne)
predicted.y -= gravity * (time * time) * 0.5f;
return predicted;
}
[[nodiscard]]
static float calc_vector_2d_distance(const Vector3<float>& delta) noexcept
{
return std::sqrt(delta.x * delta.x + delta.z * delta.z);
}
[[nodiscard]]
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
{
return vec.y;
}
[[nodiscard]]
static Vector3<float> calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
Vector3<float> predicted_target_position,
const std::optional<float> projectile_pitch) noexcept
{
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z};
}
// Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be:
// 89 look up, -89 look down
[[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::asin(direction.y));
}
[[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
{
const auto direction = (view_to - origin).normalized();
return angles::radians_to_degrees(std::atan2(direction.x, direction.z));
};
};
} // namespace omath::unity_engine
@@ -5,8 +5,8 @@
#pragma once #pragma once
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp> #include <omath/trigonometry/angle.hpp>
#include <omath/view_angles.hpp> #include <omath/trigonometry/view_angles.hpp>
namespace omath::iw_engine namespace omath::iw_engine
{ {
@@ -5,8 +5,8 @@
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp> #include <omath/trigonometry/angle.hpp>
#include <omath/view_angles.hpp> #include <omath/trigonometry/view_angles.hpp>
namespace omath::opengl_engine namespace omath::opengl_engine
{ {
@@ -62,17 +62,15 @@ namespace omath::opengl_engine
[[nodiscard]] [[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 direction = (view_to - origin).normalized();
const auto delta = view_to - origin; return angles::radians_to_degrees(std::asin(direction.y));
return angles::radians_to_degrees(std::asin(delta.y / distance));
} }
[[nodiscard]] [[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 } // namespace omath::opengl_engine
@@ -5,8 +5,8 @@
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp> #include <omath/trigonometry/angle.hpp>
#include <omath/view_angles.hpp> #include <omath/trigonometry/view_angles.hpp>
namespace omath::source_engine namespace omath::source_engine
{ {
@@ -6,8 +6,8 @@
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp> #include <omath/trigonometry/angle.hpp>
#include <omath/view_angles.hpp> #include <omath/trigonometry/view_angles.hpp>
namespace omath::unity_engine namespace omath::unity_engine
{ {
@@ -62,17 +62,15 @@ namespace omath::unity_engine
[[nodiscard]] [[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 direction = (view_to - origin).normalized();
const auto delta = view_to - origin; return angles::radians_to_degrees(std::asin(direction.y));
return angles::radians_to_degrees(std::asin(delta.y / distance));
} }
[[nodiscard]] [[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 } // namespace omath::unity_engine
@@ -6,8 +6,8 @@
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include <omath/angle.hpp> #include <omath/trigonometry/angle.hpp>
#include <omath/view_angles.hpp> #include <omath/trigonometry/view_angles.hpp>
namespace omath::unreal_engine namespace omath::unreal_engine
{ {
@@ -62,17 +62,16 @@ namespace omath::unreal_engine
[[nodiscard]] [[nodiscard]]
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 direction = (view_to - origin).normalized();
const auto delta = view_to - origin;
return angles::radians_to_degrees(std::asin(delta.z / distance)); return angles::radians_to_degrees(std::asin(direction.z));
} }
[[nodiscard]] [[nodiscard]]
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept 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 } // namespace omath::unreal_engine
+235 -25
View File
@@ -11,14 +11,12 @@
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#ifdef near #ifdef OMATH_USE_AVX2
#include <immintrin.h>
#endif
#undef near #undef near
#endif
#ifdef far
#undef far #undef far
#endif
namespace omath namespace omath
{ {
struct MatSize struct MatSize
@@ -41,6 +39,7 @@ namespace omath
class Mat final class Mat final
{ {
public: public:
using ContainedType = Type;
constexpr Mat() noexcept constexpr Mat() noexcept
{ {
clear(); clear();
@@ -88,7 +87,7 @@ namespace omath
} }
[[nodiscard]] [[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); return at(row, col);
} }
@@ -162,17 +161,19 @@ namespace omath
constexpr Mat<Rows, OtherColumns, Type, StoreType> constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{ {
Mat<Rows, OtherColumns, Type, StoreType> result; #ifdef OMATH_USE_AVX2
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
for (size_t i = 0; i < Rows; ++i) return avx_multiply_row_major(other);
for (size_t j = 0; j < OtherColumns; ++j) else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
{ return avx_multiply_col_major(other);
Type sum = 0; #else
for (size_t k = 0; k < Columns; ++k) if constexpr (StoreType == MatStoreType::ROW_MAJOR)
sum += at(i, k) * other.at(k, j); return cache_friendly_multiply_row_major(other);
result.at(i, j) = sum; else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
} return cache_friendly_multiply_col_major(other);
return result; #endif
else
std::unreachable();
} }
constexpr Mat& operator*=(const Type& f) noexcept constexpr Mat& operator*=(const Type& f) noexcept
@@ -328,6 +329,21 @@ namespace omath
return oss.str(); 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]] [[nodiscard]]
bool operator==(const Mat& mat) const bool operator==(const Mat& mat) const
{ {
@@ -374,6 +390,176 @@ namespace omath
private: private:
std::array<Type, Rows * Columns> m_data; 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]] template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
@@ -481,8 +667,7 @@ namespace omath
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type bottom, const Type top,
const Type near, const Type far) noexcept const Type near, const Type far) noexcept
{ {
return return
@@ -495,9 +680,8 @@ namespace omath
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type bottom, const Type top, const Type near, const Type far) noexcept
const Type near, const Type far) noexcept
{ {
return return
{ {
@@ -507,6 +691,23 @@ namespace omath
{ 0.f, 0.f, 0.f, 1.f } { 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 } // namespace omath
@@ -519,9 +720,18 @@ struct std::formatter<omath::Mat<Rows, Columns, Type, StoreType>> // NOLINT(*-dc
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const MatType& mat, std::format_context& ctx) static auto format(const MatType& mat, FormatContext& ctx)
{ {
return std::format_to(ctx.out(), "{}", mat.to_string()); 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());
} }
}; };
-127
View File
@@ -1,127 +0,0 @@
#pragma once
/*
THIS CODE IS DEPRECATED NEVER EVER USE Matrix CLASS
AND VERY SLOW USE Mat INSTEAD!!!!!!!!!!!
⠛⠛⣿⣿⣿⣿⣿⡷⢶⣦⣶⣶⣤⣤⣤⣀⠀⠀⠀
⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀
⠀⠀⠀⠉⠉⠉⠙⠻⣿⣿⠿⠿⠛⠛⠛⠻⣿⣿⣇⠀
⠀⠀⢤⣀⣀⣀⠀⠀⢸⣷⡄⠀⣁⣀⣤⣴⣿⣿⣿⣆
⠀⠀⠀⠀⠹⠏⠀⠀⠀⣿⣧⠀⠹⣿⣿⣿⣿⣿⡿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠿⠇⢀⣼⣿⣿⠛⢯⡿⡟
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠦⠴⢿⢿⣿⡿⠷⠀⣿⠀
⠀⠀⠀⠀⠀⠀⠀⠙⣷⣶⣶⣤⣤⣤⣤⣤⣶⣦⠃⠀
⠀⠀⠀⠀⠀⠀⠀⢐⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀
⠀⠙⠻⢿⣿⣿⣿⣿⠟⠁
*/
#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
@@ -2,7 +2,7 @@
// Created by Orange on 11/13/2024. // Created by Orange on 11/13/2024.
// //
#pragma once #pragma once
#include "linear_algebra/vector3.hpp" #include "vector3.hpp"
namespace omath namespace omath
{ {
+27 -3
View File
@@ -221,7 +221,7 @@ namespace omath
} }
#ifdef OMATH_IMGUI_INTEGRATION #ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]] [[nodiscard]]
ImVec2 to_im_vec2() const noexcept constexpr ImVec2 to_im_vec2() const noexcept
{ {
return {static_cast<float>(this->x), static_cast<float>(this->y)}; return {static_cast<float>(this->x), static_cast<float>(this->y)};
} }
@@ -234,6 +234,21 @@ namespace omath
}; };
} // namespace omath } // namespace omath
template<> struct std::hash<omath::Vector2<float>>
{
[[nodiscard]]
std::size_t operator()(const omath::Vector2<float>& vec) const noexcept
{
std::size_t hash = 0;
constexpr std::hash<float> hasher;
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
return hash;
}
};
template<class Type> template<class Type>
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp) struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
{ {
@@ -242,9 +257,18 @@ struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const omath::Vector2<Type>& vec, std::format_context& ctx) static auto format(const omath::Vector2<Type>& vec, FormatContext& ctx)
{ {
return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y); 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);
} }
}; };
+13 -12
View File
@@ -4,7 +4,7 @@
#pragma once #pragma once
#include "omath/angle.hpp" #include "omath/trigonometry/angle.hpp"
#include "omath/linear_algebra/vector2.hpp" #include "omath/linear_algebra/vector2.hpp"
#include <cstdint> #include <cstdint>
#include <expected> #include <expected>
@@ -245,15 +245,6 @@ namespace omath
return std::make_tuple(this->x, this->y, z); return std::make_tuple(this->x, this->y, z);
} }
[[nodiscard]] Vector3 view_angle_to(const Vector3& other) const noexcept
{
const auto distance = distance_to(other);
const auto delta = other - *this;
return {angles::radians_to_degrees(std::asin(delta.z / distance)),
angles::radians_to_degrees(std::atan2(delta.y, delta.x)), 0};
}
[[nodiscard]] [[nodiscard]]
bool operator<(const Vector3& other) const noexcept bool operator<(const Vector3& other) const noexcept
{ {
@@ -282,6 +273,7 @@ namespace omath
template<> struct std::hash<omath::Vector3<float>> template<> struct std::hash<omath::Vector3<float>>
{ {
[[nodiscard]]
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{ {
std::size_t hash = 0; std::size_t hash = 0;
@@ -303,9 +295,18 @@ struct std::formatter<omath::Vector3<Type>> // NOLINT(*-dcl58-cpp)
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const omath::Vector3<Type>& vec, std::format_context& ctx) static auto format(const omath::Vector3<Type>& vec, FormatContext& ctx)
{ {
return std::format_to(ctx.out(), "[{}, {}, {}]", vec.x, vec.y, vec.z); 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);
} }
}; };
+27 -3
View File
@@ -184,7 +184,7 @@ namespace omath
#ifdef OMATH_IMGUI_INTEGRATION #ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]] [[nodiscard]]
ImVec4 to_im_vec4() const noexcept constexpr ImVec4 to_im_vec4() const noexcept
{ {
return { return {
static_cast<float>(this->x), static_cast<float>(this->x),
@@ -202,6 +202,22 @@ namespace omath
}; };
} // namespace omath } // namespace omath
template<> struct std::hash<omath::Vector4<float>>
{
[[nodiscard]]
std::size_t operator()(const omath::Vector4<float>& vec) const noexcept
{
std::size_t hash = 0;
constexpr std::hash<float> hasher;
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
hash ^= hasher(vec.w) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
return hash;
}
};
template<class Type> template<class Type>
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp) struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
{ {
@@ -210,9 +226,17 @@ struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const omath::Vector4<Type>& vec, std::format_context& ctx) static auto format(const omath::Vector4<Type>& vec, FormatContext& ctx)
{ {
return std::format_to(ctx.out(), "[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w); 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);
} }
}; };
+23 -7
View File
@@ -6,8 +6,8 @@
#pragma once #pragma once
// Basic math utilities // Basic math utilities
#include "omath/angles.hpp" #include "omath/trigonometry/angles.hpp"
#include "omath/angle.hpp" #include "omath/trigonometry/angle.hpp"
// Vector classes (in dependency order) // Vector classes (in dependency order)
#include "omath/linear_algebra/vector2.hpp" #include "omath/linear_algebra/vector2.hpp"
@@ -15,18 +15,18 @@
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
// Matrix classes // Matrix classes
#include "linear_algebra/matrix.hpp"
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
// Color functionality // Color functionality
#include "omath/color.hpp" #include "omath/utility/color.hpp"
// Geometric primitives // Geometric primitives
#include "omath/triangle.hpp" #include "omath/linear_algebra/triangle.hpp"
#include "omath/view_angles.hpp" #include "omath/trigonometry/view_angles.hpp"
// 3D primitives // 3D primitives
#include "omath/3d_primitives/box.hpp" #include "omath/3d_primitives/box.hpp"
#include "omath/3d_primitives/plane.hpp"
// Collision detection // Collision detection
#include "omath/collision/line_tracer.hpp" #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/camera_trait.hpp"
#include "omath/engines/unity_engine/traits/pred_engine_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 // Unreal Engine
#include "omath/engines/unreal_engine/constants.hpp" #include "omath/engines/unreal_engine/constants.hpp"
#include "omath/engines/unreal_engine/formulas.hpp" #include "omath/engines/unreal_engine/formulas.hpp"
#include "omath/engines/unreal_engine/camera.hpp" #include "omath/engines/unreal_engine/camera.hpp"
#include "omath/engines/unreal_engine/traits/camera_trait.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"
-4
View File
@@ -22,9 +22,5 @@ namespace omath::pathfinding
static std::vector<Vector3<float>> static std::vector<Vector3<float>>
reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list, reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
const Vector3<float>& current) noexcept; const Vector3<float>& current) noexcept;
[[nodiscard]]
static auto get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept;
}; };
} // namespace omath::pathfinding } // namespace omath::pathfinding
@@ -4,8 +4,8 @@
#pragma once #pragma once
#include "omath/linear_algebra/vector3.hpp"
#include "omath/engines/source_engine/traits/pred_engine_trait.hpp" #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/proj_pred_engine.hpp"
#include "omath/projectile_prediction/projectile.hpp" #include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp" #include "omath/projectile_prediction/target.hpp"
@@ -20,7 +20,9 @@ namespace omath::projectile_prediction
Vector3<float> v3, // by-value for calc_viewpoint_from_angles Vector3<float> v3, // by-value for calc_viewpoint_from_angles
float pitch, float yaw, float time, float gravity, std::optional<float> maybe_pitch) { float pitch, float yaw, float time, float gravity, std::optional<float> maybe_pitch) {
// Presence + return types // 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::predict_target_position(target, time, gravity) } -> std::same_as<Vector3<float>>;
{ T::calc_vector_2d_distance(vec_a) } -> std::same_as<float>; { T::calc_vector_2d_distance(vec_a) } -> std::same_as<float>;
{ T::get_vector_height_coordinate(vec_b) } -> std::same_as<float>; { T::get_vector_height_coordinate(vec_b) } -> std::same_as<float>;
+110 -19
View File
@@ -4,13 +4,18 @@
#pragma once #pragma once
#include "omath/projection/error_codes.hpp"
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "omath/projection/error_codes.hpp"
#include <omath/trigonometry/angle.hpp>
#include <expected> #include <expected>
#include <omath/angle.hpp>
#include <type_traits> #include <type_traits>
#ifdef OMATH_BUILD_TESTS
// ReSharper disable once CppInconsistentNaming
class UnitTestProjection_Projection_Test;
#endif
namespace omath::projection namespace omath::projection
{ {
class ViewPort final class ViewPort final
@@ -45,7 +50,16 @@ namespace omath::projection
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType> requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
class Camera final class Camera final
{ {
#ifdef OMATH_BUILD_TESTS
friend UnitTestProjection_Projection_Test;
#endif
public: public:
enum class ScreenStart
{
TOP_LEFT_CORNER,
BOTTOM_LEFT_CORNER,
};
~Camera() = default; ~Camera() = default;
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port, Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
const FieldOfView& fov, const float near, const float far) noexcept const FieldOfView& fov, const float near, const float far) noexcept
@@ -54,12 +68,13 @@ namespace omath::projection
{ {
} }
protected:
void look_at(const Vector3<float>& target) void look_at(const Vector3<float>& target)
{ {
m_view_angles = TraitClass::calc_look_at_angle(m_origin, 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 [[nodiscard]] Mat4X4Type calc_view_projection_matrix() const noexcept
{ {
return TraitClass::calc_projection_matrix(m_field_of_view, m_view_port, m_near_plane_distance, 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; return m_origin;
} }
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
[[nodiscard]] std::expected<Vector3<float>, Error> [[nodiscard]] std::expected<Vector3<float>, Error>
world_to_screen(const Vector3<float>& world_position) const noexcept world_to_screen(const Vector3<float>& world_position) const noexcept
{ {
auto normalized_cords = world_to_view_port(world_position); const auto normalized_cords = world_to_view_port(world_position);
if (!normalized_cords.has_value()) if (!normalized_cords.has_value())
return std::unexpected{normalized_cords.error()}; return std::unexpected{normalized_cords.error()};
return ndc_to_screen_position(*normalized_cords); if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER)
return ndc_to_screen_position_from_top_left_corner(*normalized_cords);
else if constexpr (screen_start == ScreenStart::BOTTOM_LEFT_CORNER)
return ndc_to_screen_position_from_bottom_left_corner(*normalized_cords);
else
std::unreachable();
} }
[[nodiscard]] std::expected<Vector3<float>, Error> [[nodiscard]] std::expected<Vector3<float>, Error>
@@ -164,6 +186,38 @@ namespace omath::projection
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)}; 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: protected:
ViewPort m_view_port{}; 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; }); 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 | (0, 0)
1 | |
| |
| |
-1 ---------0--------- 1 --> x |
| |
| |
-1 |
v */
*/ return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / -2.f + 0.5f) * m_view_port.m_height, ndc.z};
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z}; }
[[nodiscard]] Vector3<float>
ndc_to_screen_position_from_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 } // namespace omath::projection
+1
View File
@@ -10,5 +10,6 @@ namespace omath::projection
enum class Error : uint16_t enum class Error : uint16_t
{ {
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS, WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
INV_VIEW_PROJ_MAT_DET_EQ_ZERO,
}; };
} }
@@ -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
@@ -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
@@ -3,10 +3,10 @@
// //
#pragma once #pragma once
#include "omath/angles.hpp" #include "omath/trigonometry/angles.hpp"
#include <algorithm> #include <algorithm>
#include <utility>
#include <format> #include <format>
#include <utility>
namespace omath namespace omath
{ {
@@ -123,13 +123,13 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
constexpr Angle& operator+(const Angle& other) noexcept constexpr Angle operator+(const Angle& other) noexcept
{ {
if constexpr (flags == AngleFlags::Normalized) 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) 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 else
static_assert(false); static_assert(false);
@@ -138,7 +138,7 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
constexpr Angle& operator-(const Angle& other) noexcept constexpr Angle operator-(const Angle& other) noexcept
{ {
return operator+(-other); return operator+(-other);
} }
@@ -150,17 +150,62 @@ namespace omath
} }
}; };
} // namespace omath } // namespace omath
template<class Type, Type min, Type max, omath::AngleFlags flags>
struct std::formatter<omath::Angle<Type, min, max, flags>> // NOLINT(*-dcl58-cpp) template<class T, T MinV, T MaxV, omath::AngleFlags F>
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, char> // NOLINT(*-dcl58-cpp)
{ {
[[nodiscard]] using AngleT = omath::Angle<T, MinV, MaxV, F>;
static constexpr auto parse(std::format_parse_context& ctx) static constexpr auto parse(std::format_parse_context& ctx)
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const omath::Angle<Type, min, max, flags>& deg, std::format_context& ctx) auto format(const AngleT& a, FormatContext& ctx) const
{ {
return std::format_to(ctx.out(), "{}deg", deg.as_degrees()); 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());
}
};
@@ -4,7 +4,7 @@
#pragma once #pragma once
#include "linear_algebra/vector4.hpp" #include "omath/linear_algebra/vector4.hpp"
#include <cstdint> #include <cstdint>
namespace omath namespace omath
@@ -95,7 +95,7 @@ namespace omath
hsv_data.hue = 0.f; hsv_data.hue = 0.f;
else if (max == red) 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) else if (max == green)
hsv_data.hue = 60.f * (((blue - red) / delta) + 2.f); hsv_data.hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue) else if (max == blue)
@@ -164,6 +164,26 @@ namespace omath
return {to_im_vec4()}; return {to_im_vec4()};
} }
#endif #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 } // namespace omath
template<> template<>
@@ -174,13 +194,19 @@ struct std::formatter<omath::Color> // NOLINT(*-dcl58-cpp)
{ {
return ctx.begin(); return ctx.begin();
} }
template<class FormatContext>
[[nodiscard]] [[nodiscard]]
static auto format(const omath::Color& col, std::format_context& ctx) static auto format(const omath::Color& col, FormatContext& ctx)
{ {
return std::format_to(ctx.out(), "[r:{}, g:{}, b:{}, a:{}]", if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
static_cast<int>(col.x * 255.f), return std::format_to(ctx.out(), "{}", col.to_string());
static_cast<int>(col.y * 255.f), if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
static_cast<int>(col.z * 255.f), return std::format_to(ctx.out(), L"{}", col.to_wstring());
static_cast<int>(col.w * 255.f));
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();
} }
}; };
+78
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
+30
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
View File
@@ -0,0 +1 @@
site_name: My Docs
+4 -6
View File
@@ -50,12 +50,10 @@ namespace omath::collision
const auto t_hit = side_b.dot(q) * inv_det; const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length) if (ray.infinite_length && t_hit <= k_epsilon)
{ return ray.end;
if (t_hit <= k_epsilon)
return ray.end; if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
}
else if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
return ray.end; return ray.end;
return ray.start + ray_dir * t_hit; return ray.start + ray_dir * t_hit;
@@ -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
@@ -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
@@ -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 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 direction = (look_at - cam_origin).normalized();
const auto delta = cam_origin - look_at;
return {PitchAngle::from_radians(-std::asin(delta.z / distance)), return {PitchAngle::from_radians(-std::asin(direction.z)),
YawAngle::from_radians(std::atan2(delta.y, delta.x)), RollAngle::from_radians(0.f)}; 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 Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
+4 -5
View File
@@ -28,14 +28,13 @@ namespace omath::opengl_engine
} }
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
return mat_camera_view<float, MatStoreType::COLUMN_MAJOR>(-forward_vector(angles), right_vector(angles), return mat_look_at_right_handed(cam_origin, cam_origin+forward_vector(angles), up_vector(angles));
up_vector(angles), cam_origin);
} }
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{ {
return mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(-angles.pitch) return mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll)
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(-angles.yaw) * mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(angles.yaw)
* mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll); * 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, Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept const float far) noexcept
@@ -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 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 direction = (look_at - cam_origin).normalized();
const auto delta = cam_origin - look_at;
return {PitchAngle::from_radians(-std::asin(delta.y / distance)), return {PitchAngle::from_radians(std::asin(direction.y)),
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)}; 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 Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
@@ -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 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 direction = (look_at - cam_origin).normalized();
const auto delta = cam_origin - look_at;
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 Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
+4 -11
View File
@@ -25,25 +25,18 @@ namespace omath::unity_engine
} }
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), -right_vector(angles), return mat_camera_view<float, MatStoreType::ROW_MAJOR>(-forward_vector(angles), right_vector(angles),
up_vector(angles), cam_origin); up_vector(angles), cam_origin);
} }
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{ {
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_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, Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept const float far) noexcept
{ {
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f); return omath::mat_perspective_right_handed(field_of_view, aspect_ratio, near, far);
return {
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
{0, 1.f / (fov_half_tan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1.f, 0},
};
} }
} // namespace omath::unity_engine } // namespace omath::unity_engine
@@ -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 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 direction = (look_at - cam_origin).normalized();
const auto delta = cam_origin - look_at;
return {PitchAngle::from_radians(-std::asin(delta.y / distance)), return {PitchAngle::from_radians(-std::asin(direction.y)),
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)}; 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 Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
+2 -2
View File
@@ -31,8 +31,8 @@ namespace omath::unreal_engine
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{ {
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.roll) 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, Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept const float far) noexcept
@@ -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 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 direction = (look_at - cam_origin).normalized();
const auto delta = cam_origin - look_at;
return {PitchAngle::from_radians(-std::asin(delta.z / distance)), return {PitchAngle::from_radians(-std::asin(direction.z)),
YawAngle::from_radians(std::atan2(delta.x, delta.y)), RollAngle::from_radians(0.f)}; 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 Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{ {
-364
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
+37 -21
View File
@@ -4,9 +4,25 @@
#include "omath/pathfinding/a_star.hpp" #include "omath/pathfinding/a_star.hpp"
#include <algorithm> #include <algorithm>
#include <optional> #include <optional>
#include <queue>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
namespace
{
struct OpenListNode final
{
omath::Vector3<float> position;
float f_cost;
[[nodiscard]]
bool operator>(const OpenListNode& other) const noexcept
{
return f_cost > other.f_cost;
}
};
}
namespace omath::pathfinding namespace omath::pathfinding
{ {
struct PathNode final struct PathNode final
@@ -37,23 +53,13 @@ namespace omath::pathfinding
std::ranges::reverse(path); std::ranges::reverse(path);
return path; return path;
} }
auto Astar::get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept
{
return std::ranges::min_element(open_list,
[&end_vertex](const auto& a, const auto& b)
{
const float fa = a.second.g_cost + a.first.distance_to(end_vertex);
const float fb = b.second.g_cost + b.first.distance_to(end_vertex);
return fa < fb;
});
}
std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end, std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end,
const NavigationMesh& nav_mesh) noexcept const NavigationMesh& nav_mesh) noexcept
{ {
std::unordered_map<Vector3<float>, PathNode> closed_list; std::unordered_map<Vector3<float>, PathNode> closed_list;
std::unordered_map<Vector3<float>, PathNode> open_list; std::unordered_map<Vector3<float>, PathNode> node_data;
std::priority_queue<OpenListNode, std::vector<OpenListNode>, std::greater<>> open_list;
auto maybe_start_vertex = nav_mesh.get_closest_vertex(start); auto maybe_start_vertex = nav_mesh.get_closest_vertex(start);
auto maybe_end_vertex = nav_mesh.get_closest_vertex(end); auto maybe_end_vertex = nav_mesh.get_closest_vertex(end);
@@ -64,20 +70,27 @@ namespace omath::pathfinding
const auto start_vertex = maybe_start_vertex.value(); const auto start_vertex = maybe_start_vertex.value();
const auto end_vertex = maybe_end_vertex.value(); const auto end_vertex = maybe_end_vertex.value();
open_list.emplace(start_vertex, PathNode{std::nullopt, 0.f}); node_data.emplace(start_vertex, PathNode{std::nullopt, 0.f});
open_list.push({start_vertex, start_vertex.distance_to(end_vertex)});
while (!open_list.empty()) while (!open_list.empty())
{ {
auto current_it = get_perfect_node(open_list, end_vertex); auto current = open_list.top().position;
open_list.pop();
const auto current = current_it->first; if (closed_list.contains(current))
const auto current_node = current_it->second; continue;
auto current_node_it = node_data.find(current);
if (current_node_it == node_data.end())
continue;
const auto current_node = current_node_it->second;
if (current == end_vertex) if (current == end_vertex)
return reconstruct_final_path(closed_list, current); return reconstruct_final_path(closed_list, current);
closed_list.emplace(current, current_node); closed_list.emplace(current, current_node);
open_list.erase(current_it);
for (const auto& neighbor: nav_mesh.get_neighbors(current)) for (const auto& neighbor: nav_mesh.get_neighbors(current))
{ {
@@ -86,11 +99,14 @@ namespace omath::pathfinding
const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current); const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current);
// ReSharper disable once CppTooWideScopeInitStatement auto node_it = node_data.find(neighbor);
const auto open_it = open_list.find(neighbor);
if (open_it == open_list.end() || tentative_g_cost < open_it->second.g_cost) if (node_it == node_data.end() || tentative_g_cost < node_it->second.g_cost)
open_list[neighbor] = PathNode{current, tentative_g_cost}; {
node_data[neighbor] = PathNode{current, tentative_g_cost};
const float f_cost = tentative_g_cost + neighbor.distance_to(end_vertex);
open_list.push({neighbor, f_cost});
}
} }
} }
+33 -18
View File
@@ -3,6 +3,8 @@
// //
#include "omath/pathfinding/navigation_mesh.hpp" #include "omath/pathfinding/navigation_mesh.hpp"
#include <algorithm> #include <algorithm>
#include <cstring>
#include <limits>
#include <stdexcept> #include <stdexcept>
namespace omath::pathfinding namespace omath::pathfinding
{ {
@@ -13,7 +15,7 @@ namespace omath::pathfinding
{ return a.first.distance_to(point) < b.first.distance_to(point); }); { return a.first.distance_to(point) < b.first.distance_to(point); });
if (res == m_vertex_map.cend()) if (res == m_vertex_map.cend())
return std::unexpected("Failed to get clossest point"); return std::unexpected("Failed to get closest point");
return res->first; return res->first;
} }
@@ -30,55 +32,68 @@ namespace omath::pathfinding
std::vector<uint8_t> NavigationMesh::serialize() const noexcept std::vector<uint8_t> NavigationMesh::serialize() const noexcept
{ {
auto dump_to_vector = []<typename T>(const T& t, std::vector<uint8_t>& vec) std::vector<std::uint8_t> raw;
// Pre-calculate total size for better performance
std::size_t total_size = 0;
for (const auto& [vertex, neighbors] : m_vertex_map)
{ {
for (size_t i = 0; i < sizeof(t); i++) total_size += sizeof(vertex) + sizeof(std::uint16_t) + sizeof(Vector3<float>) * neighbors.size();
vec.push_back(*(reinterpret_cast<const uint8_t*>(&t) + i)); }
raw.reserve(total_size);
auto dump_to_vector = [&raw]<typename T>(const T& t)
{
const auto* byte_ptr = reinterpret_cast<const std::uint8_t*>(&t);
raw.insert(raw.end(), byte_ptr, byte_ptr + sizeof(T));
}; };
std::vector<uint8_t> raw; for (const auto& [vertex, neighbors] : m_vertex_map)
for (const auto& [vertex, neighbors]: m_vertex_map)
{ {
const auto neighbors_count = neighbors.size(); // Clamp neighbors count to fit in uint16_t (prevents silent data corruption)
// NOTE: If neighbors.size() > 65535, only the first 65535 neighbors will be serialized.
// This is a limitation of the current serialization format using uint16_t for count.
const auto clamped_count =
std::min<std::size_t>(neighbors.size(), std::numeric_limits<std::uint16_t>::max());
const auto neighbors_count = static_cast<std::uint16_t>(clamped_count);
dump_to_vector(vertex, raw); dump_to_vector(vertex);
dump_to_vector(neighbors_count, raw); dump_to_vector(neighbors_count);
for (const auto& neighbor: neighbors) // Only serialize up to the clamped count
dump_to_vector(neighbor, raw); for (std::size_t i = 0; i < clamped_count; ++i)
dump_to_vector(neighbors[i]);
} }
return raw; return raw;
} }
void NavigationMesh::deserialize(const std::vector<uint8_t>& raw) noexcept void NavigationMesh::deserialize(const std::vector<uint8_t>& raw) noexcept
{ {
auto load_from_vector = [](const std::vector<uint8_t>& vec, size_t& offset, auto& value) auto load_from_vector = [](const std::vector<uint8_t>& vec, std::size_t& offset, auto& value)
{ {
if (offset + sizeof(value) > vec.size()) if (offset + sizeof(value) > vec.size())
{
throw std::runtime_error("Deserialize: Invalid input data size."); throw std::runtime_error("Deserialize: Invalid input data size.");
}
std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast<uint8_t*>(&value)); std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast<uint8_t*>(&value));
offset += sizeof(value); offset += sizeof(value);
}; };
m_vertex_map.clear(); m_vertex_map.clear();
size_t offset = 0; std::size_t offset = 0;
while (offset < raw.size()) while (offset < raw.size())
{ {
Vector3<float> vertex; Vector3<float> vertex;
load_from_vector(raw, offset, vertex); load_from_vector(raw, offset, vertex);
uint16_t neighbors_count; std::uint16_t neighbors_count;
load_from_vector(raw, offset, neighbors_count); load_from_vector(raw, offset, neighbors_count);
std::vector<Vector3<float>> neighbors; std::vector<Vector3<float>> neighbors;
neighbors.reserve(neighbors_count); neighbors.reserve(neighbors_count);
for (size_t i = 0; i < neighbors_count; ++i) for (std::size_t i = 0; i < neighbors_count; ++i)
{ {
Vector3<float> neighbor; Vector3<float> neighbor;
load_from_vector(raw, offset, neighbor); load_from_vector(raw, offset, neighbor);
@@ -18,97 +18,104 @@ namespace omath::projectile_prediction
[[maybe_unused]] const Target& target) const [[maybe_unused]] const Target& target) const
{ {
#if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__) #if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__)
const float bulletGravity = m_gravityConstant * projectile.m_gravityScale; const float bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
const float v0 = projectile.m_launchSpeed; const float v0 = projectile.m_launch_speed;
const float v0Sqr = v0 * v0; const float v0_sqr = v0 * v0;
const Vector3 projOrigin = projectile.m_origin; const Vector3 proj_origin = projectile.m_origin;
constexpr int SIMD_FACTOR = 8; constexpr int SIMD_FACTOR = 8;
float currentTime = m_simulationTimeStep; float current_time = m_simulation_time_step;
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR) for (; current_time <= m_maximum_simulation_time; current_time += m_simulation_time_step * SIMD_FACTOR)
{ {
const __m256 times const __m256 times
= _mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep, = _mm256_setr_ps(current_time, current_time + m_simulation_time_step,
currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3, current_time + m_simulation_time_step * 2, current_time + m_simulation_time_step * 3,
currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5, current_time + m_simulation_time_step * 4, current_time + m_simulation_time_step * 5,
currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7); current_time + m_simulation_time_step * 6, current_time + m_simulation_time_step * 7);
const __m256 targetX const __m256 target_x
= _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x)); = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x));
const __m256 targetY const __m256 target_y
= _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y)); = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y));
const __m256 timesSq = _mm256_mul_ps(times, times); const __m256 times_sq = _mm256_mul_ps(times, times);
const __m256 targetZ = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times, const __m256 target_z = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times,
_mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravityConstant), timesSq, _mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravity_constant), times_sq,
_mm256_set1_ps(target.m_origin.z))); _mm256_set1_ps(target.m_origin.z)));
const __m256 deltaX = _mm256_sub_ps(targetX, _mm256_set1_ps(projOrigin.x)); const __m256 delta_x = _mm256_sub_ps(target_x, _mm256_set1_ps(proj_origin.x));
const __m256 deltaY = _mm256_sub_ps(targetY, _mm256_set1_ps(projOrigin.y)); const __m256 delta_y = _mm256_sub_ps(target_y, _mm256_set1_ps(proj_origin.y));
const __m256 deltaZ = _mm256_sub_ps(targetZ, _mm256_set1_ps(projOrigin.z)); const __m256 delta_z = _mm256_sub_ps(target_z, _mm256_set1_ps(proj_origin.z));
const __m256 dSqr = _mm256_add_ps(_mm256_mul_ps(deltaX, deltaX), _mm256_mul_ps(deltaY, deltaY)); const __m256 d_sqr = _mm256_add_ps(_mm256_mul_ps(delta_x, delta_x), _mm256_mul_ps(delta_y, delta_y));
const __m256 bgTimesSq = _mm256_mul_ps(_mm256_set1_ps(bulletGravity), timesSq); const __m256 bg_times_sq = _mm256_mul_ps(_mm256_set1_ps(bullet_gravity), times_sq);
const __m256 term = _mm256_add_ps(deltaZ, _mm256_mul_ps(_mm256_set1_ps(0.5f), bgTimesSq)); const __m256 term = _mm256_add_ps(delta_z, _mm256_mul_ps(_mm256_set1_ps(0.5f), bg_times_sq));
const __m256 termSq = _mm256_mul_ps(term, term); const __m256 term_sq = _mm256_mul_ps(term, term);
const __m256 numerator = _mm256_add_ps(dSqr, termSq); const __m256 numerator = _mm256_add_ps(d_sqr, term_sq);
const __m256 denominator = _mm256_add_ps(timesSq, _mm256_set1_ps(1e-8f)); // Avoid division by zero const __m256 denominator = _mm256_add_ps(times_sq, _mm256_set1_ps(1e-8f)); // Avoid division by zero
const __m256 requiredV0Sqr = _mm256_div_ps(numerator, denominator); const __m256 required_v0_sqr = _mm256_div_ps(numerator, denominator);
const __m256 v0SqrVec = _mm256_set1_ps(v0Sqr + 1e-3f); const __m256 v0_sqr_vec = _mm256_set1_ps(v0_sqr + 1e-3f);
const __m256 mask = _mm256_cmp_ps(requiredV0Sqr, v0SqrVec, _CMP_LE_OQ); const __m256 mask = _mm256_cmp_ps(required_v0_sqr, v0_sqr_vec, _CMP_LE_OQ);
const unsigned validMask = _mm256_movemask_ps(mask); const unsigned valid_mask = _mm256_movemask_ps(mask);
if (!validMask) if (!valid_mask)
continue; continue;
alignas(32) float validTimes[SIMD_FACTOR]; alignas(32) float valid_times[SIMD_FACTOR];
_mm256_store_ps(validTimes, times); _mm256_store_ps(valid_times, times);
for (int i = 0; i < SIMD_FACTOR; ++i) for (int i = 0; i < SIMD_FACTOR; ++i)
{ {
if (!(validMask & (1 << i))) if (!(valid_mask & (1 << i)))
continue; continue;
const float candidateTime = validTimes[i]; const float candidate_time = valid_times[i];
if (candidateTime > m_maximumSimulationTime) if (candidate_time > m_maximum_simulation_time)
continue; continue;
// Fine search around candidate time // Fine search around candidate time
for (float fineTime = candidateTime - m_simulationTimeStep * 2; for (float fine_time = candidate_time - m_simulation_time_step * 2;
fineTime <= candidateTime + m_simulationTimeStep * 2; fineTime += m_simulationTimeStep) fine_time <= candidate_time + m_simulation_time_step * 2; fine_time += m_simulation_time_step)
{ {
if (fineTime < 0) if (fine_time < 0)
continue; continue;
const Vector3 targetPos = target.PredictPosition(fineTime, m_gravityConstant); // Manually compute predicted target position to avoid adding method to Target
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, fineTime); Vector3 target_pos = target.m_origin + target.m_velocity * fine_time;
if (target.m_is_airborne)
target_pos.z -= 0.5f * m_gravity_constant * fine_time * fine_time;
const auto pitch = calculate_pitch(proj_origin, target_pos, bullet_gravity, v0, fine_time);
if (!pitch) if (!pitch)
continue; continue;
const Vector3 delta = targetPos - projOrigin; const Vector3 delta = target_pos - proj_origin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y); const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch)); const float height = d * std::tan(angles::degrees_to_radians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height); return Vector3(target_pos.x, target_pos.y, proj_origin.z + height);
} }
} }
} }
// Fallback scalar processing for remaining times // Fallback scalar processing for remaining times
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep) for (; current_time <= m_maximum_simulation_time; current_time += m_simulation_time_step)
{ {
const Vector3 targetPos = target.PredictPosition(currentTime, m_gravityConstant); Vector3 target_pos = target.m_origin + target.m_velocity * current_time;
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, currentTime); if (target.m_is_airborne)
target_pos.z -= 0.5f * m_gravity_constant * current_time * current_time;
const auto pitch = calculate_pitch(proj_origin, target_pos, bullet_gravity, v0, current_time);
if (!pitch) if (!pitch)
continue; continue;
const Vector3 delta = targetPos - projOrigin; const Vector3 delta = target_pos - proj_origin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y); const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch)); const float height = d * std::tan(angles::degrees_to_radians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height); return Vector3(target_pos.x, target_pos.y, proj_origin.z + height);
} }
return std::nullopt; return std::nullopt;
@@ -134,22 +141,22 @@ namespace omath::projectile_prediction
return std::nullopt; return std::nullopt;
const Vector3 delta = target_pos - proj_origin; const Vector3 delta = target_pos - proj_origin;
const float dSqr = delta.x * delta.x + delta.y * delta.y; const float d_sqr = delta.x * delta.x + delta.y * delta.y;
const float h = delta.z; const float h = delta.z;
const float term = h + 0.5f * bullet_gravity * time * time; const float term = h + 0.5f * bullet_gravity * time * time;
const float requiredV0Sqr = (dSqr + term * term) / (time * time); const float required_v0_sqr = (d_sqr + term * term) / (time * time);
const float v0Sqr = v0 * v0; const float v0_sqr = v0 * v0;
if (requiredV0Sqr > v0Sqr + 1e-3f) if (required_v0_sqr > v0_sqr + 1e-3f)
return std::nullopt; return std::nullopt;
if (dSqr == 0.0f) if (d_sqr == 0.0f)
return term >= 0.0f ? 90.0f : -90.0f; return term >= 0.0f ? 90.0f : -90.0f;
const float d = std::sqrt(dSqr); const float d = std::sqrt(d_sqr);
const float tanTheta = term / d; const float tan_theta = term / d;
return angles::RadiansToDegrees(std::atan(tanTheta)); return angles::radians_to_degrees(std::atan(tan_theta));
#else #else
throw std::runtime_error( throw std::runtime_error(
std::format("{} AVX2 feature is not enabled!", std::source_location::current().function_name())); std::format("{} AVX2 feature is not enabled!", std::source_location::current().function_name()));
+75
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
+360
View File
@@ -0,0 +1,360 @@
//
// Created by Vlad on 10/7/2025.
//
#include "omath/utility/pe_pattern_scan.hpp"
#include "omath/utility/pattern_scan.hpp"
#include <fstream>
#include <span>
#include <stdexcept>
#include <variant>
// Internal PE shit defines
// Big thx for linuxpe sources as ref
// Link: https://github.com/can1357/linux-pe
namespace
{
constexpr std::uint16_t opt_hdr32_magic = 0x010B;
constexpr std::uint16_t opt_hdr64_magic = 0x020B;
// Standard fields.
// ReSharper disable CppDeclaratorNeverUsed
struct DataDirectory final
{
std::uint32_t rva;
std::uint32_t size;
};
struct OptionalHeaderX64 final
{
std::uint16_t magic;
std::uint16_t linker_version;
std::uint32_t size_code;
std::uint32_t size_init_data;
std::uint32_t size_uninit_data;
std::uint32_t entry_point;
std::uint32_t base_of_code;
// NT additional fields.
std::uint64_t image_base;
std::uint32_t section_alignment;
std::uint32_t file_alignment;
std::uint32_t os_version;
std::uint32_t img_version;
std::uint32_t subsystem_version;
std::uint32_t win32_version_value;
std::uint32_t size_image;
std::uint32_t size_headers;
std::uint32_t checksum;
std::uint16_t subsystem;
std::uint16_t characteristics;
std::uint64_t size_stack_reserve;
std::uint64_t size_stack_commit;
std::uint64_t size_heap_reserve;
std::uint64_t size_heap_commit;
std::uint32_t ldr_flags;
std::uint32_t num_data_directories;
DataDirectory data_directories[16];
};
struct OptionalHeaderX86 final
{
// Standard fields.
std::uint16_t magic{};
std::uint16_t linker_version{};
std::uint32_t size_code{};
std::uint32_t size_init_data{};
std::uint32_t size_uninit_data{};
std::uint32_t entry_point{};
std::uint32_t base_of_code{};
std::uint32_t base_of_data{};
// NT additional fields.
std::uint32_t image_base{};
std::uint32_t section_alignment{};
std::uint32_t file_alignment{};
std::uint32_t os_version{};
std::uint32_t img_version{};
std::uint32_t subsystem_version{};
std::uint32_t win32_version_value{};
std::uint32_t size_image{};
std::uint32_t size_headers{};
std::uint32_t checksum{};
std::uint16_t subsystem{};
std::uint16_t characteristics{};
std::uint32_t size_stack_reserve{};
std::uint32_t size_stack_commit{};
std::uint32_t size_heap_reserve{};
std::uint32_t size_heap_commit{};
std::uint32_t ldr_flags{};
std::uint32_t num_data_directories{};
DataDirectory data_directories[16]{};
};
template<bool x64 = true>
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
struct FileHeader final
{
std::uint16_t machine;
std::uint16_t num_sections;
std::uint32_t timedate_stamp;
std::uint32_t ptr_symbols;
std::uint32_t num_symbols;
std::uint16_t size_optional_header;
std::uint16_t characteristics;
};
struct DosHeader final
{
std::uint16_t e_magic;
std::uint16_t e_cblp;
std::uint16_t e_cp;
std::uint16_t e_crlc;
std::uint16_t e_cparhdr;
std::uint16_t e_minalloc;
std::uint16_t e_maxalloc;
std::uint16_t e_ss;
std::uint16_t e_sp;
std::uint16_t e_csum;
std::uint16_t e_ip;
std::uint16_t e_cs;
std::uint16_t e_lfarlc;
std::uint16_t e_ovno;
std::uint16_t e_res[4];
std::uint16_t e_oemid;
std::uint16_t e_oeminfo;
std::uint16_t e_res2[10];
std::uint32_t e_lfanew;
};
enum class NtArchitecture
{
x32_bit,
x64_bit,
};
template<NtArchitecture architecture>
struct ImageNtHeaders final
{
std::uint32_t signature;
FileHeader file_header;
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
};
struct SectionHeader final
{
char name[8];
union
{
std::uint32_t physical_address;
std::uint32_t virtual_size;
};
std::uint32_t virtual_address;
std::uint32_t size_raw_data;
std::uint32_t ptr_raw_data;
std::uint32_t ptr_relocs;
std::uint32_t ptr_line_numbers;
std::uint32_t num_relocs;
std::uint32_t num_line_numbers;
std::uint32_t characteristics;
};
// ReSharper restore CppDeclaratorNeverUsed
using NtHeaderVariant =
std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
} // namespace
// Internal PE scanner functions
namespace
{
[[nodiscard]]
std::optional<NtHeaderVariant> get_nt_header_from_file(std::fstream& file, const DosHeader& dos_header)
{
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
file.seekg(dos_header.e_lfanew, std::ios::beg);
file.read(reinterpret_cast<char*>(&x86_headers), sizeof(x86_headers));
if (x86_headers.optional_header.magic == opt_hdr32_magic)
return x86_headers;
if (x86_headers.optional_header.magic != opt_hdr64_magic)
return std::nullopt;
ImageNtHeaders<NtArchitecture::x64_bit> x64_headers{};
file.seekg(dos_header.e_lfanew, std::ios::beg);
file.read(reinterpret_cast<char*>(&x64_headers), sizeof(x64_headers));
return x64_headers;
}
[[nodiscard]]
std::optional<NtHeaderVariant> get_nt_header_from_loaded_module(const void* module_base_address)
{
const auto module_byte_ptr = static_cast<const std::byte*>(module_base_address);
ImageNtHeaders<NtArchitecture::x32_bit> x86_headers{};
const auto dos_header = static_cast<const DosHeader*>(module_base_address);
x86_headers = *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x32_bit>*>(module_byte_ptr
+ dos_header->e_lfanew);
if (x86_headers.optional_header.magic == opt_hdr32_magic)
return x86_headers;
if (x86_headers.optional_header.magic != opt_hdr64_magic)
return std::nullopt;
return *reinterpret_cast<const ImageNtHeaders<NtArchitecture::x64_bit>*>(module_byte_ptr
+ dos_header->e_lfanew);
}
[[nodiscard]]
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
{
constexpr std::uint16_t dos_hdr_magic = 0x5A4D;
return dos_header.e_magic != dos_hdr_magic;
}
[[nodiscard]]
constexpr bool invalid_nt_header_file(const NtHeaderVariant& variant)
{
constexpr std::uint32_t nt_hdr_magic = 0x4550;
return std::visit([&nt_hdr_magic](const auto& header) -> bool { return header.signature != nt_hdr_magic; },
variant);
}
struct ExtractedSection
{
std::uint64_t virtual_base_addr;
std::uint64_t raw_base_addr;
std::vector<std::byte> data;
};
[[nodiscard]]
std::optional<ExtractedSection> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
const std::string_view& section_name)
{
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
if (!file.is_open()) [[unlikely]]
return std::nullopt;
DosHeader dos_header{};
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
if (invalid_dos_header_file(dos_header)) [[unlikely]]
return std::nullopt;
const auto nt_headers = get_nt_header_from_file(file, dos_header);
if (!nt_headers)
return std::nullopt;
if (invalid_nt_header_file(nt_headers.value())) [[unlikely]]
return std::nullopt;
return std::visit(
[&file, &dos_header, &section_name](auto& concrete_headers) -> std::optional<ExtractedSection>
{
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
const auto offset_to_segment_table = dos_header.e_lfanew
+ concrete_headers.file_header.size_optional_header
+ sizeof(FileHeader) + size_of_signature;
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
{
SectionHeader current_section{};
file.read(reinterpret_cast<char*>(&current_section), sizeof(current_section));
if (std::string_view(current_section.name) != section_name)
continue;
std::vector<std::byte> section_data(current_section.size_raw_data);
file.seekg(current_section.ptr_raw_data, std::ios::beg);
file.read(reinterpret_cast<char*>(section_data.data()),
static_cast<std::streamsize>(section_data.size()));
return ExtractedSection{.virtual_base_addr = current_section.virtual_address
+ concrete_headers.optional_header.image_base,
.raw_base_addr = current_section.ptr_raw_data,
.data = std::move(section_data)};
}
return std::nullopt;
},
nt_headers.value());
}
} // namespace
namespace omath
{
std::optional<std::uintptr_t> PePatternScanner::scan_for_pattern_in_loaded_module(const void* module_base_address,
const std::string_view& pattern)
{
const auto base_address = reinterpret_cast<std::uintptr_t>(module_base_address);
if (!base_address)
return std::nullopt;
auto nt_header_variant = get_nt_header_from_loaded_module(module_base_address);
if (!nt_header_variant)
return std::nullopt;
return std::visit(
[base_address, &pattern](const auto& nt_header) -> std::optional<std::uintptr_t>
{
// Define .code segment as scan area
const auto start = nt_header.optional_header.base_of_code;
const auto scan_size = nt_header.optional_header.size_code;
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
// ReSharper disable once CppTooWideScopeInitStatement
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
if (result != scan_range.end())
return reinterpret_cast<std::uintptr_t>(&*result);
return std::nullopt;
},
nt_header_variant.value());
}
std::optional<PeSectionScanResult>
PePatternScanner::scan_for_pattern_in_file(const std::filesystem::path& path_to_file,
const std::string_view& pattern,
const std::string_view& target_section_name)
{
const auto pe_section = extract_section_from_pe_file(path_to_file, target_section_name);
if (!pe_section.has_value())
return std::nullopt;
const auto scan_result =
PatternScanner::scan_for_pattern(pe_section->data.cbegin(), pe_section->data.cend(), pattern);
if (scan_result == pe_section->data.cend())
return std::nullopt;
const auto offset = std::distance(pe_section->data.begin(), scan_result);
return PeSectionScanResult{.virtual_base_addr = pe_section->virtual_base_addr,
.raw_base_addr = pe_section->raw_base_addr,
.target_offset = offset};
}
} // namespace omath
+7 -4
View File
@@ -7,16 +7,19 @@ include(GoogleTest)
file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_executable(${PROJECT_NAME} ${UNIT_TESTS_SOURCES}) 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}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_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}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20
CXX_STANDARD 23 CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON) CXX_STANDARD_REQUIRED ON)
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
if (TARGET gtest) # GTest is being linked as submodule
target_link_libraries(${PROJECT_NAME} PRIVATE gtest gtest_main omath::omath)
else() # GTest is being linked as vcpkg package
find_package(GTest CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest GTest::gtest_main omath::omath)
endif()
gtest_discover_tests(${PROJECT_NAME}) gtest_discover_tests(${PROJECT_NAME})
@@ -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);
}
+123 -2
View File
@@ -5,7 +5,7 @@
#include <omath/engines/iw_engine/camera.hpp> #include <omath/engines/iw_engine/camera.hpp>
#include <omath/engines/iw_engine/constants.hpp> #include <omath/engines/iw_engine/constants.hpp>
#include <omath/engines/iw_engine/formulas.hpp> #include <omath/engines/iw_engine/formulas.hpp>
#include <random>
TEST(unit_test_iw_engine, ForwardVector) 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); 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); 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) for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
{ {
const auto projected = cam.world_to_screen({distance, 0, 0}); 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)); cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
EXPECT_EQ(cam.get_field_of_view().as_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);
} }
+122 -6
View File
@@ -5,7 +5,7 @@
#include <omath/engines/opengl_engine/camera.hpp> #include <omath/engines/opengl_engine/camera.hpp>
#include <omath/engines/opengl_engine/constants.hpp> #include <omath/engines/opengl_engine/constants.hpp>
#include <omath/engines/opengl_engine/formulas.hpp> #include <omath/engines/opengl_engine/formulas.hpp>
#include <random>
TEST(unit_test_opengl, ForwardVector) TEST(unit_test_opengl, ForwardVector)
{ {
@@ -29,7 +29,7 @@ TEST(unit_test_opengl, ForwardVectorRotationYaw)
{ {
omath::opengl_engine::ViewAngles angles; 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); const auto forward = omath::opengl_engine::forward_vector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_right.x, 0.00001f); 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); EXPECT_NEAR(forward.z, omath::opengl_engine::k_abs_right.z, 0.00001f);
} }
TEST(unit_test_opengl, ForwardVectorRotationPitch) TEST(unit_test_opengl, ForwardVectorRotationPitch)
{ {
omath::opengl_engine::ViewAngles angles; 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); const auto forward = omath::opengl_engine::forward_vector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_up.x, 0.00001f); 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); 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); 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) for (float distance = -10.f; distance > -1000.f; distance -= 0.01f)
{ {
const auto projected = cam.world_to_screen({0, 0, distance}); 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)); cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
EXPECT_EQ(cam.get_field_of_view().as_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);
} }
+122 -2
View File
@@ -5,7 +5,7 @@
#include <omath/engines/source_engine/camera.hpp> #include <omath/engines/source_engine/camera.hpp>
#include <omath/engines/source_engine/constants.hpp> #include <omath/engines/source_engine/constants.hpp>
#include <omath/engines/source_engine/formulas.hpp> #include <omath/engines/source_engine/formulas.hpp>
#include <random>
TEST(unit_test_source_engine, ForwardVector) 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); 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); 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) for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
{ {
const auto projected = cam.world_to_screen({distance, 0, 0}); 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)); cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
EXPECT_EQ(cam.get_field_of_view().as_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);
} }
+124 -3
View File
@@ -6,6 +6,7 @@
#include <omath/engines/unity_engine/constants.hpp> #include <omath/engines/unity_engine/constants.hpp>
#include <omath/engines/unity_engine/formulas.hpp> #include <omath/engines/unity_engine/formulas.hpp>
#include <print> #include <print>
#include <random>
TEST(unit_test_unity_engine, ForwardVector) 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); 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); 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) for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
{ {
const auto projected = cam.world_to_screen({0, 0, distance}); 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); constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f); const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
const auto proj = cam.world_to_screen({5.f, 3, 10.f}); const auto proj = cam.world_to_screen<omath::unity_engine::Camera::ScreenStart::BOTTOM_LEFT_CORNER>({10.f, 3, 10.f});
EXPECT_NEAR(proj->x, 951.769f, 0.001f); EXPECT_NEAR(proj->x, 1263.538, 0.001f);
EXPECT_NEAR(proj->y, 547.061f, 0.001f); EXPECT_NEAR(proj->y, 547.061f, 0.001f);
} }
@@ -112,4 +112,125 @@ TEST(unit_test_unity_engine, CameraSetAndGetOrigin)
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f)); cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
EXPECT_EQ(cam.get_field_of_view().as_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);
} }
+125 -1
View File
@@ -6,6 +6,7 @@
#include <omath/engines/unreal_engine/constants.hpp> #include <omath/engines/unreal_engine/constants.hpp>
#include <omath/engines/unreal_engine/formulas.hpp> #include <omath/engines/unreal_engine/formulas.hpp>
#include <print> #include <print>
#include <random>
TEST(unit_test_unreal_engine, ForwardVector) 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); 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); 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) for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
{ {
const auto projected = cam.world_to_screen({distance, 0, 0}); 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)); cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
EXPECT_EQ(cam.get_field_of_view().as_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);
} }
+189
View File
@@ -1,3 +1,192 @@
// //
// Created by Orange on 11/30/2024. // 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);
}
+1 -1
View File
@@ -1,8 +1,8 @@
// //
// Created by Orange on 11/30/2024. // Created by Orange on 11/30/2024.
// //
#include <omath/trigonometry/angles.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/angles.hpp>
TEST(unit_test_angles, radians_to_deg) TEST(unit_test_angles, radians_to_deg)
{ {
+1 -2
View File
@@ -1,9 +1,8 @@
// //
// Created by Vlad on 01.09.2024. // Created by Vlad on 01.09.2024.
// //
#include <omath/utility/color.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/color.hpp>
using namespace omath; using namespace omath;
@@ -0,0 +1,39 @@
//
// Created by Vlad on 10/23/2025.
//
#ifdef OMATH_IMGUI_INTEGRATION
#include <omath/omath.hpp>
#include <gtest/gtest.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
using namespace omath;
TEST(unit_test_imgui_intergration, Vector2ToImVec2)
{
constexpr Vector2 omath_vector_2d = {1.f, 2.f};
constexpr ImVec2 imgui_vector_2d = {1, 2.f};
constexpr auto converted = omath_vector_2d.to_im_vec2();
EXPECT_NEAR(converted.x, imgui_vector_2d.x, 1.e-5f);
EXPECT_NEAR(converted.y, imgui_vector_2d.y, 1.e-5f);
}
TEST(unit_test_imgui_intergration, Vector4ToImVec4)
{
constexpr Vector4 omath_vector_2d = {1.f, 2.f, 3.f, 4.f};
constexpr ImVec4 imgui_vector_4d = {1, 2.f, 3.f, 4.f};
constexpr auto converted = omath_vector_2d.to_im_vec4();
EXPECT_NEAR(converted.x, imgui_vector_4d.x, 1.e-5f);
EXPECT_NEAR(converted.y, imgui_vector_4d.y, 1.e-5f);
EXPECT_NEAR(converted.z, imgui_vector_4d.z, 1.e-5f);
EXPECT_NEAR(converted.w, imgui_vector_4d.w, 1.e-5f);
}
#endif
+2 -2
View File
@@ -2,9 +2,9 @@
// Revised unittest suite for LineTracer (segmentbased MöllerTrumbore) // Revised unittest suite for LineTracer (segmentbased MöllerTrumbore)
// Pure ASCII: avoids nonstandard characters that MSVC rejects. // Pure ASCII: avoids nonstandard characters that MSVC rejects.
// //
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/triangle.hpp"
#include "omath/collision/line_tracer.hpp" #include "omath/collision/line_tracer.hpp"
#include "omath/triangle.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <cmath> #include <cmath>
+17
View File
@@ -214,3 +214,20 @@ TEST(UnitTestMatStandalone, Enverse)
EXPECT_EQ(mv, m.inverted()); EXPECT_EQ(mv, m.inverted());
} }
TEST(UnitTestMatStandalone, Equanity)
{
constexpr omath::Vector3<float> left_handed = {0, 2, 10};
constexpr omath::Vector3<float> right_handed = {0, 2, -10};
auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000);
auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000);
auto ndc_left_handed = proj_left_handed * omath::mat_column_from_vector(left_handed);
auto ndc_right_handed = proj_right_handed * omath::mat_column_from_vector(right_handed);
ndc_left_handed /= ndc_left_handed.at(3, 0);
ndc_right_handed /= ndc_right_handed.at(3, 0);
EXPECT_EQ(ndc_left_handed, ndc_right_handed);
}
-184
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
+53
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());
}
+5 -4
View File
@@ -1,6 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp> #include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
#include <omath/engines/source_engine/traits/camera_trait.hpp>
TEST(UnitTestPrediction, PredictionTest) TEST(UnitTestPrediction, PredictionTest)
{ {
constexpr omath::projectile_prediction::Target target{ constexpr omath::projectile_prediction::Target target{
@@ -10,8 +10,9 @@ TEST(UnitTestPrediction, PredictionTest)
const auto viewPoint = const auto viewPoint =
omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).maybe_calculate_aim_point(proj, target); omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).maybe_calculate_aim_point(proj, target);
const auto [pitch, yaw, _] = proj.m_origin.view_angle_to(viewPoint.value()).as_tuple();
EXPECT_NEAR(42.547142, pitch, 0.01f); const auto [pitch, yaw, _] =omath::source_engine::CameraTrait::calc_look_at_angle(proj.m_origin, viewPoint.value());
EXPECT_NEAR(-1.181189, yaw, 0.01f);
EXPECT_NEAR(-42.547142, pitch.as_degrees(), 0.01f);
EXPECT_NEAR(-1.181189, yaw.as_degrees(), 0.01f);
} }

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