Compare commits

...

158 Commits

Author SHA1 Message Date
40a301186e Merge pull request #40 from orange-cpp/u/orange/inverted-matrix
U/orange/inverted matrix
2025-04-29 20:53:02 +03:00
a41526c494 style fix 2025-04-29 20:52:41 +03:00
a0d1dc4313 added test case 2025-04-29 20:49:59 +03:00
1c5c9360c8 added inverse method 2025-04-29 20:33:39 +03:00
4615769682 added additional methods 2025-04-29 20:10:17 +03:00
4ef674f7b4 fixed infinite recursion in compile time 2025-04-29 20:08:27 +03:00
69b9049fb0 fixed gimba lock for unity 2025-04-26 00:52:46 +03:00
2734b58bdd fixed gimba lock for opengl camera 2025-04-26 00:32:53 +03:00
d7f1f49165 resetting state 2025-04-25 23:52:10 +03:00
94b1453cae removed .idea folder 2025-04-23 02:48:45 +03:00
3e67d8a99c added credits 2025-04-23 02:46:08 +03:00
8c00ab3d9d Merge pull request #38 from orange-cpp/u/orange-cpp/3d-primitives
U/orange cpp/3d primitives
2025-04-18 17:00:38 +03:00
d14cb1e93e reset to default 2025-04-18 16:55:07 +03:00
c692cf39e1 updated readme 2025-04-18 16:53:53 +03:00
9c934c5d9c improved tests 2025-04-18 16:36:22 +03:00
Vladislav Alpatov
f8202b116d improved line tracer 2025-04-18 16:00:23 +03:00
8bf0bb8e0d improved line trace and box primitive 2025-04-18 13:56:08 +03:00
a340766348 switched to polygons 2025-04-18 12:34:24 +03:00
254674a62e fixed code style 2025-04-18 12:11:43 +03:00
97c2da893b added ratio param 2025-04-18 01:33:47 +03:00
0ce30a7038 added new build option 2025-04-18 00:51:07 +03:00
492ddfd566 added box 2025-04-18 00:43:46 +03:00
baf7ee8f88 fixed include 2025-04-16 20:35:17 +03:00
9fde11733f Merge pull request #37 from orange-cpp/u/engine_rotation_mats
U/engine rotation mats
2025-04-16 23:21:58 +03:00
0069b8bd96 improved openg gl rotation matrix, added tests 2025-04-16 19:11:02 +03:00
127bae0b78 added tests for source 2025-04-16 18:53:31 +03:00
bed204a663 added unit tests 2025-04-16 18:35:50 +03:00
3f6ea010dc fixed formating 2025-04-16 17:52:57 +03:00
592a98f38c removed method from Mat added method for unity 2025-04-16 17:52:19 +03:00
7873047550 added func
added rotation matrix for opengl

updated unit tests
2025-04-16 17:40:00 +03:00
1601f3cbc8 added func
added rotation matrix for opengl
2025-04-16 17:40:00 +03:00
2180f8ab97 removed whitespaces 2025-04-16 12:21:10 +03:00
b613ff9ef1 added missing header 2025-04-13 23:15:27 +03:00
145eadfffa Merge pull request #36 from orange-cpp/u/orange-cpp/small-refactoring
U/orange cpp/small refactoring
2025-04-12 13:34:28 +03:00
14acebad5f fixed tests 2025-04-12 00:04:07 +03:00
4a7a631932 added const method to mat 2025-04-11 23:57:56 +03:00
e08c22f604 added new build option 2025-04-11 23:54:56 +03:00
1b47f45af9 improved naming 2025-04-11 23:30:07 +03:00
466d8f7bec improvement 2025-04-11 23:20:16 +03:00
3631c5d698 replaced with STL relization 2025-04-11 23:10:02 +03:00
b58956efe3 added missing header 2025-04-11 22:59:56 +03:00
fc1e0c62b8 disabled tests 2025-04-05 20:03:39 +03:00
Orange
8e861b8a85 updated read me 2025-04-05 13:28:28 +03:00
Orange
55085604fd added include 2025-04-05 13:20:18 +03:00
Orange
7b712ed960 fixed for clang 2025-04-05 13:00:00 +03:00
138c996393 oops 2025-03-29 22:03:30 +03:00
0f2a858306 fixed in some cases confilcting with win api 2025-03-29 21:57:35 +03:00
ea6c1cc929 fix 2025-03-29 18:20:17 +03:00
eeb6e40909 Merge pull request #35 from orange-cpp/u/orange-cpp/imrpoved-color
U/orange cpp/imrpoved color
2025-03-29 17:43:36 +03:00
d72ad663cd added new methods 2025-03-29 05:41:55 +03:00
3e75d32f59 fixed style 2025-03-29 04:00:35 +03:00
a8ce5cbaa0 added vcpkg imgui package auto link 2025-03-29 01:56:09 +03:00
79f76a0755 added new option 2025-03-29 01:53:04 +03:00
5773cc7798 improved imgui handling 2025-03-24 21:48:51 +03:00
b6b0184523 fixed for clang 2025-03-24 06:48:51 +03:00
a797dd134a Update README.md 2025-03-24 06:46:02 +03:00
dc43411bd2 fixed unity view matrix building 2025-03-24 06:30:09 +03:00
8959161904 Merge pull request #34 from orange-cpp/u/orange-cpp/add-unity
U/orange cpp/add unity
2025-03-23 01:20:16 +03:00
5d5bd215b2 fix 2025-03-23 01:17:05 +03:00
a48a257648 removed comment 2025-03-23 01:12:46 +03:00
ffba4e256a name fix 2025-03-23 01:06:36 +03:00
d9219cdddb naming fixed 2025-03-23 01:02:11 +03:00
5a1014a239 fix 2025-03-23 00:57:58 +03:00
74f2241bcf uncommented test 2025-03-23 00:52:12 +03:00
8977557a61 fix 2025-03-22 17:41:01 +03:00
481d7b85df improved camera 2025-03-22 17:39:40 +03:00
2b59fb6aa2 updated formulas 2025-03-22 08:36:06 +03:00
4f037a1952 added unity engine tests 2025-03-22 08:12:16 +03:00
ef11183c3f added camera files 2025-03-22 04:26:54 +03:00
326d8baaae Update README.md 2025-03-21 05:31:44 +03:00
e46067b0b9 fixed tests includes 2025-03-21 04:58:28 +03:00
68ac7f7b3d Merge pull request #33 from orange-cpp/u/orange-cpp/changed-file-naming
U/orange cpp/changed file naming
2025-03-21 04:50:56 +03:00
17de6d407c style fix 2025-03-21 04:48:38 +03:00
59d686e252 fix 2025-03-21 04:47:01 +03:00
713af1b772 fix 2025-03-21 04:46:23 +03:00
a8922230b3 fixed name 2025-03-21 04:45:02 +03:00
b8d79eb8b4 fixed example 2025-03-21 04:43:57 +03:00
5acd166d8f fixed include names 2025-03-21 04:40:59 +03:00
c7dda0ff10 changed source files naming 2025-03-21 04:30:17 +03:00
2688d977a9 change 2025-03-21 04:21:31 +03:00
Vladislav Alpatov
b9ac44a901 renamed headers 2025-03-21 04:17:42 +03:00
35658b1f6d Merge pull request #32 from orange-cpp/u/orange-cpp/examples
U/orange cpp/examples
2025-03-19 20:17:45 +03:00
8f4b61319f disabled tests by default 2025-03-19 20:13:06 +03:00
832c2ea5ef removed inline functions 2025-03-19 20:07:44 +03:00
50c336e044 added example 2025-03-19 19:16:22 +03:00
Vladislav Alpatov
e80e22bd5b added some files 2025-03-19 18:58:35 +03:00
27576ed761 added alias 2025-03-19 18:50:47 +03:00
f85243e892 improved print method 2025-03-19 00:56:56 +03:00
9b6d0beb03 Update README.md 2025-03-17 18:20:40 +03:00
ee9829af22 Merge pull request #31 from orange-cpp/u/orange-cpp/IWEngine
Added Infinity Ward Engine Support
2025-03-17 09:20:51 +03:00
cd452b0397 updated comment 2025-03-17 09:14:42 +03:00
2fa0c500a7 added magic number 2025-03-17 08:59:41 +03:00
0740d0778c added iw engine files 2025-03-17 07:20:13 +03:00
f5c271cfa6 changed naming of engines section 2025-03-17 05:27:00 +03:00
064a31f527 Merge pull request #30 from orange-cpp/u/orange-cpp/imgui-integration
ImGUI Vector integration
2025-03-17 04:12:39 +03:00
e5d0adf247 changed default option 2025-03-17 04:11:49 +03:00
8fc107ec0f fix 2025-03-17 04:07:21 +03:00
6dd72d2448 added convertors 2025-03-17 03:56:09 +03:00
c76f6e91b0 fix 2025-03-17 02:41:08 +03:00
d1d06c24ca unit tests buid off by defalut 2025-03-15 19:13:06 +03:00
169011e238 fixed Vec3 Vec4 2025-03-15 19:11:31 +03:00
934ca0da0a added explicit constructor for angle and comment for angle 2025-03-15 18:57:41 +03:00
4200ef63a6 improved mat & camera interface 2025-03-15 18:53:18 +03:00
58e2c3b5b7 fixed members inititalization miss match 2025-03-14 19:43:50 +03:00
Vladislav Alpatov
c3202a3bc3 patch 2025-03-01 21:32:02 +03:00
Vladislav Alpatov
39ab9d065d added option to disable avx2 2025-03-01 21:30:53 +03:00
Vladislav Alpatov
ed372a1c78 fixed for clang support 2025-03-01 21:22:44 +03:00
70313f5ae0 Merge pull request #29 from orange-cpp/u/orange-cpp/template-vectors
Added template Vectors 2d 3d 4d
2025-03-01 21:17:42 +03:00
Vladislav Alpatov
978656b573 refactored 2025-03-01 21:17:03 +03:00
Vladislav Alpatov
a0f746b84c fixed style 2025-03-01 21:15:26 +03:00
Vladislav Alpatov
6d0d267743 now template 2025-03-01 21:11:46 +03:00
9ba3bc754a removed define 2025-02-23 21:56:28 +03:00
3d1844fa0e Merge pull request #28 from orange-cpp/u/orange-cpp/avx2-prediction
U/orange cpp/avx2 prediction
2025-02-23 16:32:27 +03:00
f21d29c6c2 added legacy impl 2025-02-23 10:10:35 +03:00
28a35d5bc9 added more classes 2025-02-23 09:57:29 +03:00
d9684ff73f read me update 2025-02-22 23:34:45 +03:00
900501f37e added language mention 2025-02-22 23:34:45 +03:00
5639cd0eb5 added AVX2 2025-02-22 23:34:45 +03:00
244d01c313 Merge pull request #27 from orange-cpp/u/orange-cpp/unity-build-support
added unity build support
2025-02-22 23:33:03 +03:00
e31ffac103 added unity build support 2025-02-22 23:32:29 +03:00
ae87257adf Merge pull request #26 from orange-cpp/u/orange-cpp/improved-astar
Improved A*
2025-02-22 23:06:33 +03:00
906f5099d1 improvement 2025-02-16 10:57:03 +03:00
96e4e1c9d6 added new method added concept for mat type 2025-02-16 10:06:04 +03:00
872dbe146f Merge pull request #25 from orange-cpp/u/orange-cpp/hotfix
improved cmake+hotfix of clang support
2025-01-17 16:59:30 +03:00
e0dcb65e3f improved cmake+hotfix of clang support 2025-01-17 16:56:47 +03:00
d0c532df39 hot fix 2025-01-06 05:36:27 +03:00
31907ceca3 Merge pull request #24 from orange-cpp/u/orange-cpp/improved-triangle-class
U/orange cpp/improved triangle class
2025-01-06 05:19:27 +03:00
afcfed4834 path 2025-01-06 05:17:42 +03:00
835fd110ba fix 2025-01-06 05:15:12 +03:00
29629a737d added some methods 2025-01-06 05:08:32 +03:00
6a324e8c0e improvement 2025-01-06 04:42:43 +03:00
42c84f2523 added midpoint for triangle class 2025-01-06 04:30:03 +03:00
9a4fb67289 hotfix 2025-01-02 20:32:25 +03:00
824b301d40 small code improvement 2025-01-02 18:40:19 +03:00
dcf466316c Merge pull request #23 from orange-cpp/u/orange-cpp/vec3-angle-calc
added AngleBetween method for Vector3 + tests
2025-01-02 12:54:27 +03:00
dc0bca14c5 added method + tests 2025-01-02 12:52:34 +03:00
b2db06a739 updated read me 2024-12-26 18:52:24 +03:00
cdce07f2a5 Merge pull request #22 from orange-cpp/u/orange-cpp/improved-camera
U/orange cpp/improved camera
2024-12-26 18:42:17 +03:00
931937d010 added open gl stuff 2024-12-23 17:53:47 +03:00
af880be056 added methods 2024-12-23 15:34:38 +03:00
c3bfd12971 Merge pull request #21 from orange-cpp/u/orange-cpp/dropped-shared-export
U/orange cpp/dropped shared export
2024-12-23 13:52:55 +03:00
9ad8ec755b removed header 2024-12-23 13:52:12 +03:00
409cd18de6 dropped .dll/.so support 2024-12-23 13:47:28 +03:00
001c6a8a47 fixed vcs.mxl 2024-12-23 13:43:14 +03:00
30bc3f2c6d changed readme 2024-12-21 19:41:31 +03:00
232f456a4d Merge pull request #20 from orange-cpp/u/orange-cpp/mat_sqr_brackets_op
Added brand new operator[] support for Mat/Matrix class
2024-12-21 19:34:51 +03:00
2b9575311e added operator for matrix 2024-12-21 19:32:09 +03:00
e497308349 added operator square brackets 2024-12-21 19:29:33 +03:00
390e584aee updated version 2024-12-21 16:03:54 +03:00
93082d6a8d added components check 2024-12-21 15:53:47 +03:00
c8c3c4e5fc Merge pull request #19 from luadebug/main
Update README.md Vcpkg integration
2024-12-21 14:31:30 +03:00
Saikari
24ad4ac698 Update README.md 2024-12-21 01:18:25 +03:00
221fd54f5a fixed warning related with clang 2024-12-17 12:30:05 +03:00
5f8fc4058c Merge pull request #17 from luadebug/export
Create Export for DLL (shared MSVC build)
2024-12-17 12:24:11 +03:00
さくらみこ
fc164b339b fix 2024-12-17 12:08:18 +03:00
さくらみこ
58fb6a0304 clean 2024-12-17 08:40:48 +03:00
さくらみこ
193e87847a fixup 2024-12-17 07:24:44 +03:00
Saikari
075c553521 Export 2024-12-17 04:55:13 +03:00
119 changed files with 3309 additions and 1472 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/cmake-build/ /cmake-build/
/.idea /.idea
/out /out
*.DS_Store

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/uml.iml" filepath="$PROJECT_DIR$/.idea/uml.iml" />
</modules>
</component>
</project>

2
.idea/uml.iml generated
View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

8
.idea/vcs.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/glm" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
</component>
</project>

View File

@@ -1,31 +1,92 @@
cmake_minimum_required(VERSION 3.26) cmake_minimum_required(VERSION 3.26)
project(omath VERSION 1.0.0) project(omath VERSION 1.0.1 LANGUAGES CXX)
include(CMakePackageConfigHelpers)
option(OMATH_BUILD_TESTS "Build unit tests" OFF)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
option(OMATH_BUILD_TESTS "Build unit tests" ON)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
option(OMATH_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)
if (OMATH_BUILD_AS_SHARED_LIBRARY) if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(omath SHARED source/Vector3.cpp) add_library(omath SHARED source/matrix.cpp)
else() else()
add_library(omath STATIC source/Vector3.cpp) add_library(omath STATIC source/matrix.cpp)
endif() endif()
message(STATUS "Building on ${CMAKE_HOST_SYSTEM_NAME}")
add_library(omath::omath ALIAS omath)
if (OMATH_IMGUI_INTEGRATION)
target_compile_definitions(omath PUBLIC OMATH_IMGUI_INTEGRATION)
# IMGUI is being linked as submodule
if(TARGET imgui)
target_link_libraries(omath PUBLIC imgui)
install(TARGETS imgui
EXPORT omathTargets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
else()
# Assume that IMGUI linked via VCPKG.
find_package(imgui CONFIG REQUIRED)
target_link_libraries(omath PUBLIC imgui::imgui)
endif()
endif()
if (OMATH_USE_AVX2)
target_compile_definitions(omath PUBLIC OMATH_USE_AVX2)
endif()
if (OMATH_SUPRESS_SAFETY_CHECKS)
target_compile_definitions(omath PUBLIC OMATH_SUPRESS_SAFETY_CHECKS)
endif()
set_target_properties(omath PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
if (OMATH_USE_UNITY_BUILD)
set_target_properties(omath PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20)
endif()
if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(omath PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(omath PRIVATE -mavx2 -mfma)
endif()
target_compile_features(omath PUBLIC cxx_std_23)
add_subdirectory(source) add_subdirectory(source)
add_subdirectory(extlibs)
if(OMATH_BUILD_TESTS) if(OMATH_BUILD_TESTS)
add_subdirectory(extlibs)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
if (OMATH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR) if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(omath PRIVATE /W4 /WX) target_compile_options(omath PRIVATE /W4 /WX)
elseif(OMATH_THREAT_WARNING_AS_ERROR) elseif(OMATH_THREAT_WARNING_AS_ERROR)

View File

@@ -64,6 +64,38 @@
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release" "CMAKE_BUILD_TYPE": "Release"
} }
},
{
"name": "darwin-base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "darwin-debug",
"displayName": "Darwin Debug",
"inherits": "darwin-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "darwin-release",
"displayName": "Darwin Release",
"inherits": "darwin-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
} }
] ]
} }

