Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 086eda4ee3 | |||
| 9419e390da | |||
| d919600ac2 | |||
| 11681ac601 | |||
| 6c5152297a | |||
| 547f64e4c4 | |||
| 3129e32f0c | |||
| 72b54e9673 | |||
| 2ff291b255 | |||
| 8eda1ce4bc | |||
| e1b4375621 | |||
| d84259fdcc | |||
| d64c7ad756 | |||
| 710f91999f | |||
| f3fe0e3cee | |||
| c5c5c2e972 | |||
| a7cb056ce7 | |||
| dae1555ec4 | |||
| 2c6ef1b8cc | |||
| d70e8853e8 | |||
| e35d64b486 | |||
| 9868c832a1 | |||
| 42e46f9921 | |||
| e7ccc2ead0 | |||
| 170f969697 | |||
| 131fd891b0 | |||
| a5396b72cb | |||
| ec876ea292 | |||
| 8021050fad | |||
| bd585b5412 | |||
| 06f9a8c9ee | |||
| 160b51da94 | |||
| 064edf9ef1 | |||
| f17d36dcd3 | |||
| ec4f9f6c90 | |||
| cbee8c2c95 | |||
| dc6edbb67f | |||
| 74381eda5c | |||
| 1ef7833bd9 | |||
| c10386f3f6 | |||
| 413cef4f23 | |||
| 867cee41c3 | |||
| 990fe78a33 | |||
| 1efdb50f73 | |||
|
|
86fea065e7 | ||
|
|
ac046aae6c | ||
|
|
9646054877 | ||
| 6334002639 | |||
| 72e0c0c90b | |||
| 2f2a5a00c4 | |||
| c394993418 | |||
| 476048583d | |||
| 76ae67c968 | |||
| d1d95d2f36 | |||
| 6409568334 | |||
| 83ba339eb5 | |||
| c49c93d542 | |||
| 92dab52d66 | |||
| dac3d8e43f | |||
| fb0b05d7ef | |||
| 993212e7ab | |||
| 380a9f0a16 | |||
| ba7bce5502 | |||
| ce40891e37 | |||
| c4d10f8872 | |||
| 2bb0c82c30 | |||
| a4dcf8dc3b | |||
| 17eaddbc8c | |||
| 9005c02499 | |||
| e7380b5eb6 | |||
| f8d6e4b544 | |||
| 893eca296b | |||
| b0bd58ccb2 | |||
| 44a42d39d0 | |||
| a8c7e8eb54 | |||
| cef22919a4 | |||
| f79350e609 | |||
| 1102cad390 | |||
| df4e999c82 | |||
| 3baeb182f0 | |||
| 5539bbad0d | |||
| 4d4dfae8f2 | |||
| 03c514104e | |||
| 792db7a673 | |||
| bfd399e631 | |||
| 7fef690f5e | |||
| 3df7d65ac1 | |||
| e1a1164136 | |||
| 23216279dc | |||
| 9e082f7dfa | |||
| 7750819e83 | |||
| 2ec0e2f93f | |||
| 9170ffb1a9 | |||
| e05f9ef5a9 | |||
| 89bb4aa625 | |||
|
|
9b0845593d | ||
| 617ded2dd4 | |||
| e882a224d2 | |||
| e04f6573c0 | |||
| 791e3b2313 | |||
| 26b56d757c | |||
| fbb77b9925 | |||
| 7b671dbd90 | |||
| 5875930f1a | |||
| d773985822 | |||
| a2de6f8fae | |||
| d71795006d | |||
| 561438d45c | |||
| 874b028e86 | |||
| 68ec42d9ed | |||
| 8aeb4667d7 | |||
| 565464f0cd | |||
| 04b50d4545 | |||
| e01d32fb22 | |||
| a3a023a664 | |||
| 1b5a7ed4fd | |||
|
|
362b818a71 | ||
| 29a96d64bb | |||
| 256365e52e | |||
| e333d81b81 | |||
| d66f60d419 | |||
| 4a4939b604 | |||
| ebe8d1a90e | |||
| 1a3376fe6c | |||
| 20188d7043 | |||
| f59e0d255f | |||
| 071cb15492 | |||
| f8812ed9e7 | |||
| 19d310d35f | |||
| c364879b5f | |||
| 418b7c0e7e | |||
| 69f46abce1 | |||
| de61f7a5d8 | |||
| 07a449b633 | |||
| 6bb549ef4c | |||
| 14fa810ecb | |||
| b964661030 | |||
| 9c11551c9a | |||
| 21fece7c84 | |||
| 996618994d | |||
| ce8be6dd52 | |||
| 17aac2f80e | |||
| ba927734d2 | |||
| c0d5fd18f5 | |||
| 996a9cf15a | |||
| 91078f5701 | |||
| 036d3a8992 | |||
| 7534fe8969 | |||
| 8e4f1812cc | |||
| e8f40218dd | |||
| 50054ca937 | |||
| 63220c0be7 | |||
| 3b6d19782c | |||
| 2d58330508 | |||
| abf57a55ea | |||
| 463532ba81 | |||
| d74c66990a | |||
| 7f1bc51905 | |||
| 71127f1f12 | |||
| 89041e20ae | |||
| a54dd4b52a | |||
| d7e497b617 | |||
| 80938cd913 | |||
| 830505dbe5 | |||
| 75565ecf2d | |||
| 9a7a4c7fff | |||
| c0f0bb3c2e | |||
| a097c0a2f4 | |||
| 20ae2b4dd1 | |||
| 115b5a3471 |
BIN
.github/images/logos/omath_logo_macro.png
vendored
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
.github/images/logos/omath_logo_mega.png
vendored
Normal file
|
After Width: | Height: | Size: 454 KiB |
BIN
.github/images/logos/omath_logo_micro.png
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
.github/images/logos/omath_logo_nano.png
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
.github/images/showcase/apex.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
.github/images/showcase/cod_bo2.png
vendored
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
.github/images/showcase/cs2.jpeg
vendored
Normal file
|
After Width: | Height: | Size: 644 KiB |
BIN
.github/images/yt_previews/img.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
.github/psd/omath.psd
vendored
Normal file
8
.github/workflows/cmake-multi-platform.yml
vendored
@@ -35,11 +35,11 @@ jobs:
|
||||
|
||||
- name: Configure (cmake --preset)
|
||||
shell: bash
|
||||
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON
|
||||
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: cmake --build cmake-build/build/linux-release --target all
|
||||
run: cmake --build cmake-build/build/linux-release --target unit_tests omath
|
||||
|
||||
- name: Run unit_tests
|
||||
shell: bash
|
||||
@@ -68,11 +68,11 @@ jobs:
|
||||
|
||||
- name: Configure (cmake --preset)
|
||||
shell: bash
|
||||
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON
|
||||
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: cmake --build cmake-build/build/windows-release --target all
|
||||
run: cmake --build cmake-build/build/windows-release --target unit_tests omath
|
||||
|
||||
- name: Run unit_tests.exe
|
||||
shell: bash
|
||||
|
||||
5
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "extlibs/googletest"]
|
||||
path = extlibs/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
url = https://github.com/google/googletest.git
|
||||
[submodule "extlibs/benchmark"]
|
||||
path = extlibs/benchmark
|
||||
url = https://github.com/google/benchmark.git
|
||||
|
||||
4
.idea/editor.xml
generated
@@ -201,7 +201,7 @@
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
@@ -215,7 +215,7 @@
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
|
||||
1
.idea/vcs.xml
generated
@@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/extlibs/benchmark" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,24 +1,37 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(omath VERSION 3.3.0 LANGUAGES CXX)
|
||||
project(omath VERSION 3.8.2 LANGUAGES CXX)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (MSVC)
|
||||
check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2)
|
||||
else ()
|
||||
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
|
||||
endif ()
|
||||
|
||||
option(OMATH_BUILD_TESTS "Build unit tests" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(OMATH_BUILD_BENCHMARK "Build benchmarks" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
|
||||
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
|
||||
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
|
||||
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ${COMPILER_SUPPORTS_AVX2})
|
||||
option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF)
|
||||
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
|
||||
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
|
||||
option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
|
||||
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" ON)
|
||||
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF)
|
||||
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" OFF)
|
||||
|
||||
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
|
||||
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 ()
|
||||
|
||||
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}")
|
||||
@@ -37,8 +50,11 @@ else ()
|
||||
add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
|
||||
endif ()
|
||||
|
||||
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
|
||||
|
||||
if (OMATH_IMGUI_INTEGRATION)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION)
|
||||
|
||||
@@ -88,16 +104,28 @@ if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -mavx2 -mfma)
|
||||
endif ()
|
||||
if (OMATH_USE_AVX2)
|
||||
if (MSVC)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC /arch:AVX2)
|
||||
elseif (EMSCRIPTEN)
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC -msimd128 -mavx2)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
|
||||
target_compile_options(${PROJECT_NAME} PUBLIC -mfma -mavx2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||
|
||||
add_subdirectory(extlibs)
|
||||
|
||||
|
||||
if (OMATH_BUILD_TESTS)
|
||||
add_subdirectory(extlibs)
|
||||
add_subdirectory(tests)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
|
||||
endif ()
|
||||
|
||||
if (OMATH_BUILD_BENCHMARK)
|
||||
add_subdirectory(benchmark)
|
||||
endif ()
|
||||
|
||||
if (OMATH_BUILD_EXAMPLES)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
|
||||
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "cl.exe",
|
||||
"CMAKE_CXX_COMPILER": "cl.exe"
|
||||
},
|
||||
"condition": {
|
||||
@@ -40,7 +39,6 @@
|
||||
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
|
||||
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
},
|
||||
"condition": {
|
||||
@@ -72,7 +70,6 @@
|
||||
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
|
||||
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
},
|
||||
"condition": {
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
Thanks to everyone who made this possible, including:
|
||||
|
||||
- Saikari aka luadebug for VCPKG port.
|
||||
- Saikari aka luadebug for VCPKG port and awesome new initial logo design.
|
||||
- AmbushedRaccoon for telegram post about omath to boost repository activity.
|
||||
- Billy O'Neal aka BillyONeal for fixing compilation issues due to C math library compatibility.
|
||||
|
||||
And a big hand to everyone else who has contributed over the past!
|
||||
|
||||
THANKS! <3
|
||||
|
||||
-- Orange++ <orange-cpp@yandex.ru>
|
||||
-- Orange++ <orange_github@proton.me>
|
||||
|
||||
@@ -59,7 +59,7 @@ target("...")
|
||||
cmake --preset windows-release -S .
|
||||
cmake --build cmake-build/build/windows-release --target omath -j 6
|
||||
```
|
||||
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
|
||||
Use **\<platform\>-\<build configuration\>** preset to build suitable version for yourself. Like **windows-release** or **linux-release**.
|
||||
|
||||
| Platform Name | Build Config |
|
||||
|---------------|---------------|
|
||||
|
||||
16
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (C) 2024-2025 Orange++ <orange-cpp@yandex.ru>
|
||||
Copyright (C) 2024-2025 Orange++ <orange_github@proton.me>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -14,4 +14,16 @@ freely, subject to the following restrictions:
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
4. If you are an employee, contractor, volunteer, representative,
|
||||
or have any other affiliation (past, present, or future)
|
||||
with any of the following entities:
|
||||
* "Yandex" LLC
|
||||
* "Rutube" LLC
|
||||
* "Kaspersky" LLC
|
||||
Or if you represent or are associated with any legal, organizational, or
|
||||
professional entity providing services to or on behalf of the aforementioned entities:
|
||||
You are expressly forbidden from accessing, using, modifying, distributing, or
|
||||
interacting with the Software and its source code in any form. You must immediately
|
||||
delete or destroy any physical or digital copies of the Software and/or
|
||||
its source code, including any derivative works, tools, or information obtained from the Software.
|
||||
|
||||
107
README.md
@@ -1,8 +1,8 @@
|
||||
<div align = center>
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://www.codefactor.io/repository/github/orange-cpp/omath)
|
||||
@@ -12,9 +12,26 @@
|
||||
[](https://discord.gg/eDgdaWbqwZ)
|
||||
[](https://t.me/orangennotes)
|
||||
|
||||
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
|
||||
|
||||
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
|
||||
<br>
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
**[<kbd> <br> Install <br> </kbd>][INSTALL]**
|
||||
**[<kbd> <br> Examples <br> </kbd>][EXAMPLES]**
|
||||
**[<kbd> <br> Documentation <br> </kbd>][DOCUMENTATION]**
|
||||
**[<kbd> <br> Contribute <br> </kbd>][CONTRIBUTING]**
|
||||
**[<kbd> <br> Donate <br> </kbd>][SPONSOR]**
|
||||
|
||||
---
|
||||
|
||||
<br>
|
||||
|
||||
</div>
|
||||
|
||||
Oranges's Math Library (omath) is a comprehensive, open-source library aimed at providing efficient, reliable, and versatile mathematical functions and algorithms. Developed primarily in C++, this library is designed to cater to a wide range of mathematical operations essential in scientific computing, engineering, and academic research.
|
||||
|
||||
<div align = center>
|
||||
<a href="https://www.star-history.com/#orange-cpp/omath&Date">
|
||||
@@ -26,7 +43,7 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## 👁🗨 Features
|
||||
# Features
|
||||
- **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
|
||||
- **Versatility**: Includes a wide array of mathematical functions and algorithms.
|
||||
- **Ease of Use**: Simplified interface for convenient integration into various projects.
|
||||
@@ -35,68 +52,44 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
|
||||
- **Collision Detection**: Production ready code to handle collision detection by using simple interfaces.
|
||||
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
|
||||
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
||||
- **Engine support**: Supports coordinate systems of Source, Unity, Unreal, IWEngine and canonical OpenGL.
|
||||
- **Cross platform**: Supports Windows, MacOS and Linux.
|
||||
<div align = center>
|
||||
|
||||
# Gallery
|
||||
|
||||
## Supported Render Pipelines
|
||||
| ENGINE | SUPPORT |
|
||||
|----------|---------|
|
||||
| Source | ✅YES |
|
||||
| Unity | ✅YES |
|
||||
| IWEngine | ✅YES |
|
||||
| OpenGL | ✅YES |
|
||||
| Unreal | ✅YES |
|
||||
<br>
|
||||
|
||||
## Supported Operating Systems
|
||||
[](https://youtu.be/lM_NJ1yCunw?si=-Qf5yzDcWbaxAXGQ)
|
||||
|
||||
| OS | SUPPORT |
|
||||
|----------------|---------|
|
||||
| Windows 10/11 | ✅YES |
|
||||
| Linux | ✅YES |
|
||||
| Darwin (MacOS) | ✅YES |
|
||||
<br>
|
||||
|
||||
## ⏬ Installation
|
||||
Please read our [installation guide](https://github.com/orange-cpp/omath/blob/main/INSTALL.md). If this link doesn't work check out INSTALL.md file.
|
||||
![APEX Preview]
|
||||
|
||||
## ❔ Usage
|
||||
ESP example
|
||||
```c++
|
||||
omath::source_engine::Camera cam{localPlayer.GetCameraOrigin(),
|
||||
localPlayer.GetAimPunch(),
|
||||
{1920.f, 1080.f},
|
||||
localPlayer.GetFieldOfView(),
|
||||
0.01.f, 30000.f};
|
||||
<br>
|
||||
|
||||
for (auto ent: apex_sdk::EntityList::GetAllEntities())
|
||||
{
|
||||
const auto bottom = cam.world_to_screen(ent.GetOrigin());
|
||||
const auto top = cam.world_to_screen(ent.GetBonePosition(8) + omath::Vector3<float>{0, 0, 10});
|
||||
![BO2 Preview]
|
||||
|
||||
const auto ent_health = ent.GetHealth();
|
||||
<br>
|
||||
|
||||
if (!top || !bottom || ent_health <= 0)
|
||||
continue;
|
||||
// esp rendering...
|
||||
}
|
||||
```
|
||||
## Showcase
|
||||
<details>
|
||||
<summary>OMATH for making cheats (click to open)</summary>
|
||||
![CS2 Preview]
|
||||
|
||||
With `omath/projection` module you can achieve simple ESP hack for powered by Source/Unreal/Unity engine games, like [Apex Legends](https://store.steampowered.com/app/1172470/Apex_Legends/).
|
||||
<br>
|
||||
<br>
|
||||
|
||||

|
||||
Or for InfinityWard Engine based games. Like Call of Duty Black Ops 2!
|
||||

|
||||
Or create simple trigger bot with embeded traceline from omath::collision::LineTrace
|
||||

|
||||
Or even advanced projectile aimbot
|
||||
[Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E)
|
||||
</details>
|
||||
</div>
|
||||
|
||||
## 🫵🏻 Contributing
|
||||
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests.
|
||||
|
||||
## 📜 License
|
||||
This project is licensed under the ZLIB - see the `LICENSE` file for details.
|
||||
|
||||
## 💘 Acknowledgments
|
||||
# 💘 Acknowledgments
|
||||
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)
|
||||
|
||||
<!----------------------------------{ Images }--------------------------------->
|
||||
[APEX Preview]: .github/images/showcase/apex.png
|
||||
[BO2 Preview]: .github/images/showcase/cod_bo2.png
|
||||
[CS2 Preview]: .github/images/showcase/cs2.jpeg
|
||||
|
||||
<!----------------------------------{ 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
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security issues to `orange-cpp@yandex.ru`
|
||||
Please report security issues to `orange_github@proton.me`
|
||||
|
||||
15
benchmark/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
project(omath_benchmark)
|
||||
|
||||
|
||||
file(GLOB_RECURSE OMATH_BENCHMARK_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
||||
add_executable(${PROJECT_NAME} ${OMATH_BENCHMARK_SOURCES})
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
CXX_STANDARD 23
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE benchmark::benchmark omath)
|
||||
65
benchmark/benchmark_mat.cpp
Normal 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
benchmark/benchmark_projectile_pred.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by Vlad on 9/18/2025.
|
||||
//
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <omath/omath.hpp>
|
||||
using namespace omath;
|
||||
|
||||
using namespace omath::projectile_prediction;
|
||||
|
||||
constexpr float simulation_time_step = 1.f / 1000.f;
|
||||
constexpr float hit_distance_tolerance = 5.f;
|
||||
|
||||
void source_engine_projectile_prediction(benchmark::State& state)
|
||||
{
|
||||
constexpr Target target{.m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_is_airborne = false};
|
||||
constexpr Projectile projectile = {.m_origin = {3, 2, 1}, .m_launch_speed = 5000, .m_gravity_scale = 0.4};
|
||||
|
||||
for ([[maybe_unused]] const auto _: state)
|
||||
std::ignore = ProjPredEngineLegacy(400, simulation_time_step, 50, hit_distance_tolerance)
|
||||
.maybe_calculate_aim_point(projectile, target);
|
||||
}
|
||||
|
||||
BENCHMARK(source_engine_projectile_prediction)->Iterations(10'000);
|
||||
5
benchmark/main.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Vlad on 9/17/2025.
|
||||
//
|
||||
#include <benchmark/benchmark.h>
|
||||
BENCHMARK_MAIN();
|
||||
17
docs/index.md
Normal 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 +1,9 @@
|
||||
add_subdirectory(googletest)
|
||||
|
||||
if (OMATH_BUILD_TESTS)
|
||||
add_subdirectory(googletest)
|
||||
endif ()
|
||||
|
||||
if (OMATH_BUILD_BENCHMARK)
|
||||
set(BENCHMARK_ENABLE_TESTING OFF)
|
||||
add_subdirectory(benchmark)
|
||||
endif ()
|
||||
1
extlibs/benchmark
Submodule
@@ -3,10 +3,9 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <array>
|
||||
#include "omath/triangle.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
|
||||
|
||||
namespace omath::primitives
|
||||
{
|
||||
|
||||
16
include/omath/3d_primitives/plane.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by Vlad on 8/28/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace omath::primitives
|
||||
{
|
||||
[[nodiscard]]
|
||||
std::array<Triangle<Vector3<float>>, 2> create_plane(const Vector3<float>& vertex_a,
|
||||
const Vector3<float>& vertex_b,
|
||||
const Vector3<float>& direction, float size) noexcept;
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "omath/triangle.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
|
||||
namespace omath::collision
|
||||
{
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <omath/view_angles.hpp>
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <omath/trigonometry/view_angles.hpp>
|
||||
|
||||
namespace omath::iw_engine
|
||||
{
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <omath/view_angles.hpp>
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <omath/trigonometry/view_angles.hpp>
|
||||
|
||||
namespace omath::opengl_engine
|
||||
{
|
||||
|
||||
@@ -62,17 +62,15 @@ namespace omath::opengl_engine
|
||||
[[nodiscard]]
|
||||
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto distance = origin.distance_to(view_to);
|
||||
const auto delta = view_to - origin;
|
||||
|
||||
return angles::radians_to_degrees(std::asin(delta.y / distance));
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
return angles::radians_to_degrees(std::asin(direction.y));
|
||||
}
|
||||
[[nodiscard]]
|
||||
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto delta = view_to - origin;
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
|
||||
return angles::radians_to_degrees(std::atan2(delta.z, delta.x));
|
||||
return angles::radians_to_degrees(-std::atan2(direction.x, -direction.z));
|
||||
};
|
||||
};
|
||||
} // namespace omath::opengl_engine
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <omath/view_angles.hpp>
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <omath/trigonometry/view_angles.hpp>
|
||||
|
||||
namespace omath::source_engine
|
||||
{
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <omath/view_angles.hpp>
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <omath/trigonometry/view_angles.hpp>
|
||||
|
||||
namespace omath::unity_engine
|
||||
{
|
||||
|
||||
@@ -62,17 +62,15 @@ namespace omath::unity_engine
|
||||
[[nodiscard]]
|
||||
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto distance = origin.distance_to(view_to);
|
||||
const auto delta = view_to - origin;
|
||||
|
||||
return angles::radians_to_degrees(std::asin(delta.y / distance));
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
return angles::radians_to_degrees(std::asin(direction.y));
|
||||
}
|
||||
[[nodiscard]]
|
||||
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto delta = view_to - origin;
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
|
||||
return angles::radians_to_degrees(std::atan2(delta.z, delta.x));
|
||||
return angles::radians_to_degrees(std::atan2(direction.x, direction.z));
|
||||
};
|
||||
};
|
||||
} // namespace omath::unity_engine
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <omath/view_angles.hpp>
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <omath/trigonometry/view_angles.hpp>
|
||||
|
||||
namespace omath::unreal_engine
|
||||
{
|
||||
|
||||
@@ -62,17 +62,16 @@ namespace omath::unreal_engine
|
||||
[[nodiscard]]
|
||||
static float calc_direct_pitch_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto distance = origin.distance_to(view_to);
|
||||
const auto delta = view_to - origin;
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
|
||||
return angles::radians_to_degrees(std::asin(delta.z / distance));
|
||||
return angles::radians_to_degrees(std::asin(direction.z));
|
||||
}
|
||||
[[nodiscard]]
|
||||
static float calc_direct_yaw_angle(const Vector3<float>& origin, const Vector3<float>& view_to) noexcept
|
||||
{
|
||||
const auto delta = view_to - origin;
|
||||
const auto direction = (view_to - origin).normalized();
|
||||
|
||||
return angles::radians_to_degrees(std::atan2(delta.y, delta.x));
|
||||
return angles::radians_to_degrees(std::atan2(direction.y, direction.x));
|
||||
};
|
||||
};
|
||||
} // namespace omath::unreal_engine
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Created by vlad on 9/29/2024.
|
||||
//
|
||||
#pragma once
|
||||
#include "omath/vector3.hpp"
|
||||
#include "vector3.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iomanip>
|
||||
@@ -11,14 +11,12 @@
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#ifdef near
|
||||
#ifdef OMATH_USE_AVX2
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#undef near
|
||||
#endif
|
||||
|
||||
#ifdef far
|
||||
#undef far
|
||||
#endif
|
||||
|
||||
namespace omath
|
||||
{
|
||||
struct MatSize
|
||||
@@ -88,7 +86,7 @@ namespace omath
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Type& operator[](const size_t row, const size_t col) const
|
||||
constexpr const Type& operator[](const size_t row, const size_t col) const
|
||||
{
|
||||
return at(row, col);
|
||||
}
|
||||
@@ -162,17 +160,19 @@ namespace omath
|
||||
constexpr Mat<Rows, OtherColumns, Type, StoreType>
|
||||
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
|
||||
{
|
||||
Mat<Rows, OtherColumns, Type, StoreType> result;
|
||||
|
||||
for (size_t i = 0; i < Rows; ++i)
|
||||
for (size_t j = 0; j < OtherColumns; ++j)
|
||||
{
|
||||
Type sum = 0;
|
||||
for (size_t k = 0; k < Columns; ++k)
|
||||
sum += at(i, k) * other.at(k, j);
|
||||
result.at(i, j) = sum;
|
||||
}
|
||||
return result;
|
||||
#ifdef OMATH_USE_AVX2
|
||||
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
|
||||
return avx_multiply_row_major(other);
|
||||
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
|
||||
return avx_multiply_col_major(other);
|
||||
#else
|
||||
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
|
||||
return cache_friendly_multiply_row_major(other);
|
||||
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
|
||||
return cache_friendly_multiply_col_major(other);
|
||||
#endif
|
||||
else
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
constexpr Mat& operator*=(const Type& f) noexcept
|
||||
@@ -328,6 +328,21 @@ namespace omath
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::wstring to_wstring() const noexcept
|
||||
{
|
||||
const auto ascii_string = to_string();
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
std::u8string to_u8string() const noexcept
|
||||
{
|
||||
const auto ascii_string = to_string();
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool operator==(const Mat& mat) const
|
||||
{
|
||||
@@ -374,6 +389,176 @@ namespace omath
|
||||
|
||||
private:
|
||||
std::array<Type, Rows * Columns> m_data;
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
|
||||
cache_friendly_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
|
||||
{
|
||||
Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR> result;
|
||||
for (std::size_t row_index = 0; row_index < Rows; ++row_index)
|
||||
for (std::size_t column_index = 0; column_index < Columns; ++column_index)
|
||||
{
|
||||
const Type& current_number = at(row_index, column_index);
|
||||
for (std::size_t other_column = 0; other_column < OtherColumns; ++other_column)
|
||||
result.at(row_index, other_column) += current_number * other.at(column_index, other_column);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> cache_friendly_multiply_col_major(
|
||||
const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
|
||||
{
|
||||
Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> result;
|
||||
for (std::size_t other_column = 0; other_column < OtherColumns; ++other_column)
|
||||
for (std::size_t column_index = 0; column_index < Columns; ++column_index)
|
||||
{
|
||||
const Type& current_number = other.at(column_index, other_column);
|
||||
for (std::size_t row_index = 0; row_index < Rows; ++row_index)
|
||||
result.at(row_index, other_column) += at(row_index, column_index) * current_number;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#ifdef OMATH_USE_AVX2
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>
|
||||
avx_multiply_col_major(const Mat<Columns, OtherColumns, Type, MatStoreType::COLUMN_MAJOR>& other) const
|
||||
{
|
||||
Mat<Rows, OtherColumns, Type, MatStoreType::COLUMN_MAJOR> result;
|
||||
|
||||
const Type* this_mat_data = this->raw_array().data();
|
||||
const Type* other_mat_data = other.raw_array().data();
|
||||
Type* result_mat_data = result.raw_array().data();
|
||||
|
||||
if constexpr (std::is_same_v<Type, float>)
|
||||
{
|
||||
// ReSharper disable once CppTooWideScopeInitStatement
|
||||
constexpr std::size_t vector_size = 8;
|
||||
for (std::size_t j = 0; j < OtherColumns; ++j)
|
||||
{
|
||||
auto* c_col = reinterpret_cast<float*>(result_mat_data + j * Rows);
|
||||
for (std::size_t k = 0; k < Columns; ++k)
|
||||
{
|
||||
const float bkj = reinterpret_cast<const float*>(other_mat_data)[k + j * Columns];
|
||||
const __m256 bkj_vec = _mm256_set1_ps(bkj);
|
||||
|
||||
const auto* a_col_k = reinterpret_cast<const float*>(this_mat_data + k * Rows);
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i + vector_size <= Rows; i += vector_size)
|
||||
{
|
||||
__m256 cvec = _mm256_loadu_ps(c_col + i);
|
||||
const __m256 a_vec = _mm256_loadu_ps(a_col_k + i);
|
||||
cvec = _mm256_fmadd_ps(a_vec, bkj_vec, cvec);
|
||||
_mm256_storeu_ps(c_col + i, cvec);
|
||||
}
|
||||
for (; i < Rows; ++i)
|
||||
c_col[i] += a_col_k[i] * bkj;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (std::is_same_v<Type, double>)
|
||||
{ // double
|
||||
// ReSharper disable once CppTooWideScopeInitStatement
|
||||
constexpr std::size_t vector_size = 4;
|
||||
for (std::size_t j = 0; j < OtherColumns; ++j)
|
||||
{
|
||||
auto* c_col = reinterpret_cast<double*>(result_mat_data + j * Rows);
|
||||
for (std::size_t k = 0; k < Columns; ++k)
|
||||
{
|
||||
const double bkj = reinterpret_cast<const double*>(other_mat_data)[k + j * Columns];
|
||||
const __m256d bkj_vec = _mm256_set1_pd(bkj);
|
||||
|
||||
const auto* a_col_k = reinterpret_cast<const double*>(this_mat_data + k * Rows);
|
||||
|
||||
std::size_t i = 0;
|
||||
for (; i + vector_size <= Rows; i += vector_size)
|
||||
{
|
||||
__m256d cvec = _mm256_loadu_pd(c_col + i);
|
||||
const __m256d a_vec = _mm256_loadu_pd(a_col_k + i);
|
||||
cvec = _mm256_fmadd_pd(a_vec, bkj_vec, cvec);
|
||||
_mm256_storeu_pd(c_col + i, cvec);
|
||||
}
|
||||
for (; i < Rows; ++i)
|
||||
c_col[i] += a_col_k[i] * bkj;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
std::unreachable();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<size_t OtherColumns> [[nodiscard]]
|
||||
constexpr Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR>
|
||||
avx_multiply_row_major(const Mat<Columns, OtherColumns, Type, MatStoreType::ROW_MAJOR>& other) const
|
||||
{
|
||||
Mat<Rows, OtherColumns, Type, MatStoreType::ROW_MAJOR> result;
|
||||
|
||||
const Type* this_mat_data = this->raw_array().data();
|
||||
const Type* other_mat_data = other.raw_array().data();
|
||||
Type* result_mat_data = result.raw_array().data();
|
||||
|
||||
if constexpr (std::is_same_v<Type, float>)
|
||||
{
|
||||
// ReSharper disable once CppTooWideScopeInitStatement
|
||||
constexpr std::size_t vector_size = 8;
|
||||
for (std::size_t i = 0; i < Rows; ++i)
|
||||
{
|
||||
Type* c_row = result_mat_data + i * OtherColumns;
|
||||
for (std::size_t k = 0; k < Columns; ++k)
|
||||
{
|
||||
const auto aik = static_cast<float>(this_mat_data[i * Columns + k]);
|
||||
const __m256 aik_vec = _mm256_set1_ps(aik);
|
||||
const auto* b_row = reinterpret_cast<const float*>(other_mat_data + k * OtherColumns);
|
||||
|
||||
std::size_t j = 0;
|
||||
for (; j + vector_size <= OtherColumns; j += vector_size)
|
||||
{
|
||||
__m256 cvec = _mm256_loadu_ps(c_row + j);
|
||||
const __m256 b_vec = _mm256_loadu_ps(b_row + j);
|
||||
cvec = _mm256_fmadd_ps(b_vec, aik_vec, cvec);
|
||||
|
||||
_mm256_storeu_ps(c_row + j, cvec);
|
||||
}
|
||||
for (; j < OtherColumns; ++j)
|
||||
c_row[j] += aik * b_row[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (std::is_same_v<Type, double>)
|
||||
{ // double
|
||||
// ReSharper disable once CppTooWideScopeInitStatement
|
||||
constexpr std::size_t vector_size = 4;
|
||||
for (std::size_t i = 0; i < Rows; ++i)
|
||||
{
|
||||
Type* c_row = result_mat_data + i * OtherColumns;
|
||||
for (std::size_t k = 0; k < Columns; ++k)
|
||||
{
|
||||
const auto aik = static_cast<double>(this_mat_data[i * Columns + k]);
|
||||
const __m256d aik_vec = _mm256_set1_pd(aik);
|
||||
const auto* b_row = reinterpret_cast<const double*>(other_mat_data + k * OtherColumns);
|
||||
|
||||
std::size_t j = 0;
|
||||
for (; j + vector_size <= OtherColumns; j += vector_size)
|
||||
{
|
||||
__m256d cvec = _mm256_loadu_pd(c_row + j);
|
||||
const __m256d b_vec = _mm256_loadu_pd(b_row + j);
|
||||
cvec = _mm256_fmadd_pd(b_vec, aik_vec, cvec);
|
||||
|
||||
_mm256_storeu_pd(c_row + j, cvec);
|
||||
}
|
||||
for (; j < OtherColumns; ++j)
|
||||
c_row[j] += aik * b_row[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
std::unreachable();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
|
||||
@@ -479,4 +664,75 @@ namespace omath
|
||||
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
|
||||
{0.f, 0.f, -1.f, 0.f}};
|
||||
}
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right,
|
||||
const Type bottom, const Type top,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
return
|
||||
{
|
||||
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
|
||||
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
|
||||
{ 0.f, 0.f, static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
|
||||
{ 0.f, 0.f, 0.f, 1.f }
|
||||
};
|
||||
}
|
||||
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
|
||||
[[nodiscard]]
|
||||
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right,
|
||||
const Type bottom, const Type top,
|
||||
const Type near, const Type far) noexcept
|
||||
{
|
||||
return
|
||||
{
|
||||
{ static_cast<Type>(2) / (right - left), 0.f, 0.f, -(right + left) / (right - left)},
|
||||
{ 0.f, static_cast<Type>(2) / (top - bottom), 0.f, -(top + bottom) / (top - bottom)},
|
||||
{ 0.f, 0.f, -static_cast<Type>(2) / (far - near), -(far + near) / (far - near) },
|
||||
{ 0.f, 0.f, 0.f, 1.f }
|
||||
};
|
||||
}
|
||||
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
|
||||
Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
|
||||
{
|
||||
const Vector3<T> f = (center - eye).normalized();
|
||||
const Vector3<T> s = f.cross(up).normalized();
|
||||
const Vector3<T> u = s.cross(f);
|
||||
return mat_camera_view<T, St>(f, s, u, eye);
|
||||
}
|
||||
|
||||
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
|
||||
Mat<4, 4, T, St>mat_look_at_right_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
|
||||
{
|
||||
const Vector3<T> f = (center - eye).normalized();
|
||||
const Vector3<T> s = f.cross(up).normalized();
|
||||
const Vector3<T> u = s.cross(f);
|
||||
return mat_camera_view<T, St>(-f, s, u, eye);
|
||||
}
|
||||
|
||||
} // namespace omath
|
||||
|
||||
template<size_t Rows, size_t Columns, class Type, omath::MatStoreType StoreType>
|
||||
struct std::formatter<omath::Mat<Rows, Columns, Type, StoreType>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
using MatType = omath::Mat<Rows, Columns, Type, StoreType>;
|
||||
[[nodiscard]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
static auto format(const MatType& mat, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
return std::format_to(ctx.out(), "{}", mat.to_string());
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
|
||||
return std::format_to(ctx.out(), L"{}", mat.to_wstring());
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"{}", mat.to_u8string());
|
||||
}
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
// Created by Orange on 11/13/2024.
|
||||
//
|
||||
#pragma once
|
||||
#include "omath/vector3.hpp"
|
||||
#include "vector3.hpp"
|
||||
|
||||
namespace omath
|
||||
{
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include <tuple>
|
||||
|
||||
#ifdef OMATH_IMGUI_INTEGRATION
|
||||
@@ -218,7 +219,6 @@ namespace omath
|
||||
{
|
||||
return std::make_tuple(x, y);
|
||||
}
|
||||
|
||||
#ifdef OMATH_IMGUI_INTEGRATION
|
||||
[[nodiscard]]
|
||||
ImVec2 to_im_vec2() const noexcept
|
||||
@@ -233,3 +233,27 @@ namespace omath
|
||||
#endif
|
||||
};
|
||||
} // namespace omath
|
||||
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector2<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
static auto format(const omath::Vector2<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
|
||||
return std::format_to(ctx.out(), L"[{}, {}]", vec.x, vec.y);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"[{}, {}]", vec.x, vec.y);
|
||||
}
|
||||
};
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "omath/angle.hpp"
|
||||
#include "omath/vector2.hpp"
|
||||
#include "omath/trigonometry/angle.hpp"
|
||||
#include "omath/linear_algebra/vector2.hpp"
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
@@ -159,9 +159,9 @@ namespace omath
|
||||
return Vector2<Type>::length();
|
||||
}
|
||||
|
||||
[[nodiscard]] Type distance_to(const Vector3& vOther) const noexcept
|
||||
[[nodiscard]] Type distance_to(const Vector3& v_other) const noexcept
|
||||
{
|
||||
return (*this - vOther).length();
|
||||
return (*this - v_other).length();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -279,21 +279,42 @@ namespace omath
|
||||
}
|
||||
};
|
||||
} // namespace omath
|
||||
// ReSharper disable once CppRedundantNamespaceDefinition
|
||||
namespace std
|
||||
|
||||
template<> struct std::hash<omath::Vector3<float>>
|
||||
{
|
||||
template<> struct hash<omath::Vector3<float>>
|
||||
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
|
||||
{
|
||||
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
constexpr std::hash<float> hasher;
|
||||
std::size_t hash = 0;
|
||||
constexpr std::hash<float> hasher;
|
||||
|
||||
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector3<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
static auto format(const omath::Vector3<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
return std::format_to(ctx.out(), "[{}, {}, {}]", vec.x, vec.y, vec.z);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
|
||||
return std::format_to(ctx.out(), L"[{}, {}, {}]", vec.x, vec.y, vec.z);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"[{}, {}, {}]", vec.x, vec.y, vec.z);
|
||||
}
|
||||
};
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <omath/vector3.hpp>
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
|
||||
namespace omath
|
||||
{
|
||||
@@ -201,3 +201,26 @@ namespace omath
|
||||
#endif
|
||||
};
|
||||
} // namespace omath
|
||||
|
||||
template<class Type>
|
||||
struct std::formatter<omath::Vector4<Type>> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
static auto format(const omath::Vector4<Type>& vec, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
return std::format_to(ctx.out(), "[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
|
||||
return std::format_to(ctx.out(), L"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"[{}, {}, {}, {}]", vec.x, vec.y, vec.z, vec.w);
|
||||
}
|
||||
};
|
||||
@@ -1,112 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef OMATH_ENABLE_LEGACY
|
||||
|
||||
#include "omath/vector3.hpp"
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace omath
|
||||
{
|
||||
|
||||
class Matrix final
|
||||
{
|
||||
public:
|
||||
Matrix();
|
||||
Matrix(size_t rows, size_t columns);
|
||||
|
||||
Matrix(const std::initializer_list<std::initializer_list<float>>& rows);
|
||||
|
||||
[[nodiscard]]
|
||||
static Matrix to_screen_matrix(float screen_width, float screen_height);
|
||||
|
||||
[[nodiscard]]
|
||||
static Matrix translation_matrix(const Vector3<float>& diff);
|
||||
|
||||
[[nodiscard]]
|
||||
static Matrix orientation_matrix(const Vector3<float>& forward, const Vector3<float>& right,
|
||||
const Vector3<float>& up);
|
||||
|
||||
[[nodiscard]]
|
||||
static Matrix projection_matrix(float field_of_view, float aspect_ratio, float near, float far);
|
||||
|
||||
Matrix(const Matrix& other);
|
||||
|
||||
Matrix(size_t rows, size_t columns, const float* raw_data);
|
||||
|
||||
Matrix(Matrix&& other) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
size_t row_count() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
float& operator[](size_t row, size_t column);
|
||||
|
||||
[[nodiscard]]
|
||||
size_t columns_count() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
std::pair<size_t, size_t> size() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
float& at(size_t row, size_t col);
|
||||
|
||||
[[nodiscard]]
|
||||
float sum();
|
||||
|
||||
void set_data_from_raw(const float* raw_matrix);
|
||||
|
||||
[[nodiscard]]
|
||||
Matrix transpose() const;
|
||||
|
||||
void set(float val);
|
||||
|
||||
[[nodiscard]]
|
||||
const float& at(size_t row, size_t col) const;
|
||||
|
||||
Matrix operator*(const Matrix& other) const;
|
||||
|
||||
Matrix& operator*=(const Matrix& other);
|
||||
|
||||
Matrix operator*(float f) const;
|
||||
|
||||
Matrix& operator*=(float f);
|
||||
|
||||
Matrix& operator/=(float f);
|
||||
|
||||
void clear();
|
||||
|
||||
[[nodiscard]]
|
||||
Matrix strip(size_t row, size_t column) const;
|
||||
|
||||
[[nodiscard]]
|
||||
float minor(size_t i, size_t j) const;
|
||||
|
||||
[[nodiscard]]
|
||||
float alg_complement(size_t i, size_t j) const;
|
||||
|
||||
[[nodiscard]]
|
||||
float determinant() const;
|
||||
|
||||
[[nodiscard]]
|
||||
const float* raw() const;
|
||||
|
||||
Matrix& operator=(const Matrix& other);
|
||||
|
||||
Matrix& operator=(Matrix&& other) noexcept;
|
||||
|
||||
Matrix operator/(float f) const;
|
||||
|
||||
[[nodiscard]]
|
||||
std::string to_string() const;
|
||||
|
||||
~Matrix();
|
||||
|
||||
private:
|
||||
size_t m_rows;
|
||||
size_t m_columns;
|
||||
std::unique_ptr<float[]> m_data;
|
||||
};
|
||||
} // namespace omath
|
||||
#endif
|
||||
@@ -6,27 +6,27 @@
|
||||
#pragma once
|
||||
|
||||
// Basic math utilities
|
||||
#include "omath/angles.hpp"
|
||||
#include "omath/angle.hpp"
|
||||
#include "omath/trigonometry/angles.hpp"
|
||||
#include "omath/trigonometry/angle.hpp"
|
||||
|
||||
// Vector classes (in dependency order)
|
||||
#include "omath/vector2.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/vector4.hpp"
|
||||
#include "omath/linear_algebra/vector2.hpp"
|
||||
#include "omath/linear_algebra/vector4.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
|
||||
// Matrix classes
|
||||
#include "omath/mat.hpp"
|
||||
#include "omath/matrix.hpp"
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
|
||||
// Color functionality
|
||||
#include "omath/color.hpp"
|
||||
#include "omath/utility/color.hpp"
|
||||
|
||||
// Geometric primitives
|
||||
#include "omath/triangle.hpp"
|
||||
#include "omath/view_angles.hpp"
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/trigonometry/view_angles.hpp"
|
||||
|
||||
// 3D primitives
|
||||
#include "omath/3d_primitives/box.hpp"
|
||||
#include "omath/3d_primitives/plane.hpp"
|
||||
|
||||
// Collision detection
|
||||
#include "omath/collision/line_tracer.hpp"
|
||||
@@ -81,4 +81,11 @@
|
||||
#include "omath/engines/unreal_engine/formulas.hpp"
|
||||
#include "omath/engines/unreal_engine/camera.hpp"
|
||||
#include "omath/engines/unreal_engine/traits/camera_trait.hpp"
|
||||
#include "omath/engines/unreal_engine/traits/pred_engine_trait.hpp"
|
||||
#include "omath/engines/unreal_engine/traits/pred_engine_trait.hpp"
|
||||
|
||||
// Reverse Engineering
|
||||
#include "omath/rev_eng/external_rev_object.hpp"
|
||||
#include "omath/rev_eng/internal_rev_object.hpp"
|
||||
|
||||
// Utility
|
||||
#include "omath/utility/pattern_scan.hpp"
|
||||
@@ -3,8 +3,8 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include "omath/pathfinding/navigation_mesh.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace omath::pathfinding
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// Created by Vlad on 2/23/2025.
|
||||
//
|
||||
#pragma once
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include "omath/projectile_prediction/projectile.hpp"
|
||||
#include "omath/projectile_prediction/target.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "omath/engines/source_engine/traits/pred_engine_trait.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include "omath/projectile_prediction/proj_pred_engine.hpp"
|
||||
#include "omath/projectile_prediction/projectile.hpp"
|
||||
#include "omath/projectile_prediction/target.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
@@ -20,7 +20,9 @@ namespace omath::projectile_prediction
|
||||
Vector3<float> v3, // by-value for calc_viewpoint_from_angles
|
||||
float pitch, float yaw, float time, float gravity, std::optional<float> maybe_pitch) {
|
||||
// Presence + return types
|
||||
{ T::predict_projectile_position(projectile, pitch, yaw, time, gravity) } -> std::same_as<Vector3<float>>;
|
||||
{
|
||||
T::predict_projectile_position(projectile, pitch, yaw, time, gravity)
|
||||
} -> std::same_as<Vector3<float>>;
|
||||
{ T::predict_target_position(target, time, gravity) } -> std::same_as<Vector3<float>>;
|
||||
{ T::calc_vector_2d_distance(vec_a) } -> std::same_as<float>;
|
||||
{ T::get_vector_height_coordinate(vec_b) } -> std::same_as<float>;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
|
||||
@@ -4,13 +4,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include "omath/projection/error_codes.hpp"
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <expected>
|
||||
#include <omath/angle.hpp>
|
||||
#include <omath/mat.hpp>
|
||||
#include <omath/vector3.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef OMATH_BUILD_TESTS
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class UnitTestProjection_Projection_Test;
|
||||
#endif
|
||||
|
||||
namespace omath::projection
|
||||
{
|
||||
class ViewPort final
|
||||
@@ -45,6 +50,9 @@ namespace omath::projection
|
||||
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
||||
class Camera final
|
||||
{
|
||||
#ifdef OMATH_BUILD_TESTS
|
||||
friend UnitTestProjection_Projection_Test;
|
||||
#endif
|
||||
public:
|
||||
~Camera() = default;
|
||||
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
||||
@@ -54,12 +62,13 @@ namespace omath::projection
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void look_at(const Vector3<float>& target)
|
||||
{
|
||||
m_view_angles = TraitClass::calc_look_at_angle(m_origin, target);
|
||||
m_view_projection_matrix = std::nullopt;
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Mat4X4Type calc_view_projection_matrix() const noexcept
|
||||
{
|
||||
return TraitClass::calc_projection_matrix(m_field_of_view, m_view_port, m_near_plane_distance,
|
||||
@@ -164,6 +173,38 @@ namespace omath::projection
|
||||
|
||||
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
||||
}
|
||||
[[nodiscard]]
|
||||
std::expected<Vector3<float>, Error> view_port_to_screen(const Vector3<float>& ndc) const noexcept
|
||||
{
|
||||
const auto inv_view_proj = get_view_projection_matrix().inverted();
|
||||
|
||||
if (!inv_view_proj)
|
||||
return std::unexpected(Error::INV_VIEW_PROJ_MAT_DET_EQ_ZERO);
|
||||
|
||||
auto inverted_projection =
|
||||
inv_view_proj.value() * mat_column_from_vector<float, Mat4X4Type::get_store_ordering()>(ndc);
|
||||
|
||||
if (!inverted_projection.at(3, 0))
|
||||
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
|
||||
|
||||
inverted_projection /= inverted_projection.at(3, 0);
|
||||
|
||||
return Vector3<float>{inverted_projection.at(0, 0), inverted_projection.at(1, 0),
|
||||
inverted_projection.at(2, 0)};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
|
||||
{
|
||||
return view_port_to_screen(screen_to_ndc(screen_pos));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::expected<Vector3<float>, Error> screen_to_world(const Vector2<float>& screen_pos) const noexcept
|
||||
{
|
||||
const auto& [x, y] = screen_pos;
|
||||
return screen_to_world({x, y, 1.f});
|
||||
}
|
||||
|
||||
protected:
|
||||
ViewPort m_view_port{};
|
||||
@@ -186,19 +227,25 @@ namespace omath::projection
|
||||
|
||||
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
||||
{
|
||||
/*
|
||||
^
|
||||
| y
|
||||
1 |
|
||||
|
|
||||
|
|
||||
-1 ---------0--------- 1 --> x
|
||||
|
|
||||
|
|
||||
-1 |
|
||||
v
|
||||
*/
|
||||
/*
|
||||
^
|
||||
| y
|
||||
1 |
|
||||
|
|
||||
|
|
||||
-1 ---------0--------- 1 --> x
|
||||
|
|
||||
|
|
||||
-1 |
|
||||
v
|
||||
*/
|
||||
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
|
||||
}
|
||||
|
||||
[[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
|
||||
|
||||
@@ -10,5 +10,6 @@ namespace omath::projection
|
||||
enum class Error : uint16_t
|
||||
{
|
||||
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
|
||||
INV_VIEW_PROJ_MAT_DET_EQ_ZERO,
|
||||
};
|
||||
}
|
||||
35
include/omath/rev_eng/external_rev_object.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by Vlad on 10/4/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::rev_eng
|
||||
{
|
||||
template<class ExternalMemoryManagementTrait>
|
||||
class ExternalReverseEngineeredObject
|
||||
{
|
||||
public:
|
||||
explicit ExternalReverseEngineeredObject(const std::uintptr_t addr): m_object_address(addr)
|
||||
{
|
||||
}
|
||||
private:
|
||||
std::uintptr_t m_object_address{};
|
||||
|
||||
protected:
|
||||
template<class Type>
|
||||
[[nodiscard]]
|
||||
Type get_by_offset(const std::ptrdiff_t offset) const
|
||||
{
|
||||
return ExternalMemoryManagementTrait::read_memory(m_object_address+offset);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
void set_by_offset(const std::ptrdiff_t offset, const Type& value) const
|
||||
{
|
||||
return ExternalMemoryManagementTrait::write_memory(m_object_address+offset, value);
|
||||
}
|
||||
};
|
||||
} // namespace omath::rev_eng
|
||||
37
include/omath/rev_eng/internal_rev_object.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by Vlad on 8/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::rev_eng
|
||||
{
|
||||
class InternalReverseEngineeredObject
|
||||
{
|
||||
protected:
|
||||
template<class Type>
|
||||
[[nodiscard]] Type& get_by_offset(const std::ptrdiff_t offset)
|
||||
{
|
||||
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
[[nodiscard]] const Type& get_by_offset(const std::ptrdiff_t offset) const
|
||||
{
|
||||
return *reinterpret_cast<Type*>(reinterpret_cast<std::uintptr_t>(this) + offset);
|
||||
}
|
||||
|
||||
template<std::size_t id, class ReturnType>
|
||||
ReturnType call_virtual_method(auto... arg_list)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
using VirtualMethodType = ReturnType(__thiscall*)(void*, decltype(arg_list)...);
|
||||
#else
|
||||
using VirtualMethodType = ReturnType(__fastcall*)(void*, decltype(arg_list)...);
|
||||
#endif
|
||||
return (*reinterpret_cast<VirtualMethodType**>(this))[id](this, arg_list...);
|
||||
}
|
||||
};
|
||||
} // namespace omath::rev_eng
|
||||
5
include/omath/system/pe/data_directory.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
32
include/omath/system/pe/dos_header.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
struct DosHeader final
|
||||
{
|
||||
std::uint16_t e_magic;
|
||||
std::uint16_t e_cblp;
|
||||
std::uint16_t e_cp;
|
||||
std::uint16_t e_crlc;
|
||||
std::uint16_t e_cparhdr;
|
||||
std::uint16_t e_minalloc;
|
||||
std::uint16_t e_maxalloc;
|
||||
std::uint16_t e_ss;
|
||||
std::uint16_t e_sp;
|
||||
std::uint16_t e_csum;
|
||||
std::uint16_t e_ip;
|
||||
std::uint16_t e_cs;
|
||||
std::uint16_t e_lfarlc;
|
||||
std::uint16_t e_ovno;
|
||||
std::uint16_t e_res[4];
|
||||
std::uint16_t e_oemid;
|
||||
std::uint16_t e_oeminfo;
|
||||
std::uint16_t e_res2[10];
|
||||
std::uint32_t e_lfanew;
|
||||
};
|
||||
}
|
||||
56
include/omath/system/pe/file_header.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
enum class MachineId : std::uint16_t
|
||||
{
|
||||
UNKNOWN = 0x0000,
|
||||
TARGET_HOST = 0x0001, // Useful for indicating we want to interact with the host and not a WoW guest.
|
||||
I386 = 0x014C, // Intel 386.
|
||||
R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
|
||||
R4000 = 0x0166, // MIPS little-endian
|
||||
R10000 = 0x0168, // MIPS little-endian
|
||||
WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2
|
||||
ALPHA = 0x0184, // Alpha_AXP
|
||||
SH3 = 0x01A2, // SH3 little-endian
|
||||
SH3DSP = 0x01A3,
|
||||
SH3E = 0x01A4, // SH3E little-endian
|
||||
SH4 = 0x01A6, // SH4 little-endian
|
||||
SH5 = 0x01A8, // SH5
|
||||
ARM = 0x01C0, // ARM Little-Endian
|
||||
THUMB = 0x01C2, // ARM Thumb/Thumb-2 Little-Endian
|
||||
ARMNT = 0x01C4, // ARM Thumb-2 Little-Endian
|
||||
AM33 = 0x01D3,
|
||||
POWERPC = 0x01F0, // IBM PowerPC Little-Endian
|
||||
POWERPCP = 0x01F1,
|
||||
IA64 = 0x0200, // Intel 64
|
||||
MIPS16 = 0x0266, // MIPS
|
||||
ALPHA64 = 0x0284, // ALPHA64
|
||||
MIPSFPU = 0x0366, // MIPS
|
||||
MIPSFPU16 = 0x0466, // MIPS
|
||||
AXP64 = 0x0284,
|
||||
TRICORE = 0x0520, // Infineon
|
||||
CEF = 0x0CEF,
|
||||
EBC = 0x0EBC, // EFI Byte Code
|
||||
AMD64 = 0x8664, // AMD64 (K8)
|
||||
M32R = 0x9041, // M32R little-endian
|
||||
ARM64 = 0xAA64, // ARM64 Little-Endian
|
||||
CEE = 0xC0EE,
|
||||
};
|
||||
|
||||
struct FileHeader final
|
||||
{
|
||||
MachineId machine;
|
||||
uint16_t num_sections;
|
||||
uint32_t timedate_stamp;
|
||||
uint32_t ptr_symbols;
|
||||
uint32_t num_symbols;
|
||||
uint16_t size_optional_header;
|
||||
std::uint16_t characteristics;
|
||||
};
|
||||
}
|
||||
23
include/omath/system/pe/image_nt_headers.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by Vlad on 10/9/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "file_header.hpp"
|
||||
#include "optional_header.hpp"
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
enum class NtArchitecture
|
||||
{
|
||||
x32_bit,
|
||||
x64_bit,
|
||||
};
|
||||
template<NtArchitecture architecture>
|
||||
struct ImageNtHeaders final
|
||||
{
|
||||
std::uint32_t signature;
|
||||
FileHeader file_header;
|
||||
OptionalHeader<architecture == NtArchitecture::x64_bit> optional_header;
|
||||
};
|
||||
} // namespace omath::system::pe
|
||||
118
include/omath/system/pe/optional_header.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath::system::pe
|
||||
{
|
||||
static constexpr std::uint16_t opt_hdr32_magic = 0x010B;
|
||||
static constexpr std::uint16_t opt_hdr64_magic = 0x020B;
|
||||
enum class SubsystemId : std::uint16_t
|
||||
{
|
||||
unknown = 0x0000,
|
||||
native = 0x0001,
|
||||
windows_gui = 0x0002,
|
||||
windows_cui = 0x0003,
|
||||
os2_cui = 0x0005,
|
||||
posix_cui = 0x0007,
|
||||
native_windows = 0x0008,
|
||||
windows_ce_gui = 0x0009,
|
||||
efi_application = 0x000A,
|
||||
efi_boot_service_driver = 0x000B,
|
||||
efi_runtime_driver = 0x000C,
|
||||
efi_rom = 0x000D,
|
||||
xbox = 0x000E,
|
||||
windows_boot_application = 0x0010,
|
||||
xbox_code_catalog = 0x0011,
|
||||
};
|
||||
|
||||
struct DataDirectory final
|
||||
{
|
||||
std::uint32_t rva;
|
||||
std::uint32_t size;
|
||||
};
|
||||
struct OptionalHeaderX64 final
|
||||
{
|
||||
// Standard fields.
|
||||
std::uint16_t magic;
|
||||
std::uint16_t linker_version;
|
||||
|
||||
std::uint32_t size_code;
|
||||
std::uint32_t size_init_data;
|
||||
std::uint32_t size_uninit_data;
|
||||
|
||||
std::uint32_t entry_point;
|
||||
std::uint32_t base_of_code;
|
||||
|
||||
// NT additional fields.
|
||||
std::uint64_t image_base;
|
||||
std::uint32_t section_alignment;
|
||||
std::uint32_t file_alignment;
|
||||
|
||||
std::uint32_t os_version;
|
||||
std::uint32_t img_version;
|
||||
std::uint32_t subsystem_version;
|
||||
std::uint32_t win32_version_value;
|
||||
|
||||
std::uint32_t size_image;
|
||||
std::uint32_t size_headers;
|
||||
|
||||
std::uint32_t checksum;
|
||||
SubsystemId subsystem;
|
||||
std::uint16_t characteristics;
|
||||
|
||||
std::uint64_t size_stack_reserve;
|
||||
std::uint64_t size_stack_commit;
|
||||
std::uint64_t size_heap_reserve;
|
||||
std::uint64_t size_heap_commit;
|
||||
|
||||
std::uint32_t ldr_flags;
|
||||
|
||||
std::uint32_t num_data_directories;
|
||||
DataDirectory data_directories[16];
|
||||
};
|
||||
struct OptionalHeaderX86 final
|
||||
{
|
||||
// Standard fields.
|
||||
uint16_t magic;
|
||||
uint16_t linker_version;
|
||||
|
||||
uint32_t size_code;
|
||||
uint32_t size_init_data;
|
||||
uint32_t size_uninit_data;
|
||||
|
||||
uint32_t entry_point;
|
||||
uint32_t base_of_code;
|
||||
uint32_t base_of_data;
|
||||
|
||||
// NT additional fields.
|
||||
uint32_t image_base;
|
||||
uint32_t section_alignment;
|
||||
uint32_t file_alignment;
|
||||
|
||||
std::uint32_t os_version;
|
||||
std::uint32_t img_version;
|
||||
std::uint32_t subsystem_version;
|
||||
uint32_t win32_version_value;
|
||||
|
||||
uint32_t size_image;
|
||||
uint32_t size_headers;
|
||||
|
||||
uint32_t checksum;
|
||||
SubsystemId subsystem;
|
||||
std::uint16_t characteristics;
|
||||
|
||||
uint32_t size_stack_reserve;
|
||||
uint32_t size_stack_commit;
|
||||
uint32_t size_heap_reserve;
|
||||
uint32_t size_heap_commit;
|
||||
|
||||
uint32_t ldr_flags;
|
||||
|
||||
uint32_t num_data_directories;
|
||||
DataDirectory data_directories[16];
|
||||
};
|
||||
template<bool x64 = true>
|
||||
using OptionalHeader = std::conditional_t<x64, OptionalHeaderX64, OptionalHeaderX86>;
|
||||
} // namespace omath::system::pe
|
||||
32
include/omath/system/pe/section_header.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by Vlad on 10/8/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// Section header
|
||||
//
|
||||
namespace omath::system::pe
|
||||
{
|
||||
struct SectionHeader final
|
||||
{
|
||||
char name[8];
|
||||
union
|
||||
{
|
||||
std::uint32_t physical_address;
|
||||
std::uint32_t virtual_size;
|
||||
};
|
||||
std::uint32_t virtual_address;
|
||||
|
||||
std::uint32_t size_raw_data;
|
||||
std::uint32_t ptr_raw_data;
|
||||
|
||||
std::uint32_t ptr_relocs;
|
||||
std::uint32_t ptr_line_numbers;
|
||||
std::uint32_t num_relocs;
|
||||
std::uint32_t num_line_numbers;
|
||||
|
||||
std::uint32_t characteristics;
|
||||
};
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/angles.hpp"
|
||||
#include "omath/trigonometry/angles.hpp"
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
#include <utility>
|
||||
|
||||
namespace omath
|
||||
@@ -122,13 +123,13 @@ namespace omath
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Angle& operator+(const Angle& other) noexcept
|
||||
constexpr Angle operator+(const Angle& other) noexcept
|
||||
{
|
||||
if constexpr (flags == AngleFlags::Normalized)
|
||||
return {angles::wrap_angle(m_angle + other.m_angle, min, max)};
|
||||
return Angle{angles::wrap_angle(m_angle + other.m_angle, min, max)};
|
||||
|
||||
else if constexpr (flags == AngleFlags::Clamped)
|
||||
return {std::clamp(m_angle + other.m_angle, min, max)};
|
||||
return Angle{std::clamp(m_angle + other.m_angle, min, max)};
|
||||
|
||||
else
|
||||
static_assert(false);
|
||||
@@ -137,7 +138,7 @@ namespace omath
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Angle& operator-(const Angle& other) noexcept
|
||||
constexpr Angle operator-(const Angle& other) noexcept
|
||||
{
|
||||
return operator+(-other);
|
||||
}
|
||||
@@ -149,3 +150,62 @@ namespace omath
|
||||
}
|
||||
};
|
||||
} // namespace omath
|
||||
|
||||
template<class T, T MinV, T MaxV, omath::AngleFlags F>
|
||||
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, char> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
using AngleT = omath::Angle<T, MinV, MaxV, F>;
|
||||
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
auto format(const AngleT& a, FormatContext& ctx) const
|
||||
{
|
||||
static_assert(std::is_same_v<typename FormatContext::char_type, char>);
|
||||
return std::format_to(ctx.out(), "{}deg", a.as_degrees());
|
||||
}
|
||||
};
|
||||
|
||||
// wchar_t formatter
|
||||
template<class T, T MinV, T MaxV, omath::AngleFlags F>
|
||||
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, wchar_t> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
using AngleT = omath::Angle<T, MinV, MaxV, F>;
|
||||
|
||||
static constexpr auto parse(std::wformat_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
auto format(const AngleT& a, FormatContext& ctx) const
|
||||
{
|
||||
static_assert(std::is_same_v<typename FormatContext::char_type, wchar_t>);
|
||||
return std::format_to(ctx.out(), L"{}deg", a.as_degrees());
|
||||
}
|
||||
};
|
||||
|
||||
// wchar_t formatter
|
||||
template<class T, T MinV, T MaxV, omath::AngleFlags F>
|
||||
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, char8_t> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
using AngleT = omath::Angle<T, MinV, MaxV, F>;
|
||||
|
||||
static constexpr auto parse(std::wformat_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
auto format(const AngleT& a, FormatContext& ctx) const
|
||||
{
|
||||
static_assert(std::is_same_v<typename FormatContext::char_type, char8_t>);
|
||||
return std::format_to(ctx.out(), u8"{}deg", a.as_degrees());
|
||||
}
|
||||
};
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/vector4.hpp"
|
||||
#include "omath/linear_algebra/vector4.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace omath
|
||||
@@ -96,7 +95,7 @@ namespace omath
|
||||
hsv_data.hue = 0.f;
|
||||
|
||||
else if (max == red)
|
||||
hsv_data.hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
|
||||
hsv_data.hue = 60.f * (std::fmod(static_cast<float>((green - blue) / delta), 6.f));
|
||||
else if (max == green)
|
||||
hsv_data.hue = 60.f * (((blue - red) / delta) + 2.f);
|
||||
else if (max == blue)
|
||||
@@ -165,5 +164,49 @@ namespace omath
|
||||
return {to_im_vec4()};
|
||||
}
|
||||
#endif
|
||||
[[nodiscard]] std::string to_string() const noexcept
|
||||
{
|
||||
return std::format("[r:{}, g:{}, b:{}, a:{}]",
|
||||
static_cast<int>(x * 255.f),
|
||||
static_cast<int>(y * 255.f),
|
||||
static_cast<int>(z * 255.f),
|
||||
static_cast<int>(w * 255.f));
|
||||
}
|
||||
[[nodiscard]] std::wstring to_wstring() const noexcept
|
||||
{
|
||||
const auto ascii_string = to_string();
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
[[nodiscard]] std::u8string to_u8string() const noexcept
|
||||
{
|
||||
const auto ascii_string = to_string();
|
||||
return {ascii_string.cbegin(), ascii_string.cend()};
|
||||
}
|
||||
};
|
||||
} // namespace omath
|
||||
template<>
|
||||
struct std::formatter<omath::Color> // NOLINT(*-dcl58-cpp)
|
||||
{
|
||||
[[nodiscard]]
|
||||
static constexpr auto parse(std::format_parse_context& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template<class FormatContext>
|
||||
[[nodiscard]]
|
||||
static auto format(const omath::Color& col, FormatContext& ctx)
|
||||
{
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||
return std::format_to(ctx.out(), "{}", col.to_string());
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, wchar_t>)
|
||||
return std::format_to(ctx.out(), L"{}", col.to_wstring());
|
||||
|
||||
if constexpr (std::is_same_v<typename FormatContext::char_type, char8_t>)
|
||||
return std::format_to(ctx.out(), u8"{}", col.to_u8string());
|
||||
|
||||
return std::unreachable();
|
||||
}
|
||||
};
|
||||
82
include/omath/utility/pattern_scan.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Created by Vlad on 10/4/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class unit_test_pattern_scan_read_test_Test;
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class unit_test_pattern_scan_corner_case_1_Test;
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class unit_test_pattern_scan_corner_case_2_Test;
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class unit_test_pattern_scan_corner_case_3_Test;
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
class unit_test_pattern_scan_corner_case_4_Test;
|
||||
|
||||
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
|
||||
43
include/omath/utility/pe_pattern_scan.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
namespace omath
|
||||
{
|
||||
struct PeSectionScanResult
|
||||
{
|
||||
std::uint64_t virtual_base_addr;
|
||||
std::uint64_t raw_base_addr;
|
||||
std::ptrdiff_t target_offset;
|
||||
};
|
||||
class PePatternScanner final
|
||||
{
|
||||
private:
|
||||
struct Section
|
||||
{
|
||||
std::uint64_t virtual_base_addr;
|
||||
std::uint64_t raw_base_addr;
|
||||
std::vector<std::byte> data;
|
||||
};
|
||||
|
||||
public:
|
||||
[[nodiscard]]
|
||||
static std::optional<std::uintptr_t> scan_for_pattern_in_loaded_module(const std::string_view& module_name,
|
||||
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");
|
||||
|
||||
[[nodiscard]]
|
||||
static std::optional<Section> extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name);
|
||||
};
|
||||
} // namespace omath
|
||||
1
mkdocs.yml
Normal file
@@ -0,0 +1 @@
|
||||
site_name: My Docs
|
||||
19
source/3d_primitives/plane.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by Vlad on 8/28/2025.
|
||||
//
|
||||
#include "omath/3d_primitives/plane.hpp"
|
||||
|
||||
namespace omath::primitives
|
||||
{
|
||||
std::array<Triangle<Vector3<float>>, 2> create_plane(const Vector3<float>& vertex_a,
|
||||
const Vector3<float>& vertex_b,
|
||||
const Vector3<float>& direction, const float size) noexcept
|
||||
{
|
||||
const auto second_vertex_a = vertex_a + direction * size;
|
||||
return std::array
|
||||
{
|
||||
Triangle{second_vertex_a, vertex_a, vertex_b},
|
||||
Triangle{second_vertex_a, vertex_b + direction * size, vertex_b}
|
||||
};
|
||||
}
|
||||
} // namespace omath::primitives
|
||||
@@ -50,12 +50,10 @@ namespace omath::collision
|
||||
|
||||
const auto t_hit = side_b.dot(q) * inv_det;
|
||||
|
||||
if (ray.infinite_length)
|
||||
{
|
||||
if (t_hit <= k_epsilon)
|
||||
return ray.end;
|
||||
}
|
||||
else if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
|
||||
if (ray.infinite_length && t_hit <= k_epsilon)
|
||||
return ray.end;
|
||||
|
||||
if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
|
||||
return ray.end;
|
||||
|
||||
return ray.start + ray_dir * t_hit;
|
||||
|
||||
@@ -8,11 +8,10 @@ namespace omath::iw_engine
|
||||
|
||||
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||
{
|
||||
const auto distance = cam_origin.distance_to(look_at);
|
||||
const auto delta = cam_origin - look_at;
|
||||
const auto direction = (look_at - cam_origin).normalized();
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
|
||||
YawAngle::from_radians(std::atan2(delta.y, delta.x)), RollAngle::from_radians(0.f)};
|
||||
return {PitchAngle::from_radians(-std::asin(direction.z)),
|
||||
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
|
||||
}
|
||||
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
|
||||
@@ -28,14 +28,13 @@ namespace omath::opengl_engine
|
||||
}
|
||||
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
return mat_camera_view<float, MatStoreType::COLUMN_MAJOR>(-forward_vector(angles), right_vector(angles),
|
||||
up_vector(angles), cam_origin);
|
||||
return mat_look_at_right_handed(cam_origin, cam_origin+forward_vector(angles), up_vector(angles));
|
||||
}
|
||||
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||
{
|
||||
return mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(-angles.pitch)
|
||||
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(-angles.yaw)
|
||||
* mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll);
|
||||
return mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll)
|
||||
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(angles.yaw)
|
||||
* mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(angles.pitch);
|
||||
}
|
||||
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||
const float far) noexcept
|
||||
|
||||
@@ -9,11 +9,10 @@ namespace omath::opengl_engine
|
||||
|
||||
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||
{
|
||||
const auto distance = cam_origin.distance_to(look_at);
|
||||
const auto delta = cam_origin - look_at;
|
||||
const auto direction = (look_at - cam_origin).normalized();
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(delta.y / distance)),
|
||||
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)};
|
||||
return {PitchAngle::from_radians(std::asin(direction.y)),
|
||||
YawAngle::from_radians(-std::atan2(direction.x, -direction.z)), RollAngle::from_radians(0.f)};
|
||||
}
|
||||
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
|
||||
@@ -8,11 +8,11 @@ namespace omath::source_engine
|
||||
|
||||
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||
{
|
||||
const auto distance = cam_origin.distance_to(look_at);
|
||||
const auto delta = cam_origin - look_at;
|
||||
const auto direction = (look_at - cam_origin).normalized();
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
|
||||
YawAngle::from_radians(std::atan2(delta.y, delta.x)), RollAngle::from_radians(0.f)};
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(direction.z)),
|
||||
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
|
||||
}
|
||||
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
|
||||
@@ -30,9 +30,9 @@ namespace omath::unity_engine
|
||||
}
|
||||
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||
{
|
||||
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch)
|
||||
return mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll)
|
||||
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.yaw)
|
||||
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll);
|
||||
* mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch);
|
||||
}
|
||||
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||
const float far) noexcept
|
||||
|
||||
@@ -8,11 +8,10 @@ namespace omath::unity_engine
|
||||
|
||||
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||
{
|
||||
const auto distance = cam_origin.distance_to(look_at);
|
||||
const auto delta = cam_origin - look_at;
|
||||
const auto direction = (look_at - cam_origin).normalized();
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(delta.y / distance)),
|
||||
YawAngle::from_radians(std::atan2(delta.z, delta.x)), RollAngle::from_radians(0.f)};
|
||||
return {PitchAngle::from_radians(-std::asin(direction.y)),
|
||||
YawAngle::from_radians(std::atan2(direction.x, direction.z)), RollAngle::from_radians(0.f)};
|
||||
}
|
||||
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace omath::unreal_engine
|
||||
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
|
||||
{
|
||||
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.roll)
|
||||
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.pitch)
|
||||
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw);
|
||||
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw)
|
||||
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.pitch);
|
||||
}
|
||||
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
||||
const float far) noexcept
|
||||
|
||||
@@ -8,11 +8,10 @@ namespace omath::unreal_engine
|
||||
|
||||
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
|
||||
{
|
||||
const auto distance = cam_origin.distance_to(look_at);
|
||||
const auto delta = cam_origin - look_at;
|
||||
const auto direction = (look_at - cam_origin).normalized();
|
||||
|
||||
return {PitchAngle::from_radians(-std::asin(delta.z / distance)),
|
||||
YawAngle::from_radians(std::atan2(delta.x, delta.y)), RollAngle::from_radians(0.f)};
|
||||
return {PitchAngle::from_radians(-std::asin(direction.z)),
|
||||
YawAngle::from_radians(std::atan2(direction.y, direction.x)), RollAngle::from_radians(0.f)};
|
||||
}
|
||||
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
|
||||
{
|
||||
|
||||
@@ -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
|
||||
75
source/utility/pattern_scan.cpp
Normal 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
|
||||
158
source/utility/pe_pattern_scan.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// Created by Vlad on 10/7/2025.
|
||||
//
|
||||
#include "omath/utility/pe_pattern_scan.hpp"
|
||||
#include "omath/system/pe/image_nt_headers.hpp"
|
||||
#include "omath/system/pe/section_header.hpp"
|
||||
#include "omath/utility/pattern_scan.hpp"
|
||||
#include <fstream>
|
||||
#include <omath/system/pe/dos_header.hpp>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <variant>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using namespace omath::system::pe;
|
||||
using NtHeaderVariant = std::variant<ImageNtHeaders<NtArchitecture::x64_bit>, ImageNtHeaders<NtArchitecture::x32_bit>>;
|
||||
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]]
|
||||
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;
|
||||
|
||||
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]]
|
||||
constexpr bool invalid_dos_header_file(const DosHeader& dos_header)
|
||||
{
|
||||
constexpr std::uint16_t dos_hdr_magic = 0x5A4D;
|
||||
return dos_header.e_magic != dos_hdr_magic;
|
||||
}
|
||||
[[nodiscard]]
|
||||
constexpr bool invalid_nt_header_file(const NtHeaderVariant& variant)
|
||||
{
|
||||
constexpr std::uint32_t nt_hdr_magic = 0x4550;
|
||||
return std::visit([](const auto& header) -> bool { return header.signature != nt_hdr_magic; }, variant);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace omath
|
||||
{
|
||||
|
||||
std::optional<std::uintptr_t>
|
||||
PePatternScanner::scan_for_pattern_in_loaded_module([[maybe_unused]] const std::string_view& module_name,
|
||||
[[maybe_unused]] const std::string_view& pattern)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto base_address = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(module_name.data()));
|
||||
|
||||
if (!base_address)
|
||||
return std::nullopt;
|
||||
|
||||
const auto dos_headers = reinterpret_cast<PIMAGE_DOS_HEADER>(base_address);
|
||||
const auto image_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(base_address + dos_headers->e_lfanew);
|
||||
|
||||
// Define .code segment as scan area
|
||||
const auto start = image_nt_headers->OptionalHeader.BaseOfCode;
|
||||
const auto scan_size = image_nt_headers->OptionalHeader.SizeOfCode;
|
||||
|
||||
const auto scan_range = std::span{reinterpret_cast<std::byte*>(base_address) + start, scan_size};
|
||||
|
||||
const auto result = PatternScanner::scan_for_pattern(scan_range, pattern);
|
||||
|
||||
if (result != scan_range.cend())
|
||||
return reinterpret_cast<std::uintptr_t>(&*result);
|
||||
|
||||
return std::nullopt;
|
||||
#else
|
||||
throw std::runtime_error("Pattern scan for loaded modules is only for windows platform");
|
||||
#endif
|
||||
}
|
||||
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};
|
||||
}
|
||||
std::optional<PePatternScanner::Section>
|
||||
PePatternScanner::extract_section_from_pe_file(const std::filesystem::path& path_to_file,
|
||||
const std::string_view& section_name)
|
||||
{
|
||||
std::fstream file(path_to_file, std::ios::binary | std::ios::in);
|
||||
|
||||
if (!file.is_open()) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
DosHeader dos_header{};
|
||||
file.read(reinterpret_cast<char*>(&dos_header), sizeof(dos_header));
|
||||
|
||||
if (invalid_dos_header_file(dos_header)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
const auto nt_headers = get_nt_header_from_file(file, dos_header);
|
||||
|
||||
if (invalid_nt_header_file(nt_headers)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
return std::visit(
|
||||
[&file, &dos_header, §ion_name](auto& concrete_headers) -> std::optional<Section>
|
||||
{
|
||||
constexpr std::size_t size_of_signature = sizeof(concrete_headers.signature);
|
||||
const auto offset_to_segment_table = dos_header.e_lfanew
|
||||
+ concrete_headers.file_header.size_optional_header
|
||||
+ sizeof(FileHeader) + size_of_signature;
|
||||
|
||||
file.seekg(static_cast<std::fstream::off_type>(offset_to_segment_table), std::ios::beg);
|
||||
|
||||
for (std::size_t i = 0; i < concrete_headers.file_header.num_sections; i++)
|
||||
{
|
||||
SectionHeader current_section{};
|
||||
file.read(reinterpret_cast<char*>(¤t_section), sizeof(current_section));
|
||||
|
||||
if (std::string_view(current_section.name) != section_name)
|
||||
continue;
|
||||
|
||||
std::vector<std::byte> section_data(current_section.size_raw_data);
|
||||
|
||||
file.seekg(current_section.ptr_raw_data, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(section_data.data()),
|
||||
static_cast<std::streamsize>(section_data.size()));
|
||||
return Section{.virtual_base_addr = current_section.virtual_address
|
||||
+ concrete_headers.optional_header.image_base,
|
||||
.raw_base_addr = current_section.ptr_raw_data,
|
||||
.data = std::move(section_data)};
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
nt_headers);
|
||||
}
|
||||
} // namespace omath
|
||||
@@ -7,12 +7,10 @@ include(GoogleTest)
|
||||
file(GLOB_RECURSE UNIT_TESTS_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
||||
add_executable(${PROJECT_NAME} ${UNIT_TESTS_SOURCES})
|
||||
|
||||
set_target_properties(unit_tests PROPERTIES
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
|
||||
UNITY_BUILD ON
|
||||
UNITY_BUILD_BATCH_SIZE 20
|
||||
CXX_STANDARD 23
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <omath/engines/iw_engine/camera.hpp>
|
||||
#include <omath/engines/iw_engine/constants.hpp>
|
||||
#include <omath/engines/iw_engine/formulas.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
TEST(unit_test_iw_engine, ForwardVector)
|
||||
{
|
||||
@@ -68,7 +68,6 @@ TEST(unit_test_iw_engine, ProjectTargetMovedFromCamera)
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
const auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({distance, 0, 0});
|
||||
@@ -102,4 +101,126 @@ TEST(unit_test_iw_engine, CameraSetAndGetOrigin)
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
|
||||
TEST(unit_test_iw_engine, loook_at_random_all_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.001f || std::abs(projected_pos->y - 0.f) >= 0.001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_iw_engine, loook_at_random_x_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::iw_engine::Camera({dist(gen), dist(gen), dist(gen)}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), 0.f, 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_iw_engine, loook_at_random_y_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_iw_engine, loook_at_random_z_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.025f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <omath/engines/opengl_engine/camera.hpp>
|
||||
#include <omath/engines/opengl_engine/constants.hpp>
|
||||
#include <omath/engines/opengl_engine/formulas.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
TEST(unit_test_opengl, ForwardVector)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ TEST(unit_test_opengl, ForwardVectorRotationYaw)
|
||||
{
|
||||
omath::opengl_engine::ViewAngles angles;
|
||||
|
||||
angles.yaw = omath::opengl_engine::YawAngle::from_degrees(90.f);
|
||||
angles.yaw = omath::opengl_engine::YawAngle::from_degrees(-90.f);
|
||||
|
||||
const auto forward = omath::opengl_engine::forward_vector(angles);
|
||||
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_right.x, 0.00001f);
|
||||
@@ -37,13 +37,11 @@ TEST(unit_test_opengl, ForwardVectorRotationYaw)
|
||||
EXPECT_NEAR(forward.z, omath::opengl_engine::k_abs_right.z, 0.00001f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(unit_test_opengl, ForwardVectorRotationPitch)
|
||||
{
|
||||
omath::opengl_engine::ViewAngles angles;
|
||||
|
||||
angles.pitch = omath::opengl_engine::PitchAngle::from_degrees(-90.f);
|
||||
angles.pitch = omath::opengl_engine::PitchAngle::from_degrees(90.f);
|
||||
|
||||
const auto forward = omath::opengl_engine::forward_vector(angles);
|
||||
EXPECT_NEAR(forward.x, omath::opengl_engine::k_abs_up.x, 0.00001f);
|
||||
@@ -68,7 +66,6 @@ TEST(unit_test_opengl, ProjectTargetMovedFromCamera)
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
const auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = -10.f; distance > -1000.f; distance -= 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({0, 0, distance});
|
||||
@@ -102,4 +99,123 @@ TEST(unit_test_opengl, CameraSetAndGetOrigin)
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
TEST(unit_test_opengl_engine, loook_at_random_all_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.0001f || std::abs(projected_pos->y - 0.f) >= 0.0001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_opengl_engine, loook_at_random_x_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), 0.f, 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_opengl_engine, loook_at_random_y_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_opengl_engine, loook_at_random_z_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <omath/engines/source_engine/camera.hpp>
|
||||
#include <omath/engines/source_engine/constants.hpp>
|
||||
#include <omath/engines/source_engine/formulas.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
TEST(unit_test_source_engine, ForwardVector)
|
||||
{
|
||||
@@ -68,7 +68,6 @@ TEST(unit_test_source_engine, ProjectTargetMovedFromCamera)
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
const auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({distance, 0, 0});
|
||||
@@ -122,4 +121,125 @@ TEST(unit_test_source_engine, CameraSetAndGetOrigin)
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
|
||||
TEST(unit_test_source_engine, loook_at_random_all_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.0001f || std::abs(projected_pos->y - 0.f) >= 0.0001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_source_engine, loook_at_random_x_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), 0.f, 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_source_engine, loook_at_random_y_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_source_engine, loook_at_random_z_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.025f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <omath/engines/unity_engine/constants.hpp>
|
||||
#include <omath/engines/unity_engine/formulas.hpp>
|
||||
#include <print>
|
||||
#include <random>
|
||||
|
||||
TEST(unit_test_unity_engine, ForwardVector)
|
||||
{
|
||||
@@ -68,7 +69,6 @@ TEST(unit_test_unity_engine, ProjectTargetMovedFromCamera)
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({0, 0, distance});
|
||||
@@ -112,4 +112,125 @@ TEST(unit_test_unity_engine, CameraSetAndGetOrigin)
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
TEST(unit_test_unity_engine, loook_at_random_all_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.0001f || std::abs(projected_pos->y - 0.f) >= 0.0001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unity_engine, loook_at_random_x_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), 0.f, 0.f};
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.001f || std::abs(projected_pos->y - 0.f) >= 0.001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unity_engine, loook_at_random_y_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unity_engine, loook_at_random_z_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <omath/engines/unreal_engine/constants.hpp>
|
||||
#include <omath/engines/unreal_engine/formulas.hpp>
|
||||
#include <print>
|
||||
#include <random>
|
||||
|
||||
TEST(unit_test_unreal_engine, ForwardVector)
|
||||
{
|
||||
@@ -68,7 +69,6 @@ TEST(unit_test_unreal_engine, ProjectTargetMovedFromCamera)
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
|
||||
const auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.01f, 1000.f);
|
||||
|
||||
|
||||
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
|
||||
{
|
||||
const auto projected = cam.world_to_screen({distance, 0, 0});
|
||||
@@ -102,4 +102,128 @@ TEST(unit_test_unreal_engine, CameraSetAndGetOrigin)
|
||||
cam.set_field_of_view(omath::projection::FieldOfView::from_degrees(50.f));
|
||||
|
||||
EXPECT_EQ(cam.get_field_of_view().as_degrees(), 50.f);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, loook_at_random_all_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.0001f || std::abs(projected_pos->y - 0.f) >= 0.0001f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, loook_at_random_x_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{dist(gen), dist(gen), dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, loook_at_random_y_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, dist(gen), 0.f};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
|
||||
TEST(unit_test_unreal_engine, loook_at_random_z_axis)
|
||||
{
|
||||
std::mt19937 gen(std::random_device{}()); // Seed with a non-deterministic source
|
||||
std::uniform_real_distribution<float> dist(-1000.f, 1000.f);
|
||||
|
||||
constexpr auto fov = omath::projection::FieldOfView::from_degrees(90.f);
|
||||
auto cam = omath::unreal_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.001f, 10000.f);
|
||||
|
||||
std::size_t failed_points = 0;
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
const auto position_to_look = omath::Vector3<float>{0.f, 0.f, dist(gen)};
|
||||
|
||||
if (cam.get_origin().distance_to(position_to_look) < 10)
|
||||
continue;
|
||||
|
||||
cam.look_at(position_to_look);
|
||||
|
||||
auto projected_pos = cam.world_to_view_port(position_to_look);
|
||||
|
||||
EXPECT_TRUE(projected_pos.has_value());
|
||||
|
||||
if (!projected_pos)
|
||||
continue;
|
||||
|
||||
if (std::abs(projected_pos->x - 0.f) >= 0.01f || std::abs(projected_pos->y - 0.f) >= 0.01f)
|
||||
failed_points++;
|
||||
}
|
||||
EXPECT_LE(failed_points, 100);
|
||||
}
|
||||
@@ -1,3 +1,192 @@
|
||||
//
|
||||
// Created by Orange on 11/30/2024.
|
||||
//
|
||||
|
||||
#include <omath/trigonometry/angle.hpp>
|
||||
#include <cmath>
|
||||
#include <gtest/gtest.h>
|
||||
#include <numbers>
|
||||
|
||||
using namespace omath;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Handy aliases (defaults: Type=float, [0,360], Normalized)
|
||||
using Deg = Angle<float, float(0), float(360), AngleFlags::Normalized>;
|
||||
using Pitch = Angle<float, float(-90), float(90), AngleFlags::Clamped>;
|
||||
using Turn = Angle<float, float(-180), float(180), AngleFlags::Normalized>;
|
||||
|
||||
constexpr float kEps = 1e-5f;
|
||||
|
||||
} // namespace
|
||||
|
||||
// ---------- Construction / factories ----------
|
||||
|
||||
TEST(UnitTestAngle, DefaultConstructor_IsZeroDegrees)
|
||||
{
|
||||
Deg a; // default ctor
|
||||
EXPECT_FLOAT_EQ(*a, 0.0f);
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 0.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsAboveMax)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(370.0f);
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsBelowMin)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(-10.0f);
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 350.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, FromDegrees_Clamped_ClampsToRange)
|
||||
{
|
||||
const Pitch hi = Pitch::from_degrees(100.0f);
|
||||
const Pitch lo = Pitch::from_degrees(-120.0f);
|
||||
|
||||
EXPECT_FLOAT_EQ(hi.as_degrees(), 90.0f);
|
||||
EXPECT_FLOAT_EQ(lo.as_degrees(), -90.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, FromRadians_And_AsRadians)
|
||||
{
|
||||
const Deg a = Deg::from_radians(std::numbers::pi_v<float>);
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 180.0f);
|
||||
|
||||
const Deg b = Deg::from_degrees(180.0f);
|
||||
EXPECT_NEAR(b.as_radians(), std::numbers::pi_v<float>, 1e-6f);
|
||||
}
|
||||
|
||||
// ---------- Unary minus & deref ----------
|
||||
|
||||
TEST(UnitTestAngle, UnaryMinus_Normalized)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(30.0f);
|
||||
const Deg b = -a; // wraps to 330 in [0,360)
|
||||
EXPECT_FLOAT_EQ(b.as_degrees(), 330.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, DereferenceReturnsDegrees)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(42.0f);
|
||||
EXPECT_FLOAT_EQ(*a, 42.0f);
|
||||
}
|
||||
|
||||
// ---------- Trigonometric helpers ----------
|
||||
|
||||
TEST(UnitTestAngle, SinCosTanCot_BasicCases)
|
||||
{
|
||||
const Deg a0 = Deg::from_degrees(0.0f);
|
||||
EXPECT_NEAR(a0.sin(), 0.0f, kEps);
|
||||
EXPECT_NEAR(a0.cos(), 1.0f, kEps);
|
||||
// cot(0) -> cos/sin -> div by 0: allow inf or nan
|
||||
const float cot0 = a0.cot();
|
||||
EXPECT_TRUE(std::isinf(cot0) || std::isnan(cot0));
|
||||
|
||||
const Deg a45 = Deg::from_degrees(45.0f);
|
||||
EXPECT_NEAR(a45.tan(), 1.0f, 1e-4f);
|
||||
EXPECT_NEAR(a45.cot(), 1.0f, 1e-4f);
|
||||
|
||||
const Deg a90 = Deg::from_degrees(90.0f);
|
||||
EXPECT_NEAR(a90.sin(), 1.0f, 1e-4f);
|
||||
EXPECT_NEAR(a90.cos(), 0.0f, 1e-4f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, Atan_IsAtanOfRadians)
|
||||
{
|
||||
// atan(as_radians). For 0° -> atan(0)=0.
|
||||
const Deg a0 = Deg::from_degrees(0.0f);
|
||||
EXPECT_NEAR(a0.atan(), 0.0f, kEps);
|
||||
|
||||
const Deg a45 = Deg::from_degrees(45.0f);
|
||||
// atan(pi/4) ≈ 0.665773...
|
||||
EXPECT_NEAR(a45.atan(), 0.66577375f, 1e-6f);
|
||||
}
|
||||
|
||||
// ---------- Compound arithmetic ----------
|
||||
|
||||
TEST(UnitTestAngle, PlusEquals_Normalized_Wraps)
|
||||
{
|
||||
Deg a = Deg::from_degrees(350.0f);
|
||||
a += Deg::from_degrees(20.0f); // 370 -> 10
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, MinusEquals_Normalized_Wraps)
|
||||
{
|
||||
Deg a = Deg::from_degrees(10.0f);
|
||||
a -= Deg::from_degrees(30.0f); // -20 -> 340
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), 340.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, PlusEquals_Clamped_Clamps)
|
||||
{
|
||||
Pitch p = Pitch::from_degrees(80.0f);
|
||||
p += Pitch::from_degrees(30.0f); // 110 -> clamp to 90
|
||||
EXPECT_FLOAT_EQ(p.as_degrees(), 90.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, MinusEquals_Clamped_Clamps)
|
||||
{
|
||||
Pitch p = Pitch::from_degrees(-70.0f);
|
||||
p -= Pitch::from_degrees(40.0f); // -110 -> clamp to -90
|
||||
EXPECT_FLOAT_EQ(p.as_degrees(), -90.0f);
|
||||
}
|
||||
|
||||
// ---------- Alternative ranges ----------
|
||||
|
||||
TEST(UnitTestAngle, NormalizedRange_Neg180To180)
|
||||
{
|
||||
const Turn a = Turn::from_degrees(190.0f); // -> -170
|
||||
const Turn b = Turn::from_degrees(-190.0f); // -> 170
|
||||
|
||||
EXPECT_FLOAT_EQ(a.as_degrees(), -170.0f);
|
||||
EXPECT_FLOAT_EQ(b.as_degrees(), 170.0f);
|
||||
}
|
||||
|
||||
// ---------- Comparisons (via <=>) ----------
|
||||
|
||||
TEST(UnitTestAngle, Comparisons_WorkWithPartialOrdering)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(10.0f);
|
||||
const Deg b = Deg::from_degrees(20.0f);
|
||||
const Deg c = Deg::from_degrees(10.0f);
|
||||
|
||||
EXPECT_TRUE(a < b);
|
||||
EXPECT_TRUE(b > a);
|
||||
EXPECT_TRUE(a <= c);
|
||||
EXPECT_TRUE(c >= a);
|
||||
}
|
||||
|
||||
// ---------- std::format formatter ----------
|
||||
|
||||
TEST(UnitTestAngle, Formatter_PrintsDegreesWithSuffix)
|
||||
{
|
||||
const Deg a = Deg::from_degrees(15.0f);
|
||||
EXPECT_EQ(std::format("{}", a), "15deg");
|
||||
|
||||
const Deg b = Deg::from_degrees(10.5f);
|
||||
EXPECT_EQ(std::format("{}", b), "10.5deg");
|
||||
|
||||
const Turn t = Turn::from_degrees(-170.0f);
|
||||
EXPECT_EQ(std::format("{}", t), "-170deg");
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, BinaryPlus_ReturnsWrappedSum)
|
||||
{
|
||||
Angle<> a = Deg::from_degrees(350.0f);
|
||||
const Deg b = Deg::from_degrees(20.0f);
|
||||
const Deg c = a + b; // expect 10°
|
||||
EXPECT_FLOAT_EQ(c.as_degrees(), 10.0f);
|
||||
}
|
||||
|
||||
TEST(UnitTestAngle, BinaryMinus_ReturnsWrappedDiff)
|
||||
{
|
||||
Angle<> a = Deg::from_degrees(10.0f);
|
||||
const Deg b = Deg::from_degrees(30.0f);
|
||||
const Deg c = a - b; // expect 340°
|
||||
EXPECT_FLOAT_EQ(c.as_degrees(), 340.0f);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//
|
||||
// Created by Orange on 11/30/2024.
|
||||
//
|
||||
#include <omath/trigonometry/angles.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/angles.hpp>
|
||||
|
||||
TEST(unit_test_angles, radians_to_deg)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//
|
||||
// Created by Vlad on 01.09.2024.
|
||||
//
|
||||
#include <omath/utility/color.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/color.hpp>
|
||||
|
||||
|
||||
using namespace omath;
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// Revised unit‑test suite for LineTracer (segment‑based Möller–Trumbore)
|
||||
// Pure ASCII: avoids non‑standard characters that MSVC rejects.
|
||||
//
|
||||
#include "gtest/gtest.h"
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/collision/line_tracer.hpp"
|
||||
#include "omath/triangle.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace omath;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// UnitTestMat.cpp
|
||||
#include "omath/linear_algebra/mat.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include "omath/mat.hpp"
|
||||
#include "omath/vector3.hpp"
|
||||
|
||||
using namespace omath;
|
||||
|
||||
@@ -125,7 +125,7 @@ TEST_F(UnitTestMat, Clear)
|
||||
|
||||
TEST_F(UnitTestMat, ToString)
|
||||
{
|
||||
const std::string str = m2.to_string();
|
||||
const std::string str = std::format("{}", m2);
|
||||
EXPECT_FALSE(str.empty());
|
||||
EXPECT_EQ(str, "[[ 1.000, 2.000]\n [ 3.000, 4.000]]");
|
||||
}
|
||||
|
||||
@@ -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
tests/general/unit_test_pattern_scan.cpp
Normal 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());
|
||||
}
|
||||
@@ -13,8 +13,12 @@ TEST(UnitTestProjection, Projection)
|
||||
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||
0.01f, 1000.f);
|
||||
|
||||
const auto projected = cam.world_to_screen({1000, 0, 50});
|
||||
const auto projected = cam.world_to_screen({1000.f, 0, 50.f});
|
||||
const auto result = cam.screen_to_world(projected.value());
|
||||
const auto result2 = cam.world_to_screen(result.value());
|
||||
|
||||
EXPECT_EQ(static_cast<omath::Vector2<float>>(projected.value()),
|
||||
static_cast<omath::Vector2<float>>(result2.value()));
|
||||
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
||||
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
||||
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
||||
|
||||
50
tests/general/unit_test_reverse_enineering.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Created by Vlad on 10/4/2025.
|
||||
//
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/rev_eng/internal_rev_object.hpp>
|
||||
|
||||
class Player final
|
||||
{
|
||||
public:
|
||||
virtual int foo() {return 1;}
|
||||
virtual int bar() {return 2;}
|
||||
omath::Vector3<float> m_origin{1.f, 2.f, 3.f};
|
||||
int m_health{123};
|
||||
};
|
||||
|
||||
class RevPlayer : omath::rev_eng::InternalReverseEngineeredObject
|
||||
{
|
||||
public:
|
||||
omath::Vector3<float> get_origin()
|
||||
{
|
||||
return get_by_offset<omath::Vector3<float>>(sizeof(std::uintptr_t));
|
||||
}
|
||||
int get_health()
|
||||
{
|
||||
return get_by_offset<int>(sizeof(std::uintptr_t)+sizeof(omath::Vector3<float>));
|
||||
}
|
||||
|
||||
int rev_foo()
|
||||
{
|
||||
return call_virtual_method<0, int>();
|
||||
}
|
||||
int rev_bar()
|
||||
{
|
||||
return call_virtual_method<1, int>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(unit_test_reverse_enineering, read_test)
|
||||
{
|
||||
Player player_original;
|
||||
const auto player_reversed = reinterpret_cast<RevPlayer*>(&player_original);
|
||||
|
||||
EXPECT_EQ(player_original.m_origin, player_reversed->get_origin());
|
||||
EXPECT_EQ(player_original.m_health, player_reversed->get_health());
|
||||
|
||||
EXPECT_EQ(player_original.bar(), player_reversed->rev_bar());
|
||||
EXPECT_EQ(player_original.foo(), player_reversed->rev_foo());
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
//
|
||||
// Created by Orange on 1/6/2025.
|
||||
//
|
||||
#include "omath/linear_algebra/triangle.hpp"
|
||||
#include "omath/linear_algebra/vector3.hpp"
|
||||
#include <cmath> // For std::sqrt, std::isinf, std::isnan
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/vector3.hpp>
|
||||
#include "omath/triangle.hpp"
|
||||
|
||||
|
||||
using namespace omath;
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// Created by Vlad on 02.09.2024.
|
||||
//
|
||||
|
||||
#include <omath/linear_algebra/vector2.hpp>
|
||||
#include <cfloat> // For FLT_MAX and FLT_MIN
|
||||
#include <cmath> // For std::isinf and std::isnan
|
||||
#include <gtest/gtest.h>
|
||||
#include <omath/vector2.hpp>
|
||||
|
||||
using namespace omath;
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// Created by Vlad on 01.09.2024.
|
||||
//
|
||||
|
||||
#include <omath/linear_algebra/vector3.hpp>
|
||||
#include <cfloat> // For FLT_MAX, FLT_MIN
|
||||
#include <cmath>
|
||||
#include <gtest/gtest.h>
|
||||
#include <limits> // For std::numeric_limits
|
||||
#include <omath/vector3.hpp>
|
||||
|
||||
using namespace omath;
|
||||
|
||||
|
||||