11
CREDITS.md Normal file
View File

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

View File

@@ -1,6 +1,6 @@
<div align = center> <div align = center>
![banner](https://i.imgur.com/sjtpKi8.png) ![banner](https://i.imgur.com/SM9ccP6.png)
![GitHub License](https://img.shields.io/github/license/orange-cpp/omath) ![GitHub License](https://img.shields.io/github/license/orange-cpp/omath)
![GitHub contributors](https://img.shields.io/github/contributors/orange-cpp/omath) ![GitHub contributors](https://img.shields.io/github/contributors/orange-cpp/omath)
@@ -11,21 +11,52 @@
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. Oranges's Math Library (omath) is a comprehensive, open-source library aimed at providing efficient, reliable, and versatile mathematical functions and algorithms. Developed primarily in C++, this library is designed to cater to a wide range of mathematical operations essential in scientific computing, engineering, and academic research.
## Features ## 👁‍🗨 Features
- **Efficiency**: Optimized for performance, ensuring quick computations. - **Efficiency**: Optimized for performance, ensuring quick computations using AVX2.
- **Versatility**: Includes a wide array of mathematical functions and algorithms. - **Versatility**: Includes a wide array of mathematical functions and algorithms.
- **Ease of Use**: Simplified interface for convenient integration into various projects. - **Ease of Use**: Simplified interface for convenient integration into various projects.
- **Projectile Prediction**: Projectile prediction engine with O(N) algo complexity, that can power you projectile aim-bot. - **Projectile Prediction**: Projectile prediction engine with O(N) algo complexity, that can power you projectile aim-bot.
- **3D Projection**: No need to find view-projection matrix anymore you can make your own projection pipeline. - **3D Projection**: No need to find view-projection matrix anymore you can make your own projection pipeline.
- **Collision Detection**: Production ready code to handle collision detection by using simple interfaces. - **Collision Detection**: Production ready code to handle collision detection by using simple interfaces.
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution - **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
## Getting Started ## Supported Render Pipelines
| ENGINE | SUPPORT |
|----------|---------|
| Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| Unreal | ❌NO |
## Supported Operating Systems
| OS | SUPPORT |
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
## ⏬ Getting Started
### Prerequisites ### Prerequisites
- C++ Compiler - C++ Compiler
- CMake (for building the project) - CMake (for building the project)
### Installation ### Installation
### vcpkg
**Note**: Support vcpkg for package management
1. Install vcpkg (https://github.com/microsoft/vcpkg)
2. Run the following command to install the orange-math package:
```
vcpkg install orange-math
```
CMakeLists.txt
```cmake
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
For detailed commands on installing different versions and more information, please refer to Microsoft's official instructions (https://learn.microsoft.com/en-us/vcpkg/get_started/overview)
### Build from source
1. Clone the repository: 1. Clone the repository:
``` ```
git clone https://github.com/orange-cpp/omath.git git clone https://github.com/orange-cpp/omath.git
@@ -37,10 +68,10 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
3. Build the project using CMake: 3. Build the project using CMake:
``` ```
cmake --preset windows-release -S . cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target server -j 6 cmake --build cmake-build/build/windows-release --target omath -j 6
``` ```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**. Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
## Usage ## Usage
Simple world to screen function Simple world to screen function
```c++ ```c++
TEST(UnitTestProjection, IsPointOnScreen) TEST(UnitTestProjection, IsPointOnScreen)
@@ -51,22 +82,26 @@ TEST(UnitTestProjection, IsPointOnScreen)
EXPECT_TRUE(proj.has_value()); EXPECT_TRUE(proj.has_value());
} }
``` ```
## Showcase
<details> <details>
<summary>OMATH for making cheats</summary> <summary>OMATH for making cheats (click to open)</summary>
With `omath/projection` module you can achieve simple ESP hack for powered by Source/Unreal/Unity engine games, like [Apex Legends](https://store.steampowered.com/app/1172470/Apex_Legends/). With `omath/projection` module you can achieve simple ESP hack for powered by Source/Unreal/Unity engine games, like [Apex Legends](https://store.steampowered.com/app/1172470/Apex_Legends/).
![banner](https://i.imgur.com/lcJrfcZ.png) ![banner](https://i.imgur.com/lcJrfcZ.png)
![Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E) Or for InfinityWard Engine based games. Like Call of Duty Black Ops 2!
![banner](https://i.imgur.com/F8dmdoo.png)
Or create simple trigger bot with embeded traceline from omath::collision::LineTrace
![banner](https://i.imgur.com/fxMjRKo.jpeg)
Or even advanced projectile aimbot
[Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E)
</details> </details>
## Contributing ## 🫵🏻 Contributing
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests. Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests.
## License ## 📜 License
This project is licensed under the MIT - see the `LICENSE` file for details. This project is licensed under the MIT - see the `LICENSE` file for details.
## Acknowledgments ## 💘 Acknowledgments
- Orange | [Telegram](https://t.me/orange_cpp) - [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)

View File

@@ -4,3 +4,4 @@ include(CMakeFindDependencyMacro)
# Load the targets for the omath library # Load the targets for the omath library
include("${CMAKE_CURRENT_LIST_DIR}/omathTargets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/omathTargets.cmake")
check_required_components(omath)

4
examples/CMakeLists.txt Normal file
View File

@@ -0,0 +1,4 @@
project(examples)
add_executable(ExampleProjectionMatrixBuilder example_proj_mat_builder.cpp)
target_link_libraries(ExampleProjectionMatrixBuilder PRIVATE omath::omath)

View File

@@ -0,0 +1,40 @@
//
// Created by Vlad on 3/19/2025.
//
#include <iostream>
#include <print>
#include <omath/engines/opengl_engine/formulas.hpp>
int main()
{
std::println("OMATH Projection Matrix Builder");
float fov = 0;
float near = 0;
float far = 0;
float viewPortWidth = 0;
float viewPortHeight = 0;
std::print("Enter camera fov: ");
std::cin >> fov;
std::print("Enter camera z near: ");
std::cin >> near;
std::print("Enter camera z far: ");
std::cin >> far;
std::print("Enter camera screen width: ");
std::cin >> viewPortWidth;
std::print("Enter camera screen height: ");
std::cin >> viewPortHeight;
const auto mat =
omath::opengl_engine::CalcPerspectiveProjectionMatrix(fov, viewPortWidth / viewPortHeight, near, far);
std::print("{}", mat.ToString());
};

View File

@@ -0,0 +1,17 @@
//
// Created by Vlad on 4/18/2025.
//
#pragma once
#include <array>
#include "omath/triangle.hpp"
#include "omath/vector3.hpp"
namespace omath::primitives
{
[[nodiscard]]
std::array<Triangle<Vector3<float>>, 12> CreateBox(const Vector3<float>& top, const Vector3<float>& bottom,
const Vector3<float>& dirForward, const Vector3<float>& dirRight,
float ratio = 4.f);
}

View File

@@ -1,123 +0,0 @@
//
// Created by vlad on 2/4/24.
//
#pragma once
#include "omath/Vector3.hpp"
#include <cstdint>
#include "omath/Vector4.hpp"
namespace omath
{
struct HSV
{
float m_hue{};
float m_saturation{};
float m_value{};
};
class Color final : public Vector4
{
public:
constexpr Color(float r, float g, float b, float a) : Vector4(r,g,b,a)
{
Clamp(0.f, 1.f);
}
constexpr explicit Color() : Vector4()
{
}
[[nodiscard]]
constexpr static Color FromRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return Color{Vector4(r, g, b, a) / 255.f};
}
[[nodiscard]]
constexpr static Color FromHSV(float hue, float saturation, float value)
{
float r{}, g{}, b{};
hue = std::clamp(hue, 0.f, 1.f);
const int i = static_cast<int>(hue * 6.f);
const float f = hue * 6 - i;
const float p = value * (1 - saturation);
const float q = value * (1 - f * saturation);
const float t = value * (1 - (1 - f) * saturation);
switch (i % 6)
{
case 0: r = value, g = t, b = p; break;
case 1: r = q, g = value, b = p; break;
case 2: r = p, g = value, b = t; break;
case 3: r = p, g = q, b = value; break;
case 4: r = t, g = p, b = value; break;
case 5: r = value, g = p, b = q; break;
default: return {0.f, 0.f, 0.f, 0.f};
}
return {r, g, b, 1.f};
}
[[nodiscard]]
constexpr HSV ToHSV() const
{
HSV hsvData;
const float& red = x;
const float& green = y;
const float& blue = z;
const float max = std::max({red, green, blue});
const float min = std::min({red, green, blue});
const float delta = max - min;
if (delta == 0.f)
hsvData.m_hue = 0.f;
else if (max == red)
hsvData.m_hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
else if (max == green)
hsvData.m_hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue)
hsvData.m_hue = 60.f * (((red - green) / delta) + 4.f);
if (hsvData.m_hue < 0.f)
hsvData.m_hue += 360.f;
hsvData.m_hue /= 360.f;
hsvData.m_saturation = max == 0.f ? 0.f : delta / max;
hsvData.m_value = max;
return hsvData;
}
constexpr explicit Color(const Vector4& vec) : Vector4(vec)
{
Clamp(0.f, 1.f);
}
[[nodiscard]]
constexpr Color Blend(const Color& other, float ratio) const
{
return Color( (*this * (1.f - ratio)) + (other * ratio) );
}
[[nodiscard]] static constexpr Color Red() {return {1.f, 0.f, 0.f, 1.f};}
[[nodiscard]] static constexpr Color Green() {return {0.f, 1.f, 0.f, 1.f};}
[[nodiscard]] static constexpr Color Blue() {return {0.f, 0.f, 1.f, 1.f};}
};
[[nodiscard]]
constexpr Color Blend(const Color& first, const Color& second, float ratio)
{
return Color{first * (1.f - std::clamp(ratio, 0.f, 1.f)) + second * ratio};
}
}

View File

@@ -1,33 +0,0 @@
//
// Created by Orange on 11/13/2024.
//
#pragma once
#include "omath/Vector3.hpp"
namespace omath
{
class Triangle3d final
{
public:
Triangle3d(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3);
Vector3 m_vertex1;
Vector3 m_vertex2;
Vector3 m_vertex3;
[[nodiscard]]
Vector3 CalculateNormal() const;
[[nodiscard]]
float SideALength() const;
[[nodiscard]]
float SideBLength() const;
[[nodiscard]]
Vector3 SideAVector() const;
[[nodiscard]]
Vector3 SideBVector() const;
};
}

View File

@@ -1,243 +0,0 @@
//
// Created by vlad on 10/28/23.
//
#pragma once
#include <cstdint>
#include <functional>
#include "omath/Vector2.hpp"
namespace omath
{
class Vector3 : public Vector2
{
public:
float z = 0.f;
constexpr Vector3(const float x, const float y, const float z) : Vector2(x, y), z(z) { }
constexpr Vector3() : Vector2() {};
[[nodiscard]] constexpr bool operator==(const Vector3& src) const
{
return Vector2::operator==(src) && (src.z == z);
}
[[nodiscard]] constexpr bool operator!=(const Vector3& src) const
{
return !(*this == src);
}
constexpr Vector3& operator+=(const Vector3& v)
{
Vector2::operator+=(v);
z += v.z;
return *this;
}
constexpr Vector3& operator-=(const Vector3& v)
{
Vector2::operator-=(v);
z -= v.z;
return *this;
}
constexpr Vector3& operator*=(const float fl)
{
Vector2::operator*=(fl);
z *= fl;
return *this;
}
constexpr Vector3& operator*=(const Vector3& v)
{
Vector2::operator*=(v);
z *= v.z;
return *this;
}
constexpr Vector3& operator/=(const Vector3& v)
{
Vector2::operator/=(v);
z /= v.z;
return *this;
}
constexpr Vector3& operator+=(const float fl)
{
Vector2::operator+=(fl);
z += fl;
return *this;
}
constexpr Vector3& operator/=(const float fl)
{
Vector2::operator/=(fl);
z /= fl;
return *this;
}
constexpr Vector3& operator-=(const float fl)
{
Vector2::operator-=(fl);
z -= fl;
return *this;
}
constexpr Vector3& Abs()
{
Vector2::Abs();
z = z < 0.f ? -z : z;
return *this;
}
[[nodiscard]] constexpr float DistToSqr(const Vector3& vOther) const
{
return (*this - vOther).LengthSqr();
}
[[nodiscard]] constexpr float Dot(const Vector3& vOther) const
{
return Vector2::Dot(vOther) + z * vOther.z;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr float Length() const
{
return std::hypot(x, y, z);
}
[[nodiscard]] constexpr float Length2D() const
{
return Vector2::Length();
}
[[nodiscard]] float DistTo(const Vector3& vOther) const
{
return (*this - vOther).Length();
}
[[nodiscard]] constexpr Vector3 Normalized() const
{
const float length = this->Length();
return length != 0 ? *this / length : *this;
}
#else
[[nodiscard]] float Length() const
{
return std::hypot(x, y, z);
}
[[nodiscard]] Vector3 Normalized() const
{
const float length = this->Length();
return length != 0 ? *this / length : *this;
}
[[nodiscard]] float Length2D() const
{
return Vector2::Length();
}
[[nodiscard]] float DistTo(const Vector3& vOther) const
{
return (*this - vOther).Length();
}
#endif
[[nodiscard]] constexpr float LengthSqr() const
{
return Vector2::LengthSqr() + z * z;
}
[[nodiscard]] constexpr Vector3 operator-() const
{
return {-x, -y, -z};
}
[[nodiscard]] constexpr Vector3 operator+(const Vector3& v) const
{
return {x + v.x, y + v.y, z + v.z};
}
[[nodiscard]] constexpr Vector3 operator-(const Vector3& v) const
{
return {x - v.x, y - v.y, z - v.z};
}
[[nodiscard]] constexpr Vector3 operator*(const float fl) const
{
return {x * fl, y * fl, z * fl};
}
[[nodiscard]] constexpr Vector3 operator*(const Vector3& v) const
{
return {x * v.x, y * v.y, z * v.z};
}
[[nodiscard]] constexpr Vector3 operator/(const float fl) const
{
return {x / fl, y / fl, z / fl};
}
[[nodiscard]] constexpr Vector3 operator/(const Vector3& v) const
{
return {x / v.x, y / v.y, z / v.z};
}
[[nodiscard]] constexpr Vector3 Cross(const Vector3 &v) const
{
return
{
y * v.z - z * v.y,
z * v.x - x * v.z,
x * v.y - y * v.x
};
}
[[nodiscard]] constexpr float Sum() const
{
return Sum2D() + z;
}
[[nodiscard]] constexpr float Sum2D() const
{
return Vector2::Sum();
}
[[nodiscard]] Vector3 ViewAngleTo(const Vector3& other) const;
[[nodiscard]] std::tuple<float, float, float> AsTuple() const
{
return std::make_tuple(x, y, z);
}
};
}
// ReSharper disable once CppRedundantNamespaceDefinition
namespace std
{
template<>
struct hash<omath::Vector3>
{
std::size_t operator()(const omath::Vector3& vec) const noexcept
{
std::size_t hash = 0;
constexpr std::hash<float> hasher;
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash<<6) + (hash>>2);
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash<<6) + (hash>>2);
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash<<6) + (hash>>2);
return hash;
}
};
}

View File

@@ -1,155 +0,0 @@
//
// Vector4.h
//
#pragma once
#include <omath/Vector3.hpp>
#include <algorithm>
namespace omath
{
class Vector4 : public Vector3
{
public:
float w;
constexpr Vector4(const float x, const float y, const float z, const float w) : Vector3(x, y, z), w(w) {}
constexpr Vector4() : Vector3(), w(0.f) {};
[[nodiscard]]
constexpr bool operator==(const Vector4& src) const
{
return Vector3::operator==(src) && w == src.w;
}
[[nodiscard]]
constexpr bool operator!=(const Vector4& src) const
{
return !(*this == src);
}
constexpr Vector4& operator+=(const Vector4& v)
{
Vector3::operator+=(v);
w += v.w;
return *this;
}
constexpr Vector4& operator-=(const Vector4& v)
{
Vector3::operator-=(v);
w -= v.w;
return *this;
}
constexpr Vector4& operator*=(const float scalar)
{
Vector3::operator*=(scalar);
w *= scalar;
return *this;
}
constexpr Vector4& operator*=(const Vector4& v)
{
Vector3::operator*=(v);
w *= v.w;
return *this;
}
constexpr Vector4& operator/=(const float scalar)
{
Vector3::operator/=(scalar);
w /= scalar;
return *this;
}
constexpr Vector4& operator/=(const Vector4& v)
{
Vector3::operator/=(v);
w /= v.w;
return *this;
}
[[nodiscard]] constexpr float LengthSqr() const
{
return Vector3::LengthSqr() + w * w;
}
[[nodiscard]] constexpr float Dot(const Vector4& vOther) const
{
return Vector3::Dot(vOther) + w * vOther.w;
}
[[nodiscard]] float Length() const;
constexpr Vector4& Abs()
{
Vector3::Abs();
w = w < 0.f ? -w : w;
return *this;
}
constexpr Vector4& Clamp(const float min, const float max)
{
x = std::clamp(x, min, max);
y = std::clamp(y, min, max);
z = std::clamp(z, min, max);
return *this;
}
[[nodiscard]]
constexpr Vector4 operator-() const
{
return {-x, -y, -z, -w};
}
[[nodiscard]]
constexpr Vector4 operator+(const Vector4& v) const
{
return {x + v.x, y + v.y, z + v.z, w + v.w};
}
[[nodiscard]]
constexpr Vector4 operator-(const Vector4& v) const
{
return {x - v.x, y - v.y, z - v.z, w - v.w};
}
[[nodiscard]]
constexpr Vector4 operator*(const float scalar) const
{
return {x * scalar, y * scalar, z * scalar, w * scalar};
}
[[nodiscard]]
constexpr Vector4 operator*(const Vector4& v) const
{
return {x * v.x, y * v.y, z * v.z, w * v.w};
}
[[nodiscard]]
constexpr Vector4 operator/(const float scalar) const
{
return {x / scalar, y / scalar, z / scalar, w / scalar};
}
[[nodiscard]]
constexpr Vector4 operator/(const Vector4& v) const
{
return {x / v.x, y / v.y, z / v.z, w / v.w};
}
[[nodiscard]]
constexpr float Sum() const
{
return Vector3::Sum() + w;
}
};
}

View File

@@ -3,9 +3,9 @@
// //
#pragma once #pragma once
#include "omath/Angles.hpp"
#include <algorithm> #include <algorithm>
#include <utility>
#include "omath/angles.hpp"
namespace omath namespace omath
@@ -17,11 +17,11 @@ namespace omath
}; };
template<class Type = float, Type min = Type(0), Type max = Type(360), AngleFlags flags = AngleFlags::Normalized> template<class Type = float, Type min = Type(0), Type max = Type(360), AngleFlags flags = AngleFlags::Normalized>
requires std::is_arithmetic_v<Type> requires std::is_arithmetic_v<Type>
class Angle class Angle
{ {
Type m_angle; Type m_angle;
constexpr Angle(const Type& degrees) constexpr explicit Angle(const Type& degrees)
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(degrees, min, max); m_angle = angles::WrapAngle(degrees, min, max);
@@ -34,20 +34,20 @@ namespace omath
std::unreachable(); std::unreachable();
} }
} }
public: public:
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromDegrees(const Type& degrees) constexpr static Angle FromDegrees(const Type& degrees)
{ {
return {degrees}; return Angle{degrees};
} }
constexpr Angle() : m_angle(0) constexpr Angle() : m_angle(0)
{ {
} }
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromRadians(const Type& degrees) constexpr static Angle FromRadians(const Type& degrees)
{ {
return {angles::RadiansToDegrees<Type>(degrees)}; return Angle{angles::RadiansToDegrees<Type>(degrees)};
} }
[[nodiscard]] [[nodiscard]]
@@ -98,7 +98,6 @@ namespace omath
return Cos() / Sin(); return Cos() / Sin();
} }
[[nodiscard]]
constexpr Angle& operator+=(const Angle& other) constexpr Angle& operator+=(const Angle& other)
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
@@ -118,7 +117,6 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr std::partial_ordering operator<=>(const Angle& other) const = default; constexpr std::partial_ordering operator<=>(const Angle& other) const = default;
[[nodiscard]]
constexpr Angle& operator-=(const Angle& other) constexpr Angle& operator-=(const Angle& other)
{ {
return operator+=(-other); return operator+=(-other);
@@ -148,7 +146,7 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr Angle operator-() const constexpr Angle operator-() const
{ {
return {-m_angle}; return Angle{-m_angle};
} }
}; };
} } // namespace omath

View File

@@ -3,9 +3,8 @@
// //
#pragma once #pragma once
#include <numbers>
#include <cmath> #include <cmath>
#include <numbers>
namespace omath::angles namespace omath::angles
{ {

View File

@@ -3,23 +3,22 @@
// //
#pragma once #pragma once
#include "omath/Vector3.hpp" #include "omath/triangle.hpp"
#include "omath/Triangle3d.hpp" #include "omath/vector3.hpp"
namespace omath::collision namespace omath::collision
{ {
class Ray class Ray
{ {
public: public:
Vector3 start; Vector3<float> start;
Vector3 end; Vector3<float> end;
bool infinite_length = false;
[[nodiscard]]
Vector3<float> DirectionVector() const;
[[nodiscard]] [[nodiscard]]
Vector3 DirectionVector() const; Vector3<float> DirectionVectorNormalized() const;
[[nodiscard]]
Vector3 DirectionVectorNormalized() const;
}; };
class LineTracer class LineTracer
{ {
@@ -28,12 +27,12 @@ namespace omath::collision
[[nodiscard]] [[nodiscard]]
static bool CanTraceLine(const Ray& ray, const Triangle3d& triangle); static bool CanTraceLine(const Ray& ray, const Triangle<Vector3<float>>& triangle);
// Realization of MöllerTrumbore intersection algorithm // Realization of MöllerTrumbore intersection algorithm
// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
[[nodiscard]] [[nodiscard]]
static Vector3 GetRayHitPoint(const Ray& ray, const Triangle3d& triangle); static Vector3<float> GetRayHitPoint(const Ray& ray, const Triangle<Vector3<float>>& triangle);
}; };
} }

173
include/omath/color.hpp Normal file
View File

@@ -0,0 +1,173 @@
//
// Created by vlad on 2/4/24.
//
#pragma once
#include <cstdint>
#include "omath/vector3.hpp"
#include "omath/vector4.hpp"
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace omath
{
struct HSV
{
float hue{};
float saturation{};
float value{};
};
class Color final : public Vector4<float>
{
public:
constexpr Color(const float r, const float g, const float b, const float a) : Vector4(r, g, b, a)
{
Clamp(0.f, 1.f);
}
constexpr explicit Color() = default;
[[nodiscard]]
constexpr static Color FromRGBA(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a)
{
return Color{Vector4(r, g, b, a) / 255.f};
}
[[nodiscard]]
constexpr static Color FromHSV(float hue, const float saturation, const float value)
{
float r{}, g{}, b{};
hue = std::clamp(hue, 0.f, 1.f);
const int i = static_cast<int>(hue * 6.f);
const float f = hue * 6 - i;
const float p = value * (1 - saturation);
const float q = value * (1 - f * saturation);
const float t = value * (1 - (1 - f) * saturation);
switch (i % 6)
{
case 0:
r = value, g = t, b = p;
break;
case 1:
r = q, g = value, b = p;
break;
case 2:
r = p, g = value, b = t;
break;
case 3:
r = p, g = q, b = value;
break;
case 4:
r = t, g = p, b = value;
break;
case 5:
r = value, g = p, b = q;
break;
default:
return {0.f, 0.f, 0.f, 0.f};
}
return {r, g, b, 1.f};
}
[[nodiscard]]
constexpr static Color FromHSV(const HSV& hsv)
{
return FromHSV(hsv.hue, hsv.saturation, hsv.value);
}
[[nodiscard]]
constexpr HSV ToHSV() const
{
HSV hsvData;
const float& red = x;
const float& green = y;
const float& blue = z;
const float max = std::max({red, green, blue});
const float min = std::min({red, green, blue});
const float delta = max - min;
if (delta == 0.f)
hsvData.hue = 0.f;
else if (max == red)
hsvData.hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
else if (max == green)
hsvData.hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue)
hsvData.hue = 60.f * (((red - green) / delta) + 4.f);
if (hsvData.hue < 0.f)
hsvData.hue += 360.f;
hsvData.hue /= 360.f;
hsvData.saturation = max == 0.f ? 0.f : delta / max;
hsvData.value = max;
return hsvData;
}
constexpr explicit Color(const Vector4& vec) : Vector4(vec)
{
Clamp(0.f, 1.f);
}
constexpr void SetHue(const float hue)
{
auto hsv = ToHSV();
hsv.hue = hue;
*this = FromHSV(hsv);
}
constexpr void SetSaturation(const float saturation)
{
auto hsv = ToHSV();
hsv.saturation = saturation;
*this = FromHSV(hsv);
}
constexpr void SetValue(const float value)
{
auto hsv = ToHSV();
hsv.value = value;
*this = FromHSV(hsv);
}
[[nodiscard]]
constexpr Color Blend(const Color& other, float ratio) const
{
ratio = std::clamp(ratio, 0.f, 1.f);
return Color(*this * (1.f - ratio) + other * ratio);
}
[[nodiscard]] static constexpr Color Red()
{
return {1.f, 0.f, 0.f, 1.f};
}
[[nodiscard]] static constexpr Color Green()
{
return {0.f, 1.f, 0.f, 1.f};
}
[[nodiscard]] static constexpr Color Blue()
{
return {0.f, 0.f, 1.f, 1.f};
}
};
} // namespace omath

View File

@@ -1,19 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "Constants.h"
#include "omath/projection/Camera.hpp"
namespace omath::source
{
class Camera final : public projection::Camera<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0, 180, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3& target) override;
[[nodiscard]] Mat4x4 GetViewMatrix() const override;
[[nodiscard]] Mat4x4 GetProjectionMatrix() const override;
};
}

View File

@@ -1,57 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "Constants.h"
namespace omath::source
{
[[nodiscard]]
inline Vector3 ForwardVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]]
inline Vector3 RightVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]]
inline Vector3 UpVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]] inline Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3& cam_origin)
{
return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
}
[[nodiscard]]
inline Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
{
// NOTE: Needed tp make thing draw normal, since source is wierd
// and use tricky projection matrix formula.
constexpr auto kMultiplyFactor = 0.75f;
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor;
return {
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0},
};
}
} // namespace omath::source

View File

@@ -0,0 +1,21 @@
//
// Created by Vlad on 3/17/2025.
//
#pragma once
#include "omath/engines/iw_engine/constants.hpp"
#include "omath/projection/camera.hpp"
namespace omath::iw_engine
{
class Camera final : public projection::Camera<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4x4 CalcViewMatrix() const override;
[[nodiscard]] Mat4x4 CalcProjectionMatrix() const override;
};
}

View File

@@ -0,0 +1,25 @@
//
// Created by Vlad on 3/17/2025.
//
#pragma once
#include <omath/vector3.hpp>
#include <omath/mat.hpp>
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
namespace omath::iw_engine
{
constexpr Vector3<float> kAbsUp = {0, 0, 1};
constexpr Vector3<float> kAbsRight = {0, -1, 0};
constexpr Vector3<float> kAbsForward = {1, 0, 0};
using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat1x3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -89.f, 89.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
}

View File

@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/17/2025.
//
#pragma once
#include "omath/engines/iw_engine/constants.hpp"
namespace omath::iw_engine
{
[[nodiscard]]
Vector3<float> ForwardVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> RightVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> UpVector(const ViewAngles& angles);
[[nodiscard]]
Mat4x4 RotationMatrix(const ViewAngles& angles);
[[nodiscard]] Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin);
[[nodiscard]]
Mat4x4 CalcPerspectiveProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far);
} // namespace omath::iw_engine

View File

@@ -0,0 +1,19 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include "omath/engines/opengl_engine/constants.hpp"
#include "omath/projection/camera.hpp"
namespace omath::opengl_engine
{
class Camera final : public projection::Camera<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3<float>& target) override;
[[nodiscard]] Mat4x4 CalcViewMatrix() const override;
[[nodiscard]] Mat4x4 CalcProjectionMatrix() const override;
};
}

View File

@@ -0,0 +1,26 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
namespace omath::opengl_engine
{
constexpr Vector3<float> kAbsUp = {0, 1, 0};
constexpr Vector3<float> kAbsRight = {1, 0, 0};
constexpr Vector3<float> kAbsForward = {0, 0, -1};
using Mat4x4 = Mat<4, 4, float, MatStoreType::COLUMN_MAJOR>;
using Mat3x3 = Mat<4, 4, float, MatStoreType::COLUMN_MAJOR>;
using Mat1x3 = Mat<1, 3, float, MatStoreType::COLUMN_MAJOR>;
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
}

View File

@@ -0,0 +1,26 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include "omath/engines/opengl_engine/constants.hpp"
namespace omath::opengl_engine
{
[[nodiscard]]
Vector3<float> ForwardVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> RightVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> UpVector(const ViewAngles& angles);
[[nodiscard]] Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin);
[[nodiscard]]
Mat4x4 RotationMatrix(const ViewAngles& angles);
[[nodiscard]]
Mat4x4 CalcPerspectiveProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far);
} // namespace omath::opengl_engine

View File

@@ -0,0 +1,20 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "omath/engines/source_engine/constants.hpp"
#include "omath/projection/camera.hpp"
namespace omath::source_engine
{
class Camera final : public projection::Camera<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4x4 CalcViewMatrix() const override;
[[nodiscard]] Mat4x4 CalcProjectionMatrix() const override;
};
}

View File

@@ -3,15 +3,16 @@
// //
#pragma once #pragma once
#include <omath/Vector3.hpp> #include <omath/vector3.hpp>
#include <omath/Mat.hpp> #include <omath/mat.hpp>
#include <omath/Angle.hpp> #include <omath/angle.hpp>
#include <omath/ViewAngles.hpp> #include <omath/view_angles.hpp>
namespace omath::source
namespace omath::source_engine
{ {
constexpr Vector3 kAbsUp = {0, 0, 1}; constexpr Vector3<float> kAbsUp = {0, 0, 1};
constexpr Vector3 kAbsRight = {0, -1, 0}; constexpr Vector3<float> kAbsRight = {0, -1, 0};
constexpr Vector3 kAbsForward = {1, 0, 0}; constexpr Vector3<float> kAbsForward = {1, 0, 0};
using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;

View File

@@ -0,0 +1,25 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "omath/engines/source_engine/constants.hpp"
namespace omath::source_engine
{
[[nodiscard]]
Vector3<float> ForwardVector(const ViewAngles& angles);
[[nodiscard]]
Mat4x4 RotationMatrix(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> RightVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> UpVector(const ViewAngles& angles);
[[nodiscard]] Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin);
[[nodiscard]]
Mat4x4 CalcPerspectiveProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far);
} // namespace omath::source

View File

@@ -0,0 +1,21 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include "omath/engines/unity_engine/constants.hpp"
#include "omath/projection/camera.hpp"
namespace omath::unity_engine
{
class Camera final : public projection::Camera<Mat4x4, ViewAngles>
{
public:
Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void LookAt(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4x4 CalcViewMatrix() const override;
[[nodiscard]] Mat4x4 CalcProjectionMatrix() const override;
};
}

View File

@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include <omath/vector3.hpp>
#include <omath/mat.hpp>
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
namespace omath::unity_engine
{
constexpr Vector3<float> kAbsUp = {0, 1, 0};
constexpr Vector3<float> kAbsRight = {1, 0, 0};
constexpr Vector3<float> kAbsForward = {0, 0, 1};
using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat1x3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
} // namespace omath::source

View File

@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include "omath/engines/unity_engine/constants.hpp"
namespace omath::unity_engine
{
[[nodiscard]]
Vector3<float> ForwardVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> RightVector(const ViewAngles& angles);
[[nodiscard]]
Vector3<float> UpVector(const ViewAngles& angles);
[[nodiscard]] Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin);
[[nodiscard]]
Mat4x4 RotationMatrix(const ViewAngles& angles);
[[nodiscard]]
Mat4x4 CalcPerspectiveProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far);
} // namespace omath::source

View File

@@ -4,12 +4,23 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <iomanip>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include "Vector3.hpp" #include "omath/vector3.hpp"
#include <numeric>
#ifdef near
#undef near
#endif
#ifdef far
#undef far
#endif
namespace omath namespace omath
{ {
struct MatSize struct MatSize
@@ -23,16 +34,25 @@ namespace omath
COLUMN_MAJOR COLUMN_MAJOR
}; };
template<typename M1, typename M2>
concept MatTemplateEqual =
(M1::rows == M2::rows) && (M1::columns == M2::columns) &&
std::is_same_v<typename M1::value_type, typename M2::value_type> &&
(M1::store_type == M2::store_type);
template<size_t Rows = 0, size_t Columns = 0, class Type = float, MatStoreType StoreType = MatStoreType::ROW_MAJOR> template<size_t Rows = 0, size_t Columns = 0, class Type = float, MatStoreType StoreType = MatStoreType::ROW_MAJOR>
requires std::is_arithmetic_v<Type> requires std::is_arithmetic_v<Type>
class Mat final class Mat final
{ {
public: public:
constexpr Mat() constexpr Mat() noexcept
{ {
Clear(); Clear();
} }
constexpr static MatStoreType GetStoreOrdering()
[[nodiscard]]
constexpr static MatStoreType GetStoreOrdering() noexcept
{ {
return StoreType; return StoreType;
} }
@@ -66,6 +86,18 @@ namespace omath
m_data = other.m_data; m_data = other.m_data;
} }
[[nodiscard]]
constexpr Type& operator[](const size_t row, const size_t col)
{
return At(row, col);
}
[[nodiscard]]
constexpr Type& operator[](const size_t row, const size_t col) const
{
return At(row, col);
}
constexpr Mat(Mat&& other) noexcept constexpr Mat(Mat&& other) noexcept
{ {
m_data = std::move(other.m_data); m_data = std::move(other.m_data);
@@ -89,11 +121,13 @@ namespace omath
return {Rows, Columns}; return {Rows, Columns};
} }
[[nodiscard]] constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const [[nodiscard]]
constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const
{ {
#if !defined(NDEBUG) && defined(OMATH_SUPRESS_SAFETY_CHECKS)
if (rowIndex >= Rows || columnIndex >= Columns) if (rowIndex >= Rows || columnIndex >= Columns)
throw std::out_of_range("Index out of range"); throw std::out_of_range("Index out of range");
#endif
if constexpr (StoreType == MatStoreType::ROW_MAJOR) if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return m_data[rowIndex * Columns + columnIndex]; return m_data[rowIndex * Columns + columnIndex];
@@ -115,12 +149,7 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr Type Sum() const noexcept constexpr Type Sum() const noexcept
{ {
Type sum = 0; return std::accumulate(m_data.begin(), m_data.end(), Type(0));
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
sum += At(i, j);
return sum;
} }
constexpr void Clear() noexcept constexpr void Clear() noexcept
@@ -135,6 +164,7 @@ namespace omath
// Operator overloading for multiplication with another Mat // Operator overloading for multiplication with another Mat
template<size_t OtherColumns> template<size_t OtherColumns>
[[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, StoreType> constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{ {
@@ -153,9 +183,7 @@ namespace omath
constexpr Mat& operator*=(const Type& f) noexcept constexpr Mat& operator*=(const Type& f) noexcept
{ {
for (size_t i = 0; i < Rows; ++i) std::ranges::for_each(m_data, [&f](auto& val) {val *= f;});
for (size_t j = 0; j < Columns; ++j)
At(i, j) *= f;
return *this; return *this;
} }
@@ -166,46 +194,40 @@ namespace omath
return *this = *this * other; return *this = *this * other;
} }
constexpr Mat operator*(const Type& f) const noexcept [[nodiscard]]
constexpr Mat operator*(const Type& value) const noexcept
{ {
Mat result(*this); Mat result(*this);
result *= f; result *= value;
return result; return result;
} }
constexpr Mat& operator/=(const Type& f) noexcept constexpr Mat& operator/=(const Type& value) noexcept
{ {
for (size_t i = 0; i < Rows; ++i) std::ranges::for_each(m_data, [&value](auto& val) {val /= value;});
for (size_t j = 0; j < Columns; ++j)
At(i, j) /= f;
return *this; return *this;
} }
constexpr Mat operator/(const Type& f) const noexcept [[nodiscard]]
constexpr Mat operator/(const Type& value) const noexcept
{ {
Mat result(*this); Mat result(*this);
result /= f; result /= value;
return result; return result;
} }
constexpr Mat& operator=(const Mat& other) noexcept constexpr Mat& operator=(const Mat& other) noexcept
{ {
if (this == &other) if (this != &other)
return *this; m_data = other.m_data;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
At(i, j) = other.At(i, j);
return *this; return *this;
} }
constexpr Mat& operator=(Mat&& other) noexcept constexpr Mat& operator=(Mat&& other) noexcept
{ {
if (this == &other) if (this != &other)
return *this; m_data = std::move(other.m_data);
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
At(i, j) = other.At(i, j);
return *this; return *this;
} }
@@ -229,23 +251,26 @@ namespace omath
if constexpr (Rows == 1) if constexpr (Rows == 1)
return At(0, 0); return At(0, 0);
else if constexpr (Rows == 2) if constexpr (Rows == 2)
return At(0, 0) * At(1, 1) - At(0, 1) * At(1, 0); return At(0, 0) * At(1, 1) - At(0, 1) * At(1, 0);
else
if constexpr (Rows > 2)
{ {
Type det = 0; Type det = 0;
for (size_t i = 0; i < Columns; ++i) for (size_t column = 0; column < Columns; ++column)
{ {
const Type cofactor = (i % 2 == 0 ? 1 : -1) * At(0, i) * Minor(0, i).Determinant(); const Type cofactor = At(0, column) * AlgComplement(0, column);
det += cofactor; det += cofactor;
} }
return det; return det;
} }
std::unreachable();
} }
[[nodiscard]] [[nodiscard]]
constexpr Mat<Rows - 1, Columns - 1, Type, StoreType> Minor(const size_t row, const size_t column) const constexpr Mat<Rows - 1, Columns - 1, Type, StoreType> Strip(const size_t row, const size_t column) const
{ {
static_assert(Rows-1 > 0 && Columns-1 > 0);
Mat<Rows - 1, Columns - 1, Type, StoreType> result; Mat<Rows - 1, Columns - 1, Type, StoreType> result;
for (size_t i = 0, m = 0; i < Rows; ++i) for (size_t i = 0, m = 0; i < Rows; ++i)
{ {
@@ -263,6 +288,19 @@ namespace omath
return result; return result;
} }
[[nodiscard]]
constexpr Type Minor(const size_t row, const size_t column) const
{
return Strip(row, column).Determinant();
}
[[nodiscard]]
constexpr Type AlgComplement(const size_t row, const size_t column) const
{
const auto minor = Minor(row, column);
return (row + column + 2) % 2 == 0 ? minor: -minor;
}
[[nodiscard]] [[nodiscard]]
constexpr const std::array<Type, Rows * Columns>& RawArray() const constexpr const std::array<Type, Rows * Columns>& RawArray() const
{ {
@@ -272,22 +310,27 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr std::array<Type, Rows * Columns>& RawArray() constexpr std::array<Type, Rows * Columns>& RawArray()
{ {
return const_cast<std::array<Type, Rows * Columns>>(std::as_const(*this).RawArray()); return m_data;
} }
[[nodiscard]] [[nodiscard]]
std::string ToString() const noexcept std::string ToString() const noexcept
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "[[";
for (size_t i = 0; i < Rows; ++i) for (size_t i = 0; i < Rows; ++i)
{ {
if (i > 0)
oss << " [";
for (size_t j = 0; j < Columns; ++j) for (size_t j = 0; j < Columns; ++j)
{ {
oss << At(i, j); oss << std::setw(9) << std::fixed << std::setprecision(3) << At(i, j);
if (j != Columns - 1) if (j != Columns - 1)
oss << ' '; oss << ", ";
} }
oss << '\n'; oss << (i == Rows - 1 ? "]]" : "]\n");
} }
return oss.str(); return oss.str();
} }
@@ -316,27 +359,46 @@ namespace omath
}; };
} }
[[nodiscard]]
constexpr std::optional<Mat> Inverted() const
{
const auto det = Determinant();
if (det == 0)
return std::nullopt;
const auto transposed = Transposed();
Mat result;
for (std::size_t row = 0; row < Rows; row++)
for (std::size_t column = 0; column < Rows; column++)
result.At(row, column) = transposed.AlgComplement(row, column);
result /= det;
return {result};
}
private: private:
std::array<Type, Rows * Columns> m_data; std::array<Type, Rows * Columns> m_data;
}; };
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3& vector) noexcept constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3<Type>& vector) noexcept
{ {
return {{vector.x, vector.y, vector.z, 1}}; return {{vector.x, vector.y, vector.z, 1}};
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3& vector) noexcept constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3<Type>& vector) noexcept
{ {
return {{vector.x}, {vector.y}, {vector.z}, {1}}; return {{vector.x}, {vector.y}, {vector.z}, {1}};
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3& diff) noexcept constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3<Type>& diff) noexcept
{ {
return return
{ {
@@ -388,8 +450,8 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
static Mat<4, 4, Type, St> MatCameraView(const Vector3& forward, const Vector3& right, const Vector3& up, static Mat<4, 4, Type, St> MatCameraView(const Vector3<Type>& forward, const Vector3<Type>& right,
const Vector3& cameraOrigin) noexcept const Vector3<Type>& up, const Vector3<Type>& cameraOrigin) noexcept
{ {
return Mat<4, 4, Type, St> return Mat<4, 4, Type, St>
{ {
@@ -401,10 +463,29 @@ namespace omath
} * MatTranslation<Type, St>(-cameraOrigin); } * MatTranslation<Type, St>(-cameraOrigin);
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class ViewAngles> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
Mat<4, 4, Type, St> MatRotation(const ViewAngles& angles) noexcept Mat<4, 4, Type, St> MatPerspectiveLeftHanded(const float fieldOfView, const float aspectRatio, const float near,
const float far) noexcept
{ {
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll); const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f},
{0.f, 1.f / fovHalfTan, 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}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> MatPerspectiveRightHanded(const float fieldOfView, const float aspectRatio, const float near,
const float far) noexcept
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f},
{0.f, 1.f / fovHalfTan, 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}};
} }
} // namespace omath } // namespace omath

View File

@@ -2,10 +2,10 @@
#include <initializer_list> #include <initializer_list>
#include <memory> #include <memory>
#include <string> #include <string>
#include "omath/vector3.hpp"
namespace omath namespace omath
{ {
class Vector3;
class Matrix final class Matrix final
{ {
@@ -19,10 +19,10 @@ namespace omath
static Matrix ToScreenMatrix(float screenWidth, float screenHeight); static Matrix ToScreenMatrix(float screenWidth, float screenHeight);
[[nodiscard]] [[nodiscard]]
static Matrix TranslationMatrix(const Vector3& diff); static Matrix TranslationMatrix(const Vector3<float>& diff);
[[nodiscard]] [[nodiscard]]
static Matrix OrientationMatrix(const Vector3& forward, const Vector3& right, const Vector3& up); static Matrix OrientationMatrix(const Vector3<float>& forward, const Vector3<float>& right, const Vector3<float>& up);
[[nodiscard]] [[nodiscard]]
static Matrix ProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far); static Matrix ProjectionMatrix(float fieldOfView, float aspectRatio, float near, float far);
@@ -36,6 +36,10 @@ namespace omath
[[nodiscard]] [[nodiscard]]
size_t RowCount() const noexcept; size_t RowCount() const noexcept;
[[nodiscard]]
float& operator[](size_t row, size_t column);
[[nodiscard]] [[nodiscard]]
size_t ColumnsCount() const noexcept; size_t ColumnsCount() const noexcept;

View File

@@ -1,20 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include <vector>
#include "NavigationMesh.hpp"
#include "omath/Vector3.hpp"
namespace omath::pathfinding
{
class Astar final
{
public:
[[nodiscard]]
static std::vector<Vector3> FindPath(const Vector3& start, const Vector3& end, const NavigationMesh& navMesh);
};
}

View File

@@ -0,0 +1,30 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include <vector>
#include "omath/pathfinding/navigation_mesh.hpp"
#include "omath/vector3.hpp"
namespace omath::pathfinding
{
struct PathNode;
class Astar final
{
public:
[[nodiscard]]
static std::vector<Vector3<float>> FindPath(const Vector3<float>& start, const Vector3<float>& end,
const NavigationMesh& navMesh);
private:
[[nodiscard]]
static std::vector<Vector3<float>>
ReconstructFinalPath(const std::unordered_map<Vector3<float>, PathNode>& closedList,
const Vector3<float>& current);
[[nodiscard]]
static auto GetPerfectNode(const std::unordered_map<Vector3<float>, PathNode>& openList,
const Vector3<float>& endVertex);
};
} // namespace omath::pathfinding

View File

@@ -4,11 +4,10 @@
#pragma once #pragma once
#include "omath/Vector3.hpp"
#include <expected> #include <expected>
#include <vector>
#include <string> #include <string>
#include <vector>
#include "omath/vector3.hpp"
namespace omath::pathfinding namespace omath::pathfinding
{ {
@@ -21,19 +20,19 @@ namespace omath::pathfinding
class NavigationMesh final class NavigationMesh final
{ {
public: public:
[[nodiscard]]
std::expected<Vector3<float>, std::string> GetClosestVertex(const Vector3<float>& point) const;
[[nodiscard]] [[nodiscard]]
std::expected<Vector3, std::string> GetClosestVertex(const Vector3& point) const; const std::vector<Vector3<float>>& GetNeighbors(const Vector3<float>& vertex) const;
[[nodiscard]]
const std::vector<Vector3>& GetNeighbors(const Vector3& vertex) const;
[[nodiscard]] [[nodiscard]]
bool Empty() const; bool Empty() const;
[[nodiscard]] std::vector<uint8_t> Serialize() const; [[nodiscard]] std::vector<uint8_t> Serialize() const;
void Deserialize(const std::vector<uint8_t>& raw); void Deserialize(const std::vector<uint8_t>& raw);
std::unordered_map<Vector3, std::vector<Vector3>> m_verTextMap; std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_verTextMap;
}; };
} } // namespace omath::pathfinding

View File

@@ -1,39 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include <optional>
#include "omath/Vector3.hpp"
#include "omath/prediction/Projectile.hpp"
#include "omath/prediction/Target.hpp"
namespace omath::prediction
{
class Engine final
{
public:
explicit Engine(float gravityConstant, float simulationTimeStep,
float maximumSimulationTime, float distanceTolerance);
[[nodiscard]]
std::optional<Vector3> MaybeCalculateAimPoint(const Projectile& projectile, const Target& target) const;
private:
const float m_gravityConstant;
const float m_simulationTimeStep;
const float m_maximumSimulationTime;
const float m_distanceTolerance;
[[nodiscard]]
std::optional<float> MaybeCalculateProjectileLaunchPitchAngle(const Projectile& projectile,
const Vector3& targetPosition) const;
[[nodiscard]]
bool IsProjectileReachedTarget(const Vector3& targetPosition, const Projectile& projectile, float pitch, float time) const;
};
}

View File

@@ -1,22 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include "omath/Vector3.hpp"
namespace omath::prediction
{
class Projectile final
{
public:
[[nodiscard]]
Vector3 PredictPosition(float pitch, float yaw, float time, float gravity) const;
Vector3 m_origin;
float m_launchSpeed{};
float m_gravityScale{};
};
}

View File

@@ -0,0 +1,20 @@
//
// Created by Vlad on 2/23/2025.
//
#pragma once
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include "omath/vector3.hpp"
namespace omath::projectile_prediction
{
class ProjPredEngine
{
public:
[[nodiscard]]
virtual std::optional<Vector3<float>> MaybeCalculateAimPoint(const Projectile& projectile,
const Target& target) const = 0;
virtual ~ProjPredEngine() = default;
};
} // namespace omath::projectile_prediction

View File

@@ -0,0 +1,26 @@
//
// Created by Vlad on 2/23/2025.
//
#pragma once
#include "omath/projectile_prediction/proj_pred_engine.hpp"
namespace omath::projectile_prediction
{
class ProjPredEngineAVX2 final : public ProjPredEngine
{
public:
[[nodiscard]] std::optional<Vector3<float>> MaybeCalculateAimPoint(const Projectile& projectile,
const Target& target) const override;
ProjPredEngineAVX2(float gravityConstant, float simulationTimeStep, float maximumSimulationTime);
~ProjPredEngineAVX2() override = default;
private:
[[nodiscard]] static std::optional<float> CalculatePitch(const Vector3<float>& projOrigin, const Vector3<float>& targetPos,
float bulletGravity, float v0, float time);
const float m_gravityConstant;
const float m_simulationTimeStep;
const float m_maximumSimulationTime;
};
} // namespace omath::projectile_prediction

View File

@@ -0,0 +1,41 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include <optional>
#include "omath/projectile_prediction/proj_pred_engine.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include "omath/vector3.hpp"
namespace omath::projectile_prediction
{
class ProjPredEngineLegacy final : public ProjPredEngine
{
public:
explicit ProjPredEngineLegacy(float gravityConstant, float simulationTimeStep, float maximumSimulationTime,
float distanceTolerance);
[[nodiscard]]
std::optional<Vector3<float>> MaybeCalculateAimPoint(const Projectile& projectile,
const Target& target) const override;
private:
const float m_gravityConstant;
const float m_simulationTimeStep;
const float m_maximumSimulationTime;
const float m_distanceTolerance;
[[nodiscard]]
std::optional<float> MaybeCalculateProjectileLaunchPitchAngle(const Projectile& projectile,
const Vector3<float>& targetPosition) const;
[[nodiscard]]
bool IsProjectileReachedTarget(const Vector3<float>& targetPosition, const Projectile& projectile, float pitch,
float time) const;
};
} // namespace omath::projectile_prediction

View File

@@ -0,0 +1,21 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include "omath/vector3.hpp"
namespace omath::projectile_prediction
{
class Projectile final
{
public:
[[nodiscard]]
Vector3<float> PredictPosition(float pitch, float yaw, float time, float gravity) const;
Vector3<float> m_origin;
float m_launchSpeed{};
float m_gravityScale{};
};
}

View File

@@ -3,17 +3,16 @@
// //
#pragma once #pragma once
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
namespace omath::projectile_prediction
namespace omath::prediction
{ {
class Target final class Target final
{ {
public: public:
[[nodiscard]] [[nodiscard]]
constexpr Vector3 PredictPosition(const float time, const float gravity) const constexpr Vector3<float> PredictPosition(const float time, const float gravity) const
{ {
auto predicted = m_origin + m_velocity * time; auto predicted = m_origin + m_velocity * time;
@@ -23,8 +22,8 @@ namespace omath::prediction
return predicted; return predicted;
} }
Vector3 m_origin; Vector3<float> m_origin;
Vector3 m_velocity; Vector3<float> m_velocity;
bool m_isAirborne{}; bool m_isAirborne{};
}; };
} }

View File

@@ -1,89 +0,0 @@
//
// Created by Vlad on 27.08.2024.
//
#pragma once
#include <expected>
#include <omath/Mat.hpp>
#include <omath/Vector3.hpp>
#include "ErrorCodes.hpp"
#include <omath/Angle.hpp>
#include <type_traits>
namespace omath::projection
{
class ViewPort final
{
public:
float m_width;
float m_height;
[[nodiscard]] constexpr float AspectRatio() const
{
return m_width / m_height;
}
};
using FieldOfView = const Angle<float, 0.f, 180.f, AngleFlags::Clamped>;
template<class Mat4x4Type, class ViewAnglesType>
class Camera
{
public:
virtual ~Camera() = default;
Camera(const Vector3& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort,
const FieldOfView& fov, const float near, const float far) :
m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near),
m_viewAngles(viewAngles), m_origin(position)
{
}
virtual void LookAt(const Vector3& target) = 0;
[[nodiscard]] virtual Mat4x4Type GetViewMatrix() const = 0;
[[nodiscard]] virtual Mat4x4Type GetProjectionMatrix() const = 0;
[[nodiscard]] Mat4x4Type GetViewProjectionMatrix()
{
return GetProjectionMatrix() * GetViewMatrix();
}
[[nodiscard]] std::expected<Vector3, Error> WorldToScreen(const Mat4x4Type& viewProj, const Vector3& worldPosition) const
{
auto projected = viewProj * MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition);
if (projected.At(3, 0) == 0.0f)
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
projected /= projected.At(3, 0);
if (IsNdcOutOfBounds(projected))
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
return Vector3{(projected.At(0,0)+1) / 2 * m_viewPort.m_width , (-projected.At(1,0)+1) / 2 * m_viewPort.m_height, projected.At(2,0)};
}
protected:
ViewPort m_viewPort{};
Angle<float, 0.f, 180.f, AngleFlags::Clamped> m_fieldOfView;
float m_farPlaneDistance;
float m_nearPlaneDistance;
ViewAnglesType m_viewAngles;
Vector3 m_origin;
private:
template<class Type>
[[nodiscard]]
constexpr static bool IsNdcOutOfBounds(const Type& ndc)
{
return std::ranges::any_of( ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; });
}
};
} // namespace omath::projection

View File

@@ -0,0 +1,181 @@
//
// Created by Vlad on 27.08.2024.
//
#pragma once
#include <expected>
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <type_traits>
#include "omath/projection/error_codes.hpp"
namespace omath::projection
{
class ViewPort final
{
public:
float m_width;
float m_height;
[[nodiscard]] constexpr float AspectRatio() const
{
return m_width / m_height;
}
};
using FieldOfView = Angle<float, 0.f, 180.f, AngleFlags::Clamped>;
template<class Mat4x4Type, class ViewAnglesType>
class Camera
{
public:
virtual ~Camera() = default;
Camera(const Vector3<float>& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort,
const FieldOfView& fov, const float near, const float far) :
m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near),
m_viewAngles(viewAngles), m_origin(position)
{
}
protected:
virtual void LookAt(const Vector3<float>& target) = 0;
[[nodiscard]] virtual Mat4x4Type CalcViewMatrix() const = 0;
[[nodiscard]] virtual Mat4x4Type CalcProjectionMatrix() const = 0;
[[nodiscard]] Mat4x4Type CalcViewProjectionMatrix() const
{
return CalcProjectionMatrix() * CalcViewMatrix();
}
public:
[[nodiscard]] const Mat4x4Type& GetViewProjectionMatrix() const
{
if (!m_viewProjectionMatrix.has_value())
m_viewProjectionMatrix = CalcViewProjectionMatrix();
return m_viewProjectionMatrix.value();
}
void SetFieldOfView(const FieldOfView& fov)
{
m_fieldOfView = fov;
m_viewProjectionMatrix = std::nullopt;
}
void SetNearPlane(const float near)
{
m_nearPlaneDistance = near;
m_viewProjectionMatrix = std::nullopt;
}
void SetFarPlane(const float far)
{
m_farPlaneDistance = far;
m_viewProjectionMatrix = std::nullopt;
}
void SetViewAngles(const ViewAnglesType& viewAngles)
{
m_viewAngles = viewAngles;
m_viewProjectionMatrix = std::nullopt;
}
void SetOrigin(const Vector3<float>& origin)
{
m_origin = origin;
m_viewProjectionMatrix = std::nullopt;
}
void SetViewPort(const ViewPort& viewPort)
{
m_viewPort = viewPort;
m_viewProjectionMatrix = std::nullopt;
}
[[nodiscard]] const FieldOfView& GetFieldOfView() const
{
return m_fieldOfView;
}
[[nodiscard]] const float& GetNearPlane() const
{
return m_nearPlaneDistance;
}
[[nodiscard]] const float& GetFarPlane() const
{
return m_farPlaneDistance;
}
[[nodiscard]] const ViewAnglesType& GetViewAngles() const
{
return m_viewAngles;
}
[[nodiscard]] const Vector3<float>& GetOrigin() const
{
return m_origin;
}
[[nodiscard]] std::expected<Vector3<float>, Error> WorldToScreen(const Vector3<float>& worldPosition) const
{
auto normalizedCords = WorldToViewPort(worldPosition);
if (!normalizedCords.has_value())
return std::unexpected{normalizedCords.error()};
return NdcToScreenPosition(*normalizedCords);
}
[[nodiscard]] std::expected<Vector3<float>, Error> WorldToViewPort(const Vector3<float>& worldPosition) const
{
auto projected = GetViewProjectionMatrix() *
MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition);
if (projected.At(3, 0) == 0.0f)
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
projected /= projected.At(3, 0);
if (IsNdcOutOfBounds(projected))
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
return Vector3<float>{projected.At(0, 0), projected.At(1, 0), projected.At(2, 0)};
}
protected:
ViewPort m_viewPort{};
Angle<float, 0.f, 180.f, AngleFlags::Clamped> m_fieldOfView;
mutable std::optional<Mat4x4Type> m_viewProjectionMatrix;
float m_farPlaneDistance;
float m_nearPlaneDistance;
ViewAnglesType m_viewAngles;
Vector3<float> m_origin;
private:
template<class Type>
[[nodiscard]]
constexpr static bool IsNdcOutOfBounds(const Type& ndc)
{
return std::ranges::any_of(ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; });
}
[[nodiscard]] Vector3<float> NdcToScreenPosition(const Vector3<float>& ndc) const
{
return
{
(ndc.x + 1.f) / 2.f * m_viewPort.m_width,
(1.f - ndc.y) / 2.f * m_viewPort.m_height,
ndc.z
};
}
};
} // namespace omath::projection

View File

@@ -0,0 +1,84 @@
//
// Created by Orange on 11/13/2024.
//
#pragma once
#include "omath/vector3.hpp"
namespace omath
{
/*
|\
| \
a | \ hypot
| \
-----
b
*/
template<class Vector>
class Triangle final
{
public:
constexpr Triangle() = default;
constexpr Triangle(const Vector& vertex1, const Vector& vertex2, const Vector& vertex3)
: m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3)
{
}
Vector3<float> m_vertex1;
Vector3<float> m_vertex2;
Vector3<float> m_vertex3;
[[nodiscard]]
constexpr Vector3<float> CalculateNormal() const
{
const auto b = SideBVector();
const auto a = SideAVector();
return b.Cross(a).Normalized();
}
[[nodiscard]]
float SideALength() const
{
return m_vertex1.DistTo(m_vertex2);
}
[[nodiscard]]
float SideBLength() const
{
return m_vertex3.DistTo(m_vertex2);
}
[[nodiscard]]
constexpr Vector3<float> SideAVector() const
{
return m_vertex1 - m_vertex2;
}
[[nodiscard]]
constexpr float Hypot() const
{
return m_vertex1.DistTo(m_vertex3);
}
[[nodiscard]]
constexpr bool IsRectangular() const
{
const auto sideA = SideALength();
const auto sideB = SideBLength();
const auto hypot = Hypot();
return std::abs(sideA*sideA + sideB*sideB - hypot*hypot) <= 0.0001f;
}
[[nodiscard]]
constexpr Vector3<float> SideBVector() const
{
return m_vertex3 - m_vertex2;
}
[[nodiscard]]
constexpr Vector3<float> MidPoint() const
{
return (m_vertex1 + m_vertex2 + m_vertex3) / 3;
}
};
} // namespace omath

View File

@@ -3,22 +3,31 @@
// //
#pragma once #pragma once
#include <tuple>
#include <cmath> #include <cmath>
#include <tuple>
#ifdef OMATH_IMGUI_INTEGRATION
#include <imgui.h>
#endif
namespace omath namespace omath
{ {
template<class Type>
requires std::is_arithmetic_v<Type>
class Vector2 class Vector2
{ {
public: public:
float x = 0.f; Type x = static_cast<Type>(0);
float y = 0.f; Type y = static_cast<Type>(0);
// Constructors // Constructors
constexpr Vector2() = default; constexpr Vector2() = default;
constexpr Vector2(const float x, const float y) : x(x), y(y) {} constexpr Vector2(const Type& x, const Type& y) : x(x), y(y)
{
}
// Equality operators // Equality operators
[[nodiscard]] [[nodiscard]]
@@ -66,7 +75,7 @@ namespace omath
return *this; return *this;
} }
constexpr Vector2& operator*=(const float fl) constexpr Vector2& operator*=(const Type& fl)
{ {
x *= fl; x *= fl;
y *= fl; y *= fl;
@@ -74,7 +83,7 @@ namespace omath
return *this; return *this;
} }
constexpr Vector2& operator/=(const float fl) constexpr Vector2& operator/=(const Type& fl)
{ {
x /= fl; x /= fl;
y /= fl; y /= fl;
@@ -82,7 +91,7 @@ namespace omath
return *this; return *this;
} }
constexpr Vector2& operator+=(const float fl) constexpr Vector2& operator+=(const Type& fl)
{ {
x += fl; x += fl;
y += fl; y += fl;
@@ -90,7 +99,7 @@ namespace omath
return *this; return *this;
} }
constexpr Vector2& operator-=(const float fl) constexpr Vector2& operator-=(const Type& fl)
{ {
x -= fl; x -= fl;
y -= fl; y -= fl;
@@ -99,68 +108,57 @@ namespace omath
} }
// Basic vector operations // Basic vector operations
[[nodiscard]] float DistTo(const Vector2& vOther) const [[nodiscard]] Type DistTo(const Vector2& vOther) const
{ {
return std::sqrt(DistToSqr(vOther)); return std::sqrt(DistToSqr(vOther));
} }
[[nodiscard]] constexpr float DistToSqr(const Vector2& vOther) const [[nodiscard]] constexpr Type DistToSqr(const Vector2& vOther) const
{ {
return (x - vOther.x) * (x - vOther.x) + (y - vOther.y) * (y - vOther.y); return (x - vOther.x) * (x - vOther.x) + (y - vOther.y) * (y - vOther.y);
} }
[[nodiscard]] constexpr float Dot(const Vector2& vOther) const [[nodiscard]] constexpr Type Dot(const Vector2& vOther) const
{ {
return x * vOther.x + y * vOther.y; return x * vOther.x + y * vOther.y;
} }
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard]] constexpr float Length() const [[nodiscard]] constexpr Type Length() const
{ {
return std::hypot(x, y); return std::hypot(this->x, this->y);
} }
[[nodiscard]] constexpr Vector2 Normalized() const [[nodiscard]] constexpr Vector2 Normalized() const
{ {
const float len = Length(); const Type len = Length();
return len > 0.f ? *this / len : *this; return len > 0.f ? *this / len : *this;
} }
#else #else
[[nodiscard]] float Length() const [[nodiscard]] Type Length() const
{ {
return std::hypot(x, y); return std::hypot(x, y);
} }
[[nodiscard]] Vector2 Normalized() const [[nodiscard]] Vector2 Normalized() const
{ {
const float len = Length(); const Type len = Length();
return len > 0.f ? *this / len : *this; return len > 0.f ? *this / len : *this;
} }
#endif #endif
[[nodiscard]] constexpr float LengthSqr() const [[nodiscard]] constexpr Type LengthSqr() const
{ {
return x * x + y * y; return x * x + y * y;
} }
constexpr Vector2& Abs() constexpr Vector2& Abs()
{ {
//FIXME: Replace with std::abs, if it will become constexprable // FIXME: Replace with std::abs, if it will become constexprable
x = x < 0 ? -x : x; x = x < 0 ? -x : x;
y = y < 0 ? -y : y; y = y < 0 ? -y : y;
return *this; return *this;
} }
template<class type>
[[nodiscard]] constexpr const type& As() const
{
return *reinterpret_cast<const type*>(this);
}
template<class type>
[[nodiscard]] constexpr type& As()
{
return *reinterpret_cast<type*>(this);
}
[[nodiscard]] constexpr Vector2 operator-() const [[nodiscard]] constexpr Vector2 operator-() const
{ {
return {-x, -y}; return {-x, -y};
@@ -187,16 +185,24 @@ namespace omath
return {x / fl, y / fl}; return {x / fl, y / fl};
} }
// Sum of elements // Sum of elements
[[nodiscard]] constexpr float Sum() const [[nodiscard]] constexpr Type Sum() const
{ {
return x + y; return x + y;
} }
[[nodiscard]] [[nodiscard]]
constexpr std::tuple<float, float> AsTuple() const constexpr std::tuple<Type, Type> AsTuple() const
{ {
return std::make_tuple(x, y); return std::make_tuple(x, y);
} }
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec2 ToImVec2() const
{
return {static_cast<float>(this->x), static_cast<float>(this->y)};
}
#endif
}; };
} } // namespace omath

281
include/omath/vector3.hpp Normal file
View File

@@ -0,0 +1,281 @@
//
// Created by vlad on 10/28/23.
//
#pragma once
#include <cstdint>
#include <expected>
#include <functional>
#include "omath/angle.hpp"
#include "omath/vector2.hpp"
namespace omath
{
enum class Vector3Error
{
IMPOSSIBLE_BETWEEN_ANGLE,
};
template<class Type> requires std::is_arithmetic_v<Type>
class Vector3 : public Vector2<Type>
{
public:
Type z = static_cast<Type>(0);
constexpr Vector3(const Type& x, const Type& y, const Type& z) : Vector2<Type>(x, y), z(z) { }
constexpr Vector3() : Vector2<Type>() {};
[[nodiscard]] constexpr bool operator==(const Vector3& src) const
{
return Vector2<Type>::operator==(src) && (src.z == z);
}
[[nodiscard]] constexpr bool operator!=(const Vector3& src) const
{
return !(*this == src);
}
constexpr Vector3& operator+=(const Vector3& v)
{
Vector2<Type>::operator+=(v);
z += v.z;
return *this;
}
constexpr Vector3& operator-=(const Vector3& v)
{
Vector2<Type>::operator-=(v);
z -= v.z;
return *this;
}
constexpr Vector3& operator*=(const float fl)
{
Vector2<Type>::operator*=(fl);
z *= fl;
return *this;
}
constexpr Vector3& operator*=(const Vector3& v)
{
Vector2<Type>::operator*=(v);
z *= v.z;
return *this;
}
constexpr Vector3& operator/=(const Vector3& v)
{
Vector2<Type>::operator/=(v);
z /= v.z;
return *this;
}
constexpr Vector3& operator+=(const float fl)
{
Vector2<Type>::operator+=(fl);
z += fl;
return *this;
}
constexpr Vector3& operator/=(const float fl)
{
Vector2<Type>::operator/=(fl);
z /= fl;
return *this;
}
constexpr Vector3& operator-=(const float fl)
{
Vector2<Type>::operator-=(fl);
z -= fl;
return *this;
}
constexpr Vector3& Abs()
{
Vector2<Type>::Abs();
z = z < 0.f ? -z : z;
return *this;
}
[[nodiscard]] constexpr Type DistToSqr(const Vector3& vOther) const
{
return (*this - vOther).LengthSqr();
}
[[nodiscard]] constexpr Type Dot(const Vector3& vOther) const
{
return Vector2<Type>::Dot(vOther) + z * vOther.z;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr Type Length() const
{
return std::hypot(this->x, this->y, z);
}
[[nodiscard]] constexpr Type Length2D() const
{
return Vector2<Type>::Length();
}
[[nodiscard]] Type DistTo(const Vector3& vOther) const
{
return (*this - vOther).Length();
}
[[nodiscard]] constexpr Vector3 Normalized() const
{
const Type length = this->Length();
return length != 0 ? *this / length : *this;
}
#else
[[nodiscard]] Type Length() const
{
return std::hypot(this->x, this->y, z);
}
[[nodiscard]] Vector3 Normalized() const
{
const Type length = this->Length();
return length != 0 ? *this / length : *this;
}
[[nodiscard]] Type Length2D() const
{
return Vector2<Type>::Length();
}
[[nodiscard]] Type DistTo(const Vector3& vOther) const
{
return (*this - vOther).Length();
}
#endif
[[nodiscard]] constexpr Type LengthSqr() const
{
return Vector2<Type>::LengthSqr() + z * z;
}
[[nodiscard]] constexpr Vector3 operator-() const
{
return {-this->x, -this->y, -z};
}
[[nodiscard]] constexpr Vector3 operator+(const Vector3& v) const
{
return {this->x + v.x, this->y + v.y, z + v.z};
}
[[nodiscard]] constexpr Vector3 operator-(const Vector3& v) const
{
return {this->x - v.x, this->y - v.y, z - v.z};
}
[[nodiscard]] constexpr Vector3 operator*(const float fl) const
{
return {this->x * fl, this->y * fl, z * fl};
}
[[nodiscard]] constexpr Vector3 operator*(const Vector3& v) const
{
return {this->x * v.x, this->y * v.y, z * v.z};
}
[[nodiscard]] constexpr Vector3 operator/(const float fl) const
{
return {this->x / fl, this->y / fl, z / fl};
}
[[nodiscard]] constexpr Vector3 operator/(const Vector3& v) const
{
return {this->x / v.x, this->y / v.y, z / v.z};
}
[[nodiscard]] constexpr Vector3 Cross(const Vector3 &v) const
{
return
{
this->y * v.z - z * v.y,
z * v.x - this->x * v.z,
this->x * v.y - this->y * v.x
};
}
[[nodiscard]] constexpr Type Sum() const
{
return Sum2D() + z;
}
[[nodiscard]] std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
AngleBetween(const Vector3& other) const
{
const auto bottom = Length() * other.Length();
if (bottom == 0.f)
return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE);
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::FromRadians(std::acos(Dot(other) / bottom));
}
[[nodiscard]] bool IsPerpendicular(const Vector3& other) const
{
if (const auto angle = AngleBetween(other))
return angle->AsDegrees() == 90.f;
return false;
}
[[nodiscard]] constexpr Type Sum2D() const
{
return Vector2<Type>::Sum();
}
[[nodiscard]] constexpr std::tuple<Type, Type, Type> AsTuple() const
{
return std::make_tuple(this->x, this->y, z);
}
[[nodiscard]] Vector3 ViewAngleTo(const Vector3 &other) const
{
const float distance = DistTo(other);
const auto delta = other - *this;
return
{
angles::RadiansToDegrees(std::asin(delta.z / distance)),
angles::RadiansToDegrees(std::atan2(delta.y, delta.x)),
0
};
}
};
}
// ReSharper disable once CppRedundantNamespaceDefinition
namespace std
{
template<>
struct hash<omath::Vector3<float>>
{
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{
std::size_t hash = 0;
constexpr std::hash<float> hasher;
hash ^= hasher(vec.x) + 0x9e3779b9 + (hash<<6) + (hash>>2);
hash ^= hasher(vec.y) + 0x9e3779b9 + (hash<<6) + (hash>>2);
hash ^= hasher(vec.z) + 0x9e3779b9 + (hash<<6) + (hash>>2);
return hash;
}
};
}

173
include/omath/vector4.hpp Normal file
View File

@@ -0,0 +1,173 @@
//
// Vector4.h
//
#pragma once
#include <algorithm>
#include <omath/vector3.hpp>
namespace omath
{
template <class Type>
class Vector4 : public Vector3<Type>
{
public:
Type w;
constexpr Vector4(const Type& x, const Type& y, const Type& z, const Type& w) : Vector3<Type>(x, y, z), w(w) {}
constexpr Vector4() : Vector3<Type>(), w(0) {};
[[nodiscard]]
constexpr bool operator==(const Vector4& src) const
{
return Vector3<Type>::operator==(src) && w == src.w;
}
[[nodiscard]]
constexpr bool operator!=(const Vector4& src) const
{
return !(*this == src);
}
constexpr Vector4& operator+=(const Vector4& v)
{
Vector3<Type>::operator+=(v);
w += v.w;
return *this;
}
constexpr Vector4& operator-=(const Vector4& v)
{
Vector3<Type>::operator-=(v);
w -= v.w;
return *this;
}
constexpr Vector4& operator*=(const float scalar)
{
Vector3<Type>::operator*=(scalar);
w *= scalar;
return *this;
}
constexpr Vector4& operator*=(const Vector4& v)
{
Vector3<Type>::operator*=(v);
w *= v.w;
return *this;
}
constexpr Vector4& operator/=(const float scalar)
{
Vector3<Type>::operator/=(scalar);
w /= scalar;
return *this;
}
constexpr Vector4& operator/=(const Vector4& v)
{
Vector3<Type>::operator/=(v);
w /= v.w;
return *this;
}
[[nodiscard]] constexpr Type LengthSqr() const
{
return Vector3<Type>::LengthSqr() + w * w;
}
[[nodiscard]] constexpr Type Dot(const Vector4& vOther) const
{
return Vector3<Type>::Dot(vOther) + w * vOther.w;
}
[[nodiscard]] Vector3<Type> Length() const
{
return std::sqrt(LengthSqr());
}
constexpr Vector4& Abs()
{
Vector3<Type>::Abs();
w = w < 0.f ? -w : w;
return *this;
}
constexpr Vector4& Clamp(const Type& min, const Type& max)
{
this->x = std::clamp(this->x, min, max);
this->y = std::clamp(this->y, min, max);
this->z = std::clamp(this->z, min, max);
return *this;
}
[[nodiscard]]
constexpr Vector4 operator-() const
{
return {-this->x, -this->y, -this->z, -w};
}
[[nodiscard]]
constexpr Vector4 operator+(const Vector4& v) const
{
return {this->x + v.x, this->y + v.y, this->z + v.z, w + v.w};
}
[[nodiscard]]
constexpr Vector4 operator-(const Vector4& v) const
{
return {this->x - v.x, this->y - v.y, this->z - v.z, w - v.w};
}
[[nodiscard]]
constexpr Vector4 operator*(const Type& scalar) const
{
return {this->x * scalar, this->y * scalar, this->z * scalar, w * scalar};
}
[[nodiscard]]
constexpr Vector4 operator*(const Vector4& v) const
{
return {this->x * v.x, this->y * v.y, this->z * v.z, w * v.w};
}
[[nodiscard]]
constexpr Vector4 operator/(const Type& scalar) const
{
return {this->x / scalar, this->y / scalar, this->z / scalar, w / scalar};
}
[[nodiscard]]
constexpr Vector4 operator/(const Vector4& v) const
{
return {this->x / v.x, this->y / v.y, this->z / v.z, w / v.w};
}
[[nodiscard]]
constexpr Type Sum() const
{
return Vector3<Type>::Sum() + w;
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec4 ToImVec4() const
{
return
{
static_cast<float>(this->x),
static_cast<float>(this->y),
static_cast<float>(this->z),
static_cast<float>(w),
};
}
#endif
};
}

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE box.cpp)

View File

@@ -0,0 +1,56 @@
//
// Created by Vlad on 4/18/2025.
//
#include "omath/3d_primitives/box.hpp"
namespace omath::primitives
{
std::array<Triangle<Vector3<float>>, 12> CreateBox(const Vector3<float>& top, const Vector3<float>& bottom,
const Vector3<float>& dirForward,
const Vector3<float>& dirRight,
const float ratio)
{
const auto height = top.DistTo(bottom);
const auto sideSize = height / ratio;
// corner layout (03 bottom, 47 top)
std::array<Vector3<float>, 8> p;
p[0] = bottom + (dirForward + dirRight) * sideSize; // frontrightbottom
p[1] = bottom + (dirForward - dirRight) * sideSize; // frontleftbottom
p[2] = bottom + (-dirForward + dirRight) * sideSize; // backrightbottom
p[3] = bottom + (-dirForward - dirRight) * sideSize; // backleftbottom
p[4] = top + (dirForward + dirRight) * sideSize; // frontrighttop
p[5] = top + (dirForward - dirRight) * sideSize; // frontlefttop
p[6] = top + (-dirForward + dirRight) * sideSize; // backrighttop
p[7] = top + (-dirForward - dirRight) * sideSize; // backlefttop
std::array<Triangle<Vector3<float>>, 12> poly;
// bottom face (+Y up ⇒ wind CW when viewed from above)
poly[0] = {p[0], p[2], p[3]};
poly[1] = {p[0], p[3], p[1]};
// top face
poly[2] = {p[4], p[7], p[6]};
poly[3] = {p[4], p[5], p[7]};
// front face
poly[4] = {p[0], p[5], p[1]};
poly[5] = {p[0], p[4], p[5]};
// right face
poly[6] = {p[0], p[6], p[2]};
poly[7] = {p[0], p[4], p[6]};
// back face
poly[8] = {p[2], p[7], p[3]};
poly[9] = {p[2], p[6], p[7]};
// left face
poly[10] = {p[1], p[7], p[5]};
poly[11] = {p[1], p[3], p[7]};
return poly;
}
}

View File

@@ -1,14 +1,11 @@
target_sources(omath PRIVATE target_sources(omath PRIVATE
Vector3.cpp matrix.cpp
Matrix.cpp
color.cpp color.cpp
Vector4.cpp
Vector2.cpp
Triangle3d.cpp
) )
add_subdirectory(prediction) add_subdirectory(projectile_prediction)
add_subdirectory(pathfinding) add_subdirectory(pathfinding)
add_subdirectory(projection) add_subdirectory(projection)
add_subdirectory(collision) add_subdirectory(collision)
add_subdirectory(engines) add_subdirectory(engines)
add_subdirectory(3d_primitives)

View File

@@ -1,36 +0,0 @@
#include "omath/Triangle3d.hpp"
namespace omath
{
Triangle3d::Triangle3d(const Vector3 &vertex1, const Vector3 &vertex2, const Vector3 &vertex3)
: m_vertex1(vertex1), m_vertex2(vertex2), m_vertex3(vertex3)
{
}
Vector3 Triangle3d::CalculateNormal() const
{
return (m_vertex1 - m_vertex2).Cross(m_vertex3 - m_vertex1).Normalized();
}
float Triangle3d::SideALength() const
{
return m_vertex1.DistTo(m_vertex2);
}
float Triangle3d::SideBLength() const
{
return m_vertex3.DistTo(m_vertex2);
}
Vector3 Triangle3d::SideAVector() const
{
return m_vertex1 - m_vertex2;
}
Vector3 Triangle3d::SideBVector() const
{
return m_vertex3 - m_vertex2;
}
}

View File

@@ -1,11 +0,0 @@
//
// Created by Vlad on 02.09.2024.
//
#include "omath/Vector2.hpp"
#include <cmath>
namespace omath
{
}

View File

@@ -1,23 +0,0 @@
//
// Created by vlad on 10/28/23.
//
#include <omath/Vector3.hpp>
#include <cmath>
#include <omath/Angles.hpp>
namespace omath
{
Vector3 Vector3::ViewAngleTo(const Vector3 &other) const
{
const float distance = DistTo(other);
const auto delta = other - *this;
return
{
angles::RadiansToDegrees(std::asin(delta.z / distance)),
angles::RadiansToDegrees(std::atan2(delta.y, delta.x)),
0.f
};
}
}

View File

@@ -1,16 +0,0 @@
//
// Vector4.cpp
//
#include "omath/Vector4.hpp"
#include <cmath>
namespace omath
{
float Vector4::Length() const
{
return std::sqrt(LengthSqr());
}
}

View File

@@ -1,3 +1,3 @@
target_sources(omath PRIVATE target_sources(omath PRIVATE
LineTracer.cpp line_tracer.cpp
) )

View File

@@ -1,25 +1,25 @@
// //
// Created by Orange on 11/13/2024. // Created by Orange on 11/13/2024.
// //
#include "omath/collision/LineTracer.hpp" #include "omath/collision/line_tracer.hpp"
namespace omath::collision namespace omath::collision
{ {
bool LineTracer::CanTraceLine(const Ray &ray, const Triangle3d &triangle) bool LineTracer::CanTraceLine(const Ray& ray, const Triangle<Vector3<float>>& triangle)
{ {
return GetRayHitPoint(ray, triangle) == ray.end; return GetRayHitPoint(ray, triangle) == ray.end;
} }
Vector3 Ray::DirectionVector() const Vector3<float> Ray::DirectionVector() const
{ {
return end - start; return end - start;
} }
Vector3 Ray::DirectionVectorNormalized() const Vector3<float> Ray::DirectionVectorNormalized() const
{ {
return DirectionVector().Normalized(); return DirectionVector().Normalized();
} }
Vector3 LineTracer::GetRayHitPoint(const Ray &ray, const Triangle3d &triangle) Vector3<float> LineTracer::GetRayHitPoint(const Ray& ray, const Triangle<Vector3<float>>& triangle)
{ {
constexpr float kEpsilon = std::numeric_limits<float>::epsilon(); constexpr float kEpsilon = std::numeric_limits<float>::epsilon();
@@ -41,7 +41,7 @@ namespace omath::collision
const auto u = t.Dot(p) * invDet; const auto u = t.Dot(p) * invDet;
if ((u < 0 && std::abs(u) > kEpsilon) || (u > 1 && std::abs(u-1) > kEpsilon)) if ((u < 0 && std::abs(u) > kEpsilon) || (u > 1 && std::abs(u - 1) > kEpsilon))
return ray.end; return ray.end;
const auto q = t.Cross(sideA); const auto q = t.Cross(sideA);
@@ -54,9 +54,14 @@ namespace omath::collision
const auto tHit = sideB.Dot(q) * invDet; const auto tHit = sideB.Dot(q) * invDet;
if (tHit <= kEpsilon) if (ray.infinite_length)
{
if (tHit <= kEpsilon)
return ray.end;
}
else if (tHit <= kEpsilon || tHit > 1.0f - kEpsilon)
return ray.end; return ray.end;
return ray.start + rayDir * tHit; return ray.start + rayDir * tHit;
} }
} } // namespace omath::collision

View File

@@ -2,7 +2,7 @@
// Created by vlad on 2/4/24. // Created by vlad on 2/4/24.
// //
#include "omath/Color.hpp" #include "omath/color.hpp"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>

View File

@@ -1 +1,4 @@
add_subdirectory(Source) add_subdirectory(source_engine)
add_subdirectory(opengl_engine)
add_subdirectory(iw_engine)
add_subdirectory(unity_engine)

View File

@@ -1 +0,0 @@
target_sources(omath PRIVATE Camera.cpp)

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE camera.cpp formulas.cpp)

View File

@@ -0,0 +1,34 @@
//
// Created by Vlad on 3/17/2025.
//
#include "omath/engines/iw_engine/camera.hpp"
#include "omath/engines/iw_engine/formulas.hpp"
namespace omath::iw_engine
{
Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{
}
void Camera::LookAt([[maybe_unused]] const Vector3<float>& target)
{
const float distance = m_origin.DistTo(target);
const auto delta = target - m_origin;
m_viewAngles.pitch = PitchAngle::FromRadians(std::asin(delta.z / distance));
m_viewAngles.yaw = -YawAngle::FromRadians(std::atan2(delta.y, delta.x));
m_viewAngles.roll = RollAngle::FromRadians(0.f);
}
Mat4x4 Camera::CalcViewMatrix() const
{
return iw_engine::CalcViewMatrix(m_viewAngles, m_origin);
}
Mat4x4 Camera::CalcProjectionMatrix() const
{
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
}
} // namespace omath::openg

View File

@@ -0,0 +1,54 @@
//
// Created by Vlad on 3/19/2025.
//
#include "omath/engines/iw_engine/formulas.hpp"
namespace omath::iw_engine
{
Vector3<float> ForwardVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> RightVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> UpVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Mat4x4 RotationMatrix(const ViewAngles& angles)
{
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll);
}
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{
return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
}
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
{
// NOTE: Need magic number to fix fov calculation, since IW engine inherit Quake proj matrix calculation
constexpr auto kMultiplyFactor = 0.75f;
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor;
return {
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0},
};
};
} // namespace omath::iw_engine

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE camera.cpp formulas.cpp)

View File

@@ -0,0 +1,35 @@
//
// Created by Orange on 12/23/2024.
//
#include "omath/engines/opengl_engine/camera.hpp"
#include "omath/engines/opengl_engine/formulas.hpp"
namespace omath::opengl_engine
{
Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{
}
void Camera::LookAt([[maybe_unused]] const Vector3<float>& target)
{
const float distance = m_origin.DistTo(target);
const auto delta = target - m_origin;
m_viewAngles.pitch = PitchAngle::FromRadians(std::asin(delta.z / distance));
m_viewAngles.yaw = -YawAngle::FromRadians(std::atan2(delta.y, delta.x));
m_viewAngles.roll = RollAngle::FromRadians(0.f);
}
Mat4x4 Camera::CalcViewMatrix() const
{
return opengl_engine::CalcViewMatrix(m_viewAngles, m_origin);
}
Mat4x4 Camera::CalcProjectionMatrix() const
{
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
}
} // namespace omath::opengl

View File

@@ -0,0 +1,51 @@
//
// Created by Vlad on 3/19/2025.
//
#include "omath/engines/opengl_engine/formulas.hpp"
namespace omath::opengl_engine
{
Vector3<float> ForwardVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector<float, MatStoreType::COLUMN_MAJOR>(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> RightVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector<float, MatStoreType::COLUMN_MAJOR>(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> UpVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector<float, MatStoreType::COLUMN_MAJOR>(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{
return MatCameraView<float, MatStoreType::COLUMN_MAJOR>(-ForwardVector(angles), RightVector(angles),
UpVector(angles), cam_origin);
}
Mat4x4 RotationMatrix(const ViewAngles& angles)
{
return MatRotationAxisX<float, MatStoreType::COLUMN_MAJOR>(-angles.pitch) *
MatRotationAxisY<float, MatStoreType::COLUMN_MAJOR>(-angles.yaw) *
MatRotationAxisZ<float, MatStoreType::COLUMN_MAJOR>(angles.roll);
}
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0},
{0, 0, -(far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1, 0},
};
}
} // namespace omath::opengl_engine

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE camera.cpp formulas.cpp)

View File

@@ -1,19 +1,19 @@
// //
// Created by Orange on 12/4/2024. // Created by Orange on 12/4/2024.
// //
#include "omath/engines/Source/Camera.hpp" #include "omath/engines/source_engine/camera.hpp"
#include "omath/engines/Source/Formulas.hpp" #include "omath/engines/source_engine/formulas.hpp"
namespace omath::source namespace omath::source_engine
{ {
Camera::Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const projection::FieldOfView& fov, const float near, const float far) : const projection::FieldOfView& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far) projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{ {
} }
void Camera::LookAt(const Vector3& target) void Camera::LookAt(const Vector3<float>& target)
{ {
const float distance = m_origin.DistTo(target); const float distance = m_origin.DistTo(target);
const auto delta = target - m_origin; const auto delta = target - m_origin;
@@ -24,13 +24,14 @@ namespace omath::source
m_viewAngles.roll = RollAngle::FromRadians(0.f); m_viewAngles.roll = RollAngle::FromRadians(0.f);
} }
Mat4x4 Camera::GetViewMatrix() const Mat4x4 Camera::CalcViewMatrix() const
{ {
return CalcViewMatrix(m_viewAngles, m_origin); return source_engine::CalcViewMatrix(m_viewAngles, m_origin);
} }
Mat4x4 Camera::GetProjectionMatrix() const Mat4x4 Camera::CalcProjectionMatrix() const
{ {
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance, m_farPlaneDistance); return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
} }
} // namespace omath::source } // namespace omath::source

View File

@@ -0,0 +1,54 @@
//
// Created by Vlad on 3/19/2025.
//
#include <omath/engines/source_engine/formulas.hpp>
namespace omath::source_engine
{
Vector3<float> ForwardVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Mat4x4 RotationMatrix(const ViewAngles& angles)
{
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll);
}
Vector3<float> RightVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> UpVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{
return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
}
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
{
// NOTE: Need magic number to fix fov calculation, since source inherit Quake proj matrix calculation
constexpr auto kMultiplyFactor = 0.75f;
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor;
return {
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0},
};
}
} // namespace omath::source_engine

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE formulas.cpp camera.cpp)

View File

@@ -0,0 +1,28 @@
//
// Created by Vlad on 3/22/2025.
//
#include <omath/engines/unity_engine/camera.hpp>
#include <omath/engines/unity_engine/formulas.hpp>
namespace omath::unity_engine
{
Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const projection::FieldOfView& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{
}
void Camera::LookAt([[maybe_unused]] const Vector3<float>& target)
{
throw std::runtime_error("Not implemented");
}
Mat4x4 Camera::CalcViewMatrix() const
{
return unity_engine::CalcViewMatrix(m_viewAngles, m_origin);
}
Mat4x4 Camera::CalcProjectionMatrix() const
{
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
}
} // namespace omath::unity_engine

View File

@@ -0,0 +1,51 @@
//
// Created by Vlad on 3/22/2025.
//
#include "omath/engines/unity_engine/formulas.hpp"
namespace omath::unity_engine
{
Vector3<float> ForwardVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> RightVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Vector3<float> UpVector(const ViewAngles& angles)
{
const auto vec = RotationMatrix(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{
return MatCameraView<float, MatStoreType::ROW_MAJOR>(ForwardVector(angles), -RightVector(angles),
UpVector(angles), cam_origin);
}
Mat4x4 RotationMatrix(const ViewAngles& angles)
{
return MatRotationAxisX<float, MatStoreType::ROW_MAJOR>(angles.pitch) *
MatRotationAxisY<float, MatStoreType::ROW_MAJOR>(angles.yaw) *
MatRotationAxisZ<float, MatStoreType::ROW_MAJOR>(angles.roll);
}
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
const float far)
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1.f, 0},
};
}
} // namespace omath::unity_engine

View File

@@ -1,6 +1,6 @@
#include "omath/Matrix.hpp" #include "omath/matrix.hpp"
#include "omath/Angles.hpp" #include "omath/angles.hpp"
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
#include <complex> #include <complex>
@@ -75,6 +75,11 @@ namespace omath
return m_rows; return m_rows;
} }
float& Matrix::operator[](const size_t row, const size_t column)
{
return At(row, column);
}
Matrix::Matrix(Matrix&& other) noexcept Matrix::Matrix(Matrix&& other) noexcept
{ {
m_rows = other.m_rows; m_rows = other.m_rows;
@@ -310,7 +315,7 @@ namespace omath
}; };
} }
Matrix Matrix::TranslationMatrix(const Vector3& diff) Matrix Matrix::TranslationMatrix(const Vector3<float>& diff)
{ {
return { return {
{1.f, 0.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f},
@@ -320,7 +325,7 @@ namespace omath
}; };
} }
Matrix Matrix::OrientationMatrix(const Vector3& forward, const Vector3& right, const Vector3& up) Matrix Matrix::OrientationMatrix(const Vector3<float>& forward, const Vector3<float>& right, const Vector3<float>& up)
{ {
return { return {
{right.x, up.x, forward.x, 0.f}, {right.x, up.x, forward.x, 0.f},

View File

@@ -1,62 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#include "omath/pathfinding/Astar.hpp"
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
namespace omath::pathfinding
{
struct PathNode final
{
std::optional<Vector3> cameFrom;
float gCost = 0.f;
};
std::vector<Vector3> Astar::FindPath(const Vector3 &start, const Vector3 &end, const NavigationMesh &navMesh)
{
std::unordered_map<Vector3, PathNode> closedList;
std::unordered_map<Vector3, PathNode> openList;
const auto startVertex = navMesh.GetClosestVertex(start).value();
const auto endVertex = navMesh.GetClosestVertex(end).value();
openList.emplace(startVertex, PathNode{std::nullopt, 0.f});
while (!openList.empty())
{
const auto perfectVertex = *std::ranges::min_element(openList,
[&endVertex](const auto& a, const auto& b) -> bool
{
const auto aCost = a.second.gCost + a.first.DistTo(endVertex);
const auto bCost = b.second.gCost + b.first.DistTo(endVertex);
return aCost < bCost;
});
closedList.emplace(perfectVertex);
openList.erase(perfectVertex.first);
for (const auto& neighbor : navMesh.GetNeighbors(perfectVertex.first))
if (!closedList.contains(neighbor))
openList.emplace(neighbor, PathNode{perfectVertex.first, neighbor.DistTo(perfectVertex.first) + perfectVertex.second.gCost});
if (perfectVertex.first != endVertex)
continue;
std::vector<Vector3> path = {};
for (std::optional current = perfectVertex.first; current; current = closedList.at(*current).cameFrom )
path.push_back(current.value());
return path;
}
return {};
}
}

View File

@@ -1 +1 @@
target_sources(omath PRIVATE NavigationMesh.cpp Astar.cpp) target_sources(omath PRIVATE navigation_mesh.cpp a_star.cpp)

View File

@@ -0,0 +1,100 @@
//
// Created by Vlad on 28.07.2024.
//
#include "omath/pathfinding/a_star.hpp"
#include <algorithm>
#include <optional>
#include <unordered_map>
#include <unordered_set>
namespace omath::pathfinding
{
struct PathNode final
{
std::optional<Vector3<float>> cameFrom;
float gCost = 0.f;
};
std::vector<Vector3<float>> Astar::ReconstructFinalPath(const std::unordered_map<Vector3<float>, PathNode>& closedList,
const Vector3<float>& current)
{
std::vector<Vector3<float>> path;
std::optional currentOpt = current;
while (currentOpt)
{
path.push_back(*currentOpt);
auto it = closedList.find(*currentOpt);
if (it == closedList.end())
break;
currentOpt = it->second.cameFrom;
}
std::ranges::reverse(path);
return path;
}
auto Astar::GetPerfectNode(const std::unordered_map<Vector3<float>, PathNode>& openList, const Vector3<float>& endVertex)
{
return std::ranges::min_element(openList,
[&endVertex](const auto& a, const auto& b)
{
const float fA = a.second.gCost + a.first.DistTo(endVertex);
const float fB = b.second.gCost + b.first.DistTo(endVertex);
return fA < fB;
});
}
std::vector<Vector3<float>> Astar::FindPath(const Vector3<float>& start, const Vector3<float>& end, const NavigationMesh& navMesh)
{
std::unordered_map<Vector3<float>, PathNode> closedList;
std::unordered_map<Vector3<float>, PathNode> openList;
auto maybeStartVertex = navMesh.GetClosestVertex(start);
auto maybeEndVertex = navMesh.GetClosestVertex(end);
if (!maybeStartVertex || !maybeEndVertex)
return {};
const auto startVertex = maybeStartVertex.value();
const auto endVertex = maybeEndVertex.value();
openList.emplace(startVertex, PathNode{std::nullopt, 0.f});
while (!openList.empty())
{
auto currentIt = GetPerfectNode(openList, endVertex);
const auto current = currentIt->first;
const auto currentNode = currentIt->second;
if (current == endVertex)
return ReconstructFinalPath(closedList, current);
closedList.emplace(current, currentNode);
openList.erase(currentIt);
for (const auto& neighbor: navMesh.GetNeighbors(current))
{
if (closedList.contains(neighbor))
continue;
const float tentativeGCost = currentNode.gCost + neighbor.DistTo(current);
const auto openIt = openList.find(neighbor);
if (openIt == openList.end() || tentativeGCost < openIt->second.gCost)
openList[neighbor] = PathNode{current, tentativeGCost};
}
}
return {};
}
} // namespace omath::pathfinding

View File

@@ -1,13 +1,13 @@
// //
// Created by Vlad on 28.07.2024. // Created by Vlad on 28.07.2024.
// //
#include "omath/pathfinding/NavigationMesh.hpp" #include "omath/pathfinding/navigation_mesh.hpp"
#include <stdexcept>
#include <algorithm> #include <algorithm>
#include <stdexcept>
namespace omath::pathfinding namespace omath::pathfinding
{ {
std::expected<Vector3, std::string> NavigationMesh::GetClosestVertex(const Vector3 &point) const std::expected<Vector3<float>, std::string> NavigationMesh::GetClosestVertex(const Vector3<float> &point) const
{ {
const auto res = std::ranges::min_element(m_verTextMap, const auto res = std::ranges::min_element(m_verTextMap,
[&point](const auto& a, const auto& b) [&point](const auto& a, const auto& b)
@@ -21,7 +21,7 @@ namespace omath::pathfinding
return res->first; return res->first;
} }
const std::vector<Vector3>& NavigationMesh::GetNeighbors(const Vector3 &vertex) const const std::vector<Vector3<float>>& NavigationMesh::GetNeighbors(const Vector3<float> &vertex) const
{ {
return m_verTextMap.at(vertex); return m_verTextMap.at(vertex);
} }
@@ -73,18 +73,18 @@ namespace omath::pathfinding
while (offset < raw.size()) while (offset < raw.size())
{ {
Vector3 vertex; Vector3<float> vertex;
loadFromVector(raw, offset, vertex); loadFromVector(raw, offset, vertex);
uint16_t neighborsCount; uint16_t neighborsCount;
loadFromVector(raw, offset, neighborsCount); loadFromVector(raw, offset, neighborsCount);
std::vector<Vector3> neighbors; std::vector<Vector3<float>> neighbors;
neighbors.reserve(neighborsCount); neighbors.reserve(neighborsCount);
for (size_t i = 0; i < neighborsCount; ++i) for (size_t i = 0; i < neighborsCount; ++i)
{ {
Vector3 neighbor; Vector3<float> neighbor;
loadFromVector(raw, offset, neighbor); loadFromVector(raw, offset, neighbor);
neighbors.push_back(neighbor); neighbors.push_back(neighbor);
} }

View File

@@ -1 +0,0 @@
target_sources(omath PRIVATE Engine.cpp Projectile.cpp Target.cpp)

View File

@@ -1,21 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#include "omath/prediction/Projectile.hpp"
#include <cmath>
#include <omath/engines/Source/Formulas.hpp>
namespace omath::prediction
{
Vector3 Projectile::PredictPosition(const float pitch, const float yaw, const float time, const float gravity) const
{
auto currentPos = m_origin + source::ForwardVector({source::PitchAngle::FromDegrees(-pitch),
source::YawAngle::FromDegrees(yaw),
source::RollAngle::FromDegrees(0)}) *
m_launchSpeed * time;
currentPos.z -= (gravity * m_gravityScale) * (time * time) * 0.5f;
return currentPos;
}
} // namespace omath::prediction

View File

@@ -0,0 +1 @@
target_sources(omath PRIVATE proj_pred_engine_legacy.cpp projectile.cpp target.cpp proj_pred_engine_avx2.cpp proj_pred_engine.cpp)

View File

@@ -0,0 +1,10 @@
//
// Created by Vlad on 2/23/2025.
//
#include "omath/projectile_prediction/proj_pred_engine.hpp"
namespace omath::projectile_prediction
{
} // namespace omath::projectile_prediction

View File

@@ -0,0 +1,152 @@
//
// Created by Vlad on 2/23/2025.
//
#include "omath/projectile_prediction/proj_pred_engine_avx2.hpp"
#include <source_location>
#include <stdexcept>
#if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__)
#include <immintrin.h>
#else
#include <format>
#endif
namespace omath::projectile_prediction
{
std::optional<Vector3<float>>
ProjPredEngineAVX2::MaybeCalculateAimPoint([[maybe_unused]] const Projectile& projectile,
[[maybe_unused]] const Target& target) const
{
#if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__)
const float bulletGravity = m_gravityConstant * projectile.m_gravityScale;
const float v0 = projectile.m_launchSpeed;
const float v0Sqr = v0 * v0;
const Vector3 projOrigin = projectile.m_origin;
constexpr int SIMD_FACTOR = 8;
float currentTime = m_simulationTimeStep;
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR)
{
const __m256 times =
_mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep,
currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3,
currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5,
currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7);
const __m256 targetX =
_mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x));
const __m256 targetY =
_mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y));
const __m256 timesSq = _mm256_mul_ps(times, times);
const __m256 targetZ = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times,
_mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravityConstant), timesSq,
_mm256_set1_ps(target.m_origin.z)));
const __m256 deltaX = _mm256_sub_ps(targetX, _mm256_set1_ps(projOrigin.x));
const __m256 deltaY = _mm256_sub_ps(targetY, _mm256_set1_ps(projOrigin.y));
const __m256 deltaZ = _mm256_sub_ps(targetZ, _mm256_set1_ps(projOrigin.z));
const __m256 dSqr = _mm256_add_ps(_mm256_mul_ps(deltaX, deltaX), _mm256_mul_ps(deltaY, deltaY));
const __m256 bgTimesSq = _mm256_mul_ps(_mm256_set1_ps(bulletGravity), timesSq);
const __m256 term = _mm256_add_ps(deltaZ, _mm256_mul_ps(_mm256_set1_ps(0.5f), bgTimesSq));
const __m256 termSq = _mm256_mul_ps(term, term);
const __m256 numerator = _mm256_add_ps(dSqr, termSq);
const __m256 denominator = _mm256_add_ps(timesSq, _mm256_set1_ps(1e-8f)); // Avoid division by zero
const __m256 requiredV0Sqr = _mm256_div_ps(numerator, denominator);
const __m256 v0SqrVec = _mm256_set1_ps(v0Sqr + 1e-3f);
const __m256 mask = _mm256_cmp_ps(requiredV0Sqr, v0SqrVec, _CMP_LE_OQ);
const unsigned validMask = _mm256_movemask_ps(mask);
if (!validMask)
continue;
alignas(32) float validTimes[SIMD_FACTOR];
_mm256_store_ps(validTimes, times);
for (int i = 0; i < SIMD_FACTOR; ++i)
{
if (!(validMask & (1 << i)))
continue;
const float candidateTime = validTimes[i];
if (candidateTime > m_maximumSimulationTime)
continue;
// Fine search around candidate time
for (float fineTime = candidateTime - m_simulationTimeStep * 2;
fineTime <= candidateTime + m_simulationTimeStep * 2; fineTime += m_simulationTimeStep)
{
if (fineTime < 0)
continue;
const Vector3 targetPos = target.PredictPosition(fineTime, m_gravityConstant);
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, fineTime);
if (!pitch)
continue;
const Vector3 delta = targetPos - projOrigin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height);
}
}
}
// Fallback scalar processing for remaining times
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep)
{
const Vector3 targetPos = target.PredictPosition(currentTime, m_gravityConstant);
const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, currentTime);
if (!pitch)
continue;
const Vector3 delta = targetPos - projOrigin;
const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y);
const float height = d * std::tan(angles::DegreesToRadians(*pitch));
return Vector3(targetPos.x, targetPos.y, projOrigin.z + height);
}
return std::nullopt;
}
ProjPredEngineAVX2::ProjPredEngineAVX2(const float gravityConstant, const float simulationTimeStep,
const float maximumSimulationTime) :
m_gravityConstant(gravityConstant), m_simulationTimeStep(simulationTimeStep),
m_maximumSimulationTime(maximumSimulationTime)
{
}
std::optional<float> ProjPredEngineAVX2::CalculatePitch(const Vector3<float>& projOrigin,
const Vector3<float>& targetPos, const float bulletGravity,
const float v0, const float time)
{
if (time <= 0.0f)
return std::nullopt;
const Vector3 delta = targetPos - projOrigin;
const float dSqr = delta.x * delta.x + delta.y * delta.y;
const float h = delta.z;
const float term = h + 0.5f * bulletGravity * time * time;
const float requiredV0Sqr = (dSqr + term * term) / (time * time);
const float v0Sqr = v0 * v0;
if (requiredV0Sqr > v0Sqr + 1e-3f)
return std::nullopt;
if (dSqr == 0.0f)
return term >= 0.0f ? 90.0f : -90.0f;
const float d = std::sqrt(dSqr);
const float tanTheta = term / d;
return angles::RadiansToDegrees(std::atan(tanTheta));
#else
throw std::runtime_error(
std::format("{} AVX2 feature is not enabled!", std::source_location::current().function_name()));
#endif
}
} // namespace omath::projectile_prediction

View File

@@ -1,25 +1,18 @@
// #include "omath/projectile_prediction/proj_pred_engine_legacy.hpp"
// Created by Vlad on 6/9/2024.
//
#include "omath/prediction/Engine.hpp"
#include <cmath> #include <cmath>
#include <omath/Angles.hpp> #include <omath/angles.hpp>
namespace omath::projectile_prediction
namespace omath::prediction
{ {
Engine::Engine(const float gravityConstant, const float simulationTimeStep, ProjPredEngineLegacy::ProjPredEngineLegacy(const float gravityConstant, const float simulationTimeStep,
const float maximumSimulationTime, const float distanceTolerance) const float maximumSimulationTime, const float distanceTolerance) :
: m_gravityConstant(gravityConstant), m_gravityConstant(gravityConstant), m_simulationTimeStep(simulationTimeStep),
m_simulationTimeStep(simulationTimeStep), m_maximumSimulationTime(maximumSimulationTime), m_distanceTolerance(distanceTolerance)
m_maximumSimulationTime(maximumSimulationTime),
m_distanceTolerance(distanceTolerance)
{ {
} }
std::optional<Vector3> Engine::MaybeCalculateAimPoint(const Projectile &projectile, const Target &target) const std::optional<Vector3<float>> ProjPredEngineLegacy::MaybeCalculateAimPoint(const Projectile& projectile,
const Target& target) const
{ {
for (float time = 0.f; time < m_maximumSimulationTime; time += m_simulationTimeStep) for (float time = 0.f; time < m_maximumSimulationTime; time += m_simulationTimeStep)
{ {
@@ -28,7 +21,7 @@ namespace omath::prediction
const auto projectilePitch = MaybeCalculateProjectileLaunchPitchAngle(projectile, predictedTargetPosition); const auto projectilePitch = MaybeCalculateProjectileLaunchPitchAngle(projectile, predictedTargetPosition);
if (!projectilePitch.has_value()) [[unlikely]] if (!projectilePitch.has_value()) [[unlikely]]
continue; continue;
if (!IsProjectileReachedTarget(predictedTargetPosition, projectile, projectilePitch.value(), time)) if (!IsProjectileReachedTarget(predictedTargetPosition, projectile, projectilePitch.value(), time))
continue; continue;
@@ -41,8 +34,9 @@ namespace omath::prediction
return std::nullopt; return std::nullopt;
} }
std::optional<float> Engine::MaybeCalculateProjectileLaunchPitchAngle(const Projectile &projectile, std::optional<float>
const Vector3 &targetPosition) const ProjPredEngineLegacy::MaybeCalculateProjectileLaunchPitchAngle(const Projectile& projectile,
const Vector3<float>& targetPosition) const
{ {
const auto bulletGravity = m_gravityConstant * projectile.m_gravityScale; const auto bulletGravity = m_gravityConstant * projectile.m_gravityScale;
const auto delta = targetPosition - projectile.m_origin; const auto delta = targetPosition - projectile.m_origin;
@@ -51,11 +45,11 @@ namespace omath::prediction
const auto distance2dSqr = distance2d * distance2d; const auto distance2dSqr = distance2d * distance2d;
const auto launchSpeedSqr = projectile.m_launchSpeed * projectile.m_launchSpeed; const auto launchSpeedSqr = projectile.m_launchSpeed * projectile.m_launchSpeed;
float root = launchSpeedSqr * launchSpeedSqr - bulletGravity * (bulletGravity * float root = launchSpeedSqr * launchSpeedSqr -
distance2dSqr + 2.0f * delta.z * launchSpeedSqr); bulletGravity * (bulletGravity * distance2dSqr + 2.0f * delta.z * launchSpeedSqr);
if (root < 0.0f) [[unlikely]] if (root < 0.0f) [[unlikely]]
return std::nullopt; return std::nullopt;
root = std::sqrt(root); root = std::sqrt(root);
const float angle = std::atan((launchSpeedSqr - root) / (bulletGravity * distance2d)); const float angle = std::atan((launchSpeedSqr - root) / (bulletGravity * distance2d));
@@ -63,12 +57,12 @@ namespace omath::prediction
return angles::RadiansToDegrees(angle); return angles::RadiansToDegrees(angle);
} }
bool Engine::IsProjectileReachedTarget(const Vector3 &targetPosition, const Projectile &projectile, bool ProjPredEngineLegacy::IsProjectileReachedTarget(const Vector3<float>& targetPosition, const Projectile& projectile,
const float pitch, const float time) const const float pitch, const float time) const
{ {
const auto yaw = projectile.m_origin.ViewAngleTo(targetPosition).y; const auto yaw = projectile.m_origin.ViewAngleTo(targetPosition).y;
const auto projectilePosition = projectile.PredictPosition(pitch, yaw, time, m_gravityConstant); const auto projectilePosition = projectile.PredictPosition(pitch, yaw, time, m_gravityConstant);
return projectilePosition.DistTo(targetPosition) <= m_distanceTolerance; return projectilePosition.DistTo(targetPosition) <= m_distanceTolerance;
} }
} } // namespace omath::projectile_prediction

View File

@@ -0,0 +1,21 @@
//
// Created by Vlad on 6/9/2024.
//
#include "omath/projectile_prediction/projectile.hpp"
#include <omath/engines/source_engine/formulas.hpp>
namespace omath::projectile_prediction
{
Vector3<float> Projectile::PredictPosition(const float pitch, const float yaw, const float time, const float gravity) const
{
auto currentPos = m_origin + source_engine::ForwardVector({source_engine::PitchAngle::FromDegrees(-pitch),
source_engine::YawAngle::FromDegrees(yaw),
source_engine::RollAngle::FromDegrees(0)}) *
m_launchSpeed * time;
currentPos.z -= (gravity * m_gravityScale) * (time * time) * 0.5f;
return currentPos;
}
} // namespace omath::prediction

View File

@@ -2,7 +2,7 @@
// Created by Vlad on 6/9/2024. // Created by Vlad on 6/9/2024.
// //
#include "omath/prediction/Target.hpp" #include "omath/projectile_prediction/projectile.hpp"
namespace omath::prediction namespace omath::prediction

View File

@@ -1 +1 @@
target_sources(omath PRIVATE Camera.cpp) target_sources(omath PRIVATE camera.cpp)

View File

@@ -1,7 +1,7 @@
// //
// Created by Vlad on 27.08.2024. // Created by Vlad on 27.08.2024.
// //
#include "omath/projection/Camera.hpp" #include "omath/projection/camera.hpp"
namespace omath::projection namespace omath::projection

View File

@@ -1,30 +1,41 @@
enable_testing() enable_testing()
project(unit-tests) project(unit-tests)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
include(GoogleTest) include(GoogleTest)
add_executable(unit-tests add_executable(unit-tests
general/UnitTestPrediction.cpp general/unit_test_prediction.cpp
general/UnitTestMatrix.cpp general/unit_test_matrix.cpp
general/UnitTestMat.cpp general/unit_test_mat.cpp
general/UnitTestAstar.cpp general/unit_test_a_star.cpp
general/UnitTestProjection.cpp general/unit_test_projection.cpp
general/UnitTestVector3.cpp general/unit_test_vector3.cpp
general/UnitTestVector2.cpp general/unit_test_vector2.cpp
general/UnitTestColor.cpp general/unit_test_color.cpp
general/UnitTestVector4.cpp general/unit_test_vector4.cpp
general/UnitTestLineTrace.cpp general/unit_test_line_trace.cpp
general/UnitTestAngles.cpp general/unit_test_angles.cpp
general/UnitTestViewAngles.cpp general/unit_test_view_angles.cpp
general/UnitTestAngle.cpp general/unit_test_angle.cpp
general/unit_test_triangle.cpp
general/unit_test_box_primitive.cpp
engines/UnitTestOpenGL.cpp engines/unit_test_open_gl.cpp
engines/UnitTestUnityEngine.cpp engines/unit_test_unity_engine.cpp
engines/UnitTestSourceEngine.cpp engines/unit_test_source_engine.cpp
engines/unit_test_iw_engine.cpp
) )
target_link_libraries(unit-tests PRIVATE gtest gtest_main omath) set_target_properties(unit-tests PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
target_link_libraries(unit-tests PRIVATE gtest gtest_main omath::omath)
gtest_discover_tests(unit-tests) gtest_discover_tests(unit-tests)

View File

@@ -1,37 +0,0 @@
//
// Created by Orange on 11/23/2024.
//
#include <complex>
#include <gtest/gtest.h>
#include <omath/Matrix.hpp>
#include <print>
// #include <glm/glm.hpp>
// #include "glm/ext/matrix_clip_space.hpp"
// #include "glm/ext/matrix_transform.hpp"
TEST(UnitTestOpenGL, Projection)
{
/*const auto proj_glm = glm::perspective(glm::radians(90.f), 16.f / 9.f, 0.1f, 1000.f);
// const auto proj_glm2 = glm::perspectiveLH_NO(glm::radians(90.f), 16.f / 9.f, 0.1f, 1000.f);
// const auto proj_omath = omath::Mat<4, 4, float, omath::MatStoreType::COLUMN_MAJOR>((const float*)&proj_glm);
// EXPECT_EQ(omath::opengl::PerspectiveProjectionMatrix(90, 16.f / 9.f, 0.1f, 1000.f), proj_omath);
glm::vec4 ndc_glm2 = proj_glm * glm::vec4(300.f, 0.f, -1000.f, 1.f);
ndc_glm2 /= ndc_glm2.w;
const omath::Mat<4, 1, float, omath::MatStoreType::COLUMN_MAJOR> cords_omath =
{
{0},
{0},
{-0.2f},
{1}
};
//auto ndc_omath = proj_omath * cords_omath;
// ndc_omath /= ndc_omath.At(3, 0);
*/
}

View File

@@ -1,50 +0,0 @@
//
// Created by Orange on 11/23/2024.
//
#include <gtest/gtest.h>
#include <omath/engines/Source/Camera.hpp>
#include <omath/engines/Source/Constants.h>
#include <omath/engines/Source/Formulas.hpp>
TEST(UnitTestSourceEngine, ForwardVector)
{
const auto forward = omath::source::ForwardVector({});
EXPECT_EQ(forward, omath::source::kAbsForward);
}
TEST(UnitTestSourceEngine, RightVector)
{
const auto right = omath::source::RightVector({});
EXPECT_EQ(right, omath::source::kAbsRight);
}
TEST(UnitTestSourceEngine, UpVector)
{
const auto up = omath::source::UpVector({});
EXPECT_EQ(up, omath::source::kAbsUp);
}
TEST(UnitTestSourceEngine, PerpectiveProjectionAtCenter)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::source::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
const auto viewProjMatrix = cam.GetViewProjectionMatrix();
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
{
const auto projected = cam.WorldToScreen(viewProjMatrix, {distance, 0, 0});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_NEAR(projected->x, 960, 0.00001f);
EXPECT_NEAR(projected->y, 540, 0.00001f);
}
}

View File

@@ -1,3 +0,0 @@
//
// Created by Orange on 11/27/2024.
//

View File

@@ -0,0 +1,105 @@
//
// Created by Vlad on 3/17/2025.
//
#include <gtest/gtest.h>
#include <omath/engines/iw_engine/camera.hpp>
#include <omath/engines/iw_engine/constants.hpp>
#include <omath/engines/iw_engine/formulas.hpp>
TEST(UnitTestIwEngine, ForwardVector)
{
const auto forward = omath::iw_engine::ForwardVector({});
EXPECT_EQ(forward, omath::iw_engine::kAbsForward);
}
TEST(UnitTestIwEngine, RightVector)
{
const auto right = omath::iw_engine::RightVector({});
EXPECT_EQ(right, omath::iw_engine::kAbsRight);
}
TEST(UnitTestIwEngine, UpVector)
{
const auto up = omath::iw_engine::UpVector({});
EXPECT_EQ(up, omath::iw_engine::kAbsUp);
}
TEST(UnitTestIwEngine, ForwardVectorRotationYaw)
{
omath::iw_engine::ViewAngles angles;
angles.yaw = omath::iw_engine::YawAngle::FromDegrees(-90.f);
const auto forward = omath::iw_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::iw_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::iw_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::iw_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestIwEngine, ForwardVectorRotationPitch)
{
omath::iw_engine::ViewAngles angles;
angles.pitch = omath::iw_engine::PitchAngle::FromDegrees(-89.f);
const auto forward = omath::iw_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::iw_engine::kAbsUp.x, 0.02f);
EXPECT_NEAR(forward.y, omath::iw_engine::kAbsUp.y, 0.01f);
EXPECT_NEAR(forward.z, omath::iw_engine::kAbsUp.z, 0.01f);
}
TEST(UnitTestIwEngine, ForwardVectorRotationRoll)
{
omath::iw_engine::ViewAngles angles;
angles.roll = omath::iw_engine::RollAngle::FromDegrees(90.f);
const auto forward = omath::iw_engine::UpVector(angles);
EXPECT_NEAR(forward.x, omath::iw_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::iw_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::iw_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestIwEngine, ProjectTargetMovedFromCamera)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(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.WorldToScreen({distance, 0, 0});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_NEAR(projected->x, 960, 0.00001f);
EXPECT_NEAR(projected->y, 540, 0.00001f);
}
}
TEST(UnitTestIwEngine, CameraSetAndGetFov)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}
TEST(UnitTestIwEngine, CameraSetAndGetOrigin)
{
auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}

View File

@@ -0,0 +1,105 @@
//
// Created by Orange on 11/23/2024.
//
#include <gtest/gtest.h>
#include <omath/engines/opengl_engine/camera.hpp>
#include <omath/engines/opengl_engine/constants.hpp>
#include <omath/engines/opengl_engine/formulas.hpp>
TEST(UnitTestOpenGL, ForwardVector)
{
const auto forward = omath::opengl_engine::ForwardVector({});
EXPECT_EQ(forward, omath::opengl_engine::kAbsForward);
}
TEST(UnitTestOpenGL, RightVector)
{
const auto right = omath::opengl_engine::RightVector({});
EXPECT_EQ(right, omath::opengl_engine::kAbsRight);
}
TEST(UnitTestOpenGL, UpVector)
{
const auto up = omath::opengl_engine::UpVector({});
EXPECT_EQ(up, omath::opengl_engine::kAbsUp);
}
TEST(UnitTestOpenGL, ForwardVectorRotationYaw)
{
omath::opengl_engine::ViewAngles angles;
angles.yaw = omath::opengl_engine::YawAngle::FromDegrees(90.f);
const auto forward = omath::opengl_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::opengl_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::opengl_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestOpenGL, ForwardVectorRotationPitch)
{
omath::opengl_engine::ViewAngles angles;
angles.pitch = omath::opengl_engine::PitchAngle::FromDegrees(-90.f);
const auto forward = omath::opengl_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::kAbsUp.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::opengl_engine::kAbsUp.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::opengl_engine::kAbsUp.z, 0.00001f);
}
TEST(UnitTestOpenGL, ForwardVectorRotationRoll)
{
omath::opengl_engine::ViewAngles angles;
angles.roll = omath::opengl_engine::RollAngle::FromDegrees(-90.f);
const auto forward = omath::opengl_engine::UpVector(angles);
EXPECT_NEAR(forward.x, omath::opengl_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::opengl_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::opengl_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestOpenGL, ProjectTargetMovedFromCamera)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(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.WorldToScreen({0, 0, distance});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_NEAR(projected->x, 960, 0.00001f);
EXPECT_NEAR(projected->y, 540, 0.00001f);
}
}
TEST(UnitTestOpenGL, CameraSetAndGetFov)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}
TEST(UnitTestOpenGL, CameraSetAndGetOrigin)
{
auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}

View File

@@ -0,0 +1,125 @@
//
// Created by Orange on 11/23/2024.
//
#include <gtest/gtest.h>
#include <omath/engines/source_engine/camera.hpp>
#include <omath/engines/source_engine/constants.hpp>
#include <omath/engines/source_engine/formulas.hpp>
TEST(UnitTestSourceEngine, ForwardVector)
{
const auto forward = omath::source_engine::ForwardVector({});
EXPECT_EQ(forward, omath::source_engine::kAbsForward);
}
TEST(UnitTestSourceEngine, RightVector)
{
const auto right = omath::source_engine::RightVector({});
EXPECT_EQ(right, omath::source_engine::kAbsRight);
}
TEST(UnitTestSourceEngine, UpVector)
{
const auto up = omath::source_engine::UpVector({});
EXPECT_EQ(up, omath::source_engine::kAbsUp);
}
TEST(UnitTestSourceEngine, ForwardVectorRotationYaw)
{
omath::source_engine::ViewAngles angles;
angles.yaw = omath::source_engine::YawAngle::FromDegrees(-90.f);
const auto forward = omath::source_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::source_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::source_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::source_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestSourceEngine, ForwardVectorRotationPitch)
{
omath::source_engine::ViewAngles angles;
angles.pitch = omath::source_engine::PitchAngle::FromDegrees(-89.f);
const auto forward = omath::source_engine::ForwardVector(angles);
EXPECT_NEAR(forward.x, omath::source_engine::kAbsUp.x, 0.02f);
EXPECT_NEAR(forward.y, omath::source_engine::kAbsUp.y, 0.01f);
EXPECT_NEAR(forward.z, omath::source_engine::kAbsUp.z, 0.01f);
}
TEST(UnitTestSourceEngine, ForwardVectorRotationRoll)
{
omath::source_engine::ViewAngles angles;
angles.roll = omath::source_engine::RollAngle::FromDegrees(90.f);
const auto forward = omath::source_engine::UpVector(angles);
EXPECT_NEAR(forward.x, omath::source_engine::kAbsRight.x, 0.00001f);
EXPECT_NEAR(forward.y, omath::source_engine::kAbsRight.y, 0.00001f);
EXPECT_NEAR(forward.z, omath::source_engine::kAbsRight.z, 0.00001f);
}
TEST(UnitTestSourceEngine, ProjectTargetMovedFromCamera)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(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.WorldToScreen({distance, 0, 0});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_NEAR(projected->x, 960, 0.00001f);
EXPECT_NEAR(projected->y, 540, 0.00001f);
}
}
TEST(UnitTestSourceEngine, ProjectTargetMovedUp)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
const auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
auto prev = 1080.f;
for (float distance = 0.0f; distance < 10.f; distance += 1.f)
{
const auto projected = cam.WorldToScreen({100.f, 0, distance});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_TRUE(projected->y < prev);
prev = projected->y;
}
}
TEST(UnitTestSourceEngine, CameraSetAndGetFov)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}
TEST(UnitTestSourceEngine, CameraSetAndGetOrigin)
{
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}

